Import qt6-remoteobjects_6.2.4.orig.tar.xz
authorLu YaNing <dluyaning@gmail.com>
Thu, 31 Mar 2022 13:34:25 +0000 (14:34 +0100)
committerLu YaNing <dluyaning@gmail.com>
Thu, 31 Mar 2022 13:34:25 +0000 (14:34 +0100)
[dgit import orig qt6-remoteobjects_6.2.4.orig.tar.xz]

533 files changed:
.QT-ENTERPRISE-LICENSE-AGREEMENT [new file with mode: 0644]
.cmake.conf [new file with mode: 0644]
.qmake.conf [new file with mode: 0644]
.tag [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
LICENSE.FDL [new file with mode: 0644]
LICENSE.GPL2 [new file with mode: 0644]
LICENSE.GPL3 [new file with mode: 0644]
LICENSE.GPL3-EXCEPT [new file with mode: 0644]
LICENSE.LGPL3 [new file with mode: 0644]
coin/module_config.yaml [new file with mode: 0644]
conanfile.py [new file with mode: 0644]
dependencies.yaml [new file with mode: 0644]
dist/changes-5.11.0 [new file with mode: 0644]
dist/changes-5.11.1 [new file with mode: 0644]
dist/changes-5.11.2 [new file with mode: 0644]
dist/changes-5.11.3 [new file with mode: 0644]
dist/changes-5.12.0 [new file with mode: 0644]
dist/changes-5.12.1 [new file with mode: 0644]
dist/changes-5.12.2 [new file with mode: 0644]
dist/changes-5.12.3 [new file with mode: 0644]
dist/changes-5.12.4 [new file with mode: 0644]
dist/changes-5.12.5 [new file with mode: 0644]
dist/changes-5.13.0 [new file with mode: 0644]
dist/changes-5.13.1 [new file with mode: 0644]
dist/changes-5.13.2 [new file with mode: 0644]
dist/changes-5.14.0 [new file with mode: 0644]
dist/changes-5.14.1 [new file with mode: 0644]
dist/changes-5.14.2 [new file with mode: 0644]
dist/changes-5.15.0 [new file with mode: 0644]
dist/changes-5.15.1 [new file with mode: 0644]
examples/CMakeLists.txt [new file with mode: 0644]
examples/examples.pro [new file with mode: 0644]
examples/remoteobjects/.prev_CMakeLists.txt [new file with mode: 0644]
examples/remoteobjects/CMakeLists.txt [new file with mode: 0644]
examples/remoteobjects/clientapp/CMakeLists.txt [new file with mode: 0644]
examples/remoteobjects/clientapp/clientapp.pro [new file with mode: 0644]
examples/remoteobjects/clientapp/clientapp.qrc [new file with mode: 0644]
examples/remoteobjects/clientapp/main.cpp [new file with mode: 0644]
examples/remoteobjects/clientapp/qml/plugins.qml [new file with mode: 0644]
examples/remoteobjects/clientapp/qml/plugins0.qml [new file with mode: 0644]
examples/remoteobjects/clientapp/qml/plugins1.qml [new file with mode: 0644]
examples/remoteobjects/clientapp/qml/plugins2.qml [new file with mode: 0644]
examples/remoteobjects/cppclient/CMakeLists.txt [new file with mode: 0644]
examples/remoteobjects/cppclient/cppclient.pro [new file with mode: 0644]
examples/remoteobjects/cppclient/main.cpp [new file with mode: 0644]
examples/remoteobjects/cppclient/timemodel.rep [new file with mode: 0644]
examples/remoteobjects/modelviewclient/CMakeLists.txt [new file with mode: 0644]
examples/remoteobjects/modelviewclient/doc/src/modelviewclient.qdoc [new file with mode: 0644]
examples/remoteobjects/modelviewclient/main.cpp [new file with mode: 0644]
examples/remoteobjects/modelviewclient/modelviewclient.pro [new file with mode: 0644]
examples/remoteobjects/modelviewserver/CMakeLists.txt [new file with mode: 0644]
examples/remoteobjects/modelviewserver/doc/src/modelviewserver.qdoc [new file with mode: 0644]
examples/remoteobjects/modelviewserver/main.cpp [new file with mode: 0644]
examples/remoteobjects/modelviewserver/modelviewserver.pro [new file with mode: 0644]
examples/remoteobjects/plugins/CMakeLists.txt [new file with mode: 0644]
examples/remoteobjects/plugins/imports/TimeExample/Clock.qml [new file with mode: 0644]
examples/remoteobjects/plugins/imports/TimeExample/center.png [new file with mode: 0644]
examples/remoteobjects/plugins/imports/TimeExample/clock.png [new file with mode: 0644]
examples/remoteobjects/plugins/imports/TimeExample/hour.png [new file with mode: 0644]
examples/remoteobjects/plugins/imports/TimeExample/minute.png [new file with mode: 0644]
examples/remoteobjects/plugins/imports/TimeExample/qmldir [new file with mode: 0644]
examples/remoteobjects/plugins/plugin.cpp [new file with mode: 0644]
examples/remoteobjects/plugins/plugins.pro [new file with mode: 0644]
examples/remoteobjects/plugins/plugins.qml [new file with mode: 0644]
examples/remoteobjects/plugins/plugins0.qml [new file with mode: 0644]
examples/remoteobjects/plugins/plugins1.qml [new file with mode: 0644]
examples/remoteobjects/plugins/plugins2.qml [new file with mode: 0644]
examples/remoteobjects/qmlmodelviewclient/CMakeLists.txt [new file with mode: 0644]
examples/remoteobjects/qmlmodelviewclient/doc/src/qmlmodelviewclient.qdoc [new file with mode: 0644]
examples/remoteobjects/qmlmodelviewclient/main.cpp [new file with mode: 0644]
examples/remoteobjects/qmlmodelviewclient/main.qml [new file with mode: 0644]
examples/remoteobjects/qmlmodelviewclient/qml.qrc [new file with mode: 0644]
examples/remoteobjects/qmlmodelviewclient/qmlmodelviewclient.pro [new file with mode: 0644]
examples/remoteobjects/remoteobjects.pro [new file with mode: 0644]
examples/remoteobjects/remoteobjects_server/CMakeLists.txt [new file with mode: 0644]
examples/remoteobjects/remoteobjects_server/main.cpp [new file with mode: 0644]
examples/remoteobjects/remoteobjects_server/remoteobjects_server.pro [new file with mode: 0644]
examples/remoteobjects/remoteobjects_server/timemodel.cpp [new file with mode: 0644]
examples/remoteobjects/remoteobjects_server/timemodel.h [new file with mode: 0644]
examples/remoteobjects/simpleswitch/CMakeLists.txt [new file with mode: 0644]
examples/remoteobjects/simpleswitch/directconnectclient/CMakeLists.txt [new file with mode: 0644]
examples/remoteobjects/simpleswitch/directconnectclient/client.cpp [new file with mode: 0644]
examples/remoteobjects/simpleswitch/directconnectclient/client.h [new file with mode: 0644]
examples/remoteobjects/simpleswitch/directconnectclient/directconnectclient.pro [new file with mode: 0644]
examples/remoteobjects/simpleswitch/directconnectclient/main.cpp [new file with mode: 0644]
examples/remoteobjects/simpleswitch/directconnectclient/simpleswitch.rep [new file with mode: 0644]
examples/remoteobjects/simpleswitch/directconnectdynamicclient/CMakeLists.txt [new file with mode: 0644]
examples/remoteobjects/simpleswitch/directconnectdynamicclient/directconnectdynamicclient.pro [new file with mode: 0644]
examples/remoteobjects/simpleswitch/directconnectdynamicclient/dynamicclient.cpp [new file with mode: 0644]
examples/remoteobjects/simpleswitch/directconnectdynamicclient/dynamicclient.h [new file with mode: 0644]
examples/remoteobjects/simpleswitch/directconnectdynamicclient/main.cpp [new file with mode: 0644]
examples/remoteobjects/simpleswitch/directconnectserver/CMakeLists.txt [new file with mode: 0644]
examples/remoteobjects/simpleswitch/directconnectserver/directconnectserver.pro [new file with mode: 0644]
examples/remoteobjects/simpleswitch/directconnectserver/main.cpp [new file with mode: 0644]
examples/remoteobjects/simpleswitch/directconnectserver/simpleswitch.cpp [new file with mode: 0644]
examples/remoteobjects/simpleswitch/directconnectserver/simpleswitch.h [new file with mode: 0644]
examples/remoteobjects/simpleswitch/directconnectserver/simpleswitch.rep [new file with mode: 0644]
examples/remoteobjects/simpleswitch/registryconnectedclient/CMakeLists.txt [new file with mode: 0644]
examples/remoteobjects/simpleswitch/registryconnectedclient/dynamicclient.cpp [new file with mode: 0644]
examples/remoteobjects/simpleswitch/registryconnectedclient/dynamicclient.h [new file with mode: 0644]
examples/remoteobjects/simpleswitch/registryconnectedclient/main.cpp [new file with mode: 0644]
examples/remoteobjects/simpleswitch/registryconnectedclient/registryconnectedclient.pro [new file with mode: 0644]
examples/remoteobjects/simpleswitch/registryconnectedserver/CMakeLists.txt [new file with mode: 0644]
examples/remoteobjects/simpleswitch/registryconnectedserver/main.cpp [new file with mode: 0644]
examples/remoteobjects/simpleswitch/registryconnectedserver/registryconnectedserver.pro [new file with mode: 0644]
examples/remoteobjects/simpleswitch/registryconnectedserver/simpleswitch.cpp [new file with mode: 0644]
examples/remoteobjects/simpleswitch/registryconnectedserver/simpleswitch.h [new file with mode: 0644]
examples/remoteobjects/simpleswitch/registryconnectedserver/simpleswitch.rep [new file with mode: 0644]
examples/remoteobjects/simpleswitch/simpleswitch.pro [new file with mode: 0644]
examples/remoteobjects/ssl/CMakeLists.txt [new file with mode: 0644]
examples/remoteobjects/ssl/doc/src/ssl.qdoc [new file with mode: 0644]
examples/remoteobjects/ssl/ssl.pro [new file with mode: 0644]
examples/remoteobjects/ssl/sslcppclient/CMakeLists.txt [new file with mode: 0644]
examples/remoteobjects/ssl/sslcppclient/main.cpp [new file with mode: 0644]
examples/remoteobjects/ssl/sslcppclient/sslcppclient.pro [new file with mode: 0644]
examples/remoteobjects/ssl/sslcppclient/timemodel.rep [new file with mode: 0644]
examples/remoteobjects/ssl/sslserver/CMakeLists.txt [new file with mode: 0644]
examples/remoteobjects/ssl/sslserver/cert/cert.qrc [new file with mode: 0644]
examples/remoteobjects/ssl/sslserver/cert/client.crt [new file with mode: 0644]
examples/remoteobjects/ssl/sslserver/cert/client.key [new file with mode: 0644]
examples/remoteobjects/ssl/sslserver/cert/readme [new file with mode: 0644]
examples/remoteobjects/ssl/sslserver/cert/rootCA.key [new file with mode: 0644]
examples/remoteobjects/ssl/sslserver/cert/rootCA.pem [new file with mode: 0644]
examples/remoteobjects/ssl/sslserver/cert/rootCA.srl [new file with mode: 0644]
examples/remoteobjects/ssl/sslserver/cert/server.crt [new file with mode: 0644]
examples/remoteobjects/ssl/sslserver/cert/server.key [new file with mode: 0644]
examples/remoteobjects/ssl/sslserver/main.cpp [new file with mode: 0644]
examples/remoteobjects/ssl/sslserver/sslserver.cpp [new file with mode: 0644]
examples/remoteobjects/ssl/sslserver/sslserver.h [new file with mode: 0644]
examples/remoteobjects/ssl/sslserver/sslserver.pro [new file with mode: 0644]
examples/remoteobjects/ssl/sslserver/timemodel.cpp [new file with mode: 0644]
examples/remoteobjects/ssl/sslserver/timemodel.h [new file with mode: 0644]
examples/remoteobjects/timemodel.rep [new file with mode: 0644]
examples/remoteobjects/websockets/CMakeLists.txt [new file with mode: 0644]
examples/remoteobjects/websockets/common/cert/cert.qrc [new file with mode: 0644]
examples/remoteobjects/websockets/common/cert/client.crt [new file with mode: 0644]
examples/remoteobjects/websockets/common/cert/client.key [new file with mode: 0644]
examples/remoteobjects/websockets/common/cert/readme [new file with mode: 0644]
examples/remoteobjects/websockets/common/cert/rootCA.key [new file with mode: 0644]
examples/remoteobjects/websockets/common/cert/rootCA.pem [new file with mode: 0644]
examples/remoteobjects/websockets/common/cert/rootCA.srl [new file with mode: 0644]
examples/remoteobjects/websockets/common/cert/server.crt [new file with mode: 0644]
examples/remoteobjects/websockets/common/cert/server.key [new file with mode: 0644]
examples/remoteobjects/websockets/common/common.pri [new file with mode: 0644]
examples/remoteobjects/websockets/common/websocketiodevice.cpp [new file with mode: 0644]
examples/remoteobjects/websockets/common/websocketiodevice.h [new file with mode: 0644]
examples/remoteobjects/websockets/doc/src/websocket.qdoc [new file with mode: 0644]
examples/remoteobjects/websockets/websockets.pro [new file with mode: 0644]
examples/remoteobjects/websockets/wsclient/CMakeLists.txt [new file with mode: 0644]
examples/remoteobjects/websockets/wsclient/main.cpp [new file with mode: 0644]
examples/remoteobjects/websockets/wsclient/wsclient.pro [new file with mode: 0644]
examples/remoteobjects/websockets/wsserver/CMakeLists.txt [new file with mode: 0644]
examples/remoteobjects/websockets/wsserver/main.cpp [new file with mode: 0644]
examples/remoteobjects/websockets/wsserver/wsserver.pro [new file with mode: 0644]
include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qconnection_local_backend_p.h [new file with mode: 0644]
include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qconnection_qnx_backend_p.h [new file with mode: 0644]
include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qconnection_qnx_global_p.h [new file with mode: 0644]
include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qconnection_qnx_qiodevices_p.h [new file with mode: 0644]
include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qconnection_qnx_server_p.h [new file with mode: 0644]
include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qconnection_tcpip_backend_p.h [new file with mode: 0644]
include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qconnectionfactories_p.h [new file with mode: 0644]
include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectabstractitemmodeladapter_p.h [new file with mode: 0644]
include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectabstractitemmodelreplica_p.h [new file with mode: 0644]
include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectabstractitemmodeltypes_p.h [new file with mode: 0644]
include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectcontainers_p.h [new file with mode: 0644]
include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectnode_p.h [new file with mode: 0644]
include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectpacket_p.h [new file with mode: 0644]
include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectpendingcall_p.h [new file with mode: 0644]
include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectregistrysource_p.h [new file with mode: 0644]
include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectreplica_p.h [new file with mode: 0644]
include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectsource_p.h [new file with mode: 0644]
include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectsourceio_p.h [new file with mode: 0644]
include/QtRemoteObjects/QAbstractItemModelReplica [new file with mode: 0644]
include/QtRemoteObjects/QConnectionAbstractServer [new file with mode: 0644]
include/QtRemoteObjects/QIOQnxSource [new file with mode: 0644]
include/QtRemoteObjects/QIntHash [new file with mode: 0644]
include/QtRemoteObjects/QQnxNativeIo [new file with mode: 0644]
include/QtRemoteObjects/QQnxNativeServer [new file with mode: 0644]
include/QtRemoteObjects/QRemoteObjectAbstractPersistedStore [new file with mode: 0644]
include/QtRemoteObjects/QRemoteObjectDynamicReplica [new file with mode: 0644]
include/QtRemoteObjects/QRemoteObjectHost [new file with mode: 0644]
include/QtRemoteObjects/QRemoteObjectHostBase [new file with mode: 0644]
include/QtRemoteObjects/QRemoteObjectNode [new file with mode: 0644]
include/QtRemoteObjects/QRemoteObjectPendingCall [new file with mode: 0644]
include/QtRemoteObjects/QRemoteObjectPendingCallWatcher [new file with mode: 0644]
include/QtRemoteObjects/QRemoteObjectPendingReply [new file with mode: 0644]
include/QtRemoteObjects/QRemoteObjectRegistry [new file with mode: 0644]
include/QtRemoteObjects/QRemoteObjectRegistryHost [new file with mode: 0644]
include/QtRemoteObjects/QRemoteObjectReplica [new file with mode: 0644]
include/QtRemoteObjects/QRemoteObjectSettingsStore [new file with mode: 0644]
include/QtRemoteObjects/QRemoteObjectSourceLocation [new file with mode: 0644]
include/QtRemoteObjects/QRemoteObjectSourceLocationInfo [new file with mode: 0644]
include/QtRemoteObjects/QRemoteObjectSourceLocations [new file with mode: 0644]
include/QtRemoteObjects/QtROClientFactory [new file with mode: 0644]
include/QtRemoteObjects/QtROClientIoDevice [new file with mode: 0644]
include/QtRemoteObjects/QtROIoDeviceBase [new file with mode: 0644]
include/QtRemoteObjects/QtROServerFactory [new file with mode: 0644]
include/QtRemoteObjects/QtROServerIoDevice [new file with mode: 0644]
include/QtRemoteObjects/QtRemoteObjects [new file with mode: 0644]
include/QtRemoteObjects/QtRemoteObjectsVersion [new file with mode: 0644]
include/QtRemoteObjects/headers.pri [new file with mode: 0644]
include/QtRemoteObjects/qconnection_qnx_qiodevices.h [new file with mode: 0644]
include/QtRemoteObjects/qconnection_qnx_server.h [new file with mode: 0644]
include/QtRemoteObjects/qconnectionfactories.h [new file with mode: 0644]
include/QtRemoteObjects/qremoteobjectabstractitemmodelreplica.h [new file with mode: 0644]
include/QtRemoteObjects/qremoteobjectdynamicreplica.h [new file with mode: 0644]
include/QtRemoteObjects/qremoteobjectnode.h [new file with mode: 0644]
include/QtRemoteObjects/qremoteobjectpendingcall.h [new file with mode: 0644]
include/QtRemoteObjects/qremoteobjectregistry.h [new file with mode: 0644]
include/QtRemoteObjects/qremoteobjectreplica.h [new file with mode: 0644]
include/QtRemoteObjects/qremoteobjectsettingsstore.h [new file with mode: 0644]
include/QtRemoteObjects/qremoteobjectsource.h [new file with mode: 0644]
include/QtRemoteObjects/qtremoteobjectglobal.h [new file with mode: 0644]
include/QtRemoteObjects/qtremoteobjectsversion.h [new file with mode: 0644]
include/QtRemoteObjectsQml/6.2.4/QtRemoteObjectsQml/private/qremoteobjectsqml_p.h [new file with mode: 0644]
include/QtRemoteObjectsQml/QtRemoteObjectsQml [new file with mode: 0644]
include/QtRemoteObjectsQml/QtRemoteObjectsQmlVersion [new file with mode: 0644]
include/QtRemoteObjectsQml/headers.pri [new file with mode: 0644]
include/QtRemoteObjectsQml/qtremoteobjectsqmlversion.h [new file with mode: 0644]
include/QtRepParser/QRegexParser [new file with mode: 0644]
include/QtRepParser/QtRepParser [new file with mode: 0644]
include/QtRepParser/QtRepParserVersion [new file with mode: 0644]
include/QtRepParser/headers.pri [new file with mode: 0644]
include/QtRepParser/qregexparser.h [new file with mode: 0644]
include/QtRepParser/qtrepparserversion.h [new file with mode: 0644]
mkspecs/features/features.pro [new file with mode: 0644]
mkspecs/features/remoteobjects_repc.prf [new file with mode: 0644]
mkspecs/features/repcclient.pri [new file with mode: 0644]
mkspecs/features/repccommon.pri [new file with mode: 0644]
mkspecs/features/repcmerged.pri [new file with mode: 0644]
mkspecs/features/repcserver.pri [new file with mode: 0644]
mkspecs/features/repparser.prf [new file with mode: 0644]
mkspecs/mkspecs.pro [new file with mode: 0644]
src/CMakeLists.txt [new file with mode: 0644]
src/remoteobjects/CMakeLists.txt [new file with mode: 0644]
src/remoteobjects/Qt5RemoteObjectsConfigExtras.cmake.in [new file with mode: 0644]
src/remoteobjects/Qt6RemoteObjectsMacros.cmake [new file with mode: 0644]
src/remoteobjects/configure.cmake [new file with mode: 0644]
src/remoteobjects/doc/images/DirectConnectClientServerOutput.png [new file with mode: 0644]
src/remoteobjects/doc/images/DirectConnectServerOutput.png [new file with mode: 0644]
src/remoteobjects/doc/images/README [new file with mode: 0644]
src/remoteobjects/doc/images/RemoteObjectsHighLevel.png [new file with mode: 0644]
src/remoteobjects/doc/qtremoteobjects.qdocconf [new file with mode: 0644]
src/remoteobjects/doc/snippets/README [new file with mode: 0644]
src/remoteobjects/doc/snippets/cmake-macros/CMakeLists.txt [new file with mode: 0644]
src/remoteobjects/doc/snippets/cmake-macros/main.cpp [new file with mode: 0644]
src/remoteobjects/doc/snippets/cmake-macros/simpleswitch.cpp [new file with mode: 0644]
src/remoteobjects/doc/snippets/cmake-macros/simpleswitch.h [new file with mode: 0644]
src/remoteobjects/doc/snippets/cmake-macros/simpleswitch.rep [new file with mode: 0644]
src/remoteobjects/doc/snippets/doc_src_remoteobjects.h [new file with mode: 0644]
src/remoteobjects/doc/snippets/doc_src_simpleswitch.cpp [new file with mode: 0644]
src/remoteobjects/doc/src/cmake-macros.qdoc [new file with mode: 0644]
src/remoteobjects/doc/src/qt6-changes.qdoc [new file with mode: 0644]
src/remoteobjects/doc/src/remoteobjects-compatibility.qdoc [new file with mode: 0644]
src/remoteobjects/doc/src/remoteobjects-cpp.qdoc [new file with mode: 0644]
src/remoteobjects/doc/src/remoteobjects-custom-transport.qdoc [new file with mode: 0644]
src/remoteobjects/doc/src/remoteobjects-example-dynamic-replica.qdoc [new file with mode: 0644]
src/remoteobjects/doc/src/remoteobjects-example-registry.qdoc [new file with mode: 0644]
src/remoteobjects/doc/src/remoteobjects-example-static-source.qdoc [new file with mode: 0644]
src/remoteobjects/doc/src/remoteobjects-external-schemas.qdoc [new file with mode: 0644]
src/remoteobjects/doc/src/remoteobjects-gettingstarted.qdoc [new file with mode: 0644]
src/remoteobjects/doc/src/remoteobjects-index.qdoc [new file with mode: 0644]
src/remoteobjects/doc/src/remoteobjects-interaction.qdoc [new file with mode: 0644]
src/remoteobjects/doc/src/remoteobjects-nodes.qdoc [new file with mode: 0644]
src/remoteobjects/doc/src/remoteobjects-qml.qdoc [new file with mode: 0644]
src/remoteobjects/doc/src/remoteobjects-registry.qdoc [new file with mode: 0644]
src/remoteobjects/doc/src/remoteobjects-repc.qdoc [new file with mode: 0644]
src/remoteobjects/doc/src/remoteobjects-replica.qdoc [new file with mode: 0644]
src/remoteobjects/doc/src/remoteobjects-source.qdoc [new file with mode: 0644]
src/remoteobjects/doc/src/remoteobjects-troubleshooting.qdoc [new file with mode: 0644]
src/remoteobjects/qconnection_local_backend.cpp [new file with mode: 0644]
src/remoteobjects/qconnection_local_backend_p.h [new file with mode: 0644]
src/remoteobjects/qconnection_qnx_backend.cpp [new file with mode: 0644]
src/remoteobjects/qconnection_qnx_backend_p.h [new file with mode: 0644]
src/remoteobjects/qconnection_qnx_global_p.h [new file with mode: 0644]
src/remoteobjects/qconnection_qnx_qiodevices.cpp [new file with mode: 0644]
src/remoteobjects/qconnection_qnx_qiodevices.h [new file with mode: 0644]
src/remoteobjects/qconnection_qnx_qiodevices_p.h [new file with mode: 0644]
src/remoteobjects/qconnection_qnx_server.cpp [new file with mode: 0644]
src/remoteobjects/qconnection_qnx_server.h [new file with mode: 0644]
src/remoteobjects/qconnection_qnx_server_p.h [new file with mode: 0644]
src/remoteobjects/qconnection_tcpip_backend.cpp [new file with mode: 0644]
src/remoteobjects/qconnection_tcpip_backend_p.h [new file with mode: 0644]
src/remoteobjects/qconnectionfactories.cpp [new file with mode: 0644]
src/remoteobjects/qconnectionfactories.h [new file with mode: 0644]
src/remoteobjects/qconnectionfactories_p.h [new file with mode: 0644]
src/remoteobjects/qremoteobjectabstractitemmodeladapter.cpp [new file with mode: 0644]
src/remoteobjects/qremoteobjectabstractitemmodeladapter_p.h [new file with mode: 0644]
src/remoteobjects/qremoteobjectabstractitemmodelreplica.cpp [new file with mode: 0644]
src/remoteobjects/qremoteobjectabstractitemmodelreplica.h [new file with mode: 0644]
src/remoteobjects/qremoteobjectabstractitemmodelreplica_p.h [new file with mode: 0644]
src/remoteobjects/qremoteobjectabstractitemmodeltypes_p.h [new file with mode: 0644]
src/remoteobjects/qremoteobjectcontainers.cpp [new file with mode: 0644]
src/remoteobjects/qremoteobjectcontainers_p.h [new file with mode: 0644]
src/remoteobjects/qremoteobjectdynamicreplica.cpp [new file with mode: 0644]
src/remoteobjects/qremoteobjectdynamicreplica.h [new file with mode: 0644]
src/remoteobjects/qremoteobjectnode.cpp [new file with mode: 0644]
src/remoteobjects/qremoteobjectnode.h [new file with mode: 0644]
src/remoteobjects/qremoteobjectnode_p.h [new file with mode: 0644]
src/remoteobjects/qremoteobjectpacket.cpp [new file with mode: 0644]
src/remoteobjects/qremoteobjectpacket_p.h [new file with mode: 0644]
src/remoteobjects/qremoteobjectpendingcall.cpp [new file with mode: 0644]
src/remoteobjects/qremoteobjectpendingcall.h [new file with mode: 0644]
src/remoteobjects/qremoteobjectpendingcall_p.h [new file with mode: 0644]
src/remoteobjects/qremoteobjectregistry.cpp [new file with mode: 0644]
src/remoteobjects/qremoteobjectregistry.h [new file with mode: 0644]
src/remoteobjects/qremoteobjectregistrysource.cpp [new file with mode: 0644]
src/remoteobjects/qremoteobjectregistrysource_p.h [new file with mode: 0644]
src/remoteobjects/qremoteobjectreplica.cpp [new file with mode: 0644]
src/remoteobjects/qremoteobjectreplica.h [new file with mode: 0644]
src/remoteobjects/qremoteobjectreplica_p.h [new file with mode: 0644]
src/remoteobjects/qremoteobjectsettingsstore.cpp [new file with mode: 0644]
src/remoteobjects/qremoteobjectsettingsstore.h [new file with mode: 0644]
src/remoteobjects/qremoteobjectsource.cpp [new file with mode: 0644]
src/remoteobjects/qremoteobjectsource.h [new file with mode: 0644]
src/remoteobjects/qremoteobjectsource_p.h [new file with mode: 0644]
src/remoteobjects/qremoteobjectsourceio.cpp [new file with mode: 0644]
src/remoteobjects/qremoteobjectsourceio_p.h [new file with mode: 0644]
src/remoteobjects/qtremoteobjectglobal.cpp [new file with mode: 0644]
src/remoteobjects/qtremoteobjectglobal.h [new file with mode: 0644]
src/remoteobjectsqml/CMakeLists.txt [new file with mode: 0644]
src/remoteobjectsqml/qremoteobjectsqml_p.h [new file with mode: 0644]
src/repparser/CMakeLists.txt [new file with mode: 0644]
src/repparser/parser.g [new file with mode: 0644]
src/repparser/qregexparser.h [new file with mode: 0644]
sync.profile [new file with mode: 0644]
tests/CMakeLists.txt [new file with mode: 0644]
tests/auto/CMakeLists.txt [new file with mode: 0644]
tests/auto/benchmarks/CMakeLists.txt [new file with mode: 0644]
tests/auto/benchmarks/tst_benchmarkstest.cpp [new file with mode: 0644]
tests/auto/bic/data/QtRemoteObjects.5.13.0.linux-gcc-amd64.txt [new file with mode: 0644]
tests/auto/bic/data/QtRemoteObjects.5.14.0.linux-gcc-amd64.txt [new file with mode: 0644]
tests/auto/cmake/CMakeLists.txt [new file with mode: 0644]
tests/auto/cmake/test_cmake_macros/CMakeLists.txt [new file with mode: 0644]
tests/auto/cmake/test_cmake_macros/main.cpp [new file with mode: 0644]
tests/auto/external_IODevice/CMakeLists.txt [new file with mode: 0644]
tests/auto/external_IODevice/cert/cert.qrc [new file with mode: 0644]
tests/auto/external_IODevice/cert/client.crt [new file with mode: 0644]
tests/auto/external_IODevice/cert/client.key [new file with mode: 0644]
tests/auto/external_IODevice/cert/generate.sh [new file with mode: 0644]
tests/auto/external_IODevice/cert/rootCA.key [new file with mode: 0644]
tests/auto/external_IODevice/cert/rootCA.pem [new file with mode: 0644]
tests/auto/external_IODevice/cert/rootCA.srl [new file with mode: 0644]
tests/auto/external_IODevice/cert/server-req.ext [new file with mode: 0644]
tests/auto/external_IODevice/cert/server.crt [new file with mode: 0644]
tests/auto/external_IODevice/cert/server.key [new file with mode: 0644]
tests/auto/external_IODevice/pingpong.rep [new file with mode: 0644]
tests/auto/external_IODevice/sslTestServer/CMakeLists.txt [new file with mode: 0644]
tests/auto/external_IODevice/sslTestServer/main.cpp [new file with mode: 0644]
tests/auto/external_IODevice/sslTestServer/pingpong.cpp [new file with mode: 0644]
tests/auto/external_IODevice/sslTestServer/pingpong.h [new file with mode: 0644]
tests/auto/external_IODevice/sslTestServer/sslserver.cpp [new file with mode: 0644]
tests/auto/external_IODevice/sslTestServer/sslserver.h [new file with mode: 0644]
tests/auto/external_IODevice/tst_client/CMakeLists.txt [new file with mode: 0644]
tests/auto/external_IODevice/tst_client/tst_client.cpp [new file with mode: 0644]
tests/auto/integration/CMakeLists.txt [new file with mode: 0644]
tests/auto/integration/engine.cpp [new file with mode: 0644]
tests/auto/integration/engine.h [new file with mode: 0644]
tests/auto/integration/engine.rep [new file with mode: 0644]
tests/auto/integration/enum.rep [new file with mode: 0644]
tests/auto/integration/pod.rep [new file with mode: 0644]
tests/auto/integration/speedometer.cpp [new file with mode: 0644]
tests/auto/integration/speedometer.h [new file with mode: 0644]
tests/auto/integration/speedometer.rep [new file with mode: 0644]
tests/auto/integration/temperature.h [new file with mode: 0644]
tests/auto/integration/tst_integration.cpp [new file with mode: 0644]
tests/auto/integration_external/CMakeLists.txt [new file with mode: 0644]
tests/auto/integration_external/MyInterface.rep [new file with mode: 0644]
tests/auto/integration_external/client/CMakeLists.txt [new file with mode: 0644]
tests/auto/integration_external/client/main.cpp [new file with mode: 0644]
tests/auto/integration_external/external/CMakeLists.txt [new file with mode: 0644]
tests/auto/integration_external/external/tst_integration_external.cpp [new file with mode: 0644]
tests/auto/integration_external/server/CMakeLists.txt [new file with mode: 0644]
tests/auto/integration_external/server/main.cpp [new file with mode: 0644]
tests/auto/integration_external/server/mytestserver.cpp [new file with mode: 0644]
tests/auto/integration_external/server/mytestserver.h [new file with mode: 0644]
tests/auto/integration_multiprocess/CMakeLists.txt [new file with mode: 0644]
tests/auto/integration_multiprocess/ExtPodInterface.rep [new file with mode: 0644]
tests/auto/integration_multiprocess/MyInterface.rep [new file with mode: 0644]
tests/auto/integration_multiprocess/PodInterface.rep [new file with mode: 0644]
tests/auto/integration_multiprocess/client/CMakeLists.txt [new file with mode: 0644]
tests/auto/integration_multiprocess/client/main.cpp [new file with mode: 0644]
tests/auto/integration_multiprocess/server/CMakeLists.txt [new file with mode: 0644]
tests/auto/integration_multiprocess/server/main.cpp [new file with mode: 0644]
tests/auto/integration_multiprocess/server/mytestserver.cpp [new file with mode: 0644]
tests/auto/integration_multiprocess/server/mytestserver.h [new file with mode: 0644]
tests/auto/integration_multiprocess/tst/CMakeLists.txt [new file with mode: 0644]
tests/auto/integration_multiprocess/tst/tst_integration_multiprocess.cpp [new file with mode: 0644]
tests/auto/localsockettestserver/CMakeLists.txt [new file with mode: 0644]
tests/auto/localsockettestserver/main.cpp [new file with mode: 0644]
tests/auto/modelreplica/CMakeLists.txt [new file with mode: 0644]
tests/auto/modelreplica/model.rep [new file with mode: 0644]
tests/auto/modelreplica/tst_modelreplicatest.cpp [new file with mode: 0644]
tests/auto/modelview/CMakeLists.txt [new file with mode: 0644]
tests/auto/modelview/tst_modelview.cpp [new file with mode: 0644]
tests/auto/pods/CMakeLists.txt [new file with mode: 0644]
tests/auto/pods/pods.h [new file with mode: 0644]
tests/auto/pods/tst_pods.cpp [new file with mode: 0644]
tests/auto/proxy/CMakeLists.txt [new file with mode: 0644]
tests/auto/proxy/engine.rep [new file with mode: 0644]
tests/auto/proxy/subclass.rep [new file with mode: 0644]
tests/auto/proxy/tst_proxy.cpp [new file with mode: 0644]
tests/auto/proxy_multiprocess/CMakeLists.txt [new file with mode: 0644]
tests/auto/proxy_multiprocess/client/CMakeLists.txt [new file with mode: 0644]
tests/auto/proxy_multiprocess/client/main.cpp [new file with mode: 0644]
tests/auto/proxy_multiprocess/namespace.h [new file with mode: 0644]
tests/auto/proxy_multiprocess/proxy/CMakeLists.txt [new file with mode: 0644]
tests/auto/proxy_multiprocess/proxy/main.cpp [new file with mode: 0644]
tests/auto/proxy_multiprocess/server/CMakeLists.txt [new file with mode: 0644]
tests/auto/proxy_multiprocess/server/main.cpp [new file with mode: 0644]
tests/auto/proxy_multiprocess/server/mytestserver.cpp [new file with mode: 0644]
tests/auto/proxy_multiprocess/server/mytestserver.h [new file with mode: 0644]
tests/auto/proxy_multiprocess/shared.h [new file with mode: 0644]
tests/auto/proxy_multiprocess/subclass.rep [new file with mode: 0644]
tests/auto/proxy_multiprocess/tst/CMakeLists.txt [new file with mode: 0644]
tests/auto/proxy_multiprocess/tst/tst_proxy_multiprocess.cpp [new file with mode: 0644]
tests/auto/qml/CMakeLists.txt [new file with mode: 0644]
tests/auto/qml/integration/CMakeLists.txt [new file with mode: 0644]
tests/auto/qml/integration/data/tst_integration.qml [new file with mode: 0644]
tests/auto/qml/integration/tst_integration.cpp [new file with mode: 0644]
tests/auto/qml/usertypes/CMakeLists.txt [new file with mode: 0644]
tests/auto/qml/usertypes/data/MyType.qml [new file with mode: 0644]
tests/auto/qml/usertypes/data/complex.qml [new file with mode: 0644]
tests/auto/qml/usertypes/data/composite.qml [new file with mode: 0644]
tests/auto/qml/usertypes/data/extraPropComplex.qml [new file with mode: 0644]
tests/auto/qml/usertypes/data/extraprop.qml [new file with mode: 0644]
tests/auto/qml/usertypes/data/extraprop2.qml [new file with mode: 0644]
tests/auto/qml/usertypes/data/hosted.qml [new file with mode: 0644]
tests/auto/qml/usertypes/data/model.qml [new file with mode: 0644]
tests/auto/qml/usertypes/data/subObject.qml [new file with mode: 0644]
tests/auto/qml/usertypes/data/twoReplicas.qml [new file with mode: 0644]
tests/auto/qml/usertypes/data/watcher.qml [new file with mode: 0644]
tests/auto/qml/usertypes/tst_usertypes.cpp [new file with mode: 0644]
tests/auto/qml/usertypes/usertypes.rep [new file with mode: 0644]
tests/auto/reconnect/CMakeLists.txt [new file with mode: 0644]
tests/auto/reconnect/client/CMakeLists.txt [new file with mode: 0644]
tests/auto/reconnect/client/main.cpp [new file with mode: 0644]
tests/auto/reconnect/server/CMakeLists.txt [new file with mode: 0644]
tests/auto/reconnect/server/main.cpp [new file with mode: 0644]
tests/auto/reconnect/tst/CMakeLists.txt [new file with mode: 0644]
tests/auto/reconnect/tst/tst_reconnect.cpp [new file with mode: 0644]
tests/auto/rep_from_header/CMakeLists.txt [new file with mode: 0644]
tests/auto/rep_from_header/pods.h [new file with mode: 0644]
tests/auto/rep_from_header/tst_rep_from_header.cpp [new file with mode: 0644]
tests/auto/repc/CMakeLists.txt [new file with mode: 0644]
tests/auto/repc/enums/CMakeLists.txt [new file with mode: 0644]
tests/auto/repc/enums/enums.rep [new file with mode: 0644]
tests/auto/repc/enums/tst_enums.cpp [new file with mode: 0644]
tests/auto/repc/pods/CMakeLists.txt [new file with mode: 0644]
tests/auto/repc/pods/pods.rep [new file with mode: 0644]
tests/auto/repc/pods/tst_pods.cpp [new file with mode: 0644]
tests/auto/repc/signature/CMakeLists.txt [new file with mode: 0644]
tests/auto/repc/signature/differentClassEnum/CMakeLists.txt [new file with mode: 0644]
tests/auto/repc/signature/differentClassEnum/mismatch.rep [new file with mode: 0644]
tests/auto/repc/signature/differentGlobalEnum/CMakeLists.txt [new file with mode: 0644]
tests/auto/repc/signature/differentGlobalEnum/mismatch.rep [new file with mode: 0644]
tests/auto/repc/signature/differentPropertyCount/CMakeLists.txt [new file with mode: 0644]
tests/auto/repc/signature/differentPropertyCount/mismatch.rep [new file with mode: 0644]
tests/auto/repc/signature/differentPropertyCountChild/CMakeLists.txt [new file with mode: 0644]
tests/auto/repc/signature/differentPropertyCountChild/differentPropertyCountChild.pro [new file with mode: 0644]
tests/auto/repc/signature/differentPropertyCountChild/mismatch.rep [new file with mode: 0644]
tests/auto/repc/signature/differentPropertyType/CMakeLists.txt [new file with mode: 0644]
tests/auto/repc/signature/differentPropertyType/mismatch.rep [new file with mode: 0644]
tests/auto/repc/signature/differentSignalCount/CMakeLists.txt [new file with mode: 0644]
tests/auto/repc/signature/differentSignalCount/mismatch.rep [new file with mode: 0644]
tests/auto/repc/signature/differentSignalParamCount/CMakeLists.txt [new file with mode: 0644]
tests/auto/repc/signature/differentSignalParamCount/mismatch.rep [new file with mode: 0644]
tests/auto/repc/signature/differentSignalParamType/CMakeLists.txt [new file with mode: 0644]
tests/auto/repc/signature/differentSignalParamType/mismatch.rep [new file with mode: 0644]
tests/auto/repc/signature/differentSlotCount/CMakeLists.txt [new file with mode: 0644]
tests/auto/repc/signature/differentSlotCount/mismatch.rep [new file with mode: 0644]
tests/auto/repc/signature/differentSlotParamCount/CMakeLists.txt [new file with mode: 0644]
tests/auto/repc/signature/differentSlotParamCount/mismatch.rep [new file with mode: 0644]
tests/auto/repc/signature/differentSlotParamType/CMakeLists.txt [new file with mode: 0644]
tests/auto/repc/signature/differentSlotParamType/mismatch.rep [new file with mode: 0644]
tests/auto/repc/signature/differentSlotType/CMakeLists.txt [new file with mode: 0644]
tests/auto/repc/signature/differentSlotType/mismatch.rep [new file with mode: 0644]
tests/auto/repc/signature/matchAndQuit/CMakeLists.txt [new file with mode: 0644]
tests/auto/repc/signature/matchAndQuit/main.cpp [new file with mode: 0644]
tests/auto/repc/signature/mismatch.cpp [new file with mode: 0644]
tests/auto/repc/signature/mismatch.pri [new file with mode: 0644]
tests/auto/repc/signature/scrambledProperties/CMakeLists.txt [new file with mode: 0644]
tests/auto/repc/signature/scrambledProperties/mismatch.rep [new file with mode: 0644]
tests/auto/repc/signature/scrambledSignals/CMakeLists.txt [new file with mode: 0644]
tests/auto/repc/signature/scrambledSignals/mismatch.rep [new file with mode: 0644]
tests/auto/repc/signature/scrambledSlots/CMakeLists.txt [new file with mode: 0644]
tests/auto/repc/signature/scrambledSlots/mismatch.rep [new file with mode: 0644]
tests/auto/repc/signature/server.rep [new file with mode: 0644]
tests/auto/repc/signature/signatureServer/CMakeLists.txt [new file with mode: 0644]
tests/auto/repc/signature/signatureServer/main.cpp [new file with mode: 0644]
tests/auto/repc/signature/signatureTests/CMakeLists.txt [new file with mode: 0644]
tests/auto/repc/signature/signatureTests/tst_signature.cpp [new file with mode: 0644]
tests/auto/repc/signature/state/CMakeLists.txt [new file with mode: 0644]
tests/auto/repc/signature/state/main.cpp [new file with mode: 0644]
tests/auto/repc/signature/state/mismatch.rep [new file with mode: 0644]
tests/auto/repcodegenerator/CMakeLists.txt [new file with mode: 0644]
tests/auto/repcodegenerator/classwithreadonlypropertytest.rep [new file with mode: 0644]
tests/auto/repcodegenerator/classwithsignalonlytest.rep [new file with mode: 0644]
tests/auto/repcodegenerator/preprocessortest.rep [new file with mode: 0644]
tests/auto/repcodegenerator/tst_repcodegenerator.cpp [new file with mode: 0644]
tests/auto/repfiles/localdatacenter.rep [new file with mode: 0644]
tests/auto/repfiles/tcpdatacenter.rep [new file with mode: 0644]
tests/auto/repparser/CMakeLists.txt [new file with mode: 0644]
tests/auto/repparser/tst_parser.cpp [new file with mode: 0644]
tests/auto/restart/CMakeLists.txt [new file with mode: 0644]
tests/auto/restart/client/CMakeLists.txt [new file with mode: 0644]
tests/auto/restart/client/main.cpp [new file with mode: 0644]
tests/auto/restart/server/CMakeLists.txt [new file with mode: 0644]
tests/auto/restart/server/main.cpp [new file with mode: 0644]
tests/auto/restart/server/mytestserver.cpp [new file with mode: 0644]
tests/auto/restart/server/mytestserver.h [new file with mode: 0644]
tests/auto/restart/subclass.rep [new file with mode: 0644]
tests/auto/restart/tst/CMakeLists.txt [new file with mode: 0644]
tests/auto/restart/tst/tst_restart.cpp [new file with mode: 0644]
tests/auto/shared/model_utilities.h [new file with mode: 0644]
tests/auto/subclassreplica/CMakeLists.txt [new file with mode: 0644]
tests/auto/subclassreplica/class.rep [new file with mode: 0644]
tests/auto/subclassreplica/tst_subclassreplicatest.cpp [new file with mode: 0644]
tests/global/global.cfg [new file with mode: 0644]
tests/shared/testutils.h [new file with mode: 0644]
tools/CMakeLists.txt [new file with mode: 0644]
tools/repc/.prev_CMakeLists.txt [new file with mode: 0644]
tools/repc/CMakeLists.txt [new file with mode: 0644]
tools/repc/cppcodegenerator.cpp [new file with mode: 0644]
tools/repc/cppcodegenerator.h [new file with mode: 0644]
tools/repc/main.cpp [new file with mode: 0644]
tools/repc/repc.pro [new file with mode: 0644]
tools/repc/repcodegenerator.cpp [new file with mode: 0644]
tools/repc/repcodegenerator.h [new file with mode: 0644]
tools/repc/utils.cpp [new file with mode: 0644]
tools/repc/utils.h [new file with mode: 0644]
tools/tools.pro [new file with mode: 0644]

diff --git a/.QT-ENTERPRISE-LICENSE-AGREEMENT b/.QT-ENTERPRISE-LICENSE-AGREEMENT
new file mode 100644 (file)
index 0000000..7487df8
--- /dev/null
@@ -0,0 +1,1977 @@
+QT LICENSE AGREEMENT
+Agreement version 4.4
+
+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
+        Bertel Jungin aukio D3A, 02600 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: Non-commercial and educational Licenses (optional)
+- Appendix 5: Small business and startup 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)    | <Trolltech, Nokia, Digia, The Qt Company> and  |
+| signing parties, version | <Licensee> <Version of the Agreement, e.g. 2,0,|
+| and date of signatures   | 3.2 or 4.1> <Date of the agreement signatures> |
+| 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 (file)
index 0000000..ac3b6f4
--- /dev/null
@@ -0,0 +1,2 @@
+set(QT_REPO_MODULE_VERSION "6.2.4")
+set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "")
diff --git a/.qmake.conf b/.qmake.conf
new file mode 100644 (file)
index 0000000..104abcc
--- /dev/null
@@ -0,0 +1,9 @@
+load(qt_build_config)
+CONFIG += qt_example_installs
+
+DEFINES += QT_NO_JAVA_STYLE_ITERATORS
+DEFINES += QT_NO_FOREACH
+
+MODULE_VERSION = 6.2.4
+
+QTRO_SOURCE_TREE = $$PWD
diff --git a/.tag b/.tag
new file mode 100644 (file)
index 0000000..4fffbc6
--- /dev/null
+++ b/.tag
@@ -0,0 +1 @@
+923c6dee3f0af69f848bf3bd4575e7dc8e0dc49e
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7e3820b
--- /dev/null
@@ -0,0 +1,35 @@
+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
+)
+
+# Make sure we only use latest private CMake API, aka no compatibility wrappers.
+set(QT_NO_INTERNAL_COMPATIBILITY_FUNCTIONS TRUE)
+
+# Make sure we use the fixed BASE argument of qt_add_resource.
+set(QT_USE_FIXED_QT_ADD_RESOURCE_BASE TRUE)
+
+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 (file)
index 0000000..857214d
--- /dev/null
@@ -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.
+     <https://fsf.org/>
+ 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 (file)
index 0000000..d159169
--- /dev/null
@@ -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.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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.
+
+  <signature of Ty Coon>, 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 (file)
index 0000000..94a9ed0
--- /dev/null
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ 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.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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 <http://www.gnu.org/licenses/>.
+
+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:
+
+    <program>  Copyright (C) <year>  <name of author>
+    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
+<http://www.gnu.org/licenses/>.
+
+  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
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/LICENSE.GPL3-EXCEPT b/LICENSE.GPL3-EXCEPT
new file mode 100644 (file)
index 0000000..b1cb1be
--- /dev/null
@@ -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. <http://fsf.org/>
+ 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.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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 <http://www.gnu.org/licenses/>.
+
+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:
+
+    <program>  Copyright (C) <year>  <name of author>
+    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
+<http://www.gnu.org/licenses/>.
+
+  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
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/LICENSE.LGPL3 b/LICENSE.LGPL3
new file mode 100644 (file)
index 0000000..65c5ca8
--- /dev/null
@@ -0,0 +1,165 @@
+                   GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ 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 (file)
index 0000000..16d158c
--- /dev/null
@@ -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 (file)
index 0000000..c6b0186
--- /dev/null
@@ -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 (file)
index 0000000..832cbce
--- /dev/null
@@ -0,0 +1,7 @@
+dependencies:
+  ../qtbase:
+    ref: d3b5353380797f3b67599ccebc5dc916057681e5
+    required: true
+  ../qtdeclarative:
+    ref: 26140891b4b77e2e8292f75e9d20f5798a2bd247
+    required: false
diff --git a/dist/changes-5.11.0 b/dist/changes-5.11.0
new file mode 100644 (file)
index 0000000..27072a6
--- /dev/null
@@ -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 <name>(<type>), 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 (file)
index 0000000..610e8ad
--- /dev/null
@@ -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 (file)
index 0000000..8efdf5e
--- /dev/null
@@ -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 (file)
index 0000000..28f337e
--- /dev/null
@@ -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 (file)
index 0000000..0884e4f
--- /dev/null
@@ -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 (file)
index 0000000..dfb633f
--- /dev/null
@@ -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 (file)
index 0000000..0c8bd85
--- /dev/null
@@ -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 (file)
index 0000000..8503086
--- /dev/null
@@ -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 (file)
index 0000000..e415add
--- /dev/null
@@ -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 (file)
index 0000000..e8be931
--- /dev/null
@@ -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 (file)
index 0000000..cc8d4ff
--- /dev/null
@@ -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 (file)
index 0000000..ce9927b
--- /dev/null
@@ -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 (file)
index 0000000..be59a25
--- /dev/null
@@ -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 (file)
index 0000000..2270fc6
--- /dev/null
@@ -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 (file)
index 0000000..bdb1e12
--- /dev/null
@@ -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 (file)
index 0000000..ca7ab1e
--- /dev/null
@@ -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 (file)
index 0000000..610d956
--- /dev/null
@@ -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 (file)
index 0000000..332ee9d
--- /dev/null
@@ -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 (file)
index 0000000..8bc1d30
--- /dev/null
@@ -0,0 +1,7 @@
+# Generated from examples.pro.
+
+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 (file)
index 0000000..09f19f7
--- /dev/null
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+SUBDIRS = \
+          remoteobjects
diff --git a/examples/remoteobjects/.prev_CMakeLists.txt b/examples/remoteobjects/.prev_CMakeLists.txt
new file mode 100644 (file)
index 0000000..64958e1
--- /dev/null
@@ -0,0 +1,20 @@
+# Generated from remoteobjects.pro.
+
+add_subdirectory(server)
+add_subdirectory(cppclient)
+add_subdirectory(simpleswitch)
+add_subdirectory(websockets)
+if(TARGET Qt::Widgets)
+    add_subdirectory(modelviewclient)
+    add_subdirectory(modelviewserver)
+endif()
+if(QT_CONFIG___contains___ssl)
+    add_subdirectory(ssl)
+endif()
+if(TARGET Qt::Quick)
+    add_subdirectory(plugins)
+    add_subdirectory(clientapp)
+endif()
+if(TARGET Qt::Quick AND UNIX AND NOT ANDROID)
+    add_subdirectory(qmlmodelviewclient)
+endif()
diff --git a/examples/remoteobjects/CMakeLists.txt b/examples/remoteobjects/CMakeLists.txt
new file mode 100644 (file)
index 0000000..2d6c8dd
--- /dev/null
@@ -0,0 +1,20 @@
+# Generated from remoteobjects.pro.
+
+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) # special case
+    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 (file)
index 0000000..fec53ea
--- /dev/null
@@ -0,0 +1,57 @@
+# Generated from clientapp.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(clientapp LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+  set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/clientapp")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS Gui)
+find_package(Qt6 COMPONENTS RemoteObjects)
+find_package(Qt6 COMPONENTS Quick)
+
+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 (file)
index 0000000..6d5a25d
--- /dev/null
@@ -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 (file)
index 0000000..23bdb39
--- /dev/null
@@ -0,0 +1,8 @@
+<RCC>
+    <qresource prefix="/qml">
+        <file>qml/plugins0.qml</file>
+        <file>qml/plugins.qml</file>
+        <file>qml/plugins1.qml</file>
+        <file>qml/plugins2.qml</file>
+    </qresource>
+</RCC>
diff --git a/examples/remoteobjects/clientapp/main.cpp b/examples/remoteobjects/clientapp/main.cpp
new file mode 100644 (file)
index 0000000..8f0f5d2
--- /dev/null
@@ -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 <QtGui/QGuiApplication>
+#include <QtQml/QQmlEngine>
+#include <QtQuick/QQuickView>
+
+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 (file)
index 0000000..fe5a5a6
--- /dev/null
@@ -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 (file)
index 0000000..873225e
--- /dev/null
@@ -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 (file)
index 0000000..c1d15ab
--- /dev/null
@@ -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 (file)
index 0000000..f4eaf94
--- /dev/null
@@ -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 (file)
index 0000000..cbe78f2
--- /dev/null
@@ -0,0 +1,41 @@
+# Generated from cppclient.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(CppClient LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+  set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/cppclient")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS 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 (file)
index 0000000..7b57442
--- /dev/null
@@ -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 (file)
index 0000000..08e36b6
--- /dev/null
@@ -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 <QCoreApplication>
+#include <QTimer>
+#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<MinuteTimerReplica> 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 (file)
index 0000000..cbfaf24
--- /dev/null
@@ -0,0 +1,12 @@
+#include <QtCore>
+
+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 (file)
index 0000000..c1349de
--- /dev/null
@@ -0,0 +1,41 @@
+# Generated from modelviewclient.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(modelviewclient LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+  set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/modelviewclient")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS Gui)
+find_package(Qt6 COMPONENTS Widgets)
+find_package(Qt6 COMPONENTS RemoteObjects)
+
+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 (file)
index 0000000..dc54e2f
--- /dev/null
@@ -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 (file)
index 0000000..a3361df
--- /dev/null
@@ -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 <QTreeView>
+#include <QApplication>
+#include <QRemoteObjectNode>
+#include <QAbstractItemModelReplica>
+
+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<QAbstractItemModelReplica> 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 (file)
index 0000000..473f38f
--- /dev/null
@@ -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 (file)
index 0000000..34867d3
--- /dev/null
@@ -0,0 +1,41 @@
+# Generated from modelviewserver.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(modelviewserver LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+  set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/modelviewserver")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS Gui)
+find_package(Qt6 COMPONENTS Widgets)
+find_package(Qt6 COMPONENTS RemoteObjects)
+
+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 (file)
index 0000000..789af82
--- /dev/null
@@ -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 (file)
index 0000000..d86c688
--- /dev/null
@@ -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 <QTreeView>
+#include <QApplication>
+#include <QRemoteObjectNode>
+#include <QTimer>
+#include <QStandardItemModel>
+#include <QStandardItem>
+
+#include <memory>
+
+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<QStandardItem*> addChild(int numChildren, int nestingLevel)
+{
+    QList<QStandardItem*> 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<QStandardItemModel> createModel()
+{
+    std::unique_ptr<QStandardItemModel> sourceModel = std::make_unique<QStandardItemModel>();
+    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<QStandardItem*> row;
+        row << firstItem << secondItem;
+        sourceModel->invisibleRootItem()->appendRow(row);
+        list << QStringLiteral("FancyTextNumber %1").arg(i);
+    }
+
+    // Needed by QMLModelViewClient
+    QHash<int,QByteArray> 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<QStandardItemModel> sourceModel = createModel();
+
+    QList<int> 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 (file)
index 0000000..d2fc6c4
--- /dev/null
@@ -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 (file)
index 0000000..8c9909e
--- /dev/null
@@ -0,0 +1,51 @@
+# Generated from plugins.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(qmlqrotimeexampleplugin LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+  set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/plugins/imports/TimeExample")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS Gui)
+find_package(Qt6 COMPONENTS Qml)
+find_package(Qt6 COMPONENTS 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 (file)
index 0000000..8c83e70
--- /dev/null
@@ -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 (file)
index 0000000..7fbd802
Binary files /dev/null and b/examples/remoteobjects/plugins/imports/TimeExample/center.png differ
diff --git a/examples/remoteobjects/plugins/imports/TimeExample/clock.png b/examples/remoteobjects/plugins/imports/TimeExample/clock.png
new file mode 100644 (file)
index 0000000..462edac
Binary files /dev/null and b/examples/remoteobjects/plugins/imports/TimeExample/clock.png differ
diff --git a/examples/remoteobjects/plugins/imports/TimeExample/hour.png b/examples/remoteobjects/plugins/imports/TimeExample/hour.png
new file mode 100644 (file)
index 0000000..f8061a1
Binary files /dev/null and b/examples/remoteobjects/plugins/imports/TimeExample/hour.png differ
diff --git a/examples/remoteobjects/plugins/imports/TimeExample/minute.png b/examples/remoteobjects/plugins/imports/TimeExample/minute.png
new file mode 100644 (file)
index 0000000..1297ec7
Binary files /dev/null and b/examples/remoteobjects/plugins/imports/TimeExample/minute.png differ
diff --git a/examples/remoteobjects/plugins/imports/TimeExample/qmldir b/examples/remoteobjects/plugins/imports/TimeExample/qmldir
new file mode 100644 (file)
index 0000000..be259d4
--- /dev/null
@@ -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 (file)
index 0000000..eac6313
--- /dev/null
@@ -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 <QtQml/QQmlExtensionPlugin>
+#include <QtQml/QQmlEngine>
+#include <QtQml/qqml.h>
+#include <QDebug>
+#include <QDateTime>
+#include <QBasicTimer>
+#include <QCoreApplication>
+#include <QRemoteObjectReplica>
+#include <QRemoteObjectNode>
+#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"<<t;
+        d_ptr->SetTimeZone(t.minute());
+    }
+    //Test a signal with a custom type
+    void testCustom(PresetInfo info)
+    {
+        qDebug()<<"testCustom"<<info.presetNumber()<<info.frequency()<<info.stationName();
+    }
+
+signals:
+    void timeChanged();
+    void timeChanged2(QTime t);
+    void sendCustom(PresetInfo info);
+    void isValidChanged();
+
+private:
+    QScopedPointer<MinuteTimerReplica> 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<TimeModel>(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 (file)
index 0000000..9d3f3d1
--- /dev/null
@@ -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 (file)
index 0000000..0f3f9d3
--- /dev/null
@@ -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 (file)
index 0000000..873225e
--- /dev/null
@@ -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 (file)
index 0000000..c1d15ab
--- /dev/null
@@ -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 (file)
index 0000000..f4eaf94
--- /dev/null
@@ -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 (file)
index 0000000..6b2c989
--- /dev/null
@@ -0,0 +1,56 @@
+# Generated from qmlmodelviewclient.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(qmlmodelviewclient LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+  set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/qmlmodelviewclient")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS Gui)
+find_package(Qt6 COMPONENTS Qml)
+find_package(Qt6 COMPONENTS Quick)
+find_package(Qt6 COMPONENTS 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 (file)
index 0000000..00c1874
--- /dev/null
@@ -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 (file)
index 0000000..a0186f1
--- /dev/null
@@ -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 <QGuiApplication>
+#include <QQmlApplicationEngine>
+#include <QQmlContext>
+#include <QRemoteObjectNode>
+#include <QAbstractItemModelReplica>
+
+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<QAbstractItemModelReplica> 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 (file)
index 0000000..f1926df
--- /dev/null
@@ -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 (file)
index 0000000..5f6483a
--- /dev/null
@@ -0,0 +1,5 @@
+<RCC>
+    <qresource prefix="/">
+        <file>main.qml</file>
+    </qresource>
+</RCC>
diff --git a/examples/remoteobjects/qmlmodelviewclient/qmlmodelviewclient.pro b/examples/remoteobjects/qmlmodelviewclient/qmlmodelviewclient.pro
new file mode 100644 (file)
index 0000000..4e9c12d
--- /dev/null
@@ -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 (file)
index 0000000..096d88b
--- /dev/null
@@ -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 (file)
index 0000000..a475986
--- /dev/null
@@ -0,0 +1,42 @@
+# Generated from server.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(remoteobjects_server LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+  set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/remoteobjects_server")
+
+find_package(Qt6 COMPONENTS RemoteObjects)
+find_package(Qt6 COMPONENTS Core)
+
+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 (file)
index 0000000..7eaab06
--- /dev/null
@@ -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 <QCoreApplication>
+/*
+* 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 <signal.h>
+
+  void unix_handler(int s)
+  {
+    if (s==SIGINT)
+        SigIntHandler();
+  }
+
+#elif defined(Q_OS_WIN32)
+  #include <windows.h>
+
+  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 (file)
index 0000000..1c1441d
--- /dev/null
@@ -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 (file)
index 0000000..a444f6e
--- /dev/null
@@ -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"<<time;
+    setHour(time.hour());
+    setMinute(time.minute());
+    emit timeChanged();
+    emit timeChanged2(time);
+    static PresetInfo bla(3, 93.9f, "Best Station");
+    emit sendCustom(bla);
+}
+void MinuteTimer::SetTimeZone(const int &zn)
+{
+    qDebug()<<"SetTimeZone"<<zn;
+    if (zn != zone)
+    {
+        zone = zn;
+    }
+}
diff --git a/examples/remoteobjects/remoteobjects_server/timemodel.h b/examples/remoteobjects/remoteobjects_server/timemodel.h
new file mode 100644 (file)
index 0000000..09c594a
--- /dev/null
@@ -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$
+**
+****************************************************************************/
+
+#include <QtCore>
+#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 (file)
index 0000000..8b6456d
--- /dev/null
@@ -0,0 +1,7 @@
+# Generated from simpleswitch.pro.
+
+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 (file)
index 0000000..431979e
--- /dev/null
@@ -0,0 +1,42 @@
+# Generated from directconnectclient.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(directconnectclient LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+  set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/simpleswitch/directconnectclient")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS 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 (file)
index 0000000..a8e3133
--- /dev/null
@@ -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<SimpleSwitchReplica> 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 (file)
index 0000000..9d86b74
--- /dev/null
@@ -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 <QObject>
+#include <QSharedPointer>
+
+#include "rep_simpleswitch_replica.h"
+
+class Client : public QObject
+{
+    Q_OBJECT
+public:
+    Client(QSharedPointer<SimpleSwitchReplica> 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<SimpleSwitchReplica> 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 (file)
index 0000000..3624821
--- /dev/null
@@ -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 (file)
index 0000000..1854dd3
--- /dev/null
@@ -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 <QCoreApplication>
+#include "client.h"
+
+int main(int argc, char *argv[])
+{
+    QCoreApplication a(argc, argv);
+
+
+    QSharedPointer<SimpleSwitchReplica> ptr;
+
+    QRemoteObjectNode repNode; // create remote object node
+    repNode.connectToNode(QUrl(QStringLiteral("local:replica"))); // connect with remote host node
+
+    ptr.reset(repNode.acquire<SimpleSwitchReplica>()); // 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 (file)
index 0000000..b2d7cd2
--- /dev/null
@@ -0,0 +1,7 @@
+#include <QtCore>
+
+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 (file)
index 0000000..be7f266
--- /dev/null
@@ -0,0 +1,38 @@
+# Generated from directconnectdynamicclient.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(directconnectdynamicclient LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+  set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/simpleswitch/directconnectdynamicclient")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS 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 (file)
index 0000000..8b907de
--- /dev/null
@@ -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 (file)
index 0000000..88a3fd8
--- /dev/null
@@ -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 <QMetaMethod>
+
+// constructor
+DynamicClient::DynamicClient(QSharedPointer<QRemoteObjectDynamicReplica> 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 (file)
index 0000000..ad948a9
--- /dev/null
@@ -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 <QObject>
+#include <QSharedPointer>
+
+#include <QRemoteObjectNode>
+#include <qremoteobjectdynamicreplica.h>
+
+class DynamicClient : public QObject
+{
+    Q_OBJECT
+public:
+    DynamicClient(QSharedPointer<QRemoteObjectDynamicReplica> 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<QRemoteObjectDynamicReplica> 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 (file)
index 0000000..17008ae
--- /dev/null
@@ -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 <QCoreApplication>
+
+#include "dynamicclient.h"
+
+int main(int argc, char *argv[])
+{
+    QCoreApplication a(argc, argv);
+
+    QSharedPointer<QRemoteObjectDynamicReplica> 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 (file)
index 0000000..fd68a74
--- /dev/null
@@ -0,0 +1,42 @@
+# Generated from directconnectserver.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(directconnectserver LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+  set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/simpleswitch/directconnectserver")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS 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 (file)
index 0000000..bbc3d7e
--- /dev/null
@@ -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 (file)
index 0000000..18532b6
--- /dev/null
@@ -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 <QCoreApplication>
+#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 (file)
index 0000000..5418ce1
--- /dev/null
@@ -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 "<<currState();
+
+}
+
diff --git a/examples/remoteobjects/simpleswitch/directconnectserver/simpleswitch.h b/examples/remoteobjects/simpleswitch/directconnectserver/simpleswitch.h
new file mode 100644 (file)
index 0000000..48ea61c
--- /dev/null
@@ -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$
+**
+****************************************************************************/
+
+#ifndef SIMPLESWITCH_H
+#define SIMPLESWITCH_H
+
+#include "rep_simpleswitch_source.h"
+
+class SimpleSwitch : public SimpleSwitchSimpleSource
+{
+    Q_OBJECT
+public:
+    SimpleSwitch(QObject *parent = nullptr);
+    ~SimpleSwitch() override;
+    void server_slot(bool clientState) override;
+public Q_SLOTS:
+    void timeout_slot();
+private:
+    QTimer *stateChangeTimer;
+};
+
+#endif
diff --git a/examples/remoteobjects/simpleswitch/directconnectserver/simpleswitch.rep b/examples/remoteobjects/simpleswitch/directconnectserver/simpleswitch.rep
new file mode 100644 (file)
index 0000000..b2d7cd2
--- /dev/null
@@ -0,0 +1,7 @@
+#include <QtCore>
+
+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 (file)
index 0000000..71ed839
--- /dev/null
@@ -0,0 +1,38 @@
+# Generated from registryconnectedclient.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(registryconnectedclient LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+  set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/simpleswitch/registryconnectedclient")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS 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 (file)
index 0000000..88a3fd8
--- /dev/null
@@ -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 <QMetaMethod>
+
+// constructor
+DynamicClient::DynamicClient(QSharedPointer<QRemoteObjectDynamicReplica> 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 (file)
index 0000000..ad948a9
--- /dev/null
@@ -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 <QObject>
+#include <QSharedPointer>
+
+#include <QRemoteObjectNode>
+#include <qremoteobjectdynamicreplica.h>
+
+class DynamicClient : public QObject
+{
+    Q_OBJECT
+public:
+    DynamicClient(QSharedPointer<QRemoteObjectDynamicReplica> 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<QRemoteObjectDynamicReplica> 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 (file)
index 0000000..fde8d02
--- /dev/null
@@ -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 <QCoreApplication>
+#include "dynamicclient.h"
+
+int main(int argc, char *argv[])
+{
+    QCoreApplication a(argc, argv);
+
+    QSharedPointer<QRemoteObjectDynamicReplica> 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 (file)
index 0000000..02aa54c
--- /dev/null
@@ -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 (file)
index 0000000..b78f48d
--- /dev/null
@@ -0,0 +1,42 @@
+# Generated from registryconnectedserver.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(registryconnectedserver LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+  set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/simpleswitch/registryconnectedserver")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS 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 (file)
index 0000000..5d71894
--- /dev/null
@@ -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 <QCoreApplication>
+#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 (file)
index 0000000..d00687f
--- /dev/null
@@ -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 (file)
index 0000000..5418ce1
--- /dev/null
@@ -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 "<<currState();
+
+}
+
diff --git a/examples/remoteobjects/simpleswitch/registryconnectedserver/simpleswitch.h b/examples/remoteobjects/simpleswitch/registryconnectedserver/simpleswitch.h
new file mode 100644 (file)
index 0000000..48ea61c
--- /dev/null
@@ -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$
+**
+****************************************************************************/
+
+#ifndef SIMPLESWITCH_H
+#define SIMPLESWITCH_H
+
+#include "rep_simpleswitch_source.h"
+
+class SimpleSwitch : public SimpleSwitchSimpleSource
+{
+    Q_OBJECT
+public:
+    SimpleSwitch(QObject *parent = nullptr);
+    ~SimpleSwitch() override;
+    void server_slot(bool clientState) override;
+public Q_SLOTS:
+    void timeout_slot();
+private:
+    QTimer *stateChangeTimer;
+};
+
+#endif
diff --git a/examples/remoteobjects/simpleswitch/registryconnectedserver/simpleswitch.rep b/examples/remoteobjects/simpleswitch/registryconnectedserver/simpleswitch.rep
new file mode 100644 (file)
index 0000000..4f7c9c7
--- /dev/null
@@ -0,0 +1,8 @@
+#include <QtCore>
+
+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 (file)
index 0000000..8b70a12
--- /dev/null
@@ -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 (file)
index 0000000..de476f1
--- /dev/null
@@ -0,0 +1,4 @@
+# Generated from ssl.pro.
+
+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 (file)
index 0000000..d77f35e
--- /dev/null
@@ -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 (file)
index 0000000..f36383f
--- /dev/null
@@ -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 (file)
index 0000000..fd24d07
--- /dev/null
@@ -0,0 +1,64 @@
+# Generated from sslcppclient.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(SslCppClient LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+  set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/ssl/sslcppclient")
+
+find_package(Qt6 COMPONENTS RemoteObjects)
+find_package(Qt6 COMPONENTS Core)
+
+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 (file)
index 0000000..a4f6b1c
--- /dev/null
@@ -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 <QCoreApplication>
+#include <QHostAddress>
+#include <QSslSocket>
+#include <QSslConfiguration>
+#include <QSslKey>
+#include <QTimer>
+#include "rep_timemodel_replica.h"
+
+#include <QRemoteObjectNode>
+
+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<MinuteTimerReplica> 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 (file)
index 0000000..07fb8da
--- /dev/null
@@ -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 (file)
index 0000000..cbfaf24
--- /dev/null
@@ -0,0 +1,12 @@
+#include <QtCore>
+
+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 (file)
index 0000000..a374f0a
--- /dev/null
@@ -0,0 +1,65 @@
+# Generated from sslserver.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(sslserver LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+  set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/ssl/sslserver")
+
+find_package(Qt6 COMPONENTS RemoteObjects)
+find_package(Qt6 COMPONENTS Core)
+
+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 (file)
index 0000000..65f92e2
--- /dev/null
@@ -0,0 +1,11 @@
+<RCC>
+    <qresource prefix="/sslcert">
+        <file>client.crt</file>
+        <file>client.key</file>
+        <file>rootCA.key</file>
+        <file>rootCA.pem</file>
+        <file>rootCA.srl</file>
+        <file>server.crt</file>
+        <file>server.key</file>
+    </qresource>
+</RCC>
diff --git a/examples/remoteobjects/ssl/sslserver/cert/client.crt b/examples/remoteobjects/ssl/sslserver/cert/client.crt
new file mode 100644 (file)
index 0000000..3aa0ff8
--- /dev/null
@@ -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 (file)
index 0000000..b3f4f1a
--- /dev/null
@@ -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 (file)
index 0000000..1386169
--- /dev/null
@@ -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 (file)
index 0000000..1647817
--- /dev/null
@@ -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 (file)
index 0000000..7f6cce5
--- /dev/null
@@ -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 (file)
index 0000000..d292c9f
--- /dev/null
@@ -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 (file)
index 0000000..df9d55c
--- /dev/null
@@ -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 (file)
index 0000000..05144f4
--- /dev/null
@@ -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 (file)
index 0000000..fac2584
--- /dev/null
@@ -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 <QCoreApplication>
+#include <QSslConfiguration>
+
+#include "sslserver.h"
+
+#include <QRemoteObjectHost>
+/*
+* 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 <signal.h>
+
+void unix_handler(int s)
+{
+    if (s==SIGINT)
+        SigIntHandler();
+}
+
+#elif defined(Q_OS_WIN32)
+#include <windows.h>
+
+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 (file)
index 0000000..02eeaa6
--- /dev/null
@@ -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 <QSslSocket>
+
+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<void (QSslSocket::*)(const QList<QSslError>&)>(&QSslSocket::sslErrors),
+                this, [serverSocket](const QList<QSslError>& 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 (file)
index 0000000..3dfd511
--- /dev/null
@@ -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 <QTcpServer>
+
+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 (file)
index 0000000..b8081d2
--- /dev/null
@@ -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 (file)
index 0000000..a444f6e
--- /dev/null
@@ -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"<<time;
+    setHour(time.hour());
+    setMinute(time.minute());
+    emit timeChanged();
+    emit timeChanged2(time);
+    static PresetInfo bla(3, 93.9f, "Best Station");
+    emit sendCustom(bla);
+}
+void MinuteTimer::SetTimeZone(const int &zn)
+{
+    qDebug()<<"SetTimeZone"<<zn;
+    if (zn != zone)
+    {
+        zone = zn;
+    }
+}
diff --git a/examples/remoteobjects/ssl/sslserver/timemodel.h b/examples/remoteobjects/ssl/sslserver/timemodel.h
new file mode 100644 (file)
index 0000000..09c594a
--- /dev/null
@@ -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$
+**
+****************************************************************************/
+
+#include <QtCore>
+#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 (file)
index 0000000..c07ee2c
--- /dev/null
@@ -0,0 +1,14 @@
+#include <QtCore>
+
+POD PresetInfo(int presetNumber, float frequency, QString stationName)
+POD PresetData(QList<QString> bla)
+class MinuteTimer
+{
+    PROP(int hour=1);
+    PROP(int minute=51);
+    SIGNAL(timeChanged());
+    SIGNAL(timeChanged2(QTime t));
+    SIGNAL(sendCustom(PresetInfo info));
+    SIGNAL(foo(QMap<QString, QString> foo));
+    SLOT(void SetTimeZone(const int &));
+};
diff --git a/examples/remoteobjects/websockets/CMakeLists.txt b/examples/remoteobjects/websockets/CMakeLists.txt
new file mode 100644 (file)
index 0000000..09ff32c
--- /dev/null
@@ -0,0 +1,6 @@
+# Generated from websockets.pro.
+
+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 (file)
index 0000000..65f92e2
--- /dev/null
@@ -0,0 +1,11 @@
+<RCC>
+    <qresource prefix="/sslcert">
+        <file>client.crt</file>
+        <file>client.key</file>
+        <file>rootCA.key</file>
+        <file>rootCA.pem</file>
+        <file>rootCA.srl</file>
+        <file>server.crt</file>
+        <file>server.key</file>
+    </qresource>
+</RCC>
diff --git a/examples/remoteobjects/websockets/common/cert/client.crt b/examples/remoteobjects/websockets/common/cert/client.crt
new file mode 100644 (file)
index 0000000..3aa0ff8
--- /dev/null
@@ -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 (file)
index 0000000..b3f4f1a
--- /dev/null
@@ -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 (file)
index 0000000..1386169
--- /dev/null
@@ -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 (file)
index 0000000..1647817
--- /dev/null
@@ -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 (file)
index 0000000..7f6cce5
--- /dev/null
@@ -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 (file)
index 0000000..d292c9f
--- /dev/null
@@ -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 (file)
index 0000000..df9d55c
--- /dev/null
@@ -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 (file)
index 0000000..05144f4
--- /dev/null
@@ -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 (file)
index 0000000..4ee7eef
--- /dev/null
@@ -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 (file)
index 0000000..39cb4eb
--- /dev/null
@@ -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 <QWebSocket>
+
+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 (file)
index 0000000..0e5609c
--- /dev/null
@@ -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 <QBuffer>
+#include <QIODevice>
+#include <QPointer>
+
+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<QWebSocket> 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 (file)
index 0000000..3db2e3c
--- /dev/null
@@ -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 (file)
index 0000000..bb2685a
--- /dev/null
@@ -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 (file)
index 0000000..7d4baa8
--- /dev/null
@@ -0,0 +1,69 @@
+# Generated from wsclient.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(wsclient LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+  set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/websockets/wsclient")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS Gui)
+find_package(Qt6 COMPONENTS Widgets)
+find_package(Qt6 COMPONENTS RemoteObjects)
+find_package(Qt6 COMPONENTS WebSockets)
+
+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 (file)
index 0000000..19b7672
--- /dev/null
@@ -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 <QTreeView>
+#include <QApplication>
+#include <QRemoteObjectNode>
+#include <QAbstractItemModelReplica>
+#include <QWebSocket>
+
+#ifndef QT_NO_SSL
+# include <QFile>
+# include <QSslConfiguration>
+# include <QSslKey>
+#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<QWebSocket> 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<QAbstractItemModelReplica> 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 (file)
index 0000000..f329e4a
--- /dev/null
@@ -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 (file)
index 0000000..158dec2
--- /dev/null
@@ -0,0 +1,69 @@
+# Generated from wsserver.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(wsserver LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+  set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/websockets/wsserver")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS Gui)
+find_package(Qt6 COMPONENTS Widgets)
+find_package(Qt6 COMPONENTS RemoteObjects)
+find_package(Qt6 COMPONENTS WebSockets)
+
+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 (file)
index 0000000..391e1b7
--- /dev/null
@@ -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 <QTreeView>
+#include <QApplication>
+#include <QRemoteObjectNode>
+#include <QTimer>
+#include <QStandardItemModel>
+#include <QStandardItem>
+#include <QWebSocket>
+#include <QWebSocketServer>
+
+#ifndef QT_NO_SSL
+# include <QFile>
+# include <QSslConfiguration>
+# include <QSslKey>
+#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<QStandardItem*> addChild(int numChildren, int nestingLevel)
+{
+    QList<QStandardItem*> 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<QStandardItem*> row;
+        row << firstItem << secondItem;
+        sourceModel.invisibleRootItem()->appendRow(row);
+        //sourceModel.appendRow(row);
+        list << QStringLiteral("FancyTextNumber %1").arg(i);
+    }
+
+    // Needed by QMLModelViewClient
+    QHash<int,QByteArray> roleNames = {
+        {Qt::DisplayRole, "_text"},
+        {Qt::BackgroundRole, "_color"}
+    };
+    sourceModel.setItemRoleNames(roleNames);
+
+    QList<int> 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<QAbstractSocket::SocketError>::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 (file)
index 0000000..e892091
--- /dev/null
@@ -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.2.4/QtRemoteObjects/private/qconnection_local_backend_p.h b/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qconnection_local_backend_p.h
new file mode 100644 (file)
index 0000000..a056f08
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../../../src/remoteobjects/qconnection_local_backend_p.h"
diff --git a/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qconnection_qnx_backend_p.h b/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qconnection_qnx_backend_p.h
new file mode 100644 (file)
index 0000000..3d676da
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../../../src/remoteobjects/qconnection_qnx_backend_p.h"
diff --git a/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qconnection_qnx_global_p.h b/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qconnection_qnx_global_p.h
new file mode 100644 (file)
index 0000000..b1df3a5
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../../../src/remoteobjects/qconnection_qnx_global_p.h"
diff --git a/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qconnection_qnx_qiodevices_p.h b/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qconnection_qnx_qiodevices_p.h
new file mode 100644 (file)
index 0000000..fb61d2b
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../../../src/remoteobjects/qconnection_qnx_qiodevices_p.h"
diff --git a/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qconnection_qnx_server_p.h b/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qconnection_qnx_server_p.h
new file mode 100644 (file)
index 0000000..c9c4733
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../../../src/remoteobjects/qconnection_qnx_server_p.h"
diff --git a/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qconnection_tcpip_backend_p.h b/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qconnection_tcpip_backend_p.h
new file mode 100644 (file)
index 0000000..5b920f2
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../../../src/remoteobjects/qconnection_tcpip_backend_p.h"
diff --git a/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qconnectionfactories_p.h b/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qconnectionfactories_p.h
new file mode 100644 (file)
index 0000000..501d938
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../../../src/remoteobjects/qconnectionfactories_p.h"
diff --git a/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectabstractitemmodeladapter_p.h b/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectabstractitemmodeladapter_p.h
new file mode 100644 (file)
index 0000000..e9c8964
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../../../src/remoteobjects/qremoteobjectabstractitemmodeladapter_p.h"
diff --git a/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectabstractitemmodelreplica_p.h b/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectabstractitemmodelreplica_p.h
new file mode 100644 (file)
index 0000000..64da33f
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../../../src/remoteobjects/qremoteobjectabstractitemmodelreplica_p.h"
diff --git a/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectabstractitemmodeltypes_p.h b/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectabstractitemmodeltypes_p.h
new file mode 100644 (file)
index 0000000..646a4bc
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../../../src/remoteobjects/qremoteobjectabstractitemmodeltypes_p.h"
diff --git a/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectcontainers_p.h b/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectcontainers_p.h
new file mode 100644 (file)
index 0000000..8d637d5
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../../../src/remoteobjects/qremoteobjectcontainers_p.h"
diff --git a/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectnode_p.h b/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectnode_p.h
new file mode 100644 (file)
index 0000000..be73dae
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../../../src/remoteobjects/qremoteobjectnode_p.h"
diff --git a/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectpacket_p.h b/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectpacket_p.h
new file mode 100644 (file)
index 0000000..bdad605
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../../../src/remoteobjects/qremoteobjectpacket_p.h"
diff --git a/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectpendingcall_p.h b/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectpendingcall_p.h
new file mode 100644 (file)
index 0000000..7c2b703
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../../../src/remoteobjects/qremoteobjectpendingcall_p.h"
diff --git a/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectregistrysource_p.h b/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectregistrysource_p.h
new file mode 100644 (file)
index 0000000..bb6f128
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../../../src/remoteobjects/qremoteobjectregistrysource_p.h"
diff --git a/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectreplica_p.h b/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectreplica_p.h
new file mode 100644 (file)
index 0000000..f457bca
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../../../src/remoteobjects/qremoteobjectreplica_p.h"
diff --git a/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectsource_p.h b/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectsource_p.h
new file mode 100644 (file)
index 0000000..b7e50ab
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../../../src/remoteobjects/qremoteobjectsource_p.h"
diff --git a/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectsourceio_p.h b/include/QtRemoteObjects/6.2.4/QtRemoteObjects/private/qremoteobjectsourceio_p.h
new file mode 100644 (file)
index 0000000..20eeb5e
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../../../src/remoteobjects/qremoteobjectsourceio_p.h"
diff --git a/include/QtRemoteObjects/QAbstractItemModelReplica b/include/QtRemoteObjects/QAbstractItemModelReplica
new file mode 100644 (file)
index 0000000..790a361
--- /dev/null
@@ -0,0 +1 @@
+#include "qremoteobjectabstractitemmodelreplica.h"
diff --git a/include/QtRemoteObjects/QConnectionAbstractServer b/include/QtRemoteObjects/QConnectionAbstractServer
new file mode 100644 (file)
index 0000000..9306cd4
--- /dev/null
@@ -0,0 +1 @@
+#include "qconnectionfactories.h"
diff --git a/include/QtRemoteObjects/QIOQnxSource b/include/QtRemoteObjects/QIOQnxSource
new file mode 100644 (file)
index 0000000..bd609a9
--- /dev/null
@@ -0,0 +1 @@
+#include "qconnection_qnx_qiodevices.h"
diff --git a/include/QtRemoteObjects/QIntHash b/include/QtRemoteObjects/QIntHash
new file mode 100644 (file)
index 0000000..46b3e1b
--- /dev/null
@@ -0,0 +1 @@
+#include "qtremoteobjectglobal.h"
diff --git a/include/QtRemoteObjects/QQnxNativeIo b/include/QtRemoteObjects/QQnxNativeIo
new file mode 100644 (file)
index 0000000..bd609a9
--- /dev/null
@@ -0,0 +1 @@
+#include "qconnection_qnx_qiodevices.h"
diff --git a/include/QtRemoteObjects/QQnxNativeServer b/include/QtRemoteObjects/QQnxNativeServer
new file mode 100644 (file)
index 0000000..ee615ae
--- /dev/null
@@ -0,0 +1 @@
+#include "qconnection_qnx_server.h"
diff --git a/include/QtRemoteObjects/QRemoteObjectAbstractPersistedStore b/include/QtRemoteObjects/QRemoteObjectAbstractPersistedStore
new file mode 100644 (file)
index 0000000..789612f
--- /dev/null
@@ -0,0 +1 @@
+#include "qremoteobjectnode.h"
diff --git a/include/QtRemoteObjects/QRemoteObjectDynamicReplica b/include/QtRemoteObjects/QRemoteObjectDynamicReplica
new file mode 100644 (file)
index 0000000..3c8ac01
--- /dev/null
@@ -0,0 +1 @@
+#include "qremoteobjectdynamicreplica.h"
diff --git a/include/QtRemoteObjects/QRemoteObjectHost b/include/QtRemoteObjects/QRemoteObjectHost
new file mode 100644 (file)
index 0000000..789612f
--- /dev/null
@@ -0,0 +1 @@
+#include "qremoteobjectnode.h"
diff --git a/include/QtRemoteObjects/QRemoteObjectHostBase b/include/QtRemoteObjects/QRemoteObjectHostBase
new file mode 100644 (file)
index 0000000..789612f
--- /dev/null
@@ -0,0 +1 @@
+#include "qremoteobjectnode.h"
diff --git a/include/QtRemoteObjects/QRemoteObjectNode b/include/QtRemoteObjects/QRemoteObjectNode
new file mode 100644 (file)
index 0000000..789612f
--- /dev/null
@@ -0,0 +1 @@
+#include "qremoteobjectnode.h"
diff --git a/include/QtRemoteObjects/QRemoteObjectPendingCall b/include/QtRemoteObjects/QRemoteObjectPendingCall
new file mode 100644 (file)
index 0000000..c2db880
--- /dev/null
@@ -0,0 +1 @@
+#include "qremoteobjectpendingcall.h"
diff --git a/include/QtRemoteObjects/QRemoteObjectPendingCallWatcher b/include/QtRemoteObjects/QRemoteObjectPendingCallWatcher
new file mode 100644 (file)
index 0000000..c2db880
--- /dev/null
@@ -0,0 +1 @@
+#include "qremoteobjectpendingcall.h"
diff --git a/include/QtRemoteObjects/QRemoteObjectPendingReply b/include/QtRemoteObjects/QRemoteObjectPendingReply
new file mode 100644 (file)
index 0000000..c2db880
--- /dev/null
@@ -0,0 +1 @@
+#include "qremoteobjectpendingcall.h"
diff --git a/include/QtRemoteObjects/QRemoteObjectRegistry b/include/QtRemoteObjects/QRemoteObjectRegistry
new file mode 100644 (file)
index 0000000..5a3cc82
--- /dev/null
@@ -0,0 +1 @@
+#include "qremoteobjectregistry.h"
diff --git a/include/QtRemoteObjects/QRemoteObjectRegistryHost b/include/QtRemoteObjects/QRemoteObjectRegistryHost
new file mode 100644 (file)
index 0000000..789612f
--- /dev/null
@@ -0,0 +1 @@
+#include "qremoteobjectnode.h"
diff --git a/include/QtRemoteObjects/QRemoteObjectReplica b/include/QtRemoteObjects/QRemoteObjectReplica
new file mode 100644 (file)
index 0000000..62475a9
--- /dev/null
@@ -0,0 +1 @@
+#include "qremoteobjectreplica.h"
diff --git a/include/QtRemoteObjects/QRemoteObjectSettingsStore b/include/QtRemoteObjects/QRemoteObjectSettingsStore
new file mode 100644 (file)
index 0000000..6a38595
--- /dev/null
@@ -0,0 +1 @@
+#include "qremoteobjectsettingsstore.h"
diff --git a/include/QtRemoteObjects/QRemoteObjectSourceLocation b/include/QtRemoteObjects/QRemoteObjectSourceLocation
new file mode 100644 (file)
index 0000000..46b3e1b
--- /dev/null
@@ -0,0 +1 @@
+#include "qtremoteobjectglobal.h"
diff --git a/include/QtRemoteObjects/QRemoteObjectSourceLocationInfo b/include/QtRemoteObjects/QRemoteObjectSourceLocationInfo
new file mode 100644 (file)
index 0000000..46b3e1b
--- /dev/null
@@ -0,0 +1 @@
+#include "qtremoteobjectglobal.h"
diff --git a/include/QtRemoteObjects/QRemoteObjectSourceLocations b/include/QtRemoteObjects/QRemoteObjectSourceLocations
new file mode 100644 (file)
index 0000000..46b3e1b
--- /dev/null
@@ -0,0 +1 @@
+#include "qtremoteobjectglobal.h"
diff --git a/include/QtRemoteObjects/QtROClientFactory b/include/QtRemoteObjects/QtROClientFactory
new file mode 100644 (file)
index 0000000..9306cd4
--- /dev/null
@@ -0,0 +1 @@
+#include "qconnectionfactories.h"
diff --git a/include/QtRemoteObjects/QtROClientIoDevice b/include/QtRemoteObjects/QtROClientIoDevice
new file mode 100644 (file)
index 0000000..9306cd4
--- /dev/null
@@ -0,0 +1 @@
+#include "qconnectionfactories.h"
diff --git a/include/QtRemoteObjects/QtROIoDeviceBase b/include/QtRemoteObjects/QtROIoDeviceBase
new file mode 100644 (file)
index 0000000..9306cd4
--- /dev/null
@@ -0,0 +1 @@
+#include "qconnectionfactories.h"
diff --git a/include/QtRemoteObjects/QtROServerFactory b/include/QtRemoteObjects/QtROServerFactory
new file mode 100644 (file)
index 0000000..9306cd4
--- /dev/null
@@ -0,0 +1 @@
+#include "qconnectionfactories.h"
diff --git a/include/QtRemoteObjects/QtROServerIoDevice b/include/QtRemoteObjects/QtROServerIoDevice
new file mode 100644 (file)
index 0000000..9306cd4
--- /dev/null
@@ -0,0 +1 @@
+#include "qconnectionfactories.h"
diff --git a/include/QtRemoteObjects/QtRemoteObjects b/include/QtRemoteObjects/QtRemoteObjects
new file mode 100644 (file)
index 0000000..e5053ec
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef QT_QTREMOTEOBJECTS_MODULE_H
+#define QT_QTREMOTEOBJECTS_MODULE_H
+#include <QtRemoteObjects/QtRemoteObjectsDepends>
+#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 (file)
index 0000000..7cce23e
--- /dev/null
@@ -0,0 +1 @@
+#include "qtremoteobjectsversion.h"
diff --git a/include/QtRemoteObjects/headers.pri b/include/QtRemoteObjects/headers.pri
new file mode 100644 (file)
index 0000000..0da051c
--- /dev/null
@@ -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 (file)
index 0000000..8b42dad
--- /dev/null
@@ -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 (file)
index 0000000..5a13ab4
--- /dev/null
@@ -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 (file)
index 0000000..e6e32f6
--- /dev/null
@@ -0,0 +1 @@
+#include "../../src/remoteobjects/qconnectionfactories.h"
diff --git a/include/QtRemoteObjects/qremoteobjectabstractitemmodelreplica.h b/include/QtRemoteObjects/qremoteobjectabstractitemmodelreplica.h
new file mode 100644 (file)
index 0000000..1498e88
--- /dev/null
@@ -0,0 +1 @@
+#include "../../src/remoteobjects/qremoteobjectabstractitemmodelreplica.h"
diff --git a/include/QtRemoteObjects/qremoteobjectdynamicreplica.h b/include/QtRemoteObjects/qremoteobjectdynamicreplica.h
new file mode 100644 (file)
index 0000000..b889d05
--- /dev/null
@@ -0,0 +1 @@
+#include "../../src/remoteobjects/qremoteobjectdynamicreplica.h"
diff --git a/include/QtRemoteObjects/qremoteobjectnode.h b/include/QtRemoteObjects/qremoteobjectnode.h
new file mode 100644 (file)
index 0000000..14ce150
--- /dev/null
@@ -0,0 +1 @@
+#include "../../src/remoteobjects/qremoteobjectnode.h"
diff --git a/include/QtRemoteObjects/qremoteobjectpendingcall.h b/include/QtRemoteObjects/qremoteobjectpendingcall.h
new file mode 100644 (file)
index 0000000..aaf584d
--- /dev/null
@@ -0,0 +1 @@
+#include "../../src/remoteobjects/qremoteobjectpendingcall.h"
diff --git a/include/QtRemoteObjects/qremoteobjectregistry.h b/include/QtRemoteObjects/qremoteobjectregistry.h
new file mode 100644 (file)
index 0000000..6b95543
--- /dev/null
@@ -0,0 +1 @@
+#include "../../src/remoteobjects/qremoteobjectregistry.h"
diff --git a/include/QtRemoteObjects/qremoteobjectreplica.h b/include/QtRemoteObjects/qremoteobjectreplica.h
new file mode 100644 (file)
index 0000000..52bdfa8
--- /dev/null
@@ -0,0 +1 @@
+#include "../../src/remoteobjects/qremoteobjectreplica.h"
diff --git a/include/QtRemoteObjects/qremoteobjectsettingsstore.h b/include/QtRemoteObjects/qremoteobjectsettingsstore.h
new file mode 100644 (file)
index 0000000..aa40e8c
--- /dev/null
@@ -0,0 +1 @@
+#include "../../src/remoteobjects/qremoteobjectsettingsstore.h"
diff --git a/include/QtRemoteObjects/qremoteobjectsource.h b/include/QtRemoteObjects/qremoteobjectsource.h
new file mode 100644 (file)
index 0000000..4cff76a
--- /dev/null
@@ -0,0 +1 @@
+#include "../../src/remoteobjects/qremoteobjectsource.h"
diff --git a/include/QtRemoteObjects/qtremoteobjectglobal.h b/include/QtRemoteObjects/qtremoteobjectglobal.h
new file mode 100644 (file)
index 0000000..79db2d9
--- /dev/null
@@ -0,0 +1 @@
+#include "../../src/remoteobjects/qtremoteobjectglobal.h"
diff --git a/include/QtRemoteObjects/qtremoteobjectsversion.h b/include/QtRemoteObjects/qtremoteobjectsversion.h
new file mode 100644 (file)
index 0000000..57e1263
--- /dev/null
@@ -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.2.4"
+
+#define QTREMOTEOBJECTS_VERSION 0x060204
+
+#endif // QT_QTREMOTEOBJECTS_VERSION_H
diff --git a/include/QtRemoteObjectsQml/6.2.4/QtRemoteObjectsQml/private/qremoteobjectsqml_p.h b/include/QtRemoteObjectsQml/6.2.4/QtRemoteObjectsQml/private/qremoteobjectsqml_p.h
new file mode 100644 (file)
index 0000000..ab64b5b
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../../../src/remoteobjectsqml/qremoteobjectsqml_p.h"
diff --git a/include/QtRemoteObjectsQml/QtRemoteObjectsQml b/include/QtRemoteObjectsQml/QtRemoteObjectsQml
new file mode 100644 (file)
index 0000000..32f9e54
--- /dev/null
@@ -0,0 +1,5 @@
+#ifndef QT_QTREMOTEOBJECTSQML_MODULE_H
+#define QT_QTREMOTEOBJECTSQML_MODULE_H
+#include <QtRemoteObjectsQml/QtRemoteObjectsQmlDepends>
+#include "qtremoteobjectsqmlversion.h"
+#endif
diff --git a/include/QtRemoteObjectsQml/QtRemoteObjectsQmlVersion b/include/QtRemoteObjectsQml/QtRemoteObjectsQmlVersion
new file mode 100644 (file)
index 0000000..a8394c8
--- /dev/null
@@ -0,0 +1 @@
+#include "qtremoteobjectsqmlversion.h"
diff --git a/include/QtRemoteObjectsQml/headers.pri b/include/QtRemoteObjectsQml/headers.pri
new file mode 100644 (file)
index 0000000..2a30a82
--- /dev/null
@@ -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 (file)
index 0000000..9058ec9
--- /dev/null
@@ -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.2.4"
+
+#define QTREMOTEOBJECTSQML_VERSION 0x060204
+
+#endif // QT_QTREMOTEOBJECTSQML_VERSION_H
diff --git a/include/QtRepParser/QRegexParser b/include/QtRepParser/QRegexParser
new file mode 100644 (file)
index 0000000..53e35e0
--- /dev/null
@@ -0,0 +1 @@
+#include "qregexparser.h"
diff --git a/include/QtRepParser/QtRepParser b/include/QtRepParser/QtRepParser
new file mode 100644 (file)
index 0000000..e9bfb36
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef QT_QTREPPARSER_MODULE_H
+#define QT_QTREPPARSER_MODULE_H
+#include <QtRepParser/QtRepParserDepends>
+#include "qregexparser.h"
+#include "qtrepparserversion.h"
+#endif
diff --git a/include/QtRepParser/QtRepParserVersion b/include/QtRepParser/QtRepParserVersion
new file mode 100644 (file)
index 0000000..a896408
--- /dev/null
@@ -0,0 +1 @@
+#include "qtrepparserversion.h"
diff --git a/include/QtRepParser/headers.pri b/include/QtRepParser/headers.pri
new file mode 100644 (file)
index 0000000..70bd16d
--- /dev/null
@@ -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 (file)
index 0000000..b0ffb5c
--- /dev/null
@@ -0,0 +1 @@
+#include "../../src/repparser/qregexparser.h"
diff --git a/include/QtRepParser/qtrepparserversion.h b/include/QtRepParser/qtrepparserversion.h
new file mode 100644 (file)
index 0000000..0eb2d53
--- /dev/null
@@ -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.2.4"
+
+#define QTREPPARSER_VERSION 0x060204
+
+#endif // QT_QTREPPARSER_VERSION_H
diff --git a/mkspecs/features/features.pro b/mkspecs/features/features.pro
new file mode 100644 (file)
index 0000000..572235f
--- /dev/null
@@ -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 (file)
index 0000000..8c79ed5
--- /dev/null
@@ -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 (file)
index 0000000..9e8bad4
--- /dev/null
@@ -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 (file)
index 0000000..d014bc8
--- /dev/null
@@ -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 (file)
index 0000000..0f672d2
--- /dev/null
@@ -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 (file)
index 0000000..035467a
--- /dev/null
@@ -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 (file)
index 0000000..cb5ae6b
--- /dev/null
@@ -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 (file)
index 0000000..95262a0
--- /dev/null
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+
+SUBDIRS += features
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644 (file)
index 0000000..22babd4
--- /dev/null
@@ -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 (file)
index 0000000..91b72d6
--- /dev/null
@@ -0,0 +1,68 @@
+
+#####################################################################
+## 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
+)
+
+#### Keys ignored in scope 1:.:.:remoteobjects.pro:<TRUE>:
+# 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 (file)
index 0000000..f98c37a
--- /dev/null
@@ -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 (file)
index 0000000..3cbeaf6
--- /dev/null
@@ -0,0 +1,201 @@
+#
+# 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<framework-path> arguments to resolve
+# framework style includes like #include <QtCore/qobject.h>
+# 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)
+    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}
+            ${QT_TOOL_PATH_SETUP_COMMAND}
+            COMMAND
+                ${QT_CMAKE_EXPORT_NAMESPACE}::repc
+                ${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)
+
+    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}
+                           COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::repc
+                           -o rep ${infile} ${outfile}
+                           MAIN_DEPENDENCY ${infile}
+                           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 (file)
index 0000000..b5b3687
--- /dev/null
@@ -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 (file)
index 0000000..3b3166d
Binary files /dev/null and b/src/remoteobjects/doc/images/DirectConnectClientServerOutput.png differ
diff --git a/src/remoteobjects/doc/images/DirectConnectServerOutput.png b/src/remoteobjects/doc/images/DirectConnectServerOutput.png
new file mode 100644 (file)
index 0000000..a82c272
Binary files /dev/null and b/src/remoteobjects/doc/images/DirectConnectServerOutput.png differ
diff --git a/src/remoteobjects/doc/images/README b/src/remoteobjects/doc/images/README
new file mode 100644 (file)
index 0000000..aec41a2
--- /dev/null
@@ -0,0 +1 @@
+Put all documentation images into this folder.
diff --git a/src/remoteobjects/doc/images/RemoteObjectsHighLevel.png b/src/remoteobjects/doc/images/RemoteObjectsHighLevel.png
new file mode 100644 (file)
index 0000000..54cbebb
Binary files /dev/null and b/src/remoteobjects/doc/images/RemoteObjectsHighLevel.png differ
diff --git a/src/remoteobjects/doc/qtremoteobjects.qdocconf b/src/remoteobjects/doc/qtremoteobjects.qdocconf
new file mode 100644 (file)
index 0000000..d3f8c35
--- /dev/null
@@ -0,0 +1,57 @@
+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.filterAttributes    = qtremoteobjects $QT_VERSION qtrefdoc
+qhp.QtRemoteObjects.customFilters.Qt.name = QtRemoteObjects $QT_VERSION
+qhp.QtRemoteObjects.customFilters.Qt.filterAttributes = qtremoteobjects $QT_VERSION
+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 (file)
index 0000000..72ad410
--- /dev/null
@@ -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 (file)
index 0000000..006e2f7
--- /dev/null
@@ -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 COMPONENTS RemoteObjects REQUIRED)
+#! [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 (file)
index 0000000..18532b6
--- /dev/null
@@ -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 <QCoreApplication>
+#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 (file)
index 0000000..7ee8e57
--- /dev/null
@@ -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 "<<currState();
+
+}
+
diff --git a/src/remoteobjects/doc/snippets/cmake-macros/simpleswitch.h b/src/remoteobjects/doc/snippets/cmake-macros/simpleswitch.h
new file mode 100644 (file)
index 0000000..48ea61c
--- /dev/null
@@ -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$
+**
+****************************************************************************/
+
+#ifndef SIMPLESWITCH_H
+#define SIMPLESWITCH_H
+
+#include "rep_simpleswitch_source.h"
+
+class SimpleSwitch : public SimpleSwitchSimpleSource
+{
+    Q_OBJECT
+public:
+    SimpleSwitch(QObject *parent = nullptr);
+    ~SimpleSwitch() override;
+    void server_slot(bool clientState) override;
+public Q_SLOTS:
+    void timeout_slot();
+private:
+    QTimer *stateChangeTimer;
+};
+
+#endif
diff --git a/src/remoteobjects/doc/snippets/cmake-macros/simpleswitch.rep b/src/remoteobjects/doc/snippets/cmake-macros/simpleswitch.rep
new file mode 100644 (file)
index 0000000..b2d7cd2
--- /dev/null
@@ -0,0 +1,7 @@
+#include <QtCore>
+
+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 (file)
index 0000000..066b8d4
--- /dev/null
@@ -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 <QtRemoteObjects>
+//! [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"<<zn;
+        if (zn != zone) {
+            zone = zn;
+        }
+    };
+
+protected:
+    void timerEvent(QTimerEvent *);
+
+private:
+    QTime time;
+    QBasicTimer timer;
+    int zone;
+};
+//! [implementing_source]
diff --git a/src/remoteobjects/doc/snippets/doc_src_simpleswitch.cpp b/src/remoteobjects/doc/snippets/doc_src_simpleswitch.cpp
new file mode 100644 (file)
index 0000000..f2f970a
--- /dev/null
@@ -0,0 +1,363 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+//! [simpleSwitch_rep]
+class SimpleSwitch
+{
+    PROP(bool currState=false);
+    SLOT(server_slot(bool clientState));
+};
+//! [simpleSwitch_rep]
+
+//! [simpleSwitch_repsource_example1]
+REPC_SOURCE = simpleswitch.rep
+//! [simpleSwitch_repsource_example1]
+
+//! [simpleSwitch_remoteobjectsadd_example1]
+QT       += remoteobjects
+//! [simpleSwitch_remoteobjectsadd_example1]
+
+//! [simpleSwitch_serverheader_example1]
+#ifndef SIMPLESWITCH_H
+#define SIMPLESWITCH_H
+
+#include "rep_simpleswitch_source.h"
+
+class SimpleSwitch : public SimpleSwitchSimpleSource
+{
+    Q_OBJECT
+public:
+    SimpleSwitch(QObject *parent = nullptr);
+    ~SimpleSwitch();
+    virtual void server_slot(bool clientState);
+public Q_SLOTS:
+    void timeout_slot();
+private:
+    QTimer *stateChangeTimer;
+};
+
+#endif
+//! [simpleSwitch_serverheader_example1]
+
+//! [simpleSwitch_serversource_example1]
+#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()
+{
+    // 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 "<<currState();
+
+}
+//! [simpleSwitch_serversource_example1]
+
+//! [simpleSwitch_serverhostnode_example1]
+QRemoteObjectHost srcNode(QUrl(QStringLiteral("local:switch")));
+//! [simpleSwitch_serverhostnode_example1]
+
+//! [simpleSwitch_enableremoting_example1]
+SimpleSwitch srcSwitch; // create simple switch
+srcNode.enableRemoting(&srcSwitch); // enable remoting
+//! [simpleSwitch_enableremoting_example1]
+
+//! [simpleSwitch_servermaincpp_example1]
+#include <QCoreApplication>
+#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<SimpleSwitchReplica> ptr;
+ptr.reset(repNode.acquire<SimpleSwitchReplica>()); // acquire replica of source from host node
+//! [simpleSwitch_clientacquirereplica_example1]
+
+//! [simpleSwitch_clientheader_example1]
+#ifndef _CLIENT_H
+#define _CLIENT_H
+
+#include <QObject>
+#include <QSharedPointer>
+
+#include "rep_simpleswitch_replica.h"
+
+class Client : public QObject
+{
+    Q_OBJECT
+public:
+    Client(QSharedPointer<SimpleSwitchReplica> 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<SimpleSwitchReplica> reptr;// holds reference to replica
+
+ };
+
+#endif
+//! [simpleSwitch_clientheader_example1]
+
+//! [simpleSwitch_clientcpp_example1]
+#include "client.h"
+
+// constructor
+Client::Client(QSharedPointer<SimpleSwitchReplica> 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 <QCoreApplication>
+#include "client.h"
+
+int main(int argc, char *argv[])
+{
+    QCoreApplication a(argc, argv);
+
+
+    QSharedPointer<SimpleSwitchReplica> 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<SimpleSwitchReplica>()); // 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<QRemoteObjectDynamicReplica> 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 <QObject>
+#include <QSharedPointer>
+
+#include <QRemoteObjectNode>
+#include <qremoteobjectdynamicreplica.h>
+
+class DynamicClient : public QObject
+{
+    Q_OBJECT
+public:
+    DynamicClient(QSharedPointer<QRemoteObjectDynamicReplica> 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<QRemoteObjectDynamicReplica> reptr;// holds reference to replica
+ };
+
+#endif
+//! [simpleSwitch_dynamicclientheader_example2]
+
+//! [simpleSwitch_dynamicclientcpp_example2]
+#include "dynamicclient.h"
+
+// constructor
+DynamicClient::DynamicClient(QSharedPointer<QRemoteObjectDynamicReplica> 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 <QCoreApplication>
+
+#include "dynamicclient.h"
+
+int main(int argc, char *argv[])
+{
+    QCoreApplication a(argc, argv);
+
+    QSharedPointer<QRemoteObjectDynamicReplica> 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 <QCoreApplication>
+#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 (file)
index 0000000..46047f9
--- /dev/null
@@ -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(<TARGET> rep_files)
+
+qt6_add_repc_replicas(<TARGET> 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{<TARGET>}.
+
+\section1 Examples
+
+\snippet cmake-macros/CMakeLists.txt simpleSwitch_cmake_add_repc_replica
+
+The generated file(s) will be of the form \c {rep_<replica file name>_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(<TARGET> rep_files)
+
+qt6_add_repc_sources(<TARGET> 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{<TARGET>}.
+
+\section1 Examples
+
+\snippet cmake-macros/CMakeLists.txt simpleSwitch_cmake_add_repc_source
+
+The generated file(s) will be of the form \c {rep_<replica file name>_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(<TARGET> rep_files)
+
+qt6_add_repc_merged(<TARGET> 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{<TARGET>}.
+
+\section1 Examples
+
+\snippet cmake-macros/CMakeLists.txt simpleSwitch_cmake_add_repc_merged
+
+The generated file(s) will be of the form \c {rep_<replica file name>_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(<TARGET> header_files)
+
+qt6_reps_from_headers(<TARGET> 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 (file)
index 0000000..b426061
--- /dev/null
@@ -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 (file)
index 0000000..31b7e44
--- /dev/null
@@ -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 (file)
index 0000000..c355177
--- /dev/null
@@ -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 (file)
index 0000000..659c3b4
--- /dev/null
@@ -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 (file)
index 0000000..48b26e8
--- /dev/null
@@ -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 (file)
index 0000000..7ffa295
--- /dev/null
@@ -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 (file)
index 0000000..95af8e1
--- /dev/null
@@ -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 (file)
index 0000000..cbda73b
--- /dev/null
@@ -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 (file)
index 0000000..f4bec3f
--- /dev/null
@@ -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 (file)
index 0000000..a727aa2
--- /dev/null
@@ -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 (file)
index 0000000..003c8a4
--- /dev/null
@@ -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 (file)
index 0000000..e95958b
--- /dev/null
@@ -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 (file)
index 0000000..3d75faf
--- /dev/null
@@ -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<MyTypeReplica>("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 (file)
index 0000000..c122da0
--- /dev/null
@@ -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 (file)
index 0000000..717cb14
--- /dev/null
@@ -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<Prop> or push<Prop> 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<QString,int> 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<QString,int> foo))
+        SLOT(test(QMap<QString,int> foo, QMap<QString,int> bar))
+        SLOT(test(QMap<QList<QString>,int> foo))
+        SLOT(test(const QString &foo))
+        SLOT(test(QString &foo))
+        SLOT(test(const QMap<QList<QString>,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<QString,int> bar)
+        POD Foo(QList<QString> bar)
+        POD Foo(QMap<QString,int> bar, QMap<double,int> bas)
+    \endcode
+
+    A full example would look like this
+    \code
+        POD Foo(QList<QString> 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 file base>_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_<replica file base>_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_<replica file base>_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 (file)
index 0000000..9f62677
--- /dev/null
@@ -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 (file)
index 0000000..3ac8136
--- /dev/null
@@ -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 <Type>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. "<Type>" 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 <Type>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 <Type>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 (file)
index 0000000..db5b8d9
--- /dev/null
@@ -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 (file)
index 0000000..cd91a8a
--- /dev/null
@@ -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 (file)
index 0000000..d0adb2d
--- /dev/null
@@ -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 <QtNetwork/qlocalserver.h>
+#include <QtNetwork/qlocalsocket.h>
+
+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 (file)
index 0000000..e7c85be
--- /dev/null
@@ -0,0 +1,191 @@
+/****************************************************************************
+**
+** 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<void(QQnxNativeIo::*)(QAbstractSocket::SocketError)>(&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";
+    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<QIOQnxSource> 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 (file)
index 0000000..3110ed8
--- /dev/null
@@ -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<QIOQnxSource> conn, QObject *parent = nullptr);
+
+    QIODevice *connection() const override;
+protected:
+    void doClose() override;
+
+private:
+    //TODO Source or Replica
+    QSharedPointer<QIOQnxSource> 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 (file)
index 0000000..bf87431
--- /dev/null
@@ -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 <sys/neutrino.h>
+#include <sys/dispatch.h>
+#include <sys/siginfo.h>
+#include <unistd.h> // provides SETIOV
+#include <sys/netmgr.h>  //FOR ND_LOCAL_NODE
+#include <errno.h>
+#include <QtCore/qthread.h>
+#ifdef USE_HAM
+# include <ha/ham.h>
+#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 <typename T>
+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 (file)
index 0000000..ceb2191
--- /dev/null
@@ -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), 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), 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(), 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<int>(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<int>(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 (file)
index 0000000..a01c8e4
--- /dev/null
@@ -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 <QtNetwork/qabstractsocket.h>
+#include <QtRemoteObjects/qtremoteobjectglobal.h>
+
+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 (file)
index 0000000..a719857
--- /dev/null
@@ -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 <QtCore/qreadwritelock.h>
+#include <QtCore/qscopedpointer.h>
+
+#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<QRingBuffer> obuffer;
+    MsgType msgType;
+    iov_t tx_iov[3], rx_iov[2];
+    Thread<QQnxNativeIoPrivate> 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 (file)
index 0000000..5e4173d
--- /dev/null
@@ -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<QIOQnxSource> 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<QIOQnxSource *>(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<iov_t> 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<int> coids = connections.take(scoid);
+                for (int coid : coids)
+                {
+                    const uint64_t uid = static_cast<uint64_t>(scoid) << 32 | static_cast<uint32_t>(coid);
+                    QSharedPointer<QIOQnxSource> 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<QIOQnxSource> io;
+                    const uint64_t uid = static_cast<uint64_t>(scoid) << 32 | static_cast<uint32_t>(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<int>());
+                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<uint64_t>(msg_info.scoid) << 32 | static_cast<uint32_t>(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<int>());
+                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<uint64_t>(msg_info.scoid) << 32 | static_cast<uint32_t>(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<uint64_t>(msg_info.scoid) << 32 | static_cast<uint32_t>(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<int>(msg_info.dstmsglen - sizeof(bytesLeft)));
+
+            iov_t reply_vector[2];
+            SETIOV(reply_vector, &bytesLeft, sizeof(bytesLeft));
+            SETIOV(reply_vector+1, data.data(), 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<uint64_t>(msg_info.scoid) << 32 | static_cast<uint32_t>(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(), 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<uint64_t>(msg_info.scoid) << 32 | static_cast<uint32_t>(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<QIOQnxSource> 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<QIOQnxSource>(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 (file)
index 0000000..3b168b1
--- /dev/null
@@ -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 <QtNetwork/qabstractsocket.h>
+#include <QtRemoteObjects/qtremoteobjectglobal.h>
+
+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<QIOQnxSource> 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 (file)
index 0000000..1f64acf
--- /dev/null
@@ -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 <QtCore/qatomic.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qsharedpointer.h>
+
+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<int, QSet<int> > connections;
+    QHash<uint64_t, QSharedPointer<QIOQnxSource>> sources;
+    QList<QSharedPointer<QIOQnxSource>> pending;
+    QAtomicInt running;
+    Thread<QQnxNativeServerPrivate> thread;
+    mutable QMutex mutex;
+    int terminateCoid;
+#ifdef USE_HAM
+    ham_entity_t *hamEntityHandle;
+    ham_condition_t *hamConditionHandle;
+    QHash<uint64_t, ham_action_t*> 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 (file)
index 0000000..5371aa6
--- /dev/null
@@ -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 <QtNetwork/qhostinfo.h>
+
+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<QHostAddress> 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 (file)
index 0000000..fdb8de6
--- /dev/null
@@ -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 <QtNetwork/qtcpserver.h>
+#include <QtNetwork/qtcpsocket.h>
+
+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 (file)
index 0000000..e81672f
--- /dev/null
@@ -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<int>(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<QString> 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<QnxServerImpl>(QStringLiteral("qnx"));
+#endif
+#ifdef Q_OS_LINUX
+    registerType<AbstractLocalServerImpl>(QStringLiteral("localabstract"));
+#endif
+    registerType<LocalServerImpl>(QStringLiteral("local"));
+    registerType<TcpServerImpl>(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<QnxClientIo>(QStringLiteral("qnx"));
+#endif
+#ifdef Q_OS_LINUX
+    registerType<AbstractLocalClientIo>(QStringLiteral("localabstract"));
+#endif
+    registerType<LocalClientIo>(QStringLiteral("local"));
+    registerType<TcpClientIo>(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<CustomClientIo>(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<CustomServerImpl>(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 (file)
index 0000000..b123ab8
--- /dev/null
@@ -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 <QtNetwork/qabstractsocket.h>
+
+#include <QtRemoteObjects/qtremoteobjectglobal.h>
+
+
+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<QString> 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<typename T>
+    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<QString, CreatorFunc> 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<typename T>
+    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<QString, CreatorFunc> m_creatorFuncs;
+};
+
+template <typename T>
+inline void qRegisterRemoteObjectsClient(const QString &id)
+{
+    QtROClientFactory::instance()->registerType<T>(id);
+}
+
+template <typename T>
+inline void qRegisterRemoteObjectsServer(const QString &id)
+{
+    QtROServerFactory::instance()->registerType<T>(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 (file)
index 0000000..9365a60
--- /dev/null
@@ -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 <QtCore/qdatastream.h>
+#include <QtCore/qiodevice.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/private/qobject_p.h>
+
+#include <QtRemoteObjects/qtremoteobjectglobal.h>
+#include <QtRemoteObjects/qconnectionfactories.h>
+#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<QString> 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<QIODevice> 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 (file)
index 0000000..11f193e
--- /dev/null
@@ -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 <QtCore/qitemselectionmodel.h>
+
+inline QList<QModelRoleData> createModelRoleData(const QList<int> &roles)
+{
+    QList<QModelRoleData> 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<int> filterRoles(const QList<int> &roles, const QList<int> &availableRoles)
+{
+    if (roles.isEmpty())
+        return availableRoles;
+
+    QList<int> 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<int> &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<QAbstractItemModel*>();
+    qRegisterMetaType<Qt::Orientation>();
+    qRegisterMetaType<QList<Qt::Orientation>>();
+    qRegisterMetaType<QtPrivate::ModelIndex>();
+    qRegisterMetaType<QtPrivate::IndexList>();
+    qRegisterMetaType<QtPrivate::DataEntries>();
+    qRegisterMetaType<QtPrivate::MetaAndDataEntries>();
+    qRegisterMetaType<QItemSelectionModel::SelectionFlags>();
+    qRegisterMetaType<QSize>();
+    qRegisterMetaType<QIntHash>();
+}
+
+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<int> 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<int> &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<Qt::Orientation> orientations, QList<int> sections, QList<int> 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<int> & roles) const
+{
+    QList<int> 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<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint)
+{
+    QtPrivate::IndexList indexes;
+    for (const QPersistentModelIndex &idx : parents)
+        indexes << QtPrivate::toModelIndexList((QModelIndex)idx, m_model);
+    emit layoutChanged(indexes, hint);
+}
+
+QList<QtPrivate::IndexValuePair> QAbstractItemModelSourceAdapter::fetchTree(const QModelIndex &parent, size_t &size, const QList<int> &roles)
+{
+    QList<QtPrivate::IndexValuePair> 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 (file)
index 0000000..73d52d8
--- /dev/null
@@ -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 <QtCore/qsize.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAbstractItemModel;
+class QItemSelectionModel;
+
+class QAbstractItemModelSourceAdapter : public QObject
+{
+    Q_OBJECT
+public:
+    Q_INVOKABLE explicit QAbstractItemModelSourceAdapter(QAbstractItemModel *object, QItemSelectionModel *sel, const QList<int> &roles = QList<int>());
+    Q_PROPERTY(QList<int> availableRoles READ availableRoles WRITE setAvailableRoles NOTIFY availableRolesChanged)
+    Q_PROPERTY(QIntHash roleNames READ roleNames)
+    static void registerTypes();
+    QItemSelectionModel* selectionModel() const;
+
+public Q_SLOTS:
+    QList<int> availableRoles() const { return m_availableRoles; }
+    void setAvailableRoles(QList<int> 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<int> roles);
+    QVariantList replicaHeaderRequest(QList<Qt::Orientation> orientations, QList<int> sections, QList<int> 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<int> &roles);
+
+    void sourceDataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight, const QList<int> & roles = QList<int> ()) 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<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint);
+Q_SIGNALS:
+    void availableRolesChanged();
+    void dataChanged(QtPrivate::IndexList topLeft, QtPrivate::IndexList bottomRight, QList<int> 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<QtPrivate::IndexValuePair> fetchTree(const QModelIndex &parent, size_t &size, const QList<int> &roles);
+
+    QAbstractItemModel *m_model;
+    QItemSelectionModel *m_selectionModel;
+    QList<int> m_availableRoles;
+};
+
+template <class ObjectType, class AdapterType>
+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>(&AdapterType::availableRoles, static_cast<QList<int> (QObject::*)()>(nullptr),"availableRoles");
+        m_properties[2] = QtPrivate::qtro_property_index<AdapterType>(&AdapterType::roleNames, static_cast<QIntHash (QObject::*)()>(nullptr),"roleNames");
+        m_signals[0] = 10;
+        m_signals[1] = QtPrivate::qtro_signal_index<AdapterType>(&AdapterType::availableRolesChanged, static_cast<void (QObject::*)()>(nullptr),m_signalArgCount+0,&m_signalArgTypes[0]);
+        m_signals[2] = QtPrivate::qtro_signal_index<AdapterType>(&AdapterType::dataChanged, static_cast<void (QObject::*)(QtPrivate::IndexList,QtPrivate::IndexList,QList<int>)>(nullptr),m_signalArgCount+1,&m_signalArgTypes[1]);
+        m_signals[3] = QtPrivate::qtro_signal_index<AdapterType>(&AdapterType::rowsInserted, static_cast<void (QObject::*)(QtPrivate::IndexList,int,int)>(nullptr),m_signalArgCount+2,&m_signalArgTypes[2]);
+        m_signals[4] = QtPrivate::qtro_signal_index<AdapterType>(&AdapterType::rowsRemoved, static_cast<void (QObject::*)(QtPrivate::IndexList,int,int)>(nullptr),m_signalArgCount+3,&m_signalArgTypes[3]);
+        m_signals[5] = QtPrivate::qtro_signal_index<AdapterType>(&AdapterType::rowsMoved, static_cast<void (QObject::*)(QtPrivate::IndexList,int,int,QtPrivate::IndexList,int)>(nullptr),m_signalArgCount+4,&m_signalArgTypes[4]);
+        m_signals[6] = QtPrivate::qtro_signal_index<AdapterType>(&AdapterType::currentChanged, static_cast<void (QObject::*)(QtPrivate::IndexList,QtPrivate::IndexList)>(nullptr),m_signalArgCount+5,&m_signalArgTypes[5]);
+        m_signals[7] = QtPrivate::qtro_signal_index<ObjectType>(&ObjectType::modelReset, static_cast<void (QObject::*)()>(nullptr),m_signalArgCount+6,&m_signalArgTypes[6]);
+        m_signals[8] = QtPrivate::qtro_signal_index<ObjectType>(&ObjectType::headerDataChanged, static_cast<void (QObject::*)(Qt::Orientation,int,int)>(nullptr),m_signalArgCount+7,&m_signalArgTypes[7]);
+        m_signals[9] = QtPrivate::qtro_signal_index<AdapterType>(&AdapterType::columnsInserted, static_cast<void (QObject::*)(QtPrivate::IndexList,int,int)>(nullptr),m_signalArgCount+8,&m_signalArgTypes[8]);
+        m_signals[10] = QtPrivate::qtro_signal_index<AdapterType>(&AdapterType::layoutChanged, static_cast<void (QObject::*)(QtPrivate::IndexList,QAbstractItemModel::LayoutChangeHint)>(nullptr),m_signalArgCount+9,&m_signalArgTypes[9]);
+        m_methods[0] = 6;
+        m_methods[1] = QtPrivate::qtro_method_index<AdapterType>(&AdapterType::replicaSizeRequest, static_cast<void (QObject::*)(QtPrivate::IndexList)>(nullptr),"replicaSizeRequest(QtPrivate::IndexList)",m_methodArgCount+0,&m_methodArgTypes[0]);
+        m_methods[2] = QtPrivate::qtro_method_index<AdapterType>(&AdapterType::replicaRowRequest, static_cast<void (QObject::*)(QtPrivate::IndexList,QtPrivate::IndexList,QList<int>)>(nullptr),"replicaRowRequest(QtPrivate::IndexList,QtPrivate::IndexList,QList<int>)",m_methodArgCount+1,&m_methodArgTypes[1]);
+        m_methods[3] = QtPrivate::qtro_method_index<AdapterType>(&AdapterType::replicaHeaderRequest, static_cast<void (QObject::*)(QList<Qt::Orientation>,QList<int>,QList<int>)>(nullptr),"replicaHeaderRequest(QList<Qt::Orientation>,QList<int>,QList<int>)",m_methodArgCount+2,&m_methodArgTypes[2]);
+        m_methods[4] = QtPrivate::qtro_method_index<AdapterType>(&AdapterType::replicaSetCurrentIndex, static_cast<void (QObject::*)(QtPrivate::IndexList,QItemSelectionModel::SelectionFlags)>(nullptr),"replicaSetCurrentIndex(QtPrivate::IndexList,QItemSelectionModel::SelectionFlags)",m_methodArgCount+3,&m_methodArgTypes[3]);
+        m_methods[5] = QtPrivate::qtro_method_index<AdapterType>(&AdapterType::replicaSetData, static_cast<void (QObject::*)(QtPrivate::IndexList,QVariant,int)>(nullptr),"replicaSetData(QtPrivate::IndexList,QVariant,int)",m_methodArgCount+4,&m_methodArgTypes[4]);
+        m_methods[6] = QtPrivate::qtro_method_index<AdapterType>(&AdapterType::replicaCacheRequest, static_cast<void (QObject::*)(size_t,QList<int>)>(nullptr),"replicaCacheRequest(size_t,QList<int>)",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<int>)");
+        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<int>)");
+        case 2: return QByteArrayLiteral("replicaHeaderRequest(QList<Qt::Orientation>,QList<int>,QList<int>)");
+        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<int>)");
+        }
+        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 (file)
index 0000000..bf13b36
--- /dev/null
@@ -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 <QtCore/qdebug.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qpoint.h>
+
+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<int>());
+    properties << QVariant::fromValue(QIntHash());
+    setProperties(std::move(properties));
+}
+
+void QAbstractItemModelReplicaImplementation::registerMetatypes()
+{
+    static bool alreadyRegistered = false;
+    if (alreadyRegistered)
+        return;
+
+    alreadyRegistered = true;
+    qRegisterMetaType<QAbstractItemModel*>();
+    qRegisterMetaType<Qt::Orientation>();
+    qRegisterMetaType<QList<Qt::Orientation>>();
+    qRegisterMetaType<QtPrivate::ModelIndex>();
+    qRegisterMetaType<QtPrivate::IndexList>();
+    qRegisterMetaType<QtPrivate::DataEntries>();
+    qRegisterMetaType<QtPrivate::MetaAndDataEntries>();
+    qRegisterMetaType<QItemSelectionModel::SelectionFlags>();
+    qRegisterMetaType<QSize>();
+    qRegisterMetaType<QIntHash>();
+}
+
+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<int> &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 &current, 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<int> &roles = QList<int>())
+{
+    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<int> &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<QtPrivate::MetaAndDataEntries>());
+        size = watcher->returnValue().value<QtPrivate::MetaAndDataEntries>().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<CacheEntry> &headerEntries = m_headerData[0];
+        for (int i = 0; i < size.width(); ++i )
+            headerEntries[i].data.clear();
+    }
+    {
+        QList<CacheEntry> &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<QtPrivate::MetaAndDataEntries>();
+        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<SizeWatcher*>(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<int> &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<int> &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<int> &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<RowWatcher *>(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<QtPrivate::DataEntries>();
+
+    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<RequestedData> 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<int> 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<QtPrivate::DataEntries> 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<CacheEntry> &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<int> roles;
+    QList<int> sections;
+    QList<Qt::Orientation> orientations;
+    for (const RequestedHeaderData &data : qAsConst(m_requestedHeaderData)) {
+        roles.push_back(data.role);
+        sections.push_back(data.section);
+        orientations.push_back(data.orientation);
+    }
+    QRemoteObjectPendingReply<QVariantList> 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<QPersistentModelIndex> 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<QtPrivate::MetaAndDataEntries>());
+        const QSize size = watcher->returnValue().value<QtPrivate::MetaAndDataEntries>().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<QtPrivate::MetaAndDataEntries>();
+            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<QPair<int, int>> listRanges(const QList<int> &list)
+{
+    QList<QPair<int, int>> result;
+    if (!list.isEmpty()) {
+        QPair<int, int> 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<HeaderWatcher *>(qobject);
+    Q_ASSERT(watcher);
+
+    QVariantList data = watcher->returnValue().value<QVariantList>();
+    Q_ASSERT(watcher->orientations.size() == data.size());
+    Q_ASSERT(watcher->sections.size() == data.size());
+    Q_ASSERT(watcher->roles.size() == data.size());
+    QList<int> horizontalSections;
+    QList<int> 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<int, QVariant> &dat = m_headerData[index][watcher->sections[i]].data;
+        dat[role] = data[i];
+    }
+    QList<QPair<int, int>> horRanges = listRanges(horizontalSections);
+    QList<QPair<int, int>> 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<int> &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<int, QVariant>::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<int> &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<int> 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<CacheData*>(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<void*>(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<QSize> 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<CacheEntry> elem = d->m_headerData[index];
+    if (section >= elem.size())
+        return QVariant();
+
+    const QHash<int, QVariant> &dat = elem.at(section).data;
+    QHash<int, QVariant>::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<int> QAbstractItemModelReplica::availableRoles() const
+{
+    return d->availableRoles();
+}
+
+/*!
+    \reimp
+*/
+QHash<int, QByteArray> 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 (file)
index 0000000..a08464b
--- /dev/null
@@ -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 <QtRemoteObjects/qtremoteobjectglobal.h>
+
+#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qitemselectionmodel.h>
+
+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<int> availableRoles() const;
+    QHash<int, QByteArray> 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<int> &rolesHint);
+    QScopedPointer<QAbstractItemModelReplicaImplementation> 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 (file)
index 0000000..57f368a
--- /dev/null
@@ -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 <list>
+#include <unordered_map>
+#include <unordered_set>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+    const int DefaultNodesCacheSize = 1000;
+}
+
+struct CacheEntry
+{
+    QHash<int, QVariant> data;
+    Qt::ItemFlags flags;
+
+    explicit CacheEntry()
+        : flags(Qt::NoItemFlags)
+    {}
+};
+
+using CachedRowEntry = QList<CacheEntry>;
+
+template <class Key, class Value>
+struct LRUCache
+{
+    typedef std::pair<Key, Value*> Pair;
+    std::list<Pair> cachedItems;
+    typedef typename std::list<Pair>::iterator CacheIterator;
+    std::unordered_map<Key, CacheIterator> 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<std::pair<Key, CacheIterator>> 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<int, CacheData> 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<int> roles;
+};
+
+struct RequestedHeaderData
+{
+    int role;
+    int section;
+    Qt::Orientation orientation;
+};
+
+class SizeWatcher : public QRemoteObjectPendingCallWatcher
+{
+    Q_OBJECT
+public:
+    SizeWatcher(QtPrivate::IndexList _parentList, const QRemoteObjectPendingReply<QSize> &reply)
+        : QRemoteObjectPendingCallWatcher(reply),
+          parentList(_parentList) {}
+    QtPrivate::IndexList parentList;
+};
+
+class RowWatcher : public QRemoteObjectPendingCallWatcher
+{
+    Q_OBJECT
+public:
+    RowWatcher(QtPrivate::IndexList _start, QtPrivate::IndexList _end, QList<int> _roles, const QRemoteObjectPendingReply<QtPrivate::DataEntries> &reply)
+        : QRemoteObjectPendingCallWatcher(reply),
+          start(_start),
+          end(_end),
+          roles(_roles) {}
+    QtPrivate::IndexList start, end;
+    QList<int> roles;
+};
+
+class HeaderWatcher : public QRemoteObjectPendingCallWatcher
+{
+    Q_OBJECT
+public:
+    HeaderWatcher(QList<Qt::Orientation> _orientations, QList<int> _sections, QList<int> _roles, const QRemoteObjectPendingReply<QVariantList> &reply)
+        : QRemoteObjectPendingCallWatcher(reply),
+          orientations(_orientations),
+          sections(_sections),
+          roles(_roles) {}
+    QList<Qt::Orientation> orientations;
+    QList<int> 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<int> 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<int> &availableRoles() const
+    {
+        if (m_availableRoles.isEmpty())
+            m_availableRoles = propAsVariant(0).value<QList<int>>();
+        return m_availableRoles;
+    }
+
+    QHash<int, QByteArray> roleNames() const
+    {
+       QIntHash roles = propAsVariant(1).value<QIntHash>();
+       return roles;
+    }
+
+    void setModel(QAbstractItemModelReplica *model);
+    bool clearCache(const QtPrivate::IndexList &start, const QtPrivate::IndexList &end, const QList<int> &roles);
+
+Q_SIGNALS:
+    void availableRolesChanged();
+    void dataChanged(QtPrivate::IndexList topLeft, QtPrivate::IndexList bottomRight, QList<int> 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<QSize> replicaSizeRequest(QtPrivate::IndexList parentList)
+    {
+        static int __repc_index = QAbstractItemModelReplicaImplementation::staticMetaObject.indexOfSlot("replicaSizeRequest(QtPrivate::IndexList)");
+        QVariantList __repc_args;
+        __repc_args << QVariant::fromValue(parentList);
+        return QRemoteObjectPendingReply<QSize>(sendWithReply(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args));
+    }
+    QRemoteObjectPendingReply<QtPrivate::DataEntries> replicaRowRequest(QtPrivate::IndexList start, QtPrivate::IndexList end, QList<int> roles)
+    {
+        static int __repc_index = QAbstractItemModelReplicaImplementation::staticMetaObject.indexOfSlot("replicaRowRequest(QtPrivate::IndexList,QtPrivate::IndexList,QList<int>)");
+        QVariantList __repc_args;
+        __repc_args << QVariant::fromValue(start) << QVariant::fromValue(end) << QVariant::fromValue(roles);
+        return QRemoteObjectPendingReply<QtPrivate::DataEntries>(sendWithReply(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args));
+    }
+    QRemoteObjectPendingReply<QVariantList> replicaHeaderRequest(QList<Qt::Orientation> orientations, QList<int> sections, QList<int> roles)
+    {
+        static int __repc_index = QAbstractItemModelReplicaImplementation::staticMetaObject.indexOfSlot("replicaHeaderRequest(QList<Qt::Orientation>,QList<int>,QList<int>)");
+        QVariantList __repc_args;
+        __repc_args << QVariant::fromValue(orientations) << QVariant::fromValue(sections) << QVariant::fromValue(roles);
+        return QRemoteObjectPendingReply<QVariantList>(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<QtPrivate::MetaAndDataEntries> replicaCacheRequest(size_t size, QList<int> roles)
+    {
+        static int __repc_index = QAbstractItemModelReplicaImplementation::staticMetaObject.indexOfSlot("replicaCacheRequest(size_t,QList<int>)");
+        QVariantList __repc_args;
+        __repc_args << QVariant::fromValue(size) << QVariant::fromValue(roles);
+        return QRemoteObjectPendingReply<QtPrivate::MetaAndDataEntries>(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<int> &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 &current, const QModelIndex &previous);
+    void fillCache(const QtPrivate::IndexValuePair &pair,const QList<int> &roles);
+    void onLayoutChanged(const QtPrivate::IndexList &parents, QAbstractItemModel::LayoutChangeHint hint);
+public:
+    QScopedPointer<QItemSelectionModel> m_selectionModel;
+    QList<CacheEntry> m_headerData[2];
+
+    CacheData m_rootItem;
+    inline CacheData* cacheData(const QModelIndex &index) const {
+        if (!index.isValid())
+            return const_cast<CacheData*>(&m_rootItem);
+        if (index.internalPointer()) {
+            auto parent = static_cast<CacheData*>(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<RequestedData> m_requestedData;
+    QList<RequestedHeaderData> m_requestedHeaderData;
+    QList<QRemoteObjectPendingCallWatcher*> m_pendingRequests;
+    QAbstractItemModelReplica *q;
+    mutable QList<int> m_availableRoles;
+    std::unordered_set<CacheData*> m_activeParents;
+    QtRemoteObjects::InitialAction m_initialAction;
+    QList<int> 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 (file)
index 0000000..f6905c0
--- /dev/null
@@ -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 <QtCore/qabstractitemmodel.h>
+#include <QtCore/qdatastream.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qitemselectionmodel.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qnamespace.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qvariant.h>
+#include <QtRemoteObjects/qtremoteobjectglobal.h>
+
+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<ModelIndex> 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<IndexValuePair> 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<IndexValuePair> data;
+};
+
+struct MetaAndDataEntries : DataEntries
+{
+    QList<int> 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<int>(orient);
+}
+
+inline QDataStream& operator>>(QDataStream &stream, Qt::Orientation &orient)
+{
+    int val;
+    QDataStream &ret = stream >> val;
+    orient = static_cast<Qt::Orientation>(val);
+    return ret;
+}
+
+inline QDataStream& operator<<(QDataStream &stream, QItemSelectionModel::SelectionFlags command)
+{
+    return stream << static_cast<int>(command);
+}
+
+inline QDataStream& operator>>(QDataStream &stream, QItemSelectionModel::SelectionFlags &command)
+{
+    int val;
+    QDataStream &ret = stream >> val;
+    command = static_cast<QItemSelectionModel::SelectionFlags>(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<int>(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<Qt::ItemFlags>(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<QAbstractItemModel *>(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 (file)
index 0000000..911cbba
--- /dev/null
@@ -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 <QtCore/qiodevice.h>
+
+#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 (file)
index 0000000..2be67c8
--- /dev/null
@@ -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 <QtCore/qassociativeiterable.h>
+#include <QtCore/qsequentialiterable.h>
+#include <QtCore/qvariant.h>
+
+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 (file)
index 0000000..bd39000
--- /dev/null
@@ -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 <QtCore/qmetaobject.h>
+
+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<QRemoteObjectReplicaImplementation>(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<void*>(const_cast<QRemoteObjectDynamicReplica*>(this));
+
+    // not entirely sure that one is needed... TODO: check
+    auto impl = qSharedPointerCast<QRemoteObjectReplicaImplementation>(d_impl);
+    if (QString::fromLatin1(name) == impl->m_objectName)
+        return static_cast<void*>(const_cast<QRemoteObjectDynamicReplica*>(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<QConnectedReplicaImplementation>(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<QVariant*>(argv[0]);
+            else
+                args << QVariant(mp.metaType(), argv[0]);
+            QRemoteObjectReplica::send(QMetaObject::WriteProperty, saved_id, args);
+        } else {
+            if (mp.userType() == QMetaType::QVariant)
+                *reinterpret_cast<QVariant*>(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<QRemoteObjectPendingCall*>(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 (file)
index 0000000..f30d0d0
--- /dev/null
@@ -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 <QtRemoteObjects/qremoteobjectreplica.h>
+
+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 (file)
index 0000000..f527cfa
--- /dev/null
@@ -0,0 +1,2825 @@
+/****************************************************************************
+**
+** 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 <QtCore/qabstractitemmodel.h>
+#include <memory>
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QtRemoteObjects;
+using namespace QRemoteObjectStringLiterals;
+
+using GadgetType = QList<QVariant>;
+
+struct ManagedGadgetTypeEntry
+{
+    GadgetType gadgetType;
+    QMetaType gadgetMetaType;
+    QList<QMetaType> enumMetaTypes;
+    std::shared_ptr<QMetaObject> metaObject;
+
+    void unregisterMetaTypes()
+    {
+        QMetaType::unregisterMetaType(gadgetMetaType);
+        for (auto enumMetaType : enumMetaTypes)
+            QMetaType::unregisterMetaType(enumMetaType);
+    }
+};
+
+static QMutex s_managedTypesMutex;
+static QHash<int, ManagedGadgetTypeEntry> s_managedTypes;
+static QHash<int, QSet<QtROIoDeviceBase*>> s_trackedConnections;
+
+static void GadgetsStaticMetacallFunction(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
+{
+    if (_c == QMetaObject::ReadProperty) {
+        GadgetType *_t = reinterpret_cast<GadgetType *>(_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<GadgetType *>(_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<GadgetType*>(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<const GadgetType*>(copy));
+}
+
+static void GadgetTypedMoveConstructor(const QtPrivate::QMetaTypeInterface *, void *where, void *copy)
+{
+    new(where) GadgetType(std::move(*reinterpret_cast<GadgetType*>(copy)));
+}
+
+static bool GadgetEqualsFn(const QtPrivate::QMetaTypeInterface *, const void *a, const void *b)
+{
+    return *reinterpret_cast<const GadgetType*>(a) == *reinterpret_cast<const GadgetType*>(b);
+}
+
+static void GadgetDebugStreamFn(const QtPrivate::QMetaTypeInterface *, QDebug &dbg, const void *a)
+{
+    const GadgetType *gadgetProperties = reinterpret_cast<const GadgetType *>(a);
+    for (const auto &prop : *gadgetProperties)
+        dbg << prop;
+}
+
+static void GadgetDataStreamOutFn(const QtPrivate::QMetaTypeInterface *, QDataStream &ds, const void *a)
+{
+    const GadgetType *gadgetProperties = reinterpret_cast<const GadgetType *>(a);
+    for (const auto &prop : *gadgetProperties)
+        ds << prop;
+}
+
+static void GadgetDataStreamInFn(const QtPrivate::QMetaTypeInterface *, QDataStream &ds, void *a)
+{
+    GadgetType *gadgetProperties = reinterpret_cast<GadgetType *>(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<typename T>
+static void EnumDestructor(const QtPrivate::QMetaTypeInterface *, void *ptr)
+{
+    static_cast<T*>(ptr)->~T();
+}
+
+template<typename T>
+static void EnumConstructor(const QtPrivate::QMetaTypeInterface *, void *where)
+{
+    new(where) T;
+}
+
+template<typename T>
+static void EnumCopyConstructor(const QtPrivate::QMetaTypeInterface *, void *where, const void *copy)
+{
+    new(where) T(*static_cast<const T*>(copy));
+}
+
+template<typename T>
+static void EnumMoveConstructor(const QtPrivate::QMetaTypeInterface *, void *where, void *copy)
+{
+    new(where) T(std::move(*static_cast<T*>(copy)));
+}
+
+// Not used, but keeping these in case we end up with a need for save/load.
+template<typename T>
+static void EnumSaveOperator(QDataStream & out, const void *data)
+{
+    const T value = *static_cast<const T *>(data);
+    out << value;
+}
+
+template<typename T>
+static void EnumLoadOperator(QDataStream &in, void *data)
+{
+    T value = *static_cast<T *>(data);
+    in >> value;
+}
+
+template<typename T>
+static bool EnumEqualsFn(const QtPrivate::QMetaTypeInterface *, const void *a, const void *b)
+{
+    return *static_cast<const T*>(a) == *static_cast<const T*>(b);
+}
+
+template<typename T>
+static bool EnumLessThanFn(const QtPrivate::QMetaTypeInterface *, const void *a, const void *b)
+{
+    return *static_cast<const T*>(a) < *static_cast<const T*>(b);
+}
+
+template<typename T>
+static void EnumDebugStreamFn(const QtPrivate::QMetaTypeInterface *, QDebug &dbg, const void *a)
+{
+    dbg << *static_cast<const T *>(a);
+}
+
+template<typename T>
+static void EnumDataStreamOutFn(const QtPrivate::QMetaTypeInterface *, QDataStream &ds, const void *a)
+{
+    ds << *static_cast<const T *>(a);
+}
+
+template<typename T>
+static void EnumDataStreamInFn(const QtPrivate::QMetaTypeInterface *, QDataStream &ds, void *a)
+{
+    ds >> *static_cast<T *>(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 <typename K, typename V, typename Query>
+bool map_contains(const QMap<K,V> &map, const Query &key, typename QMap<K,V>::const_iterator &result)
+{
+    const typename QMap<K,V>::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>(&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://<target device>: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<SomeObject>();
+\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 &registryUrl, 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");
+
+    // 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://localhost: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
+    // 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://<target device>:12123");
+
+    // Because of the reverseProxy, we can expose objects on this device
+    // and they will make their way to proxyNode...
+    nodeOnRemoteDevice.enableRemoting<OtherObject>(&otherObject);
+\endcode
+
+\code
+    // Acquire() can now see the objects on other devices through proxyNode,
+    // due to the reverseProxy call.
+    OtherObject *oo = myInternalHost.acquire<OtherObject>();
+\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<QRemoteObjectHost *>(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<QRemoteObjectReplicaImplementation> rep = qSharedPointerCast<QRemoteObjectReplicaImplementation>(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<<remoteObjectAddresses();
+    }
+}
+
+/*!
+    Returns a pointer to the Node's \l {QRemoteObjectRegistry}, if the Node
+    is using the Registry feature; otherwise it returns \nullptr.
+*/
+const QRemoteObjectRegistry *QRemoteObjectNode::registry() const
+{
+    Q_D(const QRemoteObjectNode);
+    return d->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<EnumPair> values;
+};
+
+struct GadgetProperty {
+    QByteArray name;
+    QByteArray type;
+};
+
+struct GadgetData {
+    QList<GadgetProperty> properties;
+    QList<EnumData> 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<QByteArray, GadgetData>;
+struct TypeInfo : public QtPrivate::QMetaTypeInterface
+{
+    const QMetaObject *metaObject;
+};
+static const QMetaObject *metaObjectFn(const QtPrivate::QMetaTypeInterface *self)
+{
+    return static_cast<const TypeInfo *>(self)->metaObject;
+}
+
+template <class Int>
+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<Int>,
+            EnumCopyConstructor<Int>,
+            EnumMoveConstructor<Int>,
+            EnumDestructor<Int>,
+            EnumEqualsFn<Int>,
+            EnumLessThanFn<Int>,
+            EnumDebugStreamFn<Int>,
+            EnumDataStreamOutFn<Int>,
+            EnumDataStreamInFn<Int>,
+            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<qint8>(name, size);
+        break;
+    case 2:
+        result = enumMetaType<qint16>(name, size);
+        break;
+    case 4:
+        result = enumMetaType<qint32>(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<qint64>,
+//                                                 &EnumConstructor<qint64>, size, flags, meta);
+//        break;
+    default:
+        qWarning() << "Invalid enum detected" << name << "with size" << size << ".  Defaulting to register as int.";
+        size = 4;
+        result = enumMetaType<qint32>(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<TypeInfo *> 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<QMetaObject>{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<qint32>(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<QByteArray, QByteArray> classEnums;
+
+    in >> typeString;
+    type = typeString.toLatin1();
+    builder.addClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE, type);
+    builder.setClassName(type);
+
+    in >> numEnums;
+    QList<quint32> 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 *>(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<QReplicaImplementationInterface> rep = replicas.value(name).toStrongRef();
+    if (!rep) { //already deleted
+        replicas.remove(name);
+        return false;
+    }
+
+    return true;
+}
+
+static QDebug operator<<(QDebug debug,
+                         const QHash<QString, QWeakPointer<QReplicaImplementationInterface>> &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<QReplicaImplementationInterface> 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<QReplicaImplementationInterface> 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<QConnectedReplicaImplementation> rep = qSharedPointerCast<QConnectedReplicaImplementation>(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<QRemoteObjectReplicaImplementation> rep = qSharedPointerCast<QRemoteObjectReplicaImplementation>(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<QConnectedReplicaImplementation *>(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<QString, QRemoteObjectSourceBase*>::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<QtROIoDeviceBase*>(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<QRemoteObjectReplicaImplementation> rep = qSharedPointerCast<QRemoteObjectReplicaImplementation>(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<QConnectedReplicaImplementation> rep = qSharedPointerCast<QConnectedReplicaImplementation>(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<QConnectedReplicaImplementation> rep = qSharedPointerCast<QConnectedReplicaImplementation>(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<QConnectedReplicaImplementation> rep = qSharedPointerCast<QConnectedReplicaImplementation>(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<QRemoteObjectReplicaImplementation> rep = qSharedPointerCast<QRemoteObjectReplicaImplementation>(replicas.value(rxName).toStrongRef());
+            if (rep) {
+                QConnectedReplicaImplementation *connectedRep = nullptr;
+                if (!rep->isShortCircuit()) {
+                    connectedRep = static_cast<QConnectedReplicaImplementation *>(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<QRO_>()) {
+                        // This is a type that requires registration
+                        QRO_ typeInfo = rxValue.value<QRO_>();
+                        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<QRemoteObjectReplicaImplementation> rep = qSharedPointerCast<QRemoteObjectReplicaImplementation>(replicas.value(rxName).toStrongRef());
+            if (rep) {
+                static QVariant null(QMetaType::fromType<QObject *>(), nullptr);
+                QVariant paramValue;
+                // Qt usually supports 9 arguments, so ten should be usually safe
+                QVarLengthArray<void*, 10> 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<void*>(reinterpret_cast<const void*>(&rxArgs.at(i)));
+                        else {
+                            rxArgs[i] = decodeVariant(std::move(rxArgs[i]), signal.parameterMetaType(i));
+                            param[i + 1] = const_cast<void *>(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<QRemoteObjectReplicaImplementation> rep = qSharedPointerCast<QRemoteObjectReplicaImplementation>(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<QRemoteObjectNode *>();
+    qRegisterMetaType<QRemoteObjectNode::ErrorCode>();
+    qRegisterMetaType<QAbstractSocket::SocketError>(); //For queued qnx error()
+    qRegisterMetaType<QRemoteObjectPackets::QRO_>();
+    qRegisterMetaType<QRemoteObjectPackets::QSQ_>();
+    qRegisterMetaType<QRemoteObjectPackets::QAS_>();
+    qRegisterMetaType<QtROSequentialContainer>();
+    qRegisterMetaType<QtROAssociativeContainer>();
+    // 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 &registryAddress, 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 &registryAddress,
+                                     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 &registryAddress, 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 &registryUrl)
+{
+    return d_func()->setRegistryUrlRegistryHostImpl(registryUrl);
+}
+
+bool QRemoteObjectRegistryHostPrivate::setRegistryUrlRegistryHostImpl(const QUrl &registryUrl)
+{
+    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<QRemoteObjectRegistry>());
+        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 &registryAddress)
+{
+    Q_D(QRemoteObjectNode);
+    return d->setRegistryUrlNodeImpl(registryAddress);
+}
+
+bool QRemoteObjectNodePrivate::setRegistryUrlNodeImpl(const QUrl &registryAddr)
+{
+    Q_Q(QRemoteObjectNode);
+    if (registry) {
+        setLastError(QRemoteObjectNode::RegistryAlreadyHosted);
+        return false;
+    }
+
+    registryAddress = registryAddr;
+    setRegistry(q->acquire<QRemoteObjectRegistry>());
+    //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_>());
+    QRO_ childInfo = property.value<QRO_>();
+    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<QRemoteObjectDynamicReplica*>(nullptr);
+        else
+            retval = QVariant::fromValue<QAbstractItemModelReplica*>(nullptr);
+        return retval;
+    }
+
+    const bool newReplica = !replicas.contains(childInfo.name) || rep->isInitialized();
+    if (newReplica) {
+        if (rep->isInitialized()) {
+            auto childRep = qSharedPointerCast<QConnectedReplicaImplementation>(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<QConnectedReplicaImplementation> childRep = qSharedPointerCast<QConnectedReplicaImplementation>(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<Shape>();
+        // will return a QStringList containing "Circle" and "Square"
+        auto instance1 = clientNode.acquire<Shape>("Circle");
+        auto instance2 = clientNode.acquire<Shape>("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<int> 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<int>, roles));
+    QAbstractItemAdapterSourceAPI<QAbstractItemModel, QAbstractItemModelSourceAdapter> *api =
+        new QAbstractItemAdapterSourceAPI<QAbstractItemModel, QAbstractItemModelSourceAdapter>(name);
+    if (!this->objectName().isEmpty())
+        adapter->setObjectName(this->objectName().append(QLatin1String("Adapter")));
+    return enableRemoting(model, api, adapter);
+}
+
+/*!
+    \fn template <template <typename> class ApiDefinition, typename ObjectType> bool QRemoteObjectHostBase::enableRemoting(ObjectType *object)
+
+    This templated function overload enables a host node to provide remote
+    access to a QObject \a object with a specified (and compile-time checked)
+    interface. Client nodes connected to the node hosting this object may
+    obtain Replicas of this Source.
+
+    This is best illustrated by example:
+    \code
+        #include "rep_TimeModel_source.h"
+        MinuteTimer timer;
+        hostNode.enableRemoting<MinuteTimerSourceAPI>(&timer);
+    \endcode
+
+    Here the MinuteTimerSourceAPI is the set of Signals/Slots/Properties
+    defined by the TimeModel.rep file. Compile time checks are made to verify
+    the input QObject can expose the requested API, it will fail to compile
+    otherwise. This allows a subset of \a object 's interface to be exposed,
+    and allows the types of conversions supported by Signal/Slot connections.
+
+    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 QObject.
+
+    \sa disableRemoting()
+*/
+
+/*!
+    \internal
+    Enables a host node to provide remote access to a QObject \a object
+    with the API defined by \a api. Client nodes connected to the node
+    hosting this object may obtain Replicas of this Source.
+
+    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 QObject.
+
+    \sa disableRemoting()
+*/
+bool QRemoteObjectHostBase::enableRemoting(QObject *object, const SourceApiMap *api, QObject *adapter)
+{
+    Q_D(QRemoteObjectHostBase);
+    return d->remoteObjectIo->enableRemoting(object, api, adapter);
+}
+
+/*!
+    \qmlmethod bool Host::disableRemoting(object remoteObject)
+    Disables remote access for the QObject \a remoteObject. Returns \c false if
+    the current node is a client node or if the \a remoteObject is not
+    registered, and returns \c true if remoting is successfully disabled for
+    the Source object.
+
+    \warning Replicas of this object will no longer be valid after calling this method.
+
+    \sa enableRemoting()
+*/
+
+/*!
+    Disables remote access for the QObject \a remoteObject. Returns \c false if
+    the current node is a client node or if the \a remoteObject is not
+    registered, and returns \c true if remoting is successfully disabled for
+    the Source object.
+
+    \warning Replicas of this object will no longer be valid after calling this method.
+
+    \sa enableRemoting()
+*/
+bool QRemoteObjectHostBase::disableRemoting(QObject *remoteObject)
+{
+    Q_D(QRemoteObjectHostBase);
+    if (!d->remoteObjectIo) {
+        d->setLastError(OperationNotValidOnClientNode);
+        return false;
+    }
+
+    if (!d->remoteObjectIo->disableRemoting(remoteObject)) {
+        d->setLastError(SourceNotRegistered);
+        return false;
+    }
+
+    return true;
+}
+
+/*!
+    \since 5.12
+
+    In order to \l QRemoteObjectHost::enableRemoting() \l Source objects over
+    \l {External QIODevices}, Qt Remote Objects needs access to the
+    communications channel (a \l QIODevice) between the respective nodes. It is
+    the addHostSideConnection() call that enables this on the \l Source side,
+    taking the \a ioDevice as input. Any enableRemoting() call will still work
+    without calling addHostSideConnection, but the Node will not be able to
+    share the \l Source objects without being provided the connection to
+    the Replica node. Before calling this function you must call
+    \l {QRemoteObjectHost::}{setHostUrl}() with a unique URL and
+    \l {QRemoteObjectHost::}{AllowExternalRegistration}.
+
+    \sa addClientSideConnection
+*/
+void QRemoteObjectHostBase::addHostSideConnection(QIODevice *ioDevice)
+{
+    Q_D(QRemoteObjectHostBase);
+    if (!ioDevice || !ioDevice->isOpen()) {
+        qWarning() << "A null or closed QIODevice was passed to addHostSideConnection().  Ignoring.";
+        return;
+    }
+    if (!d->remoteObjectIo)
+        d->remoteObjectIo = new QRemoteObjectSourceIo(this);
+    QtROExternalIoDevice *device = new QtROExternalIoDevice(ioDevice, this);
+    return d->remoteObjectIo->newConnection(device);
+}
+
+/*!
+    Returns a pointer to a \l Replica which is specifically derived from \l
+    QAbstractItemModel. The \a name provided must match the name used with the
+    matching \l {QRemoteObjectHostBase::}{enableRemoting} that put
+    the \l Model on the network. \a action specifies whether the model should
+    fetch data before the \l {QRemoteObjectReplica::}{initialized} signal is
+    emitted. If it's set to QtRemoteObjects::PrefetchData, then the data for
+    roles in the \a rolesHint will be prefetched. If \a rolesHint is empty, then
+    the data for all the roles exposed by \l Source will be prefetched.
+
+    The returned model will be empty until it is initialized with the \l Source.
+*/
+QAbstractItemModelReplica *QRemoteObjectNode::acquireModel(const QString &name, QtRemoteObjects::InitialAction action, const QList<int> &rolesHint)
+{
+    QAbstractItemModelReplicaImplementation *rep = acquire<QAbstractItemModelReplicaImplementation>(name);
+    return new QAbstractItemModelReplica(rep, action, rolesHint);
+}
+
+QRemoteObjectHostBasePrivate::QRemoteObjectHostBasePrivate()
+    : QRemoteObjectNodePrivate()
+    , remoteObjectIo(nullptr)
+{ }
+
+QRemoteObjectHostBasePrivate::~QRemoteObjectHostBasePrivate()
+{ }
+
+QRemoteObjectHostPrivate::QRemoteObjectHostPrivate()
+    : QRemoteObjectHostBasePrivate()
+{ }
+
+QRemoteObjectHostPrivate::~QRemoteObjectHostPrivate()
+{ }
+
+QRemoteObjectRegistryHostPrivate::QRemoteObjectRegistryHostPrivate()
+    : QRemoteObjectHostBasePrivate()
+    , registrySource(nullptr)
+{ }
+
+QRemoteObjectRegistryHostPrivate::~QRemoteObjectRegistryHostPrivate()
+{ }
+
+ProxyInfo::ProxyInfo(QRemoteObjectNode *node, QRemoteObjectHostBase *parent,
+                     QRemoteObjectHostBase::RemoteObjectNameFilter filter)
+    : QObject(parent)
+    , proxyNode(node)
+    , parentNode(parent)
+    , proxyFilter(filter)
+{
+    const auto registry = node->registry();
+    proxyNode->setObjectName(QString::fromLatin1("_ProxyNode"));
+
+    connect(registry, &QRemoteObjectRegistry::remoteObjectAdded, this,
+            [this](const QRemoteObjectSourceLocation &entry)
+    {
+        this->proxyObject(entry, ProxyDirection::Forward);
+    });
+    connect(registry, &QRemoteObjectRegistry::remoteObjectRemoved, this,
+            &ProxyInfo::unproxyObject);
+    connect(registry, &QRemoteObjectRegistry::initialized, this, [registry, this]() {
+        QRemoteObjectSourceLocations locations = registry->sourceLocations();
+        QRemoteObjectSourceLocations::const_iterator i = locations.constBegin();
+        while (i != locations.constEnd()) {
+            proxyObject(QRemoteObjectSourceLocation(i.key(), i.value()));
+            ++i;
+        }
+    });
+
+    connect(registry, &QRemoteObjectRegistry::stateChanged, this,
+            [this](QRemoteObjectRegistry::State state, QRemoteObjectRegistry::State /*oldState*/) {
+        if (state != QRemoteObjectRegistry::Suspect)
+            return;
+        // unproxy all objects
+        for (ProxyReplicaInfo* info : proxiedReplicas)
+            disableAndDeleteObject(info);
+        proxiedReplicas.clear();
+    });
+}
+
+ProxyInfo::~ProxyInfo() {
+    for (ProxyReplicaInfo* info : proxiedReplicas)
+        delete info;
+    delete proxyNode;
+}
+
+bool ProxyInfo::setReverseProxy(QRemoteObjectHostBase::RemoteObjectNameFilter filter)
+{
+    if (qobject_cast<QRemoteObjectRegistryHost *>(parentNode) == nullptr) {
+        qWarning() << "Setting up reverseProxy() can only be done on a Registry node.";
+        return false;
+    }
+    const auto registry = parentNode->registry();
+    this->reverseFilter = filter;
+
+    connect(registry, &QRemoteObjectRegistry::remoteObjectAdded, this,
+            [this](const QRemoteObjectSourceLocation &entry)
+    {
+        this->proxyObject(entry, ProxyDirection::Reverse);
+    });
+    connect(registry, &QRemoteObjectRegistry::remoteObjectRemoved, this,
+            &ProxyInfo::unproxyObject);
+    connect(registry, &QRemoteObjectRegistry::initialized, this, [registry, this]() {
+        QRemoteObjectSourceLocations locations = registry->sourceLocations();
+        QRemoteObjectSourceLocations::const_iterator i = locations.constBegin();
+        while (i != locations.constEnd()) {
+            proxyObject(QRemoteObjectSourceLocation(i.key(), i.value()), ProxyDirection::Reverse);
+            ++i;
+        }
+    });
+
+    return true;
+}
+
+void ProxyInfo::proxyObject(const QRemoteObjectSourceLocation &entry, ProxyDirection direction)
+{
+    const QString name = entry.first;
+    const QString typeName = entry.second.typeName;
+
+    if (direction == ProxyDirection::Forward) {
+        // If we are using the reverse proxy, this can be called when reverse proxy objects are added
+        // Don't try to proxy those back.  We can detect this because the hosting node will be our proxyNode.
+        auto host = qobject_cast<QRemoteObjectHost *>(proxyNode);
+        if (host && entry.second.hostUrl == host->hostUrl())
+            return;
+        if (!proxyFilter(name, typeName))
+            return;
+        Q_ASSERT(!proxiedReplicas.contains(name));
+
+        qCDebug(QT_REMOTEOBJECT) << "Starting proxy for" << name << "from" << entry.second.hostUrl;
+
+        if (entry.second.typeName == QAIMADAPTER()) {
+            QAbstractItemModelReplica *rep = proxyNode->acquireModel(name);
+            proxiedReplicas.insert(name, new ProxyReplicaInfo{rep, direction});
+            connect(rep, &QAbstractItemModelReplica::initialized, this,
+                    [rep, name, this]() { this->parentNode->enableRemoting(rep, name, QList<int>()); });
+        } else {
+            QRemoteObjectDynamicReplica *rep = proxyNode->acquireDynamic(name);
+            proxiedReplicas.insert(name, new ProxyReplicaInfo{rep, direction});
+            connect(rep, &QRemoteObjectDynamicReplica::initialized, this,
+                    [rep, name, this]() { this->parentNode->enableRemoting(rep, name); });
+        }
+    } else {
+        // If we are using the reverse proxy, this can be called when proxy objects are added
+        // Don't try to proxy those back.  We can detect this because the hosting node will be the parentNode.
+        // Since we know the parentNode has to be a RegistryNode for reverse proxy to work, we compare against
+        // the registryUrl().
+        if (entry.second.hostUrl == parentNode->registryUrl())
+            return;
+        if (!reverseFilter(name, typeName))
+            return;
+        Q_ASSERT(!proxiedReplicas.contains(name));
+
+        qCDebug(QT_REMOTEOBJECT) << "Starting reverse proxy for" << name << "from" << entry.second.hostUrl;
+
+        if (entry.second.typeName == QAIMADAPTER()) {
+            QAbstractItemModelReplica *rep = this->parentNode->acquireModel(name);
+            proxiedReplicas.insert(name, new ProxyReplicaInfo{rep, direction});
+            connect(rep, &QAbstractItemModelReplica::initialized, this,
+                    [rep, name, this]()
+            {
+                QRemoteObjectHostBase *host = qobject_cast<QRemoteObjectHostBase *>(this->proxyNode);
+                Q_ASSERT(host);
+                host->enableRemoting(rep, name, QList<int>());
+            });
+        } else {
+            QRemoteObjectDynamicReplica *rep = this->parentNode->acquireDynamic(name);
+            proxiedReplicas.insert(name, new ProxyReplicaInfo{rep, direction});
+            connect(rep, &QRemoteObjectDynamicReplica::initialized, this,
+                    [rep, name, this]()
+            {
+                QRemoteObjectHostBase *host = qobject_cast<QRemoteObjectHostBase *>(this->proxyNode);
+                Q_ASSERT(host);
+                host->enableRemoting(rep, name);
+            });
+        }
+    }
+
+}
+
+void ProxyInfo::unproxyObject(const QRemoteObjectSourceLocation &entry)
+{
+    const QString name = entry.first;
+
+    if (proxiedReplicas.contains(name)) {
+        qCDebug(QT_REMOTEOBJECT)  << "Stopping proxy for" << name;
+        auto const info = proxiedReplicas.take(name);
+        disableAndDeleteObject(info);
+    }
+}
+
+void ProxyInfo::disableAndDeleteObject(ProxyReplicaInfo* info)
+{
+    if (info->direction == ProxyDirection::Forward)
+        this->parentNode->disableRemoting(info->replica);
+    else {
+        QRemoteObjectHostBase *host = qobject_cast<QRemoteObjectHostBase *>(this->proxyNode);
+        Q_ASSERT(host);
+        host->disableRemoting(info->replica);
+    }
+    delete info;
+}
+
+
+QT_END_NAMESPACE
+
+#include "moc_qremoteobjectnode.cpp"
diff --git a/src/remoteobjects/qremoteobjectnode.h b/src/remoteobjects/qremoteobjectnode.h
new file mode 100644 (file)
index 0000000..ec32e5a
--- /dev/null
@@ -0,0 +1,248 @@
+/****************************************************************************
+**
+** 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 QREMOTEOBJECTNODE_H
+#define QREMOTEOBJECTNODE_H
+
+#include <QtCore/qsharedpointer.h>
+#include <QtCore/qmetaobject.h>
+#include <QtRemoteObjects/qtremoteobjectglobal.h>
+#include <QtRemoteObjects/qremoteobjectregistry.h>
+#include <QtRemoteObjects/qremoteobjectdynamicreplica.h>
+
+#include <functional>
+
+QT_BEGIN_NAMESPACE
+
+class QRemoteObjectReplica;
+class SourceApiMap;
+class QAbstractItemModel;
+class QAbstractItemModelReplica;
+class QItemSelectionModel;
+class QRemoteObjectAbstractPersistedStorePrivate;
+class QRemoteObjectNodePrivate;
+class QRemoteObjectHostBasePrivate;
+class QRemoteObjectHostPrivate;
+class QRemoteObjectRegistryHostPrivate;
+
+class Q_REMOTEOBJECTS_EXPORT QRemoteObjectAbstractPersistedStore : public QObject
+{
+    Q_OBJECT
+
+public:
+    QRemoteObjectAbstractPersistedStore (QObject *parent = nullptr);
+    virtual ~QRemoteObjectAbstractPersistedStore();
+
+    virtual void saveProperties(const QString &repName, const QByteArray &repSig, const QVariantList &values) = 0;
+    virtual QVariantList restoreProperties(const QString &repName, const QByteArray &repSig) = 0;
+
+protected:
+    QRemoteObjectAbstractPersistedStore(QRemoteObjectAbstractPersistedStorePrivate &, QObject *parent);
+    Q_DECLARE_PRIVATE(QRemoteObjectAbstractPersistedStore)
+};
+
+class Q_REMOTEOBJECTS_EXPORT QRemoteObjectNode : public QObject
+{
+    Q_OBJECT
+    Q_PROPERTY(QUrl registryUrl READ registryUrl WRITE setRegistryUrl)
+    Q_PROPERTY(QRemoteObjectAbstractPersistedStore* persistedStore READ persistedStore WRITE setPersistedStore)
+    Q_PROPERTY(int heartbeatInterval READ heartbeatInterval WRITE setHeartbeatInterval NOTIFY heartbeatIntervalChanged)
+
+public:
+    enum ErrorCode{
+        NoError,
+        RegistryNotAcquired,
+        RegistryAlreadyHosted,
+        NodeIsNoServer,
+        ServerAlreadyCreated,
+        UnintendedRegistryHosting,
+        OperationNotValidOnClientNode,
+        SourceNotRegistered,
+        MissingObjectName,
+        HostUrlInvalid,
+        ProtocolMismatch,
+        ListenFailed
+    };
+    Q_ENUM(ErrorCode)
+
+    QRemoteObjectNode(QObject *parent = nullptr);
+    QRemoteObjectNode(const QUrl &registryAddress, QObject *parent = nullptr);
+    ~QRemoteObjectNode() override;
+
+    Q_INVOKABLE bool connectToNode(const QUrl &address);
+    void addClientSideConnection(QIODevice *ioDevice);
+    virtual void setName(const QString &name);
+    template < class ObjectType >
+    ObjectType *acquire(const QString &name = QString())
+    {
+        return new ObjectType(this, name);
+    }
+
+    template<typename T>
+    QStringList instances() const
+    {
+        const QMetaObject *mobj = &T::staticMetaObject;
+        const int index = mobj->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE);
+        if (index == -1)
+            return QStringList();
+
+        const QString typeName = QString::fromLatin1(mobj->classInfo(index).value());
+        return instances(typeName);
+    }
+    QStringList instances(QStringView typeName) const;
+
+    QRemoteObjectDynamicReplica *acquireDynamic(const QString &name);
+    QAbstractItemModelReplica *acquireModel(const QString &name, QtRemoteObjects::InitialAction action = QtRemoteObjects::FetchRootSize, const QList<int> &rolesHint = {});
+    QUrl registryUrl() const;
+    virtual bool setRegistryUrl(const QUrl &registryAddress);
+    bool waitForRegistry(int timeout = 30000);
+    const QRemoteObjectRegistry *registry() const;
+
+    QRemoteObjectAbstractPersistedStore *persistedStore() const;
+    void setPersistedStore(QRemoteObjectAbstractPersistedStore *persistedStore);
+
+    ErrorCode lastError() const;
+
+    int heartbeatInterval() const;
+    void setHeartbeatInterval(int interval);
+
+    typedef std::function<void (QUrl)> RemoteObjectSchemaHandler;
+    void registerExternalSchema(const QString &schema, RemoteObjectSchemaHandler handler);
+
+Q_SIGNALS:
+    void remoteObjectAdded(const QRemoteObjectSourceLocation &);
+    void remoteObjectRemoved(const QRemoteObjectSourceLocation &);
+
+    void error(QRemoteObjectNode::ErrorCode errorCode);
+    void heartbeatIntervalChanged(int heartbeatInterval);
+
+protected:
+    QRemoteObjectNode(QRemoteObjectNodePrivate &, QObject *parent);
+
+    void timerEvent(QTimerEvent*) override;
+
+private:
+    void initializeReplica(QRemoteObjectReplica *instance, const QString &name = QString());
+    void persistProperties(const QString &repName, const QByteArray &repSig, const QVariantList &props);
+    QVariantList retrieveProperties(const QString &repName, const QByteArray &repSig);
+
+    Q_DECLARE_PRIVATE(QRemoteObjectNode)
+    friend class QRemoteObjectReplica;
+    friend class QConnectedReplicaImplementation;
+};
+
+class Q_REMOTEOBJECTS_EXPORT QRemoteObjectHostBase : public QRemoteObjectNode
+{
+    Q_OBJECT
+public:
+    enum AllowedSchemas { BuiltInSchemasOnly, AllowExternalRegistration };
+    Q_ENUM(AllowedSchemas)
+    ~QRemoteObjectHostBase() override;
+    void setName(const QString &name) override;
+
+    template <template <typename> class ApiDefinition, typename ObjectType>
+    bool enableRemoting(ObjectType *object)
+    {
+        ApiDefinition<ObjectType> *api = new ApiDefinition<ObjectType>(object);
+        return enableRemoting(object, api);
+    }
+    Q_INVOKABLE bool enableRemoting(QObject *object, const QString &name = QString());
+    bool enableRemoting(QAbstractItemModel *model, const QString &name, const QList<int> roles, QItemSelectionModel *selectionModel = nullptr);
+    Q_INVOKABLE bool disableRemoting(QObject *remoteObject);
+    void addHostSideConnection(QIODevice *ioDevice);
+
+    typedef std::function<bool(QStringView, QStringView)> RemoteObjectNameFilter;
+    bool proxy(const QUrl &registryUrl, const QUrl &hostUrl={},
+               RemoteObjectNameFilter filter=[](QStringView, QStringView) {return true; });
+    // TODO: Currently the reverse aspect requires the registry, so this is supported only for
+    // QRemoteObjectRegistryHost for now. Consider enabling it also for QRemoteObjectHost.
+    bool reverseProxy(RemoteObjectNameFilter filter=[](QStringView, QStringView) {return true; });
+
+protected:
+    virtual QUrl hostUrl() const;
+    virtual bool setHostUrl(const QUrl &hostAddress, AllowedSchemas allowedSchemas=BuiltInSchemasOnly);
+    QRemoteObjectHostBase(QRemoteObjectHostBasePrivate &, QObject *);
+
+private:
+    bool enableRemoting(QObject *object, const SourceApiMap *, QObject *adapter = nullptr);
+    Q_DECLARE_PRIVATE(QRemoteObjectHostBase)
+};
+
+class Q_REMOTEOBJECTS_EXPORT QRemoteObjectHost : public QRemoteObjectHostBase
+{
+    Q_OBJECT
+    Q_PROPERTY(QUrl hostUrl READ hostUrl WRITE setHostUrl NOTIFY hostUrlChanged)
+
+public:
+    QRemoteObjectHost(QObject *parent = nullptr);
+    QRemoteObjectHost(const QUrl &address, const QUrl &registryAddress = QUrl(),
+                      AllowedSchemas allowedSchemas=BuiltInSchemasOnly, QObject *parent = nullptr);
+    QRemoteObjectHost(const QUrl &address, QObject *parent);
+    ~QRemoteObjectHost() override;
+    QUrl hostUrl() const override;
+    bool setHostUrl(const QUrl &hostAddress, AllowedSchemas allowedSchemas=BuiltInSchemasOnly) override;
+
+Q_SIGNALS:
+    void hostUrlChanged();
+
+protected:
+    QRemoteObjectHost(QRemoteObjectHostPrivate &, QObject *);
+
+private:
+    Q_DECLARE_PRIVATE(QRemoteObjectHost)
+};
+
+class Q_REMOTEOBJECTS_EXPORT QRemoteObjectRegistryHost : public QRemoteObjectHostBase
+{
+    Q_OBJECT
+public:
+    QRemoteObjectRegistryHost(const QUrl &registryAddress = QUrl(), QObject *parent = nullptr);
+    ~QRemoteObjectRegistryHost() override;
+    bool setRegistryUrl(const QUrl &registryUrl) override;
+
+protected:
+    QRemoteObjectRegistryHost(QRemoteObjectRegistryHostPrivate &, QObject *);
+
+private:
+    Q_DECLARE_PRIVATE(QRemoteObjectRegistryHost)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/remoteobjects/qremoteobjectnode_p.h b/src/remoteobjects/qremoteobjectnode_p.h
new file mode 100644 (file)
index 0000000..9bf9632
--- /dev/null
@@ -0,0 +1,244 @@
+/****************************************************************************
+**
+** 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 QREMOTEOBJECTNODE_P_H
+#define QREMOTEOBJECTNODE_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 <QtCore/private/qobject_p.h>
+#include "qremoteobjectsourceio_p.h"
+#include "qremoteobjectreplica.h"
+#include "qremoteobjectnode.h"
+
+#include <QtCore/qbasictimer.h>
+#include <QtCore/qmutex.h>
+
+QT_BEGIN_NAMESPACE
+
+#define qRODebug(x) qCDebug(QT_REMOTEOBJECT) << qPrintable(QtPrivate::deref_for_methodcall(x).objectName())
+#define qROWarning(x) qCWarning(QT_REMOTEOBJECT) << qPrintable(QtPrivate::deref_for_methodcall(x).objectName())
+#define qROCritical(x) qCCritical(QT_REMOTEOBJECT) << qPrintable(QtPrivate::deref_for_methodcall(x).objectName())
+#define qROFatal(x) qCFatal(QT_REMOTEOBJECT) << qPrintable(QtPrivate::deref_for_methodcall(x).objectName())
+#define qROPrivDebug() qCDebug(QT_REMOTEOBJECT) << qPrintable(q_ptr->objectName())
+#define qROPrivWarning() qCWarning(QT_REMOTEOBJECT) << qPrintable(q_ptr->objectName())
+#define qROPrivCritical() qCCritical(QT_REMOTEOBJECT) << qPrintable(q_ptr->objectName())
+#define qROPrivFatal() qCFatal(QT_REMOTEOBJECT) << qPrintable(q_ptr->objectName())
+
+class QRemoteObjectRegistry;
+class QRegistrySource;
+class QConnectedReplicaImplementation;
+
+class QRemoteObjectAbstractPersistedStorePrivate : public QObjectPrivate
+{
+public:
+    QRemoteObjectAbstractPersistedStorePrivate();
+    virtual ~QRemoteObjectAbstractPersistedStorePrivate();
+
+    Q_DECLARE_PUBLIC(QRemoteObjectAbstractPersistedStore)
+};
+
+class QRemoteObjectMetaObjectManager
+{
+public:
+    QRemoteObjectMetaObjectManager() {}
+    ~QRemoteObjectMetaObjectManager();
+
+    const QMetaObject *metaObjectForType(const QString &type);
+    QMetaObject *addDynamicType(QtROIoDeviceBase* connection, QDataStream &in);
+    void addFromMetaObject(const QMetaObject *);
+
+private:
+    QHash<QString, QMetaObject*> dynamicTypes;
+    QHash<QString, const QMetaObject*> staticTypes;
+    QHash<QtPrivate::QMetaTypeInterface *, QMetaType> enumsToBeAssignedMetaObject;
+    QHash<QMetaObject *, QList<QMetaType>> enumTypes;
+};
+
+struct ProxyReplicaInfo;
+class ProxyInfo : public QObject
+{
+    Q_OBJECT
+public:
+    ProxyInfo(QRemoteObjectNode *node, QRemoteObjectHostBase *parent, QRemoteObjectHostBase::RemoteObjectNameFilter filter);
+    ~ProxyInfo() override;
+    enum class ProxyDirection { Forward, Reverse };
+
+    bool setReverseProxy(QRemoteObjectHostBase::RemoteObjectNameFilter filter);
+    void proxyObject(const QRemoteObjectSourceLocation &entry, ProxyDirection direction = ProxyDirection::Forward);
+    void unproxyObject(const QRemoteObjectSourceLocation &entry);
+
+    QRemoteObjectNode *proxyNode;
+    QRemoteObjectHostBase *parentNode;
+    QRemoteObjectHostBase::RemoteObjectNameFilter proxyFilter;
+    QRemoteObjectHostBase::RemoteObjectNameFilter reverseFilter;
+    QHash<QString, ProxyReplicaInfo*> proxiedReplicas;
+
+private:
+    void disableAndDeleteObject(ProxyReplicaInfo* info);
+};
+
+struct ProxyReplicaInfo
+{
+    // We need QObject, so we can hold Dynamic Replicas and QAIM Adapters
+    QObject* replica;
+    ProxyInfo::ProxyDirection direction;
+    ~ProxyReplicaInfo() { delete replica; }
+};
+
+class QRemoteObjectNodePrivate : public QObjectPrivate
+{
+public:
+    QRemoteObjectNodePrivate();
+    ~QRemoteObjectNodePrivate() override;
+
+    virtual QRemoteObjectSourceLocations remoteObjectAddresses() const;
+
+    void setReplicaImplementation(const QMetaObject *, QRemoteObjectReplica *, const QString &);
+
+    void setLastError(QRemoteObjectNode::ErrorCode errorCode);
+
+    void connectReplica(QObject *object, QRemoteObjectReplica *instance);
+    void openConnectionIfNeeded(const QString &name);
+
+    bool initConnection(const QUrl &address);
+    bool hasInstance(const QString &name);
+    void setRegistry(QRemoteObjectRegistry *);
+    QVariant handlePointerToQObjectProperty(QConnectedReplicaImplementation *rep, int index, const QVariant &property);
+    void handlePointerToQObjectProperties(QConnectedReplicaImplementation *rep, QVariantList &properties);
+
+    void onClientRead(QObject *obj);
+    void onRemoteObjectSourceAdded(const QRemoteObjectSourceLocation &entry);
+    void onRemoteObjectSourceRemoved(const QRemoteObjectSourceLocation &entry);
+    void onRegistryInitialized();
+    void onShouldReconnect(QtROClientIoDevice *ioDevice);
+
+    virtual QReplicaImplementationInterface *handleNewAcquire(const QMetaObject *meta, QRemoteObjectReplica *instance, const QString &name);
+    void handleReplicaConnection(const QString &name);
+    void handleReplicaConnection(const QByteArray &sourceSignature, QConnectedReplicaImplementation *rep, QtROIoDeviceBase *connection);
+    void initialize();
+    bool setRegistryUrlNodeImpl(const QUrl &registryAddr);
+
+private:
+    bool checkSignatures(const QByteArray &a, const QByteArray &b);
+
+public:
+    struct SourceInfo
+    {
+        QtROIoDeviceBase* device;
+        QString typeName;
+        QByteArray objectSignature;
+    };
+
+    QMutex mutex;
+    QUrl registryAddress;
+    QHash<QString, QWeakPointer<QReplicaImplementationInterface> > replicas;
+    QMap<QString, SourceInfo> connectedSources;
+    QMap<QString, QRemoteObjectNode::RemoteObjectSchemaHandler> schemaHandlers;
+    QSet<QtROClientIoDevice*> pendingReconnect;
+    QSet<QUrl> requestedUrls;
+    QRemoteObjectRegistry *registry;
+    int retryInterval;
+    QBasicTimer reconnectTimer;
+    QRemoteObjectNode::ErrorCode lastError;
+    QString rxName;
+    QRemoteObjectPackets::ObjectInfoList rxObjects;
+    QVariantList rxArgs;
+    QVariant rxValue;
+    QRemoteObjectAbstractPersistedStore *persistedStore;
+    int m_heartbeatInterval = 0;
+    QRemoteObjectMetaObjectManager dynamicTypeManager;
+    Q_DECLARE_PUBLIC(QRemoteObjectNode)
+};
+
+class QRemoteObjectHostBasePrivate : public QRemoteObjectNodePrivate
+{
+public:
+    QRemoteObjectHostBasePrivate();
+    ~QRemoteObjectHostBasePrivate() override;
+    QReplicaImplementationInterface *handleNewAcquire(const QMetaObject *meta, QRemoteObjectReplica *instance, const QString &name) override;
+
+    bool setHostUrlBaseImpl(const QUrl &hostAddress,
+                            QRemoteObjectHostBase::AllowedSchemas allowedSchemas =
+                                    QRemoteObjectHostBase::BuiltInSchemasOnly);
+
+public:
+    QRemoteObjectSourceIo *remoteObjectIo;
+    ProxyInfo *proxyInfo = nullptr;
+    Q_DECLARE_PUBLIC(QRemoteObjectHostBase);
+};
+
+class QRemoteObjectHostPrivate : public QRemoteObjectHostBasePrivate
+{
+public:
+    QRemoteObjectHostPrivate();
+    ~QRemoteObjectHostPrivate() override;
+
+    bool setHostUrlHostImpl(const QUrl &hostAddress,
+                            QRemoteObjectHostBase::AllowedSchemas allowedSchemas =
+                                    QRemoteObjectHostBase::BuiltInSchemasOnly);
+
+    Q_DECLARE_PUBLIC(QRemoteObjectHost);
+};
+
+class QRemoteObjectRegistryHostPrivate : public QRemoteObjectHostBasePrivate
+{
+public:
+    QRemoteObjectRegistryHostPrivate();
+    ~QRemoteObjectRegistryHostPrivate() override;
+    QRemoteObjectSourceLocations remoteObjectAddresses() const override;
+    QRegistrySource *registrySource;
+
+    bool setRegistryUrlRegistryHostImpl(const QUrl &registryUrl);
+
+    Q_DECLARE_PUBLIC(QRemoteObjectRegistryHost);
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/remoteobjects/qremoteobjectpacket.cpp b/src/remoteobjects/qremoteobjectpacket.cpp
new file mode 100644 (file)
index 0000000..5406fbf
--- /dev/null
@@ -0,0 +1,1165 @@
+/****************************************************************************
+**
+** 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 <QtCore/qabstractitemmodel.h>
+#include <QtCore/qbytearrayview.h>
+
+#include "qremoteobjectcontainers_p.h"
+#include "qremoteobjectpendingcall.h"
+#include "qremoteobjectsource.h"
+#include "qremoteobjectsource_p.h"
+#include "qremoteobjectpacket_p.h"
+#include "qconnectionfactories.h"
+#include "qconnectionfactories_p.h"
+#include <cstring>
+
+//#define QTRO_VERBOSE_PROTOCOL
+QT_BEGIN_NAMESPACE
+
+
+// Add methods so we can use QMetaEnum in a set
+// Note for both functions we are skipping string comparisons/hashes.  Since the
+// metaObjects are the same, we can just use the address of the string.
+inline bool operator==(const QMetaEnum e1, const QMetaEnum e2)
+{
+    return e1.enclosingMetaObject() == e2.enclosingMetaObject()
+           && e1.name() == e2.name()
+           && e1.enumName() == e2.enumName()
+           && e1.scope() == e2.scope();
+}
+
+inline size_t qHash(const QMetaEnum &key, size_t seed=0) Q_DECL_NOTHROW
+{
+    return qHash(key.enclosingMetaObject(), seed) ^ qHash(static_cast<const void *>(key.name()), seed)
+           ^ qHash(static_cast<const void *>(key.enumName()), seed) ^ qHash(static_cast<const void *>(key.scope()), seed);
+}
+
+static bool isSequentialGadgetType(QMetaType metaType)
+{
+    if (QMetaType::canConvert(metaType, QMetaType::fromType<QSequentialIterable>())) {
+        static QHash<int, bool> lookup;
+        if (!lookup.contains(metaType.id())) {
+            auto stubVariant = QVariant(metaType, nullptr);
+            auto asIterable = stubVariant.value<QSequentialIterable>();
+            auto valueMetaType = asIterable.metaContainer().valueMetaType();
+            lookup[metaType.id()] = valueMetaType.flags().testFlag(QMetaType::IsGadget);
+        }
+        return lookup[metaType.id()];
+    }
+    return false;
+}
+
+static bool isAssociativeGadgetType(QMetaType metaType)
+{
+    if (QMetaType::canConvert(metaType, QMetaType::fromType<QAssociativeIterable>())) {
+        static QHash<int, bool> lookup;
+        if (!lookup.contains(metaType.id())) {
+            auto stubVariant = QVariant(metaType, nullptr);
+            auto asIterable = stubVariant.value<QAssociativeIterable>();
+            auto valueMetaType = asIterable.metaContainer().mappedMetaType();
+            lookup[metaType.id()] = valueMetaType.flags().testFlag(QMetaType::IsGadget);
+        }
+        return lookup[metaType.id()];
+    }
+    return false;
+}
+
+using namespace QtRemoteObjects;
+
+namespace QRemoteObjectPackets {
+
+QMetaType transferTypeForEnum(QMetaType enumType)
+{
+    const auto size = enumType.sizeOf();
+    switch (size) {
+    case 1: return QMetaType::fromType<qint8>();
+    case 2: return QMetaType::fromType<qint16>();
+    case 4: return QMetaType::fromType<qint32>();
+    // Qt currently only supports enum values of 4 or less bytes (QMetaEnum value(index) returns int)
+//                    case 8: args.push_back(QVariant(QMetaType::Int, argv[i + 1])); break;
+    default:
+        qCWarning(QT_REMOTEOBJECT_IO) << "Invalid enum detected (Dynamic Replica)" << enumType.name() << "with size" << size;
+        return QMetaType::fromType<qint32>();
+    }
+}
+
+// QDataStream sends QVariants of custom types by sending their typename, allowing decode
+// on the receiving side.  For QtRO and enums, this won't work, as the enums have different
+// scopes.  E.g., the examples have ParentClassSource::MyEnum and ParentClassReplica::MyEnum.
+// Dynamic types will be created as ParentClass::MyEnum.  So instead, we change the variants
+// to integers (encodeVariant) when sending them.  On the receive side, the we know the
+// types of properties and the signatures for methods, so we can use that information to
+// decode the integer variant into an enum variant (via decodeVariant).
+QVariant encodeVariant(const QVariant &value)
+{
+    const auto metaType = value.metaType();
+    if (metaType.flags().testFlag(QMetaType::IsEnumeration)) {
+        auto converted = QVariant(value);
+        auto transferType = transferTypeForEnum(metaType);
+        converted.convert(transferType);
+#ifdef QTRO_VERBOSE_PROTOCOL
+        qDebug() << "Converting from enum to integer type" << transferType.sizeOf() << converted << value;
+#endif
+        return converted;
+    }
+    if (isSequentialGadgetType(metaType)) { // Doesn't include QtROSequentialContainer
+        // TODO Way to create the QVariant without copying the QSQ_?
+        QSQ_ sequence(value);
+#ifdef QTRO_VERBOSE_PROTOCOL
+        qDebug() << "Encoding sequential container" << metaType.name() << "to QSQ_ to transmit";
+#endif
+        return QVariant::fromValue<QSQ_>(sequence);
+    }
+    if (metaType == QMetaType::fromType<QtROSequentialContainer>()) {
+        QSQ_ sequence(value);
+#ifdef QTRO_VERBOSE_PROTOCOL
+        qDebug() << "Encoding QtROSequentialContainer container to QSQ_ to transmit";
+#endif
+        return QVariant::fromValue<QSQ_>(sequence);
+    }
+    if (isAssociativeGadgetType(metaType)) { // Doesn't include QtROAssociativeContainer
+        QAS_ map(value);
+#ifdef QTRO_VERBOSE_PROTOCOL
+        qDebug() << "Encoding associative container" << metaType.name() << "to QAS_ to transmit";
+#endif
+        return QVariant::fromValue<QAS_>(map);
+    }
+    if (metaType == QMetaType::fromType<QtROAssociativeContainer>()) {
+        QAS_ map(value);
+#ifdef QTRO_VERBOSE_PROTOCOL
+        qDebug() << "Encoding QtROAssociativeContainer container to QAS_ to transmit";
+#endif
+        return QVariant::fromValue<QAS_>(map);
+    }
+    return value;
+}
+
+QVariant decodeVariant(QVariant &&value, QMetaType metaType)
+{
+    if (metaType.flags().testFlag(QMetaType::IsEnumeration)) {
+#ifdef QTRO_VERBOSE_PROTOCOL
+        QVariant encoded(value);
+#endif
+        value.convert(metaType);
+#ifdef QTRO_VERBOSE_PROTOCOL
+        qDebug() << "Converting to enum from integer type" << value << encoded;
+#endif
+    } else if (value.metaType() == QMetaType::fromType<QRemoteObjectPackets::QSQ_>()) {
+        const auto *qsq_ = static_cast<const QRemoteObjectPackets::QSQ_ *>(value.constData());
+        QDataStream in(qsq_->values);
+        auto containerType = QMetaType::fromName(qsq_->typeName.constData());
+        bool isRegistered = containerType.isRegistered();
+        if (isRegistered) {
+            QVariant seq{containerType, nullptr};
+            if (!seq.canView<QSequentialIterable>()) {
+                qWarning() << "Unsupported container" << qsq_->typeName.constData()
+                           << "(not viewable)";
+                return QVariant();
+            }
+            QSequentialIterable seqIter = seq.view<QSequentialIterable>();
+            if (!seqIter.metaContainer().canAddValue()) {
+                qWarning() << "Unsupported container" << qsq_->typeName.constData()
+                           << "(Unable to add values)";
+                return QVariant();
+            }
+            QByteArray valueTypeName;
+            quint32 count;
+            in >> valueTypeName;
+            in >> count;
+            QMetaType valueType = QMetaType::fromName(valueTypeName.constData());
+            QVariant tmp{valueType, nullptr};
+            for (quint32 i = 0; i < count; i++) {
+                if (!valueType.load(in, tmp.data())) {
+                    if (seqIter.metaContainer().canRemoveValue() || i == 0) {
+                        for (quint32 ii = 0; ii < i; ii++)
+                            seqIter.removeValue();
+                        qWarning("QSQ_: unable to load type '%s', returning an empty list.", valueTypeName.constData());
+                    } else {
+                        qWarning("QSQ_: unable to load type '%s', returning a partial list.", valueTypeName.constData());
+                    }
+                    break;
+                }
+                seqIter.addValue(tmp);
+            }
+            value = seq;
+#ifdef QTRO_VERBOSE_PROTOCOL
+            qDebug() << "Decoding QSQ_ to sequential container" << containerType.name()
+                     << valueTypeName;
+#endif
+        } else {
+            QtROSequentialContainer container{};
+            in >> container;
+            container.m_typeName = qsq_->typeName;
+            value = QVariant(QMetaType::fromType<QtROSequentialContainer>(), &container);
+#ifdef QTRO_VERBOSE_PROTOCOL
+            qDebug() << "Decoding QSQ_ to QtROSequentialContainer of"
+                     << container.m_valueTypeName;
+#endif
+        }
+    } else if (value.metaType() == QMetaType::fromType<QRemoteObjectPackets::QAS_>()) {
+        const auto *qas_ = static_cast<const QRemoteObjectPackets::QAS_ *>(value.constData());
+        QDataStream in(qas_->values);
+        auto containerType = QMetaType::fromName(qas_->typeName.constData());
+        bool isRegistered = containerType.isRegistered();
+        if (isRegistered) {
+            QVariant map{containerType, nullptr};
+            if (!map.canView<QAssociativeIterable>()) {
+                qWarning() << "Unsupported container" << qas_->typeName.constData()
+                           << "(not viewable)";
+                return QVariant();
+            }
+            QAssociativeIterable mapIter = map.view<QAssociativeIterable>();
+            if (!mapIter.metaContainer().canSetMappedAtKey()) {
+                qWarning() << "Unsupported container" << qas_->typeName.constData()
+                           << "(Unable to insert values)";
+                return QVariant();
+            }
+            QByteArray keyTypeName, valueTypeName;
+            quint32 count;
+            in >> keyTypeName;
+            QMetaType keyType = QMetaType::fromName(keyTypeName.constData());
+            if (!keyType.isValid()) {
+                // This happens for class enums, where the passed keyType is <ClassName>::<enum>
+                // For a compiled replica, the keyType is <ClassName>Replica::<enum>
+                // Since the full typename is registered, we can pull the keyType from there
+                keyType = mapIter.metaContainer().keyMetaType();
+            }
+            QMetaType transferType = keyType;
+            if (keyType.flags().testFlag(QMetaType::IsEnumeration))
+                transferType = transferTypeForEnum(keyType);
+            QVariant key{transferType, nullptr};
+            in >> valueTypeName;
+            QMetaType valueType = QMetaType::fromName(valueTypeName.constData());
+            QVariant val{valueType, nullptr};
+            in >> count;
+            for (quint32 i = 0; i < count; i++) {
+                if (!transferType.load(in, key.data())) {
+                    map = QVariant{containerType, nullptr};
+                    qWarning("QAS_: unable to load key of type '%s', returning an empty map.",
+                             keyTypeName.constData());
+                    break;
+                }
+                if (!valueType.load(in, val.data())) {
+                    map = QVariant{containerType, nullptr};
+                    qWarning("QAS_: unable to load value of type '%s', returning an empty map.",
+                             valueTypeName.constData());
+                    break;
+                }
+                if (transferType != keyType) {
+                    QVariant enumKey(key);
+                    enumKey.convert(keyType);
+                    mapIter.setValue(enumKey, val);
+                } else {
+                    mapIter.setValue(key, val);
+                }
+            }
+            value = map;
+#ifdef QTRO_VERBOSE_PROTOCOL
+            qDebug() << "Decoding QAS_ to associative container" << containerType.name()
+                     << valueTypeName << keyTypeName << count << mapIter.size() << map;
+#endif
+        } else {
+            QtROAssociativeContainer container{};
+            in >> container;
+            container.m_typeName = qas_->typeName;
+            value = QVariant(QMetaType::fromType<QtROAssociativeContainer>(), &container);
+#ifdef QTRO_VERBOSE_PROTOCOL
+            qDebug() << "Decoding QAS_ to QtROAssociativeContainer of"
+                     << container.m_valueTypeName;
+#endif
+        }
+    }
+    return std::move(value);
+}
+
+void QDataStreamCodec::serializeProperty(const QRemoteObjectSourceBase *source, int internalIndex)
+{
+    serializeProperty(m_packet, source, internalIndex);
+}
+
+void QDataStreamCodec::serializeProperty(QDataStream &ds, const QRemoteObjectSourceBase *source, int internalIndex)
+{
+    const int propertyIndex = source->m_api->sourcePropertyIndex(internalIndex);
+    Q_ASSERT (propertyIndex >= 0);
+    const auto target = source->m_api->isAdapterProperty(internalIndex) ? source->m_adapter : source->m_object;
+    const auto property = target->metaObject()->property(propertyIndex);
+    const QVariant value = property.read(target);
+    if (property.metaType().flags().testFlag(QMetaType::PointerToQObject)) {
+        auto const childSource = source->m_children.value(internalIndex);
+        auto valueAsPointerToQObject = qvariant_cast<QObject *>(value);
+        if (childSource->m_object != valueAsPointerToQObject)
+            childSource->resetObject(valueAsPointerToQObject);
+        QRO_ qro(childSource);
+        if (source->d->isDynamic && qro.type == ObjectType::CLASS && childSource->m_object && !source->d->sentTypes.contains(qro.typeName)) {
+            QDataStream classDef(&qro.classDefinition, QIODevice::WriteOnly);
+            serializeDefinition(classDef, childSource);
+            source->d->sentTypes.insert(qro.typeName);
+        }
+        ds << QVariant::fromValue<QRO_>(qro);
+        if (qro.isNull)
+            return;
+        const int propertyCount = childSource->m_api->propertyCount();
+        // Put the properties in a buffer, the receiver may not know how to
+        // interpret the types until it registers new ones.
+        QDataStream params(&qro.parameters, QIODevice::WriteOnly);
+        params << propertyCount;
+        for (int internalIndex = 0; internalIndex < propertyCount; ++internalIndex)
+            serializeProperty(params, childSource, internalIndex);
+        ds << qro.parameters;
+        return;
+    }
+    if (source->d->isDynamic && property.userType() == QMetaType::QVariant
+        && value.metaType().flags().testFlag(QMetaType::IsGadget)) {
+        const auto typeName = QString::fromLatin1(value.metaType().name());
+        if (!source->d->sentTypes.contains(typeName)) {
+            QRO_ qro(value);
+            ds << QVariant::fromValue<QRO_>(qro);
+            ds << qro.parameters;
+            source->d->sentTypes.insert(typeName);
+            return;
+        }
+    }
+    ds << encodeVariant(value);
+}
+
+void QDataStreamCodec::serializeHandshakePacket()
+{
+    m_packet.setId(Handshake);
+    m_packet << QString(protocolVersion);
+    m_packet.finishPacket();
+}
+
+void QDataStreamCodec::serializeInitPacket(const QRemoteObjectRootSource *source)
+{
+    m_packet.setId(InitPacket);
+    m_packet << source->name();
+    serializeProperties(source);
+    m_packet.finishPacket();
+}
+
+void QDataStreamCodec::serializeProperties(const QRemoteObjectSourceBase *source)
+{
+    const SourceApiMap *api = source->m_api;
+
+    //Now copy the property data
+    const int numProperties = api->propertyCount();
+    m_packet << quint32(numProperties);  //Number of properties
+
+    for (int internalIndex = 0; internalIndex < numProperties; ++internalIndex)
+        serializeProperty(source, internalIndex);
+}
+
+bool deserializeQVariantList(QDataStream &s, QList<QVariant> &l)
+{
+    // note: optimized version of: QDataStream operator>>(QDataStream& s, QList<T>& l)
+    quint32 c;
+    s >> c;
+
+    const qsizetype count = static_cast<qsizetype>(c);
+    const qsizetype listSize = l.size();
+    if (listSize < count)
+        l.reserve(count);
+    else if (listSize > count)
+        l.resize(count);
+
+    for (int i = 0; i < l.size(); ++i)
+    {
+        if (s.atEnd())
+            return false;
+        s >> l[i];
+    }
+    for (auto i = l.size(); i < count; ++i)
+    {
+        if (s.atEnd())
+            return false;
+        s >> l.emplace_back();
+    }
+    return true;
+}
+
+void QDataStreamCodec::deserializeInitPacket(QDataStream &in, QVariantList &values)
+{
+    const bool success = deserializeQVariantList(in, values);
+    Q_ASSERT(success);
+    Q_UNUSED(success)
+}
+
+void QDataStreamCodec::serializeInitDynamicPacket(const QRemoteObjectRootSource *source)
+{
+    m_packet.setId(InitDynamicPacket);
+    m_packet << source->name();
+    serializeDefinition(m_packet, source);
+    serializeProperties(source);
+    m_packet.finishPacket();
+}
+
+static ObjectType getObjectType(const QString &typeName)
+{
+    if (typeName == QLatin1String("QAbstractItemModelAdapter"))
+        return ObjectType::MODEL;
+    auto tid = QMetaType::fromName(typeName.toUtf8()).id();
+    if (tid == QMetaType::UnknownType)
+        return ObjectType::CLASS;
+    QMetaType type(tid);
+    auto mo = type.metaObject();
+    if (mo && mo->inherits(&QAbstractItemModel::staticMetaObject))
+        return ObjectType::MODEL;
+    return ObjectType::CLASS;
+}
+
+static QByteArrayView resolveEnumName(QMetaType t, bool &isFlag)
+{
+    // Takes types like `MyPOD::Position` or `QFlags<MyPOD::Position>` and returns 'Position`
+    QByteArrayView enumName(t.name());
+    isFlag = enumName.startsWith("QFlags<");
+    auto lastColon = enumName.lastIndexOf(':');
+    if (lastColon >= 0)
+        enumName = QByteArrayView(t.name() + lastColon + 1);
+    if (isFlag)
+        enumName.chop(1);
+    return enumName;
+}
+
+static QMetaEnum metaEnumFromType(QMetaType t)
+{
+    if (t.flags().testFlag(QMetaType::IsEnumeration)) {
+        if (const QMetaObject *m = t.metaObject()) {
+            bool isFlag;
+            auto enumName = resolveEnumName(t, isFlag);
+            if (isFlag) {
+                for (int i = m->enumeratorOffset(); i < m->enumeratorCount(); i++) {
+                    auto testType = m->enumerator(i);
+                    if (testType.isFlag() &&
+                        enumName.compare(QByteArrayView(testType.enumName())) == 0)
+                        return testType;
+                }
+            }
+            return m->enumerator(m->indexOfEnumerator(enumName.data()));
+        }
+    }
+    return QMetaEnum();
+}
+
+static bool checkEnum(QMetaType metaType, QSet<QMetaEnum> &enums)
+{
+    if (metaType.flags().testFlag(QMetaType::IsEnumeration)) {
+        QMetaEnum meta = metaEnumFromType(metaType);
+        enums.insert(meta);
+        return true;
+    }
+    return false;
+}
+
+static void recurseMetaobject(const QMetaObject *mo, QSet<const QMetaObject *> &gadgets, QSet<QMetaEnum> &enums)
+{
+    if (!mo || gadgets.contains(mo))
+        return;
+    gadgets.insert(mo);
+    const int numProperties = mo->propertyCount();
+    for (int i = 0; i < numProperties; ++i) {
+        const auto property = mo->property(i);
+        if (checkEnum(property.metaType(), enums))
+            continue;
+        if (property.metaType().flags().testFlag(QMetaType::IsGadget))
+            recurseMetaobject(property.metaType().metaObject(), gadgets, enums);
+    }
+}
+
+// A Source may only use a subset of the metaobjects properties/signals/slots, so we only search
+// the ones in the API.  For nested pointer types, we will have another api to limit the search.
+// For nested PODs/enums, we search the entire qobject (using the recurseMetaobject call()).
+void recurseForGadgets(QSet<const QMetaObject *> &gadgets, QSet<QMetaEnum> &enums, const QRemoteObjectSourceBase *source)
+{
+    const SourceApiMap *api = source->m_api;
+
+    const int numSignals = api->signalCount();
+    const int numMethods = api->methodCount();
+    const int numProperties = api->propertyCount();
+
+    for (int si = 0; si < numSignals; ++si) {
+        const int params = api->signalParameterCount(si);
+        for (int pi = 0; pi < params; ++pi) {
+            const int type = api->signalParameterType(si, pi);
+            const auto metaType = QMetaType(type);
+            if (checkEnum(metaType, enums))
+                continue;
+            if (!metaType.flags().testFlag(QMetaType::IsGadget))
+                continue;
+            const auto mo = metaType.metaObject();
+            if (source->d->sentTypes.contains(QLatin1String(mo->className())))
+                continue;
+            recurseMetaobject(mo, gadgets, enums);
+            source->d->sentTypes.insert(QLatin1String(mo->className()));
+        }
+    }
+
+    for (int mi = 0; mi < numMethods; ++mi) {
+        const int params = api->methodParameterCount(mi);
+        for (int pi = 0; pi < params; ++pi) {
+            const int type = api->methodParameterType(mi, pi);
+            const auto metaType = QMetaType(type);
+            if (checkEnum(metaType, enums))
+                continue;
+            if (!metaType.flags().testFlag(QMetaType::IsGadget))
+                continue;
+            const auto mo = metaType.metaObject();
+            if (source->d->sentTypes.contains(QLatin1String(mo->className())))
+                continue;
+            recurseMetaobject(mo, gadgets, enums);
+            source->d->sentTypes.insert(QLatin1String(mo->className()));
+        }
+    }
+    for (int pi = 0; pi < numProperties; ++pi) {
+        const int index = api->sourcePropertyIndex(pi);
+        Q_ASSERT(index >= 0);
+        const auto target = api->isAdapterProperty(pi) ? source->m_adapter : source->m_object;
+        const auto metaProperty = target->metaObject()->property(index);
+        const auto metaType = metaProperty.metaType();
+        if (checkEnum(metaType, enums))
+            continue;
+        if (metaType.flags().testFlag(QMetaType::PointerToQObject)) {
+            auto const objectType = getObjectType(QString::fromLatin1(metaProperty.typeName()));
+            if (objectType == ObjectType::CLASS) {
+                auto const childSource = source->m_children.value(pi);
+                if (childSource->m_object)
+                    recurseForGadgets(gadgets, enums, childSource);
+            }
+        }
+        if (!metaType.flags().testFlag(QMetaType::IsGadget))
+            continue;
+        const auto mo = metaType.metaObject();
+        if (source->d->sentTypes.contains(QLatin1String(mo->className())))
+            continue;
+        recurseMetaobject(mo, gadgets, enums);
+        source->d->sentTypes.insert(QLatin1String(mo->className()));
+    }
+}
+
+static bool checkForEnumsInSource(const QMetaObject *meta, const QRemoteObjectSourceBase *source)
+{
+    if (source->m_object->inherits(meta->className()))
+        return true;
+    for (const auto &child : source->m_children) {
+        if (child->m_object && checkForEnumsInSource(meta, child))
+            return true;
+    }
+    return false;
+}
+
+static void serializeEnum(QDataStream &ds, const QMetaEnum &enumerator)
+{
+    ds << QByteArray::fromRawData(enumerator.name(), qsizetype(qstrlen(enumerator.name())));
+    ds << enumerator.isFlag();
+    ds << enumerator.isScoped();
+    const auto typeName = QByteArray(enumerator.scope()).append("::").append(enumerator.name());
+    const quint32 size = quint32(QMetaType::fromName(typeName.constData()).sizeOf());
+    ds << size;
+#ifdef QTRO_VERBOSE_PROTOCOL
+    qDebug("  Enum (name = %s, size = %d, isFlag = %s, isScoped = %s):", enumerator.name(), size, enumerator.isFlag() ? "true" : "false", enumerator.isScoped() ? "true" : "false");
+#endif
+    const int keyCount = enumerator.keyCount();
+    ds << keyCount;
+    for (int k = 0; k < keyCount; ++k) {
+        ds << QByteArray::fromRawData(enumerator.key(k), qsizetype(qstrlen(enumerator.key(k))));
+        ds << enumerator.value(k);
+#ifdef QTRO_VERBOSE_PROTOCOL
+        qDebug("    Key %d (name = %s, value = %d):", k, enumerator.key(k), enumerator.value(k));
+#endif
+    }
+}
+
+static void serializeGadgets(QDataStream &ds, const QSet<const QMetaObject *> &gadgets, const QSet<QMetaEnum> &enums, const QRemoteObjectSourceBase *source=nullptr)
+{
+    // Determine how to handle the enums found
+    QSet<QMetaEnum> qtEnums;
+    QSet<const QMetaObject *> dynamicEnumMetaObjects;
+    for (const auto &metaEnum : enums) {
+        auto const metaObject = metaEnum.enclosingMetaObject();
+        if (gadgets.contains(metaObject)) // Part of a gadget will we serialize
+            continue;
+        // This checks if the enum is defined in our object heirarchy, in which case it will
+        // already have been serialized.
+        if (source && checkForEnumsInSource(metaObject, source->d->root))
+            continue;
+        // qtEnums are enumerations already known by Qt, so we only need register them.
+        // We don't need to send all of the key/value data.
+        if (metaObject == &Qt::staticMetaObject) // Are the other Qt metaclasses for enums?
+            qtEnums.insert(metaEnum);
+        else
+            dynamicEnumMetaObjects.insert(metaEnum.enclosingMetaObject());
+    }
+    ds << quint32(qtEnums.size());
+    for (const auto &metaEnum : qtEnums) {
+        QByteArray enumName(metaEnum.scope());
+        enumName.append("::", 2).append(metaEnum.name());
+        ds << enumName;
+    }
+    const auto allMetaObjects = gadgets + dynamicEnumMetaObjects;
+    ds << quint32(allMetaObjects.size());
+#ifdef QTRO_VERBOSE_PROTOCOL
+    qDebug() << "  Found" << gadgets.size() << "gadget/pod and" << (allMetaObjects.size() - gadgets.size()) << "enum types";
+    int i = 0;
+#endif
+    // There isn't an easy way to update a metaobject incrementally, so we
+    // send all of the metaobject's enums, but no properties, when an external
+    // enum is requested.
+    for (auto const meta : allMetaObjects) {
+        ds << QByteArray::fromRawData(meta->className(), qsizetype(qstrlen(meta->className())));
+        int propertyCount = gadgets.contains(meta) ? meta->propertyCount() : 0;
+        ds << quint32(propertyCount);
+#ifdef QTRO_VERBOSE_PROTOCOL
+        qDebug("  Gadget %d (name = %s, # properties = %d, # enums = %d):", i++, meta->className(), propertyCount, meta->enumeratorCount() - meta->enumeratorOffset());
+#endif
+        for (int j = 0; j < propertyCount; j++) {
+            auto prop = meta->property(j);
+#ifdef QTRO_VERBOSE_PROTOCOL
+            qDebug("    Data member %d (name = %s, type = %s):", j, prop.name(), prop.typeName());
+#endif
+            ds << QByteArray::fromRawData(prop.name(), qsizetype(qstrlen(prop.name())));
+            ds << QByteArray::fromRawData(prop.typeName(), qsizetype(qstrlen(prop.typeName())));
+        }
+        int enumCount = meta->enumeratorCount() - meta->enumeratorOffset();
+        ds << quint32(enumCount);
+        for (int j = meta->enumeratorOffset(); j < meta->enumeratorCount(); j++) {
+            auto const enumMeta = meta->enumerator(j);
+            serializeEnum(ds, enumMeta);
+        }
+    }
+}
+
+void QDataStreamCodec::serializeDefinition(QDataStream &ds, const QRemoteObjectSourceBase *source)
+{
+    const SourceApiMap *api = source->m_api;
+    const QByteArray desiredClassName(api->typeName().toLatin1());
+    const QByteArray originalClassName = api->className();
+    // The dynamic class will be called typeName on the receiving side of this definition
+    // However, there are types like enums that have the QObject's class name.  Replace()
+    // will convert a parameter such as "ParentClassSource::MyEnum" to "ParentClass::MyEnum"
+    // so the type can be properly resolved and registered.
+    auto replace = [&originalClassName, &desiredClassName](QByteArray &name) {
+        name.replace(originalClassName, desiredClassName);
+    };
+
+    ds << source->m_api->typeName();
+#ifdef QTRO_VERBOSE_PROTOCOL
+    qDebug() << "Serializing definition for" << source->m_api->typeName();
+#endif
+
+    //Now copy the property data
+    const int numEnums = api->enumCount();
+    const auto metaObject = source->m_object->metaObject();
+    ds << quint32(numEnums);  //Number of Enums
+#ifdef QTRO_VERBOSE_PROTOCOL
+    qDebug() << "  Found" << numEnums << "enumeration types";
+#endif
+    for (int i = 0; i < numEnums; ++i) {
+        auto enumerator = metaObject->enumerator(api->sourceEnumIndex(i));
+        Q_ASSERT(enumerator.isValid());
+        serializeEnum(ds, enumerator);
+    }
+
+    QSet<const QMetaObject *> gadgets;
+    QSet<QMetaEnum> enums;
+    recurseForGadgets(gadgets, enums, source);
+    serializeGadgets(ds, gadgets, enums, source);
+
+    const int numSignals = api->signalCount();
+    ds << quint32(numSignals);  //Number of signals
+    for (int i = 0; i < numSignals; ++i) {
+        const int index = api->sourceSignalIndex(i);
+        Q_ASSERT(index >= 0);
+        auto signature = api->signalSignature(i);
+        replace(signature);
+        const int count = api->signalParameterCount(i);
+        for (int pi = 0; pi < count; ++pi) {
+            const auto metaType = QMetaType(api->signalParameterType(i, pi));
+            if (isSequentialGadgetType(metaType))
+                signature.replace(metaType.name(), "QtROSequentialContainer");
+            else if (isAssociativeGadgetType(metaType))
+                signature.replace(metaType.name(), "QtROAssociativeContainer");
+        }
+#ifdef QTRO_VERBOSE_PROTOCOL
+        qDebug() << "  Signal" << i << "(signature =" << signature << "parameter names =" << api->signalParameterNames(i) << ")";
+#endif
+        ds << signature;
+        ds << api->signalParameterNames(i);
+    }
+
+    const int numMethods = api->methodCount();
+    ds << quint32(numMethods);  //Number of methods
+    for (int i = 0; i < numMethods; ++i) {
+        const int index = api->sourceMethodIndex(i);
+        Q_ASSERT(index >= 0);
+        auto signature = api->methodSignature(i);
+        replace(signature);
+        const int count = api->methodParameterCount(i);
+        for (int pi = 0; pi < count; ++pi) {
+            const auto metaType = QMetaType(api->methodParameterType(i, pi));
+            if (isSequentialGadgetType(metaType))
+                signature.replace(metaType.name(), "QtROSequentialContainer");
+            else if (isAssociativeGadgetType(metaType))
+                signature.replace(metaType.name(), "QtROAssociativeContainer");
+        }
+        auto typeName = api->typeName(i);
+        replace(typeName);
+#ifdef QTRO_VERBOSE_PROTOCOL
+        qDebug() << "  Slot" << i << "(signature =" << signature << "parameter names =" << api->methodParameterNames(i) << "return type =" << typeName << ")";
+#endif
+        ds << signature;
+        ds << typeName;
+        ds << api->methodParameterNames(i);
+    }
+
+    const int numProperties = api->propertyCount();
+    ds << quint32(numProperties);  //Number of properties
+    for (int i = 0; i < numProperties; ++i) {
+        const int index = api->sourcePropertyIndex(i);
+        Q_ASSERT(index >= 0);
+
+        const auto target = api->isAdapterProperty(i) ? source->m_adapter : source->m_object;
+        const auto metaProperty = target->metaObject()->property(index);
+        ds << metaProperty.name();
+#ifdef QTRO_VERBOSE_PROTOCOL
+        qDebug() << "  Property" << i << "name =" << metaProperty.name();
+#endif
+        if (metaProperty.metaType().flags().testFlag(QMetaType::PointerToQObject)) {
+            auto objectType = getObjectType(QLatin1String(metaProperty.typeName()));
+            ds << (objectType == ObjectType::CLASS ? "QObject*" : "QAbstractItemModel*");
+#ifdef QTRO_VERBOSE_PROTOCOL
+            qDebug() << "    Type:" << (objectType == ObjectType::CLASS ? "QObject*" : "QAbstractItemModel*");
+#endif
+        } else {
+            if (isSequentialGadgetType(metaProperty.metaType())) {
+                ds << "QtROSequentialContainer";
+#ifdef QTRO_VERBOSE_PROTOCOL
+                qDebug() << "    Type:" << "QtROSequentialContainer";
+#endif
+            } else if (isAssociativeGadgetType(metaProperty.metaType())) {
+                ds << "QtROAssociativeContainer";
+#ifdef QTRO_VERBOSE_PROTOCOL
+                qDebug() << "    Type:" << "QtROAssociativeContainer";
+#endif
+            } else {
+                ds << metaProperty.typeName();
+#ifdef QTRO_VERBOSE_PROTOCOL
+                qDebug() << "    Type:" << metaProperty.typeName();
+#endif
+            }
+        }
+        if (metaProperty.notifySignalIndex() == -1) {
+            ds << QByteArray();
+#ifdef QTRO_VERBOSE_PROTOCOL
+            qDebug() << "    Notification signal: None";
+#endif
+        } else {
+            auto signature = metaProperty.notifySignal().methodSignature();
+            replace(signature);
+            ds << signature;
+#ifdef QTRO_VERBOSE_PROTOCOL
+            qDebug() << "    Notification signal:" << signature;
+#endif
+        }
+    }
+}
+
+void QDataStreamCodec::serializeAddObjectPacket(const QString &name, bool isDynamic)
+{
+    m_packet.setId(AddObject);
+    m_packet << name;
+    m_packet << isDynamic;
+    m_packet.finishPacket();
+}
+
+void QDataStreamCodec::deserializeAddObjectPacket(QDataStream &ds, bool &isDynamic)
+{
+    ds >> isDynamic;
+}
+
+void QDataStreamCodec::serializeRemoveObjectPacket(const QString &name)
+{
+    m_packet.setId(RemoveObject);
+    m_packet << name;
+    m_packet.finishPacket();
+}
+//There is no deserializeRemoveObjectPacket - no parameters other than id and name
+
+void QDataStreamCodec::serializeInvokePacket(const QString &name, int call, int index, const QVariantList &args, int serialId, int propertyIndex)
+{
+    m_packet.setId(InvokePacket);
+    m_packet << name;
+    m_packet << call;
+    m_packet << index;
+
+    m_packet << quint32(args.size());
+    for (const auto &arg : args)
+        m_packet << encodeVariant(arg);
+
+    m_packet << serialId;
+    m_packet << propertyIndex;
+    m_packet.finishPacket();
+}
+
+void QDataStreamCodec::deserializeInvokePacket(QDataStream& in, int &call, int &index, QVariantList &args, int &serialId, int &propertyIndex)
+{
+    in >> call;
+    in >> index;
+    const bool success = deserializeQVariantList(in, args);
+    Q_ASSERT(success);
+    Q_UNUSED(success)
+    in >> serialId;
+    in >> propertyIndex;
+}
+
+void QDataStreamCodec::serializeInvokeReplyPacket(const QString &name, int ackedSerialId, const QVariant &value)
+{
+    m_packet.setId(InvokeReplyPacket);
+    m_packet << name;
+    m_packet << ackedSerialId;
+    m_packet << value;
+    m_packet.finishPacket();
+}
+
+void QDataStreamCodec::deserializeInvokeReplyPacket(QDataStream& in, int &ackedSerialId, QVariant &value){
+    in >> ackedSerialId;
+    in >> value;
+}
+
+void QDataStreamCodec::serializePropertyChangePacket(QRemoteObjectSourceBase *source, int signalIndex)
+{
+    int internalIndex = source->m_api->propertyRawIndexFromSignal(signalIndex);
+    m_packet.setId(PropertyChangePacket);
+    m_packet << source->name();
+    m_packet << internalIndex;
+    serializeProperty(source, internalIndex);
+    m_packet.finishPacket();
+}
+
+void QDataStreamCodec::deserializePropertyChangePacket(QDataStream& in, int &index, QVariant &value)
+{
+    in >> index;
+    in >> value;
+}
+
+void QDataStreamCodec::serializeObjectListPacket(const ObjectInfoList &objects)
+{
+    m_packet.setId(ObjectList);
+    m_packet << objects;
+    m_packet.finishPacket();
+}
+
+void QDataStreamCodec::deserializeObjectListPacket(QDataStream &in, ObjectInfoList &objects)
+{
+    in >> objects;
+}
+
+void QDataStreamCodec::serializePingPacket(const QString &name)
+{
+    m_packet.setId(Ping);
+    m_packet << name;
+    m_packet.finishPacket();
+}
+
+void QDataStreamCodec::serializePongPacket(const QString &name)
+{
+    m_packet.setId(Pong);
+    m_packet << name;
+    m_packet.finishPacket();
+}
+
+QRO_::QRO_(QRemoteObjectSourceBase *source)
+    : name(source->name())
+    , typeName(source->m_api->typeName())
+    , type(source->m_adapter ? ObjectType::MODEL : getObjectType(typeName))
+    , isNull(source->m_object == nullptr)
+    , classDefinition()
+    , parameters()
+{}
+
+QRO_::QRO_(const QVariant &value)
+    : type(ObjectType::GADGET)
+    , isNull(false)
+{
+    const auto metaType = value.metaType();
+    auto meta = metaType.metaObject();
+    QDataStream out(&classDefinition, QIODevice::WriteOnly);
+    const int numProperties = meta->propertyCount();
+    const auto name = metaType.name();
+    const auto typeName = QByteArray::fromRawData(name, qsizetype(qstrlen(name)));
+    out << quint32(0) << quint32(1);
+    out << typeName;
+    out << numProperties;
+#ifdef QTRO_VERBOSE_PROTOCOL
+    qDebug("Serializing POD definition to QRO_ (name = %s)", typeName.constData());
+#endif
+    for (int i = 0; i < numProperties; ++i) {
+        const auto property = meta->property(i);
+#ifdef QTRO_VERBOSE_PROTOCOL
+        qDebug("  Data member %d (name = %s, type = %s):", i, property.name(), property.typeName());
+#endif
+        out << QByteArray::fromRawData(property.name(), qsizetype(qstrlen(property.name())));
+        out << QByteArray::fromRawData(property.typeName(), qsizetype(qstrlen(property.typeName())));
+    }
+    int enumCount = meta->enumeratorCount() - meta->enumeratorOffset();
+    out << quint32(enumCount);
+    for (int j = meta->enumeratorOffset(); j < meta->enumeratorCount(); j++) {
+        auto const enumMeta = meta->enumerator(j);
+        serializeEnum(out, enumMeta);
+    }
+    QDataStream ds(&parameters, QIODevice::WriteOnly);
+    ds << value;
+#ifdef QTRO_VERBOSE_PROTOCOL
+    qDebug() << "  Value:" << value;
+#endif
+}
+
+QDataStream &operator<<(QDataStream &stream, const QRO_ &info)
+{
+    stream << info.name << info.typeName << quint8(info.type) << info.classDefinition << info.isNull;
+    qCDebug(QT_REMOTEOBJECT) << "Serializing " << info;
+    // info.parameters will be filled in by serializeProperty
+    return stream;
+}
+
+QDataStream &operator>>(QDataStream &stream, QRO_ &info)
+{
+    quint8 tmpType;
+    stream >> info.name >> info.typeName >> tmpType >> info.classDefinition >> info.isNull;
+    info.type = static_cast<ObjectType>(tmpType);
+    qCDebug(QT_REMOTEOBJECT) << "Deserializing " << info;
+    if (!info.isNull)
+        stream >> info.parameters;
+    return stream;
+}
+
+QSQ_::QSQ_(const QVariant &variant)
+{
+    QSequentialIterable sequence;
+    QMetaType valueType;
+    if (variant.metaType() == QMetaType::fromType<QtROSequentialContainer>()) {
+        auto container = static_cast<const QtROSequentialContainer *>(variant.constData());
+        typeName = container->m_typeName;
+        valueType = container->m_valueType;
+        valueTypeName = container->m_valueTypeName;
+        sequence = QSequentialIterable(reinterpret_cast<const QVariantList *>(variant.constData()));
+    } else {
+        sequence = variant.value<QSequentialIterable>();
+        typeName = QByteArray(variant.metaType().name());
+        valueType = sequence.metaContainer().valueMetaType();
+        valueTypeName = QByteArray(valueType.name());
+    }
+#ifdef QTRO_VERBOSE_PROTOCOL
+    qDebug("Serializing POD sequence to QSQ_ (type = %s, valueType = %s) with size = %lld",
+           typeName.constData(), valueTypeName.constData(), sequence.size());
+#endif
+    QDataStream ds(&values, QIODevice::WriteOnly);
+    ds << valueTypeName;
+    auto pos = ds.device()->pos();
+    ds << quint32(sequence.size());
+    for (const auto &v : sequence) {
+        if (!valueType.save(ds, v.data())) {
+            ds.device()->seek(pos);
+            ds.resetStatus();
+            ds << quint32(0);
+            values.resize(ds.device()->pos());
+            qWarning("QSQ_: unable to save type '%s', sending empty list.", valueType.name());
+            break;
+        }
+    }
+}
+
+QDataStream &operator<<(QDataStream &stream, const QSQ_ &sequence)
+{
+    stream << sequence.typeName << sequence.valueTypeName << sequence.values;
+    qCDebug(QT_REMOTEOBJECT) << "Serializing " << sequence;
+    return stream;
+}
+
+QDataStream &operator>>(QDataStream &stream, QSQ_ &sequence)
+{
+    stream >> sequence.typeName >> sequence.valueTypeName >> sequence.values;
+    qCDebug(QT_REMOTEOBJECT) << "Deserializing " << sequence;
+    return stream;
+}
+
+QAS_::QAS_(const QVariant &variant)
+{
+    QAssociativeIterable map;
+    QMetaType keyType, transferType, valueType;
+    const QtROAssociativeContainer *container = nullptr;
+    if (variant.metaType() == QMetaType::fromType<QtROAssociativeContainer>()) {
+        container = static_cast<const QtROAssociativeContainer *>(variant.constData());
+        typeName = container->m_typeName;
+        keyType = container->m_keyType;
+        keyTypeName = container->m_keyTypeName;
+        valueType = container->m_valueType;
+        valueTypeName = container->m_valueTypeName;
+        map = QAssociativeIterable(reinterpret_cast<const QVariantMap *>(variant.constData()));
+    } else {
+        map = variant.value<QAssociativeIterable>();
+        typeName = QByteArray(variant.metaType().name());
+        keyType = map.metaContainer().keyMetaType();
+        keyTypeName = QByteArray(keyType.name());
+        valueType = map.metaContainer().mappedMetaType();
+        valueTypeName = QByteArray(valueType.name());
+    }
+    // Special handling for enums...
+    transferType = keyType;
+    if (keyType.flags().testFlag(QMetaType::IsEnumeration)) {
+        transferType = transferTypeForEnum(keyType);
+        auto meta = keyType.metaObject();
+        // If we are the source, make sure the typeName is converted for any downstream replicas
+        // the `meta` variable will be non-null when the enum is a class enum
+        if (meta && !container) {
+            const int ind = meta->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE);
+            if (ind >= 0) {
+                bool isFlag = keyTypeName.startsWith("QFlags<");
+                if (isFlag || keyTypeName.startsWith(meta->className())) {
+#ifdef QTRO_VERBOSE_PROTOCOL
+                    QByteArray orig(keyTypeName);
+#endif
+                    if (isFlag) {
+                        // Q_DECLARE_FLAGS(Flags, Enum) -> `typedef QFlags<Enum> Flags;`
+                        // We know we have an enum for `Flags` because we sent the enums
+                        // from the source, so we just need to look up the alias.
+                        keyTypeName = keyTypeName.mid(7);
+                        keyTypeName.chop(1); // Remove trailing '>'
+                        int index = keyTypeName.lastIndexOf(':');
+                        for (int i = meta->enumeratorOffset(); i < meta->enumeratorCount(); i++) {
+                            auto en = meta->enumerator(i);
+                            auto name = keyTypeName.data() + index + 1;
+                            if (en.isFlag() && qstrcmp(en.enumName(), name) == 0)
+                                keyTypeName.replace(index + 1, qstrlen(en.enumName()), en.name());
+                        }
+                    }
+                    keyTypeName.replace(meta->className(), meta->classInfo(ind).value());
+                    QByteArray repName(meta->classInfo(ind).value());
+                    repName.append("Replica");
+                    typeName.replace(meta->className(), repName);
+#ifdef QTRO_VERBOSE_PROTOCOL
+                    qDebug() << "Converted map key typename from" << orig << "to" << keyTypeName;
+#endif
+                }
+            }
+        }
+    }
+
+#ifdef QTRO_VERBOSE_PROTOCOL
+    qDebug("Serializing POD map to QAS_ (type = %s, keyType = %s, valueType = %s), size = %lld",
+           typeName.constData(), keyTypeName.constData(), valueTypeName.constData(),
+           map.size());
+#endif
+    QDataStream ds(&values, QIODevice::WriteOnly);
+    ds << keyTypeName;
+    ds << valueTypeName;
+    auto pos = ds.device()->pos();
+    ds << quint32(map.size());
+    QAssociativeIterable::const_iterator iter = map.begin();
+    for (int i = 0; i < map.size(); i++) {
+        QVariant key(container ? container->m_keys.at(i) : iter.key());
+        if (transferType != keyType)
+            key.convert(transferType);
+        if (!transferType.save(ds, key.data())) {
+            ds.device()->seek(pos);
+            ds.resetStatus();
+            ds << quint32(0);
+            values.resize(ds.device()->pos());
+            qWarning("QAS_: unable to save key '%s', sending empty map.", keyType.name());
+            break;
+        }
+        if (!valueType.save(ds, iter.value().data())) {
+            ds.device()->seek(pos);
+            ds.resetStatus();
+            ds << quint32(0);
+            values.resize(ds.device()->pos());
+            qWarning("QAS_: unable to save value '%s', sending empty map.", valueType.name());
+            break;
+        }
+        iter++;
+    }
+}
+
+QDataStream &operator<<(QDataStream &stream, const QAS_ &map)
+{
+    stream << map.typeName << map.keyTypeName << map.valueTypeName << map.values;
+    qCDebug(QT_REMOTEOBJECT) << "Serializing " << map;
+    return stream;
+}
+
+QDataStream &operator>>(QDataStream &stream, QAS_ &map)
+{
+    stream >> map.typeName >> map.keyTypeName >> map.valueTypeName >> map.values;
+    qCDebug(QT_REMOTEOBJECT) << "Deserializing " << map;
+    return stream;
+}
+
+DataStreamPacket::DataStreamPacket(quint16 id)
+    : QDataStream(&array, QIODevice::WriteOnly), baseAddress(0), size(0)
+{
+    this->setVersion(QtRemoteObjects::dataStreamVersion);
+    this->setByteOrder(QDataStream::LittleEndian);
+    *this << quint32(0);
+    *this << id;
+}
+
+void CodecBase::send(const QSet<QtROIoDeviceBase *> &connections)
+{
+    const auto bytearray = getPayload();
+    for (auto conn : connections)
+        conn->write(bytearray);
+    reset();
+}
+
+void CodecBase::send(const QList<QtROIoDeviceBase *> &connections)
+{
+    const auto bytearray = getPayload();
+    for (auto conn : connections)
+        conn->write(bytearray);
+    reset();
+}
+
+void CodecBase::send(QtROIoDeviceBase *connection)
+{
+    const auto bytearray = getPayload();
+    connection->write(bytearray);
+    reset();
+}
+
+} // namespace QRemoteObjectPackets
+
+QT_END_NAMESPACE
diff --git a/src/remoteobjects/qremoteobjectpacket_p.h b/src/remoteobjects/qremoteobjectpacket_p.h
new file mode 100644 (file)
index 0000000..b97136d
--- /dev/null
@@ -0,0 +1,327 @@
+/****************************************************************************
+**
+** 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 QTREMOTEOBJECTPACKET_P_H
+#define QTREMOTEOBJECTPACKET_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 "qtremoteobjectglobal.h"
+#include "qremoteobjectsource.h"
+#include "qconnectionfactories.h"
+
+#include <QtCore/qassociativeiterable.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qsequentialiterable.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qdatastream.h>
+
+#include <cstdlib>
+
+QT_BEGIN_NAMESPACE
+
+class QMetaObjectBuilder;
+class QRemoteObjectSourceBase;
+class QRemoteObjectRootSource;
+
+namespace QRemoteObjectPackets {
+
+Q_NAMESPACE
+
+class DataStreamPacket;
+
+struct ObjectInfo
+{
+    QString name;
+    QString typeName;
+    QByteArray signature;
+};
+
+inline QDebug operator<<(QDebug dbg, const ObjectInfo &info)
+{
+    dbg.nospace() << "ObjectInfo(" << info.name << ", " << info.typeName << ", " << info.signature <<")";
+    return dbg.space();
+}
+
+inline QDataStream& operator<<(QDataStream &stream, const ObjectInfo &info)
+{
+    return stream << info.name << info.typeName << info.signature;
+}
+
+inline QDataStream& operator>>(QDataStream &stream, ObjectInfo &info)
+{
+    return stream >> info.name >> info.typeName >> info.signature;
+}
+
+using ObjectInfoList = QList<ObjectInfo>;
+
+enum class ObjectType : quint8 { CLASS, MODEL, GADGET };
+Q_ENUM_NS(ObjectType)
+
+// Use a short name, as QVariant::save writes the name every time a qvariant of
+// this type is serialized
+class QRO_
+{
+public:
+    QRO_() : type(ObjectType::CLASS), isNull(true) {}
+    explicit QRO_(QRemoteObjectSourceBase *source);
+    explicit QRO_(const QVariant &value);
+    QString name, typeName;
+    ObjectType type;
+    bool isNull;
+    QByteArray classDefinition;
+    QByteArray parameters;
+};
+
+inline QDebug operator<<(QDebug dbg, const QRO_ &info)
+{
+    dbg.nospace() << "QRO_(name: " << info.name << ", typeName: " << info.typeName << ", type: " << info.type
+                  << ", valid: " << (info.isNull ? "true" : "false") << ", paremeters: {" << info.parameters <<")"
+                  << (info.classDefinition.isEmpty() ? " no definitions)" : " with definitions)");
+    return dbg.space();
+}
+
+QDataStream& operator<<(QDataStream &stream, const QRO_ &info);
+
+QDataStream& operator>>(QDataStream &stream, QRO_ &info);
+
+// Class for transmitting sequence data.  Needed because containers for custom
+// types (and even primitive types in Qt5) are not registered with the metaObject
+// system.  This wrapper allows us to create the desired container if it is
+// registered, or a QtROSequentialContainer if it is not.  QtROSequentialContainer
+// is derived from QVariantList, so it can be used from QML similar to the API
+// type.
+class QSQ_
+{
+public:
+    QSQ_() {}
+    explicit QSQ_(const QVariant &lst);
+    QByteArray typeName, valueTypeName;
+    QByteArray values;
+};
+
+inline QDebug operator<<(QDebug dbg, const QSQ_ &seq)
+{
+    dbg.nospace() << "QSQ_(typeName: " << seq.typeName << ", valueType: " << seq.valueTypeName
+                  << ", values: {" << seq.values <<")";
+    return dbg.space();
+}
+
+QDataStream& operator<<(QDataStream &stream, const QSQ_ &info);
+
+QDataStream& operator>>(QDataStream &stream, QSQ_ &info);
+
+// Class for transmitting associative containers.  Needed because containers for
+// custom types (and even primitive types in Qt5) are not registered with the
+// metaObject system.  This wrapper allows us to create the desired container if
+// it is registered, or a QtROAssociativeContainer if it is not.
+// QtROAssociativeContainer is derived from QVariantMap, so it can be used from
+// QML similar to the API type.
+class QAS_
+{
+public:
+    QAS_() {}
+    explicit QAS_(const QVariant &lst);
+    QByteArray typeName, keyTypeName, valueTypeName;
+    QByteArray values;
+};
+
+inline QDebug operator<<(QDebug dbg, const QAS_ &seq)
+{
+    dbg.nospace() << "QAS_(typeName: " << seq.typeName << ", keyType: " << seq.keyTypeName
+                  << ", valueType: " << seq.valueTypeName << ", values: {" << seq.values <<")";
+    return dbg.space();
+}
+
+QDataStream& operator<<(QDataStream &stream, const QAS_ &info);
+
+QDataStream& operator>>(QDataStream &stream, QAS_ &info);
+
+//Helper class for creating a QByteArray from a QRemoteObjectPacket
+class DataStreamPacket : public QDataStream
+{
+public:
+    DataStreamPacket(quint16 id = QtRemoteObjects::InvokePacket);
+
+    void setId(quint16 id)
+    {
+        device()->seek(baseAddress);
+        *this << quint32(0);
+        *this << id;
+    }
+
+    void finishPacket()
+    {
+        size = device()->pos();
+        device()->seek(baseAddress);
+        *this << quint32(size - baseAddress - sizeof(quint32));
+        baseAddress = size; // Allow appending until reset() is called
+    }
+
+    const QByteArray &payload()
+    {
+        array.resize(size);
+        return array;
+    }
+
+    void reset()
+    {
+        baseAddress = 0;
+        size = 0;
+        array.clear();
+    }
+
+private:
+    QByteArray array;
+    int baseAddress;
+    int size;
+
+    Q_DISABLE_COPY(DataStreamPacket)
+};
+
+class CodecBase
+{
+public:
+    CodecBase() = default;
+    CodecBase(const CodecBase &) = default;
+    CodecBase(CodecBase &&) = default;
+    CodecBase &operator=(const CodecBase &) = default;
+    CodecBase &operator=(CodecBase &&) = default;
+    virtual ~CodecBase() = default;
+
+    virtual void serializeObjectListPacket(const ObjectInfoList &) = 0;
+    virtual void deserializeObjectListPacket(QDataStream &in, ObjectInfoList &) = 0;
+    virtual void serializeInitPacket(const QRemoteObjectRootSource *) = 0;
+    virtual void serializeInitDynamicPacket(const QRemoteObjectRootSource *) = 0;
+    virtual void serializePropertyChangePacket(QRemoteObjectSourceBase *source,
+                                               int signalIndex) = 0;
+    virtual void deserializePropertyChangePacket(QDataStream &in, int &index, QVariant &value) = 0;
+    virtual void serializeProperty(const QRemoteObjectSourceBase *source, int internalIndex) = 0;
+    // Heartbeat packets
+    virtual void serializePingPacket(const QString &name) = 0;
+    virtual void serializePongPacket(const QString &name) = 0;
+    virtual void serializeInvokePacket(const QString &name, int call, int index,
+                                       const QVariantList &args, int serialId = -1,
+                                       int propertyIndex = -1) = 0;
+    virtual void deserializeInvokePacket(QDataStream &in, int &call, int &index, QVariantList &args,
+                                         int &serialId, int &propertyIndex) = 0;
+    virtual void serializeInvokeReplyPacket(const QString &name, int ackedSerialId,
+                                            const QVariant &value) = 0;
+    virtual void serializeHandshakePacket() = 0;
+    virtual void serializeRemoveObjectPacket(const QString &name) = 0;
+    //There is no deserializeRemoveObjectPacket - no parameters other than id and name
+    virtual void serializeAddObjectPacket(const QString &name, bool isDynamic) = 0;
+    virtual void deserializeAddObjectPacket(QDataStream &, bool &isDynamic) = 0;
+    virtual void deserializeInitPacket(QDataStream &, QVariantList &) = 0;
+    virtual void deserializeInvokeReplyPacket(QDataStream &in, int &ackedSerialId,
+                                              QVariant &value) = 0;
+    void send(const QSet<QtROIoDeviceBase *> &connections);
+    void send(const QVector<QtROIoDeviceBase *> &connections);
+    void send(QtROIoDeviceBase *connection);
+
+protected:
+    // A payload can consist of one or more packets
+    virtual const QByteArray &getPayload() = 0;
+    virtual void reset() {}
+};
+
+class QDataStreamCodec : public CodecBase
+{
+public:
+    void serializeObjectListPacket(const ObjectInfoList &) override;
+    void deserializeObjectListPacket(QDataStream &in, ObjectInfoList &) override;
+    void serializeInitPacket(const QRemoteObjectRootSource *) override;
+    void serializeInitDynamicPacket(const QRemoteObjectRootSource*) override;
+    void serializePropertyChangePacket(QRemoteObjectSourceBase *source, int signalIndex) override;
+    void deserializePropertyChangePacket(QDataStream &in, int &index, QVariant &value) override;
+    void serializeProperty(const QRemoteObjectSourceBase *source, int internalIndex) override;
+    void serializePingPacket(const QString &name) override;
+    void serializePongPacket(const QString &name) override;
+    void serializeInvokePacket(const QString &name, int call, int index, const QVariantList &args,
+                               int serialId = -1, int propertyIndex = -1) override;
+    void deserializeInvokePacket(QDataStream &in, int &call, int &index, QVariantList &args,
+                                 int &serialId, int &propertyIndex) override;
+    void serializeInvokeReplyPacket(const QString &name, int ackedSerialId,
+                                    const QVariant &value) override;
+    void serializeHandshakePacket() override;
+    void serializeRemoveObjectPacket(const QString &name) override;
+    void serializeAddObjectPacket(const QString &name, bool isDynamic) override;
+    void deserializeAddObjectPacket(QDataStream &, bool &isDynamic) override;
+    void deserializeInitPacket(QDataStream &, QVariantList &) override;
+    void deserializeInvokeReplyPacket(QDataStream &in, int &ackedSerialId,
+                                      QVariant &value) override;
+
+protected:
+    const QByteArray &getPayload() override {
+        return m_packet.payload();
+    }
+    void reset() override {
+        m_packet.reset();
+    }
+private:
+    void serializeDefinition(QDataStream &, const QRemoteObjectSourceBase *);
+    void serializeProperty(QDataStream &ds, const QRemoteObjectSourceBase *source, int internalIndex);
+    void serializeProperties(const QRemoteObjectSourceBase *source);
+    DataStreamPacket m_packet;
+};
+
+QMetaType transferTypeForEnum(QMetaType enumType);
+QVariant encodeVariant(const QVariant &value);
+QVariant decodeVariant(QVariant &&value, QMetaType metaType);
+
+} // namespace QRemoteObjectPackets
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QRemoteObjectPackets::QRO_)
+
+#endif
diff --git a/src/remoteobjects/qremoteobjectpendingcall.cpp b/src/remoteobjects/qremoteobjectpendingcall.cpp
new file mode 100644 (file)
index 0000000..e94c191
--- /dev/null
@@ -0,0 +1,271 @@
+/****************************************************************************
+**
+** 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 "qremoteobjectpendingcall.h"
+#include "qremoteobjectpendingcall_p.h"
+
+#include "qremoteobjectreplica_p.h"
+
+#include <QtCore/qcoreapplication.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QRemoteObjectPendingCallData::QRemoteObjectPendingCallData(int serialId, QRemoteObjectReplicaImplementation *replica)
+    : replica(replica)
+    , serialId(serialId)
+    , error(QRemoteObjectPendingCall::InvalidMessage)
+    , watcherHelper(nullptr)
+{
+}
+
+QRemoteObjectPendingCallData::~QRemoteObjectPendingCallData()
+{
+}
+
+void QRemoteObjectPendingCallWatcherHelper::add(QRemoteObjectPendingCallWatcher *watcher)
+{
+    connect(this, &QRemoteObjectPendingCallWatcherHelper::finished, watcher, [watcher]() {
+        emit watcher->finished(watcher);
+    }, Qt::QueuedConnection);
+}
+
+void QRemoteObjectPendingCallWatcherHelper::emitSignals()
+{
+    emit finished();
+}
+
+/*!
+    \class QRemoteObjectPendingCall
+    \inmodule QtRemoteObjects
+    \brief Encapsulates the result of an asynchronous method call.
+*/
+
+QRemoteObjectPendingCall::QRemoteObjectPendingCall()
+    : d(new QRemoteObjectPendingCallData)
+{
+}
+
+QRemoteObjectPendingCall::~QRemoteObjectPendingCall()
+{
+}
+
+QRemoteObjectPendingCall::QRemoteObjectPendingCall(const QRemoteObjectPendingCall& other)
+    : d(other.d)
+{
+}
+
+QRemoteObjectPendingCall::QRemoteObjectPendingCall(QRemoteObjectPendingCallData *dd)
+    : d(dd)
+{
+}
+
+QRemoteObjectPendingCall &QRemoteObjectPendingCall::operator=(const QRemoteObjectPendingCall &other)
+{
+    d = other.d;
+    return *this;
+}
+
+/*!
+    Returns the return value of the remote call.
+
+    returnValue will only be valid when the remote call has finished and there
+    are no \l {error}s.
+*/
+QVariant QRemoteObjectPendingCall::returnValue() const
+{
+    if (!d)
+        return QVariant();
+
+    QMutexLocker locker(&d->mutex);
+    return d->returnValue;
+}
+
+/*!
+    \enum QRemoteObjectPendingCall::Error
+
+    This enum type specifies the possible error values for a remote call:
+
+    \value NoError
+           No error occurred.
+    \value InvalidMessage
+           The default error state prior to the remote call finishing.
+*/
+
+/*!
+    Returns the error, if any, from the remote call.
+*/
+QRemoteObjectPendingCall::Error QRemoteObjectPendingCall::error() const
+{
+    if (!d)
+        return QRemoteObjectPendingCall::InvalidMessage;
+
+    QMutexLocker locker(&d->mutex);
+    return d->error;
+}
+
+/*!
+    Returns true if the remote call has finished, false otherwise.
+
+    A finished call will include a returnValue or \l error.
+*/
+bool QRemoteObjectPendingCall::isFinished() const
+{
+    if (!d)
+        return true; // considered finished
+
+    QMutexLocker locker(&d->mutex);
+    return d->error != InvalidMessage;
+}
+
+/*!
+    Blocks for up to \a timeout milliseconds, until the remote call has finished.
+
+    Returns \c true on success, \c false otherwise.
+*/
+bool QRemoteObjectPendingCall::waitForFinished(int timeout)
+{
+    if (!d)
+        return false;
+
+    if (d->error != QRemoteObjectPendingCall::InvalidMessage)
+        return true; // already finished
+
+    QMutexLocker locker(&d->mutex);
+    if (!d->replica)
+        return false;
+
+    return d->replica->waitForFinished(*this, timeout);
+}
+
+QRemoteObjectPendingCall QRemoteObjectPendingCall::fromCompletedCall(const QVariant &returnValue)
+{
+    QRemoteObjectPendingCallData *data = new QRemoteObjectPendingCallData;
+    data->returnValue = returnValue;
+    data->error = NoError;
+    return QRemoteObjectPendingCall(data);
+}
+
+class QRemoteObjectPendingCallWatcherPrivate: public QObjectPrivate
+{
+public:
+    Q_DECLARE_PUBLIC(QRemoteObjectPendingCallWatcher)
+};
+
+/*!
+    \class QRemoteObjectPendingCallWatcher
+    \inmodule QtRemoteObjects
+    \brief Provides a QObject-based API for watching a QRemoteObjectPendingCall.
+
+    QRemoteObjectPendingCallWatcher provides a signal indicating when a QRemoteObjectPendingCall
+    has finished, allowing for convenient, non-blocking handling of the call.
+*/
+
+QRemoteObjectPendingCallWatcher::QRemoteObjectPendingCallWatcher(const QRemoteObjectPendingCall &call, QObject *parent)
+    : QObject(*new QRemoteObjectPendingCallWatcherPrivate, parent)
+    , QRemoteObjectPendingCall(call)
+{
+    if (d) {
+        QMutexLocker locker(&d->mutex);
+        if (!d->watcherHelper) {
+            d->watcherHelper.reset(new QRemoteObjectPendingCallWatcherHelper);
+            if (d->error != QRemoteObjectPendingCall::InvalidMessage) {
+                // cause a signal emission anyways
+                QMetaObject::invokeMethod(d->watcherHelper.data(), "finished", Qt::QueuedConnection);
+            }
+        }
+        d->watcherHelper->add(this);
+    }
+}
+
+QRemoteObjectPendingCallWatcher::~QRemoteObjectPendingCallWatcher()
+{
+}
+
+/*!
+    Returns true if the remote call has finished, false otherwise.
+
+    A finished call will include a returnValue or error.
+*/
+bool QRemoteObjectPendingCallWatcher::isFinished() const
+{
+    if (!d)
+        return true; // considered finished
+
+    QMutexLocker locker(&d->mutex);
+    return d->error != QRemoteObjectPendingCall::InvalidMessage;
+}
+
+/*!
+    Blocks until the remote call has finished.
+*/
+void QRemoteObjectPendingCallWatcher::waitForFinished()
+{
+    if (d) {
+        QRemoteObjectPendingCall::waitForFinished();
+
+        // our signals were queued, so deliver them
+        QCoreApplication::sendPostedEvents(d->watcherHelper.data(), QEvent::MetaCall);
+        QCoreApplication::sendPostedEvents(this, QEvent::MetaCall);
+    }
+}
+
+/*!
+    \fn QRemoteObjectPendingCallWatcher::finished(QRemoteObjectPendingCallWatcher *self)
+
+    This signal is emitted when the remote call has finished. \a self is the pointer to
+    the watcher object that emitted the signal. A finished call will include a
+    returnValue or error.
+*/
+
+/*!
+    \class QRemoteObjectPendingReply
+    \inmodule QtRemoteObjects
+    \brief A templated version of QRemoteObjectPendingCall.
+*/
+
+/*! \fn template <typename T> T QRemoteObjectPendingReply<T>::returnValue() const
+
+    Returns a strongly typed version of the return value of the remote call.
+*/
+
+QT_END_NAMESPACE
+
+#include "moc_qremoteobjectpendingcall.cpp"
diff --git a/src/remoteobjects/qremoteobjectpendingcall.h b/src/remoteobjects/qremoteobjectpendingcall.h
new file mode 100644 (file)
index 0000000..e895842
--- /dev/null
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** 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 QREMOTEOBJECTPENDINGCALL_H
+#define QREMOTEOBJECTPENDINGCALL_H
+
+#include <QtRemoteObjects/qtremoteobjectglobal.h>
+
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRemoteObjectPendingCallWatcherPrivate;
+class QRemoteObjectPendingCallData;
+
+class Q_REMOTEOBJECTS_EXPORT QRemoteObjectPendingCall
+{
+public:
+    enum Error {
+        NoError,
+        InvalidMessage
+    };
+
+    QRemoteObjectPendingCall();
+    QRemoteObjectPendingCall(const QRemoteObjectPendingCall &other);
+    ~QRemoteObjectPendingCall();
+
+    QRemoteObjectPendingCall &operator=(const QRemoteObjectPendingCall &other);
+
+    QVariant returnValue() const;
+    QRemoteObjectPendingCall::Error error() const;
+
+    bool isFinished() const;
+
+    bool waitForFinished(int timeout = 30000);
+
+    static QRemoteObjectPendingCall fromCompletedCall(const QVariant &returnValue);
+
+protected:
+    QRemoteObjectPendingCall(QRemoteObjectPendingCallData *dd);
+
+    /// Shared data, note: might be null
+    QExplicitlySharedDataPointer<QRemoteObjectPendingCallData> d;
+
+private:
+    friend class QConnectedReplicaImplementation;
+};
+
+QT_END_NAMESPACE
+Q_DECLARE_METATYPE(QRemoteObjectPendingCall)
+QT_BEGIN_NAMESPACE
+
+class Q_REMOTEOBJECTS_EXPORT QRemoteObjectPendingCallWatcher: public QObject, public QRemoteObjectPendingCall
+{
+    Q_OBJECT
+
+public:
+    QRemoteObjectPendingCallWatcher(const QRemoteObjectPendingCall &call, QObject *parent = nullptr);
+    ~QRemoteObjectPendingCallWatcher() override;
+
+    bool isFinished() const;
+
+    void waitForFinished();
+
+Q_SIGNALS:
+    void finished(QRemoteObjectPendingCallWatcher *self);
+
+private:
+    Q_DECLARE_PRIVATE(QRemoteObjectPendingCallWatcher)
+};
+
+template<typename T>
+class QRemoteObjectPendingReply : public QRemoteObjectPendingCall
+{
+public:
+    typedef T Type;
+
+    QRemoteObjectPendingReply() = default;
+    explicit QRemoteObjectPendingReply(const QRemoteObjectPendingCall &call)
+        : QRemoteObjectPendingCall(call)
+    {
+    }
+
+    QRemoteObjectPendingReply &operator=(const QRemoteObjectPendingCall &other)
+    {
+        QRemoteObjectPendingCall::operator=(other);
+        return *this;
+    }
+
+    Type returnValue() const
+    {
+        return qvariant_cast<Type>(QRemoteObjectPendingCall::returnValue());
+    }
+
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/remoteobjects/qremoteobjectpendingcall_p.h b/src/remoteobjects/qremoteobjectpendingcall_p.h
new file mode 100644 (file)
index 0000000..59eb77c
--- /dev/null
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** 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 QREMOTEOBJECTPENDINGCALL_P_H
+#define QREMOTEOBJECTPENDINGCALL_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 "qremoteobjectpendingcall.h"
+
+#include <QtCore/qmutex.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRemoteObjectPendingCallWatcherHelper;
+class QRemoteObjectReplicaImplementation;
+
+class QRemoteObjectPendingCallData : public QSharedData
+{
+public:
+    typedef QExplicitlySharedDataPointer<QRemoteObjectPendingCallData> Ptr;
+
+    explicit QRemoteObjectPendingCallData(int serialId = -1, QRemoteObjectReplicaImplementation *replica = nullptr);
+    ~QRemoteObjectPendingCallData();
+
+    QRemoteObjectReplicaImplementation *replica;
+    int serialId;
+
+    QVariant returnValue;
+    QRemoteObjectPendingCall::Error error;
+
+    mutable QMutex mutex;
+
+    mutable QScopedPointer<QRemoteObjectPendingCallWatcherHelper> watcherHelper;
+};
+
+class QRemoteObjectPendingCallWatcherHelper: public QObject
+{
+    Q_OBJECT
+public:
+    void add(QRemoteObjectPendingCallWatcher *watcher);
+
+    void emitSignals();
+
+Q_SIGNALS:
+    void finished();
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/remoteobjects/qremoteobjectregistry.cpp b/src/remoteobjects/qremoteobjectregistry.cpp
new file mode 100644 (file)
index 0000000..6052f1e
--- /dev/null
@@ -0,0 +1,244 @@
+/****************************************************************************
+**
+** 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 "qremoteobjectregistry.h"
+#include "qremoteobjectreplica_p.h"
+
+#include <private/qobject_p.h>
+#include <QtCore/qset.h>
+#include <QtCore/qdatastream.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRemoteObjectRegistryPrivate : public QObjectPrivate
+{
+    Q_DECLARE_PUBLIC(QRemoteObjectRegistry)
+
+    QRemoteObjectSourceLocations sourceLocationsActualCalculation() const
+    {
+        return q_func()->propAsVariant(0).value<QRemoteObjectSourceLocations>();
+    }
+    Q_OBJECT_COMPUTED_PROPERTY(QRemoteObjectRegistryPrivate, QRemoteObjectSourceLocations,
+                               sourceLocations,
+                               &QRemoteObjectRegistryPrivate::sourceLocationsActualCalculation)
+    QRemoteObjectSourceLocations hostedSources;
+};
+
+/*!
+    \class QRemoteObjectRegistry
+    \inmodule QtRemoteObjects
+    \brief A class holding information about \l {Source} objects available on the Qt Remote Objects network.
+
+    The Registry is a special Source/Replica pair held by a \l
+    {QRemoteObjectNode} {node} itself. It knows about all other \l {Source}s
+    available on the network, and simplifies the process of connecting to other
+    \l {QRemoteObjectNode} {node}s.
+*/
+QRemoteObjectRegistry::QRemoteObjectRegistry(QObject *parent)
+    : QRemoteObjectReplica(*new QRemoteObjectRegistryPrivate, parent)
+{
+    connect(this, &QRemoteObjectRegistry::stateChanged, this, &QRemoteObjectRegistry::pushToRegistryIfNeeded);
+}
+
+QRemoteObjectRegistry::QRemoteObjectRegistry(QRemoteObjectNode *node, const QString &name, QObject *parent)
+    : QRemoteObjectReplica(*new QRemoteObjectRegistryPrivate, parent)
+{
+    connect(this, &QRemoteObjectRegistry::stateChanged, this, &QRemoteObjectRegistry::pushToRegistryIfNeeded);
+    initializeNode(node, name);
+}
+
+/*!
+    \fn void QRemoteObjectRegistry::remoteObjectAdded(const QRemoteObjectSourceLocation &entry)
+
+    This signal is emitted whenever a new source location is added to the registry.
+
+    \a entry is a QRemoteObjectSourceLocation, a typedef for QPair<QString, QUrl>.
+
+    \sa remoteObjectRemoved()
+*/
+
+/*!
+    \fn void QRemoteObjectRegistry::remoteObjectRemoved(const QRemoteObjectSourceLocation &entry)
+
+    This signal is emitted whenever a Source location is removed from the Registry.
+
+    \a entry is a QRemoteObjectSourceLocation, a typedef for QPair<QString, QUrl>.
+
+    \sa remoteObjectAdded()
+*/
+
+/*!
+    \property QRemoteObjectRegistry::sourceLocations
+    \brief The set of sources known to the registry.
+
+    This property is a QRemoteObjectSourceLocations, which is a typedef for
+    QHash<QString, QUrl>. Each known \l Source is the QString key, while the
+    url for the host node is the corresponding value for that key in the hash.
+*/
+
+/*!
+    Destructor for QRemoteObjectRegistry.
+*/
+QRemoteObjectRegistry::~QRemoteObjectRegistry()
+{}
+
+void QRemoteObjectRegistry::registerMetatypes()
+{
+    static bool initialized = false;
+    if (initialized)
+        return;
+    initialized = true;
+    qRegisterMetaType<QRemoteObjectSourceLocation>();
+    qRegisterMetaType<QRemoteObjectSourceLocations>();
+}
+
+void QRemoteObjectRegistry::initialize()
+{
+    QRemoteObjectRegistry::registerMetatypes();
+    QVariantList properties;
+    properties.reserve(3);
+    properties << QVariant::fromValue(QRemoteObjectSourceLocations());
+    properties << QVariant::fromValue(QRemoteObjectSourceLocation());
+    properties << QVariant::fromValue(QRemoteObjectSourceLocation());
+    setProperties(std::move(properties));
+}
+
+void QRemoteObjectRegistry::notifySourceLocationsChanged()
+{
+    d_func()->sourceLocations.notify();
+}
+
+/*!
+    Returns a QRemoteObjectSourceLocations object, which includes the name
+    and additional information of all sources known to the registry.
+*/
+QRemoteObjectSourceLocations QRemoteObjectRegistry::sourceLocations() const
+{
+    return d_func()->sourceLocations.value();
+}
+
+QBindable<QRemoteObjectSourceLocations> QRemoteObjectRegistry::bindableSourceLocations() const
+{
+    return &d_func()->sourceLocations;
+}
+
+/*!
+    \internal
+*/
+void QRemoteObjectRegistry::addSource(const QRemoteObjectSourceLocation &entry)
+{
+    Q_D(QRemoteObjectRegistry);
+    if (d->hostedSources.contains(entry.first)) {
+        qCWarning(QT_REMOTEOBJECT) << "Node warning: ignoring source" << entry.first
+                                   << "as this node already has a source by that name.";
+        return;
+    }
+    d->hostedSources.insert(entry.first, entry.second);
+    if (state() != QRemoteObjectReplica::State::Valid)
+        return;
+
+    if (sourceLocations().contains(entry.first)) {
+        qCWarning(QT_REMOTEOBJECT) << "Node warning: ignoring source" << entry.first
+                                   << "as another source (" << sourceLocations().value(entry.first)
+                                   << ") has already registered that name.";
+        return;
+    }
+    qCDebug(QT_REMOTEOBJECT) << "An entry was added to the registry - Sending to source" << entry.first << entry.second;
+    // This does not set any data to avoid a coherency problem between client and server
+    static int index = QRemoteObjectRegistry::staticMetaObject.indexOfMethod("addSource(QRemoteObjectSourceLocation)");
+    QVariantList args;
+    args << QVariant::fromValue(entry);
+    send(QMetaObject::InvokeMetaMethod, index, args);
+}
+
+/*!
+    \internal
+*/
+void QRemoteObjectRegistry::removeSource(const QRemoteObjectSourceLocation &entry)
+{
+    Q_D(QRemoteObjectRegistry);
+    if (!d->hostedSources.contains(entry.first))
+        return;
+
+    d->hostedSources.remove(entry.first);
+    if (state() != QRemoteObjectReplica::State::Valid)
+        return;
+
+    qCDebug(QT_REMOTEOBJECT) << "An entry was removed from the registry - Sending to source" << entry.first << entry.second;
+    // This does not set any data to avoid a coherency problem between client and server
+    static int index = QRemoteObjectRegistry::staticMetaObject.indexOfMethod("removeSource(QRemoteObjectSourceLocation)");
+    QVariantList args;
+    args << QVariant::fromValue(entry);
+    send(QMetaObject::InvokeMetaMethod, index, args);
+}
+
+/*!
+    \internal
+    This internal function supports the edge case where the \l Registry
+    is connected after \l Source objects are added to this \l Node, or
+    the connection to the \l Registry is lost. When connected/reconnected, this
+    function synchronizes local \l Source objects with the \l Registry.
+*/
+void QRemoteObjectRegistry::pushToRegistryIfNeeded()
+{
+    Q_D(QRemoteObjectRegistry);
+    if (state() != QRemoteObjectReplica::State::Valid)
+        return;
+
+    if (d->hostedSources.isEmpty())
+        return;
+
+    const auto &sourceLocs = sourceLocations();
+    for (auto it = d->hostedSources.begin(); it != d->hostedSources.end(); ) {
+        const QString &loc = it.key();
+        const auto sourceLocsIt = sourceLocs.constFind(loc);
+        if (sourceLocsIt != sourceLocs.cend()) {
+            qCWarning(QT_REMOTEOBJECT) << "Node warning: Ignoring Source" << loc << "as another source ("
+                                       << sourceLocsIt.value() << ") has already registered that name.";
+            it = d->hostedSources.erase(it);
+        } else {
+            static const int index = QRemoteObjectRegistry::staticMetaObject.indexOfMethod("addSource(QRemoteObjectSourceLocation)");
+            QVariantList args{QVariant::fromValue(QRemoteObjectSourceLocation(loc, it.value()))};
+            send(QMetaObject::InvokeMetaMethod, index, args);
+            ++it;
+        }
+    }
+}
+
+QT_END_NAMESPACE
diff --git a/src/remoteobjects/qremoteobjectregistry.h b/src/remoteobjects/qremoteobjectregistry.h
new file mode 100644 (file)
index 0000000..82514f4
--- /dev/null
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** 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 QREMOTEOBJECTREGISTRY_P_H
+#define QREMOTEOBJECTREGISTRY_P_H
+
+#include <QtRemoteObjects/qremoteobjectreplica.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRemoteObjectRegistryPrivate;
+class QRemoteObjectNodePrivate;
+
+class Q_REMOTEOBJECTS_EXPORT QRemoteObjectRegistry : public QRemoteObjectReplica
+{
+    Q_OBJECT
+    Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_TYPE, "Registry")
+
+    Q_PROPERTY(QRemoteObjectSourceLocations sourceLocations READ sourceLocations STORED false
+               BINDABLE bindableSourceLocations)
+
+public:
+    ~QRemoteObjectRegistry() override;
+    static void registerMetatypes();
+
+    QRemoteObjectSourceLocations sourceLocations() const;
+    QBindable<QRemoteObjectSourceLocations> bindableSourceLocations() const;
+
+Q_SIGNALS:
+    void remoteObjectAdded(const QRemoteObjectSourceLocation &entry);
+    void remoteObjectRemoved(const QRemoteObjectSourceLocation &entry);
+
+protected Q_SLOTS:
+    void addSource(const QRemoteObjectSourceLocation &entry);
+    void removeSource(const QRemoteObjectSourceLocation &entry);
+    void pushToRegistryIfNeeded();
+
+private:
+    void initialize() override;
+    void notifySourceLocationsChanged();
+
+    explicit QRemoteObjectRegistry(QObject *parent = nullptr);
+    explicit QRemoteObjectRegistry(QRemoteObjectNode *node, const QString &name, QObject *parent = nullptr);
+
+    Q_DECLARE_PRIVATE(QRemoteObjectRegistry)
+    friend class QT_PREPEND_NAMESPACE(QRemoteObjectNode);
+    friend class QT_PREPEND_NAMESPACE(QRemoteObjectNodePrivate);
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/remoteobjects/qremoteobjectregistrysource.cpp b/src/remoteobjects/qremoteobjectregistrysource.cpp
new file mode 100644 (file)
index 0000000..fc57c37
--- /dev/null
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** 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 "qremoteobjectregistrysource_p.h"
+#include <QtCore/qdatastream.h>
+
+QT_BEGIN_NAMESPACE
+
+QRegistrySource::QRegistrySource(QObject *parent)
+    : QObject(parent)
+{
+}
+
+QRegistrySource::~QRegistrySource()
+{
+}
+
+QRemoteObjectSourceLocations QRegistrySource::sourceLocations() const
+{
+    qCDebug(QT_REMOTEOBJECT) << "sourceLocations property requested on RegistrySource" << m_sourceLocations;
+    return m_sourceLocations;
+}
+
+void QRegistrySource::removeServer(const QUrl &url)
+{
+    for (auto it = m_sourceLocations.begin(), end = m_sourceLocations.end(); it != end; /* erasing */) {
+        if (it.value().hostUrl == url)
+            it = m_sourceLocations.erase(it);
+        else
+            ++it;
+    }
+}
+
+void QRegistrySource::addSource(const QRemoteObjectSourceLocation &entry)
+{
+    qCDebug(QT_REMOTEOBJECT) << "An entry was added to the RegistrySource" << entry;
+    if (m_sourceLocations.contains(entry.first)) {
+        if (m_sourceLocations[entry.first].hostUrl == entry.second.hostUrl)
+            qCWarning(QT_REMOTEOBJECT) << "Node warning: Ignoring Source" << entry.first
+                                       << "as this Node already has a Source by that name.";
+        else
+            qCWarning(QT_REMOTEOBJECT) << "Node warning: Ignoring Source" << entry.first
+                                       << "as another source (" << m_sourceLocations[entry.first]
+                                       << ") has already registered that name.";
+        return;
+    }
+    m_sourceLocations[entry.first] = entry.second;
+    emit remoteObjectAdded(entry);
+}
+
+void QRegistrySource::removeSource(const QRemoteObjectSourceLocation &entry)
+{
+    if (m_sourceLocations.contains(entry.first) && m_sourceLocations[entry.first].hostUrl == entry.second.hostUrl) {
+        m_sourceLocations.remove(entry.first);
+        emit remoteObjectRemoved(entry);
+    }
+}
+
+QT_END_NAMESPACE
diff --git a/src/remoteobjects/qremoteobjectregistrysource_p.h b/src/remoteobjects/qremoteobjectregistrysource_p.h
new file mode 100644 (file)
index 0000000..fcf4355
--- /dev/null
@@ -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: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 QREGISTRYSOURCE_P_H
+#define QREGISTRYSOURCE_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 "qtremoteobjectglobal.h"
+
+QT_BEGIN_NAMESPACE
+
+class QRegistrySource : public QObject
+{
+    Q_OBJECT
+    Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_TYPE, "Registry")
+
+    Q_PROPERTY(QRemoteObjectSourceLocations sourceLocations READ sourceLocations)
+
+public:
+    explicit QRegistrySource(QObject *parent = nullptr);
+    ~QRegistrySource() override;
+
+    QRemoteObjectSourceLocations sourceLocations() const;
+
+Q_SIGNALS:
+    void remoteObjectAdded(const QRemoteObjectSourceLocation &entry);
+    void remoteObjectRemoved(const QRemoteObjectSourceLocation &entry);
+
+public Q_SLOTS:
+    void addSource(const QRemoteObjectSourceLocation &entry);
+    void removeSource(const QRemoteObjectSourceLocation &entry);
+    void removeServer(const QUrl &url);
+
+private:
+    QRemoteObjectSourceLocations m_sourceLocations;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/remoteobjects/qremoteobjectreplica.cpp b/src/remoteobjects/qremoteobjectreplica.cpp
new file mode 100644 (file)
index 0000000..6a59385
--- /dev/null
@@ -0,0 +1,976 @@
+/****************************************************************************
+**
+** 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 "qremoteobjectreplica.h"
+#include "qremoteobjectreplica_p.h"
+
+#include "qremoteobjectnode.h"
+#include "qremoteobjectnode_p.h"
+#include "qremoteobjectdynamicreplica.h"
+#include "qremoteobjectpacket_p.h"
+#include "qremoteobjectpendingcall_p.h"
+#include "qconnectionfactories_p.h"
+#include "qremoteobjectsource_p.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdatastream.h>
+#include <QtCore/qelapsedtimer.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qthread.h>
+
+#include <limits>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QRemoteObjectPackets;
+
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_GCC("-Wtautological-compare")
+
+#if !defined(Q_OS_WIN) && !defined(Q_OS_INTEGRITY)
+Q_STATIC_ASSERT_X(&QRemoteObjectReplica::staticMetaObject == &QRemoteObjectDynamicReplica::staticMetaObject,
+                  "m_signalOffset initializer expects QRemoteObjectDynamicReplica to not have a unique staticMetaObject");
+#endif
+
+QT_WARNING_POP
+
+// If QRemoteObjectDynamicReplica ever gets its own staticMetaObject, some commented out code will need to be
+// used.  It was changed to avoid a Coverity complaint.  We use the above static assert to detect if this changes
+// in the future.  See FIX #1, #2, #3 in this file.
+
+QRemoteObjectReplicaImplementation::QRemoteObjectReplicaImplementation(const QString &name, const QMetaObject *meta, QRemoteObjectNode *_node)
+    : QObject(nullptr), m_objectName(name), m_metaObject(meta), m_numSignals(0), m_methodOffset(0)
+    // Uncomment the following two lines if QRemoteObjectDynamicReplica gets a unique staticMetaObject (FIX #1, #2)
+    //, m_signalOffset(meta ? QRemoteObjectReplica::staticMetaObject.methodCount() : QRemoteObjectDynamicReplica::staticMetaObject.methodCount())
+    //, m_propertyOffset(meta ? QRemoteObjectReplica::staticMetaObject.propertyCount() : QRemoteObjectDynamicReplica::staticMetaObject.propertyCount())
+    , m_signalOffset(QRemoteObjectReplica::staticMetaObject.methodCount())
+    , m_propertyOffset(QRemoteObjectReplica::staticMetaObject.propertyCount())
+    , m_node(_node)
+    , m_objectSignature(QtPrivate::qtro_classinfo_signature(m_metaObject))
+    , m_state(meta ? QRemoteObjectReplica::Default : QRemoteObjectReplica::Uninitialized)
+{
+}
+
+QRemoteObjectReplicaImplementation::~QRemoteObjectReplicaImplementation()
+{
+}
+
+QConnectedReplicaImplementation::QConnectedReplicaImplementation(const QString &name, const QMetaObject *meta, QRemoteObjectNode *node)
+    : QRemoteObjectReplicaImplementation(name, meta, node), connectionToSource(nullptr)
+{
+    m_heartbeatTimer.setTimerType(Qt::CoarseTimer);
+    m_heartbeatTimer.setSingleShot(true);
+    m_heartbeatTimer.setInterval(node->heartbeatInterval());
+
+    connect(node, &QRemoteObjectNode::heartbeatIntervalChanged, this, [this](int interval) {
+        m_heartbeatTimer.stop();
+        m_heartbeatTimer.setInterval(interval);
+        if (interval)
+            m_heartbeatTimer.start();
+    });
+    connect(&m_heartbeatTimer, &QTimer::timeout, this, [this] {
+        // TODO: Revisit if a baseclass method can be used to avoid specialized cast
+        // conditional logic.
+
+        if (m_pendingCalls.contains(0)) {
+            m_pendingCalls.take(0);
+            // The source didn't respond in time, disconnect the connection
+            if (connectionToSource) {
+                auto clientIo = qobject_cast<QtROClientIoDevice *>(connectionToSource);
+                if (clientIo)
+                    clientIo->disconnectFromServer();
+                else
+                    connectionToSource->close();
+            }
+        } else {
+            if (connectionToSource.isNull()) {
+                qCDebug(QT_REMOTEOBJECT) << "Ignoring heartbeat as there is no source connected.";
+                return;
+            }
+            connectionToSource->d_func()->m_codec->serializePingPacket(m_objectName);
+            if (sendCommandWithReply(0).d->serialId == -1) {
+                m_heartbeatTimer.stop();
+                auto clientIo = qobject_cast<QtROClientIoDevice *>(connectionToSource);
+                if (clientIo)
+                    clientIo->disconnectFromServer();
+                else
+                    connectionToSource->close();
+            }
+        }
+    });
+
+    if (!meta)
+        return;
+
+    auto offsetMeta = m_metaObject;
+    QtRemoteObjects::getTypeNameAndMetaobjectFromClassInfo(offsetMeta);
+    for (int index = offsetMeta->propertyOffset(); index < offsetMeta->propertyCount(); ++index) {
+        const QMetaProperty property = offsetMeta->property(index);
+        if (property.metaType().flags().testFlag(QMetaType::PointerToQObject))
+            m_childIndices << index - offsetMeta->propertyOffset();
+    }
+}
+
+QConnectedReplicaImplementation::~QConnectedReplicaImplementation()
+{
+    if (!connectionToSource.isNull()) {
+        qCDebug(QT_REMOTEOBJECT) << "Replica deleted: sending RemoveObject to RemoteObjectSource" << m_objectName;
+        connectionToSource->d_func()->m_codec->serializeRemoveObjectPacket(m_objectName);
+        sendCommand();
+    }
+    for (auto prop : m_propertyStorage) {
+        if (prop.canConvert<QObject*>())
+            prop.value<QObject *>()->deleteLater();
+    }
+}
+
+bool QRemoteObjectReplicaImplementation::needsDynamicInitialization() const
+{
+    return m_metaObject == nullptr;
+}
+
+void QRemoteObjectReplicaImplementation::setState(QRemoteObjectReplica::State state)
+{
+    if (m_state.loadAcquire() != QRemoteObjectReplica::Suspect && m_state.loadAcquire() >= state)
+        return;
+
+    int oldState = m_state.loadAcquire();
+    m_state.storeRelease(state);
+
+    // We should emit initialized before emitting any changed signals in case connections are made in a
+    // Slot responding to initialized/validChanged.
+    if (m_state.loadAcquire() == QRemoteObjectReplica::Valid) {
+        // we're initialized now, emit signal
+        emitInitialized();
+    }
+
+    const static int stateChangedIndex = QRemoteObjectReplica::staticMetaObject.indexOfMethod("stateChanged(State,State)");
+    Q_ASSERT(stateChangedIndex != -1);
+    void *args[] = {nullptr, &state, &oldState};
+    QMetaObject::activate(this, metaObject(), stateChangedIndex, args);
+}
+
+void QRemoteObjectReplicaImplementation::emitNotified()
+{
+    const static int notifiedIndex = QRemoteObjectReplica::staticMetaObject.indexOfMethod("notified()");
+    Q_ASSERT(notifiedIndex != -1);
+    void *args[] = {nullptr};
+    QMetaObject::activate(this, metaObject(), notifiedIndex, args);
+}
+
+bool QConnectedReplicaImplementation::sendCommand()
+{
+    Q_ASSERT(connectionToSource);
+    if (!connectionToSource->isOpen())
+        return false;
+
+    connectionToSource->d_func()->m_codec->send(connectionToSource);
+    if (m_heartbeatTimer.interval())
+        m_heartbeatTimer.start();
+    return true;
+}
+
+QList<int> QConnectedReplicaImplementation::childIndices() const
+{
+    return m_childIndices;
+}
+
+void QConnectedReplicaImplementation::initialize(QVariantList &&values)
+{
+    qCDebug(QT_REMOTEOBJECT) << "initialize()" << m_propertyStorage.size();
+    const int nParam = int(values.size());
+    QVarLengthArray<int> changedProperties(nParam);
+    const int offset = m_propertyOffset;
+    for (int i = 0; i < nParam; ++i) {
+        qCDebug(QT_REMOTEOBJECT) << "  in loop" << i << m_propertyStorage.size();
+        changedProperties[i] = -1;
+        if (m_propertyStorage[i] != values.at(i)) {
+            const QMetaProperty property = m_metaObject->property(i+offset);
+            m_propertyStorage[i] = QRemoteObjectPackets::decodeVariant(std::move(values[i]), property.metaType());
+            changedProperties[i] = i;
+        }
+        qCDebug(QT_REMOTEOBJECT) << "SETPROPERTY" << i << m_metaObject->property(i+offset).name()
+                                 << m_propertyStorage[i].typeName()
+                                 << m_propertyStorage[i].toString();
+    }
+
+    Q_ASSERT(m_state.loadAcquire() < QRemoteObjectReplica::Valid || m_state.loadAcquire() == QRemoteObjectReplica::Suspect);
+    setState(QRemoteObjectReplica::Valid);
+
+    void *args[] = {nullptr, nullptr};
+    for (int i = 0; i < nParam; ++i) {
+        if (changedProperties[i] < 0)
+            continue;
+        const int notifyIndex = m_metaObject->property(changedProperties[i]+offset).notifySignalIndex();
+        if (notifyIndex < 0)
+            continue;
+        qCDebug(QT_REMOTEOBJECT) << " Before activate" << notifyIndex << m_metaObject->property(notifyIndex).name();
+        args[1] = m_propertyStorage[i].data();
+        QMetaObject::activate(this, metaObject(), notifyIndex, args);
+    }
+    emitNotified();
+
+    qCDebug(QT_REMOTEOBJECT) << "isSet = true for" << m_objectName;
+    if (node()->heartbeatInterval())
+        m_heartbeatTimer.start();
+}
+
+void QRemoteObjectReplicaImplementation::emitInitialized()
+{
+    const static int initializedIndex = QRemoteObjectReplica::staticMetaObject.indexOfMethod("initialized()");
+    Q_ASSERT(initializedIndex != -1);
+    void *noArgs[] = {nullptr};
+    QMetaObject::activate(this, metaObject(), initializedIndex, noArgs);
+}
+
+/*!
+    \internal
+*/
+void QRemoteObjectReplica::persistProperties(const QString &repName, const QByteArray &repSig, const QVariantList &props) const
+{
+    if (!node()) {
+        qWarning("Tried calling persistProperties on a replica (%s) that hasn't been initialized with a node", qPrintable(repName));
+        return;
+    }
+    node()->persistProperties(repName, repSig, props);
+}
+
+/*!
+    \internal
+*/
+QVariantList QRemoteObjectReplica::retrieveProperties(const QString &repName, const QByteArray &repSig) const
+{
+    if (!node()) {
+        qWarning("Tried calling retrieveProperties on a replica (%s) that hasn't been initialized with a node", qPrintable(repName));
+        return QVariantList();
+    }
+    return node()->retrieveProperties(repName, repSig);
+}
+
+void QRemoteObjectReplicaImplementation::setDynamicMetaObject(const QMetaObject *meta)
+{
+    Q_ASSERT(!m_metaObject);
+
+    m_metaObject = meta;
+}
+
+void QConnectedReplicaImplementation::setDynamicMetaObject(const QMetaObject *meta)
+{
+    QRemoteObjectReplicaImplementation::setDynamicMetaObject(meta);
+
+    for (int index = m_metaObject->propertyOffset(); index < m_metaObject->propertyCount(); ++index) {
+        const QMetaProperty property = m_metaObject->property(index);
+        if (property.metaType().flags().testFlag(QMetaType::PointerToQObject))
+            m_childIndices << index - m_metaObject->propertyOffset();
+    }
+}
+
+void QRemoteObjectReplicaImplementation::setDynamicProperties(QVariantList &&values)
+{
+    const int offset = m_propertyOffset;
+    int propertyIndex = -1;
+    for (auto &prop : values) {
+        propertyIndex++;
+        const QMetaProperty property = m_metaObject->property(propertyIndex+offset);
+        prop = QRemoteObjectPackets::decodeVariant(std::move(prop), property.metaType());
+    }
+    //rely on order of properties;
+    setProperties(std::move(values));
+}
+
+void QConnectedReplicaImplementation::setDynamicProperties(QVariantList &&values)
+{
+    QRemoteObjectReplicaImplementation::setDynamicProperties(std::move(values));
+    for (QRemoteObjectReplica *obj : qExchange(m_parentsNeedingConnect, {}))
+        configurePrivate(obj);
+
+    Q_ASSERT(m_state.loadAcquire() < QRemoteObjectReplica::Valid);
+    setState(QRemoteObjectReplica::Valid);
+
+    void *args[] = {nullptr, nullptr};
+    for (int index = m_metaObject->propertyOffset(); index < m_metaObject->propertyCount(); ++index) {
+        const QMetaProperty mp = m_metaObject->property(index);
+        if (mp.hasNotifySignal()) {
+            qCDebug(QT_REMOTEOBJECT) << " Before activate" << index << m_metaObject->property(index).name();
+            args[1] = this->m_propertyStorage[index-m_propertyOffset].data();
+            QMetaObject::activate(this, metaObject(), mp.notifySignalIndex(), args);
+        }
+    }
+    emitNotified();
+
+    qCDebug(QT_REMOTEOBJECT) << "isSet = true for" << m_objectName;
+}
+
+bool QConnectedReplicaImplementation::isInitialized() const
+{
+    return  m_state.loadAcquire() > QRemoteObjectReplica::Default && m_state.loadAcquire() != QRemoteObjectReplica::SignatureMismatch;
+}
+
+bool QConnectedReplicaImplementation::waitForSource(int timeout)
+{
+    switch (state()) {
+    case QRemoteObjectReplica::State::Valid:
+        return true;
+    case QRemoteObjectReplica::State::SignatureMismatch:
+        return false;
+    default:
+        break;
+    }
+
+    const static int stateChangedIndex = QRemoteObjectReplica::staticMetaObject.indexOfMethod("stateChanged(State,State)");
+    Q_ASSERT(stateChangedIndex != -1);
+
+    QEventLoop loop;
+    QMetaObject::connect(this, stateChangedIndex,
+                         &loop, QEventLoop::staticMetaObject.indexOfMethod("quit()"),
+                         Qt::DirectConnection, nullptr);
+
+    QTimer t; // NB: Related to QTBUG-94570 - don't use QTimer::singleShot here.
+    if (timeout >= 0) {
+        t.setSingleShot(true);
+        connect(&t, &QTimer::timeout, &loop, &QEventLoop::quit);
+        t.start(timeout);
+    }
+
+    // enter the event loop and wait for a reply
+    loop.exec(QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents);
+
+    return state() == QRemoteObjectReplica::State::Valid;
+}
+
+void QConnectedReplicaImplementation::_q_send(QMetaObject::Call call, int index, const QVariantList &args)
+{
+    static const bool debugArgs = qEnvironmentVariableIsSet("QT_REMOTEOBJECT_DEBUG_ARGUMENTS");
+
+    Q_ASSERT(call == QMetaObject::InvokeMetaMethod || call == QMetaObject::WriteProperty);
+    if (connectionToSource.isNull()) {
+        qCWarning(QT_REMOTEOBJECT) << "connectionToSource is null";
+        return;
+    }
+
+    if (call == QMetaObject::InvokeMetaMethod) {
+        if (debugArgs) {
+            qCDebug(QT_REMOTEOBJECT) << "Send" << call << this->m_metaObject->method(index).name() << index << args << connectionToSource;
+        } else {
+            qCDebug(QT_REMOTEOBJECT) << "Send" << call << this->m_metaObject->method(index).name() << index << connectionToSource;
+        }
+        if (index < m_methodOffset) //index - m_methodOffset < 0 is invalid, and can't be resolved on the Source side
+            qCWarning(QT_REMOTEOBJECT) << "Skipping invalid method invocation.  Index not found:" << index << "( offset =" << m_methodOffset << ") object:" << m_objectName << this->m_metaObject->method(index).name();
+        else {
+            connectionToSource->d_func()->m_codec->serializeInvokePacket(m_objectName, call, index - m_methodOffset, args);
+            sendCommand();
+        }
+    } else {
+        qCDebug(QT_REMOTEOBJECT) << "Send" << call << this->m_metaObject->property(index).name() << index << args << connectionToSource;
+        if (index < m_propertyOffset) //index - m_propertyOffset < 0 is invalid, and can't be resolved on the Source side
+            qCWarning(QT_REMOTEOBJECT) << "Skipping invalid property invocation.  Index not found:" << index << "( offset =" << m_propertyOffset << ") object:" << m_objectName << this->m_metaObject->property(index).name();
+        else {
+            connectionToSource->d_func()->m_codec->serializeInvokePacket(m_objectName, call, index - m_propertyOffset, args);
+            sendCommand();
+        }
+    }
+}
+
+QRemoteObjectPendingCall QConnectedReplicaImplementation::_q_sendWithReply(QMetaObject::Call call, int index, const QVariantList &args)
+{
+    Q_ASSERT(call == QMetaObject::InvokeMetaMethod);
+    if (connectionToSource.isNull()) {
+        qCWarning(QT_REMOTEOBJECT) << "connectionToSource is null";
+        return QRemoteObjectPendingCall();
+    }
+
+    qCDebug(QT_REMOTEOBJECT) << "Send" << call << this->m_metaObject->method(index).name() << index << args << connectionToSource;
+    int serialId = (m_curSerialId == std::numeric_limits<int>::max() ? 1 : m_curSerialId++);
+    connectionToSource->d_func()->m_codec->serializeInvokePacket(m_objectName, call, index - m_methodOffset, args, serialId);
+    return sendCommandWithReply(serialId);
+}
+
+QRemoteObjectPendingCall QConnectedReplicaImplementation::sendCommandWithReply(int serialId)
+{
+    bool success = sendCommand();
+    if (!success) {
+        return QRemoteObjectPendingCall(); // invalid
+    }
+
+    qCDebug(QT_REMOTEOBJECT) << "Sent InvokePacket with serial id:" << serialId;
+    QRemoteObjectPendingCall pendingCall(new QRemoteObjectPendingCallData(serialId, this));
+    Q_ASSERT(!m_pendingCalls.contains(serialId));
+    m_pendingCalls[serialId] = pendingCall;
+    return pendingCall;
+}
+
+void QConnectedReplicaImplementation::notifyAboutReply(int ackedSerialId, const QVariant &value)
+{
+    QRemoteObjectPendingCall call = m_pendingCalls.take(ackedSerialId);
+    if (ackedSerialId == 0) {
+        m_heartbeatTimer.stop();
+        if (m_heartbeatTimer.interval())
+            m_heartbeatTimer.start();
+        return;
+    }
+
+    QMutexLocker mutex(&call.d->mutex);
+
+    // clear error flag
+    call.d->error = QRemoteObjectPendingCall::NoError;
+    call.d->returnValue = value;
+
+    // notify watchers if needed
+    if (call.d->watcherHelper)
+        call.d->watcherHelper->emitSignals();
+}
+
+bool QConnectedReplicaImplementation::waitForFinished(const QRemoteObjectPendingCall& call, int timeout)
+{
+    if (!call.d->watcherHelper)
+        call.d->watcherHelper.reset(new QRemoteObjectPendingCallWatcherHelper);
+
+    call.d->mutex.unlock();
+
+    QEventLoop loop;
+    loop.connect(call.d->watcherHelper.data(), &QRemoteObjectPendingCallWatcherHelper::finished,
+                 &loop, &QEventLoop::quit);
+
+    QTimer t; // NB: Related to QTBUG-94570 - don't use QTimer::singleShot here.
+    if (timeout >= 0) {
+        t.setSingleShot(true);
+        connect(&t, &QTimer::timeout, &loop, &QEventLoop::quit);
+        t.start(timeout);
+    }
+
+    // enter the event loop and wait for a reply
+    loop.exec(QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents);
+
+    call.d->mutex.lock();
+
+    return call.d->error != QRemoteObjectPendingCall::InvalidMessage;
+}
+
+const QVariant QConnectedReplicaImplementation::getProperty(int i) const
+{
+    Q_ASSERT_X(i >= 0 && i < m_propertyStorage.size(), __FUNCTION__, qPrintable(QString(QLatin1String("0 <= %1 < %2")).arg(i).arg(m_propertyStorage.size())));
+    return m_propertyStorage[i];
+}
+
+void QConnectedReplicaImplementation::setProperties(QVariantList &&properties)
+{
+    Q_ASSERT(m_propertyStorage.isEmpty());
+    m_propertyStorage.reserve(properties.length());
+    m_propertyStorage = std::move(properties);
+}
+
+void QConnectedReplicaImplementation::setProperty(int i, const QVariant &prop)
+{
+    m_propertyStorage[i] = prop;
+}
+
+void QConnectedReplicaImplementation::setConnection(QtROIoDeviceBase *conn)
+{
+    if (connectionToSource.isNull()) {
+        connectionToSource = conn;
+        qCDebug(QT_REMOTEOBJECT) << "setConnection started" << conn << m_objectName;
+    }
+    requestRemoteObjectSource();
+}
+
+void QConnectedReplicaImplementation::setDisconnected()
+{
+    Q_ASSERT(connectionToSource);
+    connectionToSource.clear();
+    setState(QRemoteObjectReplica::State::Suspect);
+    for (const int index : childIndices()) {
+        auto pointerToQObject = qvariant_cast<QObject *>(getProperty(index));
+        auto child = qobject_cast<QRemoteObjectReplica *>(pointerToQObject);
+        if (child)
+            static_cast<QConnectedReplicaImplementation *>(child->d_impl.data())->setDisconnected();
+    }
+}
+
+void QConnectedReplicaImplementation::requestRemoteObjectSource()
+{
+    Q_ASSERT(connectionToSource);
+    connectionToSource->d_func()->m_codec->serializeAddObjectPacket(m_objectName, needsDynamicInitialization());
+    sendCommand();
+}
+
+void QRemoteObjectReplicaImplementation::configurePrivate(QRemoteObjectReplica *rep)
+{
+    qCDebug(QT_REMOTEOBJECT) << "configurePrivate starting for" << this->m_objectName;
+    //We need to connect the Replicant only signals too
+    // Uncomment the following two lines if QRemoteObjectDynamicReplica gets a unique staticMetaObject (FIX #3)
+    //const QMetaObject *m =  rep->inherits("QRemoteObjectDynamicReplica") ?
+    //            &QRemoteObjectDynamicReplica::staticMetaObject : &QRemoteObjectReplica::staticMetaObject;
+    const QMetaObject *m = &QRemoteObjectReplica::staticMetaObject;
+    for (int i = m->methodOffset(); i < m->methodCount(); ++i)
+    {
+        const QMetaMethod mm = m->method(i);
+        if (mm.methodType() == QMetaMethod::Signal) {
+            const bool res = QMetaObject::connect(this, i, rep, i, Qt::DirectConnection, nullptr);
+            qCDebug(QT_REMOTEOBJECT) << "  Rep connect"<<i<<res<<mm.name();
+            Q_UNUSED(res)
+        }
+    }
+    if (m_methodOffset == 0) //We haven't initialized the offsets yet
+    {
+        const int index = m_metaObject->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE);
+        const QMetaObject *metaObject = m_metaObject;
+        if (index != -1) { //We have an object created from repc or at least with QCLASSINFO defined
+            while (true) {
+                Q_ASSERT(metaObject->superClass()); //This recurses to QObject, which doesn't have QCLASSINFO_REMOTEOBJECT_TYPE
+                if (index != metaObject->superClass()->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE)) //At the point we don't find the same QCLASSINFO_REMOTEOBJECT_TYPE,
+                                //we have the metaobject we should work from
+                    break;
+                metaObject = metaObject->superClass();
+            }
+        }
+
+        for (int i = m_signalOffset; i < metaObject->methodCount(); ++i) {
+            const QMetaMethod mm = metaObject->method(i);
+            if (mm.methodType() == QMetaMethod::Signal) {
+                ++m_numSignals;
+                const bool res = QMetaObject::connect(this, i, rep, i, Qt::DirectConnection, nullptr);
+                qCDebug(QT_REMOTEOBJECT) << "  Connect"<<i<<res<<mm.name();
+                Q_UNUSED(res)
+            }
+        }
+        m_methodOffset = m_signalOffset + m_numSignals;
+        qCDebug(QT_REMOTEOBJECT) << QStringLiteral("configurePrivate finished, signalOffset = %1, methodOffset = %2, #Signals = %3").arg(m_signalOffset).arg(m_methodOffset).arg(m_numSignals);
+    } else { //We have initialized offsets, this is an additional Replica attaching
+        for (int i = m_signalOffset; i < m_methodOffset; ++i) {
+            const bool res = QMetaObject::connect(this, i, rep, i, Qt::DirectConnection, nullptr);
+            qCDebug(QT_REMOTEOBJECT) << "  Connect"<<i<<res<<m_metaObject->method(i).name();
+            Q_UNUSED(res)
+        }
+        if (isInitialized()) {
+            qCDebug(QT_REMOTEOBJECT) << QStringLiteral("ReplicaImplementation initialized, emitting signal on replica");
+            emit rep->initialized(); //Emit from new replica only
+        }
+        if (state() != QRemoteObjectReplica::Valid) {
+            qCDebug(QT_REMOTEOBJECT) << QStringLiteral("ReplicaImplementation not currently valid, emitting signal on replica");
+            emit rep->stateChanged(state(), m_metaObject ? QRemoteObjectReplica::Default : QRemoteObjectReplica::Uninitialized);
+        }
+
+        qCDebug(QT_REMOTEOBJECT) << QStringLiteral("configurePrivate finished, added replica to existing ReplicaImplementation");
+    }
+}
+
+void QConnectedReplicaImplementation::configurePrivate(QRemoteObjectReplica *rep)
+{
+    if (m_metaObject) {
+        // see QRemoteObjectReplicaImplementation::configurePrivate
+        const bool firstReplicaInstance = (m_methodOffset == 0);
+
+        QRemoteObjectReplicaImplementation::configurePrivate(rep);
+
+        // ensure that notify signals are emitted for the new replica, when
+        // we are initializing an nth replica of the same type
+        if (!firstReplicaInstance) {
+            const int offset = m_propertyOffset;
+            const int nParam = int(m_propertyStorage.count());
+            void *args[] = {nullptr, nullptr};
+            for (int i = 0; i < nParam; ++i) {
+                const int notifyIndex = m_metaObject->property(i+offset).notifySignalIndex();
+                if (notifyIndex < 0)
+                    continue;
+                qCDebug(QT_REMOTEOBJECT) << " Before activate" << notifyIndex << m_metaObject->property(i+offset).name();
+                args[1] = m_propertyStorage[i].data();
+                // NOTE: this over-emits (assumes all values have changed)
+                QMetaObject::activate(rep, rep->metaObject(), notifyIndex - m_signalOffset, args);
+            }
+        }
+    } else
+        m_parentsNeedingConnect.append(rep);
+}
+
+/*!
+    \class QRemoteObjectReplica
+    \inmodule QtRemoteObjects
+    \brief A class interacting with (but not implementing) a Qt API on the Remote Object network.
+
+    A Remote Object Replica is a QObject proxy for another QObject (called the
+    \l {Source} object). Once initialized, a replica can be considered a
+    "latent copy" of the \l {Source} object. That is, every change to a
+    Q_PROPERTY on the \l {Source}, or signal emitted by the \l {Source} will be
+    updated/emitted by all \l {Replica} objects. Latency
+    is introduced by process scheduling by any OSes involved and network
+    communication latency. As long as the replica has been initialized and the
+    communication is not disrupted, receipt and order of changes is guaranteed.
+
+    The \l {isInitialized} and \l {state} properties (and corresponding
+    \l {initialized()}/\l {stateChanged()} signals) allow the state of a
+    \l {Replica} to be determined.
+
+    While Qt Remote Objects (QtRO) handles the initialization and
+    synchronization of \l {Replica} objects, there are numerous steps happening
+    behind the scenes which can fail and that aren't encountered in single
+    process Qt applications. See \l {Troubleshooting} for advice on how to
+    handle such issues when using a remote objects network.
+*/
+
+/*!
+    \enum QRemoteObjectReplica::State
+
+    This enum type specifies the various state codes associated with QRemoteObjectReplica states:
+
+    \value Uninitialized Initial value of DynamicReplica, where nothing is
+    known about the replica before connection to source.
+
+    \value Default Initial value of static replica, where any defaults set in
+    the .rep file are available so it can be used if necessary.
+
+    \value Valid Indicates the replica is connected, has good property values
+    and can be interacted with.
+
+    \value Suspect Error state that occurs if the connection to the source is
+    lost after it is initialized.
+
+    \value SignatureMismatch Error state that occurs if a connection to the
+    source is made, but the source and replica are not derived from the same
+    .rep (only possible for static Replicas).
+*/
+
+/*!
+    \fn void QRemoteObjectReplica::stateChanged(State state, State oldState)
+
+    This signal is emitted whenever a replica's state toggles between
+    \l QRemoteObjectReplica::State.
+
+    The change in state is represented with \a state and \a oldState.
+
+    \sa state(), initialized()
+*/
+
+/*!
+    \fn void QRemoteObjectReplica::initialized()
+
+    This signal is emitted once the replica is initialized. An intialized replica
+    has all property values set, but has not yet emitted any property change
+    notifications.
+
+    \sa isInitialized(), stateChanged()
+*/
+
+/*!
+    \fn void QRemoteObjectReplica::notified()
+
+    This signal is emitted once the replica is initialized and all property change
+    notifications have been emitted.
+
+    It is sometimes useful to respond to property changes as events.
+    For example, you might want to display a user notification when a certain
+    property change occurs. However, this user notification would then also be
+    triggered when a replica first became \c QRemoteObjectReplica::Valid, as
+    all property change signals are emitted at that time. This isn't always desirable,
+    and \c notified allows the developer to distinguish between these two cases.
+*/
+
+/*!
+    \internal
+    \enum QRemoteObjectReplica::ConstructorType
+*/
+
+/*!
+    \property QRemoteObjectReplica::state
+    \brief Returns the replica state.
+
+    This property holds the replica \l QRemoteObjectReplica::State.
+*/
+
+/*!
+    \property QRemoteObjectReplica::node
+    \brief A pointer to the node this object was acquired from.
+*/
+
+/*!
+    \internal This (protected) constructor for QRemoteObjectReplica can be used to create
+    replica objects from QML.
+*/
+QRemoteObjectReplica::QRemoteObjectReplica(ConstructorType t)
+    : QObject(nullptr)
+    , d_impl(t == DefaultConstructor ? new QStubReplicaImplementation : nullptr)
+{
+    qRegisterMetaType<State>("State");
+}
+
+QRemoteObjectReplica::QRemoteObjectReplica(QObjectPrivate &dptr, QObject *parent)
+    : QObject(dptr, parent)
+    , d_impl(new QStubReplicaImplementation)
+{
+}
+
+/*!
+    \internal
+*/
+QRemoteObjectReplica::~QRemoteObjectReplica()
+{
+}
+
+/*!
+    \internal
+*/
+void QRemoteObjectReplica::send(QMetaObject::Call call, int index, const QVariantList &args)
+{
+    Q_ASSERT(index != -1);
+
+    d_impl->_q_send(call, index, args);
+}
+
+/*!
+    \internal
+*/
+QRemoteObjectPendingCall QRemoteObjectReplica::sendWithReply(QMetaObject::Call call, int index, const QVariantList &args)
+{
+    return d_impl->_q_sendWithReply(call, index, args);
+}
+
+/*!
+    \internal
+*/
+const QVariant QRemoteObjectReplica::propAsVariant(int i) const
+{
+    return d_impl->getProperty(i);
+}
+
+/*!
+    \internal
+*/
+void QRemoteObjectReplica::initializeNode(QRemoteObjectNode *node, const QString &name)
+{
+    node->initializeReplica(this, name);
+}
+
+/*!
+    \internal
+*/
+void QRemoteObjectReplica::setProperties(QVariantList &&properties)
+{
+    d_impl->setProperties(std::move(properties));
+}
+
+/*!
+    \internal
+*/
+void QRemoteObjectReplica::setChild(int i, const QVariant &value)
+{
+    d_impl->setProperty(i, value);
+}
+
+/*!
+    Returns \c true if this replica has been initialized with data from the
+    \l {Source} object.  Returns \c false otherwise.
+
+    \sa state()
+*/
+bool QRemoteObjectReplica::isInitialized() const
+{
+    return d_impl->isInitialized();
+}
+
+/*!
+    Returns \c true if this replica has been initialized with data from the
+    \l {Source} object.  Returns \c false otherwise.
+
+    \sa isInitialized()
+*/
+QRemoteObjectReplica::State QRemoteObjectReplica::state() const
+{
+    return d_impl->state();
+}
+
+QRemoteObjectNode *QRemoteObjectReplica::node() const
+{
+    return d_impl->node();
+}
+
+void QRemoteObjectReplica::setNode(QRemoteObjectNode *_node)
+{
+    const QRemoteObjectNode *curNode = node();
+    if (curNode) {
+        qCWarning(QT_REMOTEOBJECT) << "Ignoring call to setNode as the node has already been set";
+        return;
+    }
+    d_impl.clear();
+    _node->initializeReplica(this);
+}
+
+/*!
+    \internal
+*/
+void QRemoteObjectReplica::initialize()
+{
+}
+
+/*!
+    Returns \c true if this replica has been initialized and has a valid
+    connection with the \l {QRemoteObjectNode} {node} hosting the \l {Source}.
+    Returns \c false otherwise.
+
+    \sa isInitialized()
+*/
+bool QRemoteObjectReplica::isReplicaValid() const
+{
+    return state() == Valid;
+}
+
+/*!
+    Blocking call that waits for the replica to become initialized or until the
+    \a timeout (in ms) expires. Returns \c true if the replica is initialized
+    when the call completes, \c false otherwise.
+
+    If \a timeout is -1, this function will not time out.
+
+    \sa isInitialized(), initialized()
+*/
+bool QRemoteObjectReplica::waitForSource(int timeout)
+{
+    return d_impl->waitForSource(timeout);
+}
+
+QInProcessReplicaImplementation::QInProcessReplicaImplementation(const QString &name, const QMetaObject *meta, QRemoteObjectNode * node)
+    : QRemoteObjectReplicaImplementation(name, meta, node)
+{
+}
+
+QInProcessReplicaImplementation::~QInProcessReplicaImplementation()
+{
+}
+
+const QVariant QInProcessReplicaImplementation::getProperty(int i) const
+{
+    Q_ASSERT(connectionToSource);
+    Q_ASSERT(connectionToSource->m_object);
+    const int index = i + QRemoteObjectSource::qobjectPropertyOffset;
+    Q_ASSERT(index >= 0 && index < connectionToSource->m_object->metaObject()->propertyCount());
+    return connectionToSource->m_object->metaObject()->property(index).read(connectionToSource->m_object);
+}
+
+void QInProcessReplicaImplementation::setProperties(QVariantList &&)
+{
+    //TODO some verification here maybe?
+}
+
+void QInProcessReplicaImplementation::setProperty(int i, const QVariant &property)
+{
+    Q_ASSERT(connectionToSource);
+    Q_ASSERT(connectionToSource->m_object);
+    const int index = i + QRemoteObjectSource::qobjectPropertyOffset;
+    Q_ASSERT(index >= 0 && index < connectionToSource->m_object->metaObject()->propertyCount());
+    connectionToSource->m_object->metaObject()->property(index).write(connectionToSource->m_object, property);
+}
+
+void QInProcessReplicaImplementation::_q_send(QMetaObject::Call call, int index, const QVariantList &args)
+{
+    Q_ASSERT(call == QMetaObject::InvokeMetaMethod || call == QMetaObject::WriteProperty);
+
+    const SourceApiMap *api = connectionToSource->m_api;
+    if (call == QMetaObject::InvokeMetaMethod) {
+        const int resolvedIndex = api->sourceMethodIndex(index - m_methodOffset);
+        if (resolvedIndex < 0)
+            qCWarning(QT_REMOTEOBJECT) << "Skipping invalid invocation.  Index not found:" << index - m_methodOffset;
+        else
+            connectionToSource->invoke(call, index - m_methodOffset, args);
+    } else {
+        const int resolvedIndex = connectionToSource->m_api->sourcePropertyIndex(index - m_propertyOffset);
+        if (resolvedIndex < 0)
+            qCWarning(QT_REMOTEOBJECT) << "Skipping invalid property setter.  Index not found:" << index - m_propertyOffset;
+        else
+            connectionToSource->invoke(call, index - m_propertyOffset, args);
+    }
+}
+
+QRemoteObjectPendingCall QInProcessReplicaImplementation::_q_sendWithReply(QMetaObject::Call call, int index, const QVariantList &args)
+{
+    Q_ASSERT(call == QMetaObject::InvokeMetaMethod);
+
+    const int ReplicaIndex = index - m_methodOffset;
+    auto metaType = QMetaType::fromName(connectionToSource->m_api->typeName(ReplicaIndex).constData());
+    if (!metaType.sizeOf())
+        metaType = QMetaType(QMetaType::UnknownType);
+    QVariant returnValue(metaType, nullptr);
+
+    const int resolvedIndex = connectionToSource->m_api->sourceMethodIndex(ReplicaIndex);
+    if (resolvedIndex < 0) {
+        qCWarning(QT_REMOTEOBJECT) << "Skipping invalid invocation.  Index not found:" << ReplicaIndex;
+        return QRemoteObjectPendingCall();
+    }
+
+    connectionToSource->invoke(call, ReplicaIndex, args, &returnValue);
+    return QRemoteObjectPendingCall::fromCompletedCall(returnValue);
+}
+
+QStubReplicaImplementation::QStubReplicaImplementation() {}
+
+QStubReplicaImplementation::~QStubReplicaImplementation() {}
+
+const QVariant QStubReplicaImplementation::getProperty(int i) const
+{
+    Q_ASSERT_X(i >= 0 && i < m_propertyStorage.size(), __FUNCTION__, qPrintable(QString(QLatin1String("0 <= %1 < %2")).arg(i).arg(m_propertyStorage.size())));
+    return m_propertyStorage[i];
+}
+
+void QStubReplicaImplementation::setProperties(QVariantList &&properties)
+{
+    Q_ASSERT(m_propertyStorage.isEmpty());
+    m_propertyStorage.reserve(properties.length());
+    m_propertyStorage = std::move(properties);
+}
+
+void QStubReplicaImplementation::setProperty(int i, const QVariant &prop)
+{
+    m_propertyStorage[i] = prop;
+}
+
+void QStubReplicaImplementation::_q_send(QMetaObject::Call call, int index, const QVariantList &args)
+{
+    Q_UNUSED(call)
+    Q_UNUSED(index)
+    Q_UNUSED(args)
+    qWarning("Tried calling a slot or setting a property on a replica that hasn't been initialized with a node");
+}
+
+QRemoteObjectPendingCall QStubReplicaImplementation::_q_sendWithReply(QMetaObject::Call call, int index, const QVariantList &args)
+{
+    Q_UNUSED(call)
+    Q_UNUSED(index)
+    Q_UNUSED(args)
+    qWarning("Tried calling a slot or setting a property on a replica that hasn't been initialized with a node");
+    return QRemoteObjectPendingCall(); //Invalid
+}
+
+QT_END_NAMESPACE
diff --git a/src/remoteobjects/qremoteobjectreplica.h b/src/remoteobjects/qremoteobjectreplica.h
new file mode 100644 (file)
index 0000000..c77149b
--- /dev/null
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** 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 QQREMOTEOBJECTREPLICA_H
+#define QQREMOTEOBJECTREPLICA_H
+
+#include <QtRemoteObjects/qtremoteobjectglobal.h>
+
+#include <QtCore/qsharedpointer.h>
+
+Q_MOC_INCLUDE(<QtRemoteObjects/qremoteobjectnode.h>)
+
+QT_BEGIN_NAMESPACE
+
+class QObjectPrivate;
+class QRemoteObjectPendingCall;
+class QRemoteObjectReplicaImplementation;
+class QReplicaImplementationInterface;
+class QRemoteObjectNode;
+
+class Q_REMOTEOBJECTS_EXPORT QRemoteObjectReplica : public QObject
+{
+    Q_OBJECT
+    Q_PROPERTY(QRemoteObjectNode *node READ node WRITE setNode)
+    Q_PROPERTY(State state READ state NOTIFY stateChanged)
+public:
+    enum State {
+        Uninitialized,
+        Default,
+        Valid,
+        Suspect,
+        SignatureMismatch
+    };
+    Q_ENUM(State)
+
+public:
+    ~QRemoteObjectReplica() override;
+
+    bool isReplicaValid() const;
+    bool waitForSource(int timeout = 30000);
+    bool isInitialized() const;
+    State state() const;
+    QRemoteObjectNode *node() const;
+    virtual void setNode(QRemoteObjectNode *node);
+
+Q_SIGNALS:
+    void initialized();
+    void notified();
+    void stateChanged(State state, State oldState);
+
+protected:
+    enum ConstructorType {DefaultConstructor, ConstructWithNode};
+    explicit QRemoteObjectReplica(ConstructorType t = DefaultConstructor);
+    QRemoteObjectReplica(QObjectPrivate &dptr, QObject *parent);
+
+    virtual void initialize();
+    void send(QMetaObject::Call call, int index, const QVariantList &args);
+    QRemoteObjectPendingCall sendWithReply(QMetaObject::Call call, int index, const QVariantList &args);
+
+protected:
+    void setProperties(QVariantList &&);
+    void setChild(int i, const QVariant &);
+    const QVariant propAsVariant(int i) const;
+    void persistProperties(const QString &repName, const QByteArray &repSig, const QVariantList &props) const;
+    QVariantList retrieveProperties(const QString &repName, const QByteArray &repSig) const;
+    void initializeNode(QRemoteObjectNode *node, const QString &name = QString());
+    QSharedPointer<QReplicaImplementationInterface> d_impl;
+private:
+    friend class QRemoteObjectNodePrivate;
+    friend class QConnectedReplicaImplementation;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/remoteobjects/qremoteobjectreplica_p.h b/src/remoteobjects/qremoteobjectreplica_p.h
new file mode 100644 (file)
index 0000000..9234ae5
--- /dev/null
@@ -0,0 +1,206 @@
+/****************************************************************************
+**
+** 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 QREMOTEOBJECTREPLICA_P_H
+#define QREMOTEOBJECTREPLICA_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 "qremoteobjectreplica.h"
+
+#include "qremoteobjectpendingcall.h"
+
+#include "qremoteobjectpacket_p.h"
+
+#include <QtCore/qcompilerdetection.h>
+#include <QtCore/qdatastream.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/qtimer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRemoteObjectReplica;
+class QRemoteObjectSource;
+class QtROIoDeviceBase;
+
+class QReplicaImplementationInterface
+{
+public:
+    virtual ~QReplicaImplementationInterface() {}
+    virtual const QVariant getProperty(int i) const = 0;
+    virtual void setProperties(QVariantList &&) = 0;
+    virtual void setProperty(int i, const QVariant &) = 0;
+    virtual bool isInitialized() const = 0;
+    virtual QRemoteObjectReplica::State state() const = 0;
+    virtual bool waitForSource(int) = 0;
+    virtual QRemoteObjectNode *node() const = 0;
+
+    virtual void _q_send(QMetaObject::Call call, int index, const QVariantList &args) = 0;
+    virtual QRemoteObjectPendingCall _q_sendWithReply(QMetaObject::Call call, int index, const QVariantList &args) = 0;
+};
+
+class QStubReplicaImplementation final : public QReplicaImplementationInterface
+{
+public:
+    explicit QStubReplicaImplementation();
+    ~QStubReplicaImplementation() override;
+
+    const QVariant getProperty(int i) const override;
+    void setProperties(QVariantList &&) override;
+    void setProperty(int i, const QVariant &) override;
+    bool isInitialized() const override { return false; }
+    QRemoteObjectReplica::State state() const override { return QRemoteObjectReplica::State::Uninitialized;}
+    bool waitForSource(int) override { return false; }
+    QRemoteObjectNode *node() const override { return nullptr; }
+
+    void _q_send(QMetaObject::Call call, int index, const QVariantList &args) override;
+    QRemoteObjectPendingCall _q_sendWithReply(QMetaObject::Call call, int index, const QVariantList &args) override;
+    QVariantList m_propertyStorage;
+};
+
+class QRemoteObjectReplicaImplementation : public QObject, public QReplicaImplementationInterface
+{
+public:
+    explicit QRemoteObjectReplicaImplementation(const QString &name, const QMetaObject *, QRemoteObjectNode *);
+    ~QRemoteObjectReplicaImplementation() override;
+
+    bool needsDynamicInitialization() const;
+
+    const QVariant getProperty(int i) const override = 0;
+    void setProperties(QVariantList &&) override = 0;
+    void setProperty(int i, const QVariant &) override = 0;
+    virtual bool isShortCircuit() const = 0;
+    bool isInitialized() const override { return true; }
+    QRemoteObjectReplica::State state() const override { return QRemoteObjectReplica::State(m_state.loadRelaxed()); }
+    void setState(QRemoteObjectReplica::State state);
+    bool waitForSource(int) override { return true; }
+    virtual bool waitForFinished(const QRemoteObjectPendingCall &, int) { return true; }
+    virtual void notifyAboutReply(int, const QVariant &) {}
+    virtual void configurePrivate(QRemoteObjectReplica *);
+    void emitInitialized();
+    void emitNotified();
+    QRemoteObjectNode *node() const override { return m_node; }
+
+    void _q_send(QMetaObject::Call call, int index, const QVariantList &args) override = 0;
+    QRemoteObjectPendingCall _q_sendWithReply(QMetaObject::Call call, int index, const QVariantList &args) override = 0;
+
+    //Dynamic replica functions
+    virtual void setDynamicMetaObject(const QMetaObject *meta);
+    virtual void setDynamicProperties(QVariantList &&values);
+
+    QString m_objectName;
+    const QMetaObject *m_metaObject;
+
+    //Dynamic Replica data
+    int m_numSignals;//TODO maybe here too
+    int m_methodOffset;
+    int m_signalOffset;
+    int m_propertyOffset;
+    QRemoteObjectNode *m_node;
+    QByteArray m_objectSignature;
+    QAtomicInt m_state;
+};
+
+class QConnectedReplicaImplementation final : public QRemoteObjectReplicaImplementation
+{
+public:
+    explicit QConnectedReplicaImplementation(const QString &name, const QMetaObject *, QRemoteObjectNode *);
+    ~QConnectedReplicaImplementation() override;
+    const QVariant getProperty(int i) const override;
+    void setProperties(QVariantList &&) override;
+    void setProperty(int i, const QVariant &) override;
+    bool isShortCircuit() const final { return false; }
+    bool isInitialized() const override;
+    bool waitForSource(int timeout) override;
+    QList<int> childIndices() const;
+    void initialize(QVariantList &&values);
+    void configurePrivate(QRemoteObjectReplica *) override;
+    void requestRemoteObjectSource();
+    bool sendCommand();
+    QRemoteObjectPendingCall sendCommandWithReply(int serialId);
+    bool waitForFinished(const QRemoteObjectPendingCall &call, int timeout) override;
+    void notifyAboutReply(int ackedSerialId, const QVariant &value) override;
+    void setConnection(QtROIoDeviceBase *conn);
+    void setDisconnected();
+
+    void _q_send(QMetaObject::Call call, int index, const QVariantList &args) override;
+    QRemoteObjectPendingCall _q_sendWithReply(QMetaObject::Call call, int index, const QVariantList& args) override;
+
+    void setDynamicMetaObject(const QMetaObject *meta) override;
+    void setDynamicProperties(QVariantList &&) override;
+    QList<QRemoteObjectReplica *> m_parentsNeedingConnect;
+    QVariantList m_propertyStorage;
+    QList<int> m_childIndices;
+    QPointer<QtROIoDeviceBase> connectionToSource;
+
+    // pending call data
+    int m_curSerialId = 1; // 0 is reserved for heartbeat signals
+    QHash<int, QRemoteObjectPendingCall> m_pendingCalls;
+    QTimer m_heartbeatTimer;
+};
+
+class QInProcessReplicaImplementation final : public QRemoteObjectReplicaImplementation
+{
+public:
+    explicit QInProcessReplicaImplementation(const QString &name, const QMetaObject *, QRemoteObjectNode *);
+    ~QInProcessReplicaImplementation() override;
+
+    const QVariant getProperty(int i) const override;
+    void setProperties(QVariantList &&) override;
+    void setProperty(int i, const QVariant &) override;
+    bool isShortCircuit() const final { return true; }
+
+    void _q_send(QMetaObject::Call call, int index, const QVariantList &args) override;
+    QRemoteObjectPendingCall _q_sendWithReply(QMetaObject::Call call, int index, const QVariantList& args) override;
+
+    QPointer<QRemoteObjectSourceBase> connectionToSource;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/remoteobjects/qremoteobjectsettingsstore.cpp b/src/remoteobjects/qremoteobjectsettingsstore.cpp
new file mode 100644 (file)
index 0000000..2c4c66d
--- /dev/null
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** 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 "qremoteobjectsettingsstore.h"
+
+#include "qremoteobjectnode_p.h"
+
+#include <QtCore/private/qobject_p.h>
+#include <QtCore/qsettings.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+    \qmltype SettingsStore
+    \inqmlmodule QtRemoteObjects
+    \brief A basic store for persisted properties.
+
+    This type provides simple QSettings-based storage for properties marked as PERSISTED. It is used in
+    conjunction with Node::persistedStore:
+
+    \code
+    Node {
+        persistedStore: SettingsStore {}
+    }
+    \endcode
+*/
+
+class QRemoteObjectSettingsStorePrivate : public QRemoteObjectAbstractPersistedStorePrivate
+{
+public:
+    QRemoteObjectSettingsStorePrivate();
+    virtual ~QRemoteObjectSettingsStorePrivate();
+
+    QSettings settings;
+    Q_DECLARE_PUBLIC(QRemoteObjectSettingsStore)
+};
+
+QRemoteObjectSettingsStorePrivate::QRemoteObjectSettingsStorePrivate()
+{
+}
+
+QRemoteObjectSettingsStorePrivate::~QRemoteObjectSettingsStorePrivate()
+{
+}
+
+QRemoteObjectSettingsStore::QRemoteObjectSettingsStore(QObject *parent)
+    : QRemoteObjectAbstractPersistedStore(*new QRemoteObjectSettingsStorePrivate, parent)
+{
+}
+
+QRemoteObjectSettingsStore::~QRemoteObjectSettingsStore()
+{
+}
+
+QVariantList QRemoteObjectSettingsStore::restoreProperties(const QString &repName, const QByteArray &repSig)
+{
+    Q_D(QRemoteObjectSettingsStore);
+    d->settings.beginGroup(repName + QLatin1Char('/') + QString::fromLatin1(repSig));
+    QVariantList values = d->settings.value(QStringLiteral("values")).toList();
+    d->settings.endGroup();
+    return values;
+}
+
+void QRemoteObjectSettingsStore::saveProperties(const QString &repName, const QByteArray &repSig, const QVariantList &values)
+{
+    Q_D(QRemoteObjectSettingsStore);
+    d->settings.beginGroup(repName + QLatin1Char('/') + QString::fromLatin1(repSig));
+    d->settings.setValue(QStringLiteral("values"), values);
+    d->settings.endGroup();
+    d->settings.sync();
+}
+
+QT_END_NAMESPACE
diff --git a/src/remoteobjects/qremoteobjectsettingsstore.h b/src/remoteobjects/qremoteobjectsettingsstore.h
new file mode 100644 (file)
index 0000000..53f2ace
--- /dev/null
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** 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 QREMOTEOBJECTSETTINGSSTORE_H
+#define QREMOTEOBJECTSETTINGSSTORE_H
+
+#include <QtRemoteObjects/qremoteobjectnode.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRemoteObjectSettingsStorePrivate;
+
+class Q_REMOTEOBJECTS_EXPORT QRemoteObjectSettingsStore : public QRemoteObjectAbstractPersistedStore
+{
+    Q_OBJECT
+
+public:
+    QRemoteObjectSettingsStore(QObject *parent = nullptr);
+    ~QRemoteObjectSettingsStore() override;
+
+    void saveProperties(const QString &repName, const QByteArray &repSig, const QVariantList &values) override;
+    QVariantList restoreProperties(const QString &repName, const QByteArray &repSig) override;
+
+private:
+    Q_DECLARE_PRIVATE(QRemoteObjectSettingsStore)
+};
+
+QT_END_NAMESPACE
+
+#endif // QREMOTEOBJECTSETTINGSSTORE_H
diff --git a/src/remoteobjects/qremoteobjectsource.cpp b/src/remoteobjects/qremoteobjectsource.cpp
new file mode 100644 (file)
index 0000000..75b746d
--- /dev/null
@@ -0,0 +1,684 @@
+/****************************************************************************
+**
+** 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 "qremoteobjectsource.h"
+#include "qremoteobjectsource_p.h"
+#include "qremoteobjectnode.h"
+#include "qremoteobjectdynamicreplica.h"
+
+#include "qconnectionfactories_p.h"
+#include "qremoteobjectsourceio_p.h"
+#include "qremoteobjectabstractitemmodeladapter_p.h"
+
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qabstractitemmodel.h>
+
+#include <algorithm>
+#include <iterator>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QRemoteObjectPackets;
+using namespace QRemoteObjectStringLiterals;
+
+const int QRemoteObjectSourceBase::qobjectPropertyOffset = QObject::staticMetaObject.propertyCount();
+const int QRemoteObjectSourceBase::qobjectMethodOffset = QObject::staticMetaObject.methodCount();
+static const QByteArray s_classinfoRemoteobjectSignature(QCLASSINFO_REMOTEOBJECT_SIGNATURE);
+
+namespace QtPrivate {
+
+// The stringData, methodMatch and QMetaObjectPrivate methods are modified versions of the code
+// from qmetaobject_p.h/qmetaobject.cpp.  The modifications are based on our custom need to match
+// a method name that comes from the .rep file.
+// The QMetaObjectPrivate struct should only have members appended to maintain binary compatibility,
+// so we should be fine with only the listed version with the fields we use.
+inline const QByteArray apiStringData(const QMetaObject *mo, int index)
+{
+    uint offset = mo->d.stringdata[2*index];
+    uint length = mo->d.stringdata[2*index + 1];
+    const char *string = reinterpret_cast<const char *>(mo->d.stringdata) + offset;
+    return QByteArray::fromRawData(string, length);
+}
+
+
+// From QMetaMethod in qmetaobject.h
+struct Data {
+    enum { Size = 6 };
+
+    uint name() const { return d[0]; }
+    uint argc() const { return d[1]; }
+    uint parameters() const { return d[2]; }
+    uint tag() const { return d[3]; }
+    uint flags() const { return d[4]; }
+    uint metaTypeOffset() const { return d[5]; }
+    bool operator==(const Data &other) const { return d == other.d; }
+
+    const uint *d;
+};
+
+inline bool apiMethodMatch(const QMetaObject *m, const Data &data, const QByteArray &name, int argc,
+                           const int *types)
+{
+    if (data.argc() != uint(argc))
+        return false;
+    if (apiStringData(m, data.name()) != name)
+        return false;
+    for (int i = 0; i < argc; ++i) {
+        auto mt = QMetaType(m->d.metaTypes[data.metaTypeOffset() + i + 1]);
+        if (mt != QMetaType(types[i]))
+            return false;
+    }
+    return true;
+}
+
+struct QMetaObjectPrivate
+{
+    // revision 7 is Qt 5.0 everything lower is not supported
+    // revision 8 is Qt 5.12: It adds the enum name to QMetaEnum
+    enum { OutputRevision = 8 }; // Used by moc, qmetaobjectbuilder and qdbus
+
+    int revision;
+    int className;
+    int classInfoCount, classInfoData;
+    int methodCount, methodData;
+    int propertyCount, propertyData;
+    int enumeratorCount, enumeratorData;
+    int constructorCount, constructorData;
+    int flags;
+    int signalCount;
+};
+
+inline Data fromRelativeMethodIndex(const QMetaObject *mobj, int index)
+{
+    const auto priv = reinterpret_cast<const QMetaObjectPrivate*>(mobj->d.data);
+    return { mobj->d.data + priv->methodData + index * Data::Size };
+}
+
+int qtro_method_index_impl(const QMetaObject * staticMetaObj, const char *className,
+                                      const char *methodName, int *count, int const **types)
+{
+    int result = staticMetaObj->indexOfMethod(methodName);
+    if (result >= 0)
+        return result;
+    // We can have issues, specifically with enums, since the compiler can infer the class.  Since
+    // indexOfMethod() is doing string comparisons for registered types, "MyEnum" and "MyClass::MyEnum"
+    // won't match.
+    // Below is similar to QMetaObject->indexOfMethod, but template magic has already matched parameter
+    // types, so we need to find a match for the API method name + parameters.  Neither approach works
+    // 100%, as the below code doesn't match a parameter of type "size_t" (which the template match
+    // identifies as "ulong").  These subtleties can cause the below string comparison fails.
+    // There is no known case that would fail both methods.
+    // TODO: is there a way to make this a constexpr so a failure is detected at compile time?
+    int nameLength = strchr(methodName, '(') - methodName;
+    const auto name = QByteArray::fromRawData(methodName, nameLength);
+    for (const QMetaObject *m = staticMetaObj; m; m = m->d.superdata) {
+        const auto priv = reinterpret_cast<const QMetaObjectPrivate*>(m->d.data);
+        int i = (priv->methodCount - 1);
+        const int end = priv->signalCount;
+        for (; i >= end; --i) {
+            const Data data = fromRelativeMethodIndex(m, i);
+            if (apiMethodMatch(m, data, name, *count, *types))
+                return i + m->methodOffset();
+        }
+    }
+    qWarning() << "No matching method for" << methodName << "in the provided metaclass" << className;
+    return -1;
+}
+
+} // namespace QtPrivate
+
+QByteArray QtPrivate::qtro_classinfo_signature(const QMetaObject *metaObject)
+{
+    if (!metaObject)
+        return QByteArray{};
+
+    for (int i = metaObject->classInfoOffset(); i < metaObject->classInfoCount(); ++i) {
+        auto ci = metaObject->classInfo(i);
+        if (s_classinfoRemoteobjectSignature == ci.name())
+            return ci.value();
+    }
+    return QByteArray{};
+}
+
+inline bool qtro_is_cloned_method(const QMetaObject *mobj, int index)
+{
+    int local_method_index = index - mobj->methodOffset();
+    if (local_method_index < 0 && mobj->superClass())
+        return qtro_is_cloned_method(mobj->superClass(), index);
+    const QtPrivate::Data data = QtPrivate::fromRelativeMethodIndex(mobj, local_method_index);
+    if (data.flags() & 0x20 /*MethodFlags::MethodCloned*/)
+        return true;
+    return false;
+}
+
+QRemoteObjectSourceBase::QRemoteObjectSourceBase(QObject *obj, Private *d, const SourceApiMap *api,
+                                                 QObject *adapter)
+    : QObject(obj),
+      m_object(obj),
+      m_adapter(adapter),
+      m_api(api),
+      d(d)
+{
+    if (!obj) {
+        qCWarning(QT_REMOTEOBJECT) << "QRemoteObjectSourceBase: Cannot replicate a NULL object" << m_api->name();
+        return;
+    }
+
+    setConnections();
+
+    const auto nChildren = api->m_models.count() + api->m_subclasses.count();
+    if (nChildren > 0) {
+        QList<int> roles;
+        const int numProperties = api->propertyCount();
+        int modelIndex = 0, subclassIndex = 0;
+        for (int i = 0; i < numProperties; ++i) {
+            if (api->isAdapterProperty(i))
+                continue;
+            const int index = api->sourcePropertyIndex(i);
+            const auto property = m_object->metaObject()->property(index);
+            const auto metaType = property.metaType();
+            if (metaType.flags().testFlag(QMetaType::PointerToQObject)) {
+                auto propertyMeta = metaType.metaObject();
+                QObject *child = property.read(m_object).value<QObject *>();
+                const QMetaObject *meta = child ? child->metaObject() : propertyMeta;
+                if (!meta)
+                    continue;
+                if (meta->inherits(&QAbstractItemModel::staticMetaObject)) {
+                    const auto modelInfo = api->m_models.at(modelIndex++);
+                    QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(child);
+                    QAbstractItemAdapterSourceAPI<QAbstractItemModel, QAbstractItemModelSourceAdapter> *modelApi =
+                        new QAbstractItemAdapterSourceAPI<QAbstractItemModel, QAbstractItemModelSourceAdapter>(modelInfo.name);
+                    if (!model)
+                        m_children.insert(i, new QRemoteObjectSource(nullptr, d, modelApi, nullptr, api->name()));
+                    else {
+                        roles.clear();
+                        const auto knownRoles = model->roleNames();
+                        for (auto role : modelInfo.roles.split('|')) {
+                            if (role.isEmpty())
+                                continue;
+                            const int roleIndex = knownRoles.key(role, -1);
+                            if (roleIndex == -1) {
+                                qCWarning(QT_REMOTEOBJECT) << "Invalid role" << role << "for model" << model->metaObject()->className();
+                                qCWarning(QT_REMOTEOBJECT) << "  known roles:" << knownRoles;
+                            } else
+                                roles << roleIndex;
+                        }
+                        auto adapter = new QAbstractItemModelSourceAdapter(model, nullptr,
+                                                                           roles.isEmpty() ? knownRoles.keys().toVector() : roles);
+                        m_children.insert(i, new QRemoteObjectSource(model, d, modelApi, adapter, api->name()));
+                    }
+                } else {
+                    const auto classApi = api->m_subclasses.at(subclassIndex++);
+                    m_children.insert(i, new QRemoteObjectSource(child, d, classApi, nullptr, api->name()));
+                }
+            }
+        }
+    }
+}
+
+QRemoteObjectSource::QRemoteObjectSource(QObject *obj, Private *dd, const SourceApiMap *api, QObject *adapter, const QString &parentName)
+    : QRemoteObjectSourceBase(obj, dd, api, adapter)
+    , m_name(api->typeName() == QLatin1String("QAbstractItemModelAdapter") ? MODEL().arg(parentName + QLatin1String("::") + api->name()) :
+                                                                             CLASS().arg(parentName + QLatin1String("::") + api->name()))
+{
+    if (obj)
+        d->m_sourceIo->registerSource(this);
+}
+
+QRemoteObjectRootSource::QRemoteObjectRootSource(QObject *obj, const SourceApiMap *api,
+                                                 QObject *adapter, QRemoteObjectSourceIo *sourceIo)
+    : QRemoteObjectSourceBase(obj, new Private(sourceIo, this), api, adapter)
+    , m_name(api->name())
+{
+    d->m_sourceIo->registerSource(this);
+}
+
+QRemoteObjectSourceBase::~QRemoteObjectSourceBase()
+{
+    delete m_api;
+}
+
+void QRemoteObjectSourceBase::setConnections()
+{
+    const QMetaObject *meta = m_object->metaObject();
+
+    const int index = meta->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE);
+    if (index != -1) { //We have an object created from repc or at least with QCLASSINFO defined
+        while (true) {
+            Q_ASSERT(meta->superClass()); //This recurses to QObject, which doesn't have QCLASSINFO_REMOTEOBJECT_TYPE
+            if (index != meta->superClass()->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE)) //At the point we don't find the same QCLASSINFO_REMOTEOBJECT_TYPE,
+                            //we have the metaobject we should work from
+                break;
+            meta = meta->superClass();
+        }
+    }
+
+    for (int idx = 0; idx < m_api->signalCount(); ++idx) {
+        const int sourceIndex = m_api->sourceSignalIndex(idx);
+        const bool isAdapter = m_api->isAdapterSignal(idx);
+        const auto targetMeta = isAdapter ? m_adapter->metaObject() : meta;
+
+        // don't connect cloned signals, or we end up with multiple emissions
+        if (qtro_is_cloned_method(targetMeta, sourceIndex))
+            continue;
+        // This basically connects the parent Signals (note, all dynamic properties have onChange
+        //notifications, thus signals) to us.  Normally each Signal is mapped to a unique index,
+        //but since we are forwarding them all, we keep the offset constant.
+        //
+        //We know no one will inherit from this class, so no need to worry about indices from
+        //derived classes.
+        const auto target = isAdapter ? m_adapter : m_object;
+        if (!QMetaObject::connect(target, sourceIndex, this, QRemoteObjectSource::qobjectMethodOffset+idx, Qt::DirectConnection, nullptr)) {
+            qCWarning(QT_REMOTEOBJECT) << "QRemoteObjectSourceBase: QMetaObject::connect returned false. Unable to connect.";
+            return;
+        }
+
+        qCDebug(QT_REMOTEOBJECT) << "Connection made" << idx << sourceIndex
+                                 << targetMeta->method(sourceIndex).name();
+    }
+}
+
+void QRemoteObjectSourceBase::resetObject(QObject *newObject)
+{
+    if (m_object)
+        m_object->disconnect(this);
+    if (m_adapter) {
+        m_adapter->disconnect(this);
+        delete m_adapter;
+        m_adapter = nullptr;
+    }
+    // We need some dynamic replica specific code here, in case an object had null sub-classes that
+    // have been replaced with real objects.  In this case, the ApiMap could be wrong and need updating.
+    if (newObject && qobject_cast<QRemoteObjectDynamicReplica *>(newObject) && m_api->isDynamic()) {
+        auto api = static_cast<const DynamicApiMap*>(m_api);
+        if (api->m_properties[0] == 0) { // 0 is an index into QObject itself, so this isn't a valid QtRO index
+            const auto rep = qobject_cast<QRemoteObjectDynamicReplica *>(newObject);
+            auto tmp = m_api;
+            m_api = new DynamicApiMap(newObject, rep->metaObject(), api->m_name, QLatin1String(rep->metaObject()->className()));
+            qCDebug(QT_REMOTEOBJECT) << "  Reset m_api for" << api->m_name << "using new metaObject:" << rep->metaObject()->className();
+            delete tmp;
+        }
+    }
+
+    m_object = newObject;
+    auto model = qobject_cast<QAbstractItemModel *>(newObject);
+    if (model) {
+        d->m_sourceIo->registerSource(this);
+        m_adapter = new QAbstractItemModelSourceAdapter(model, nullptr, model->roleNames().keys().toVector());
+    }
+
+    setParent(newObject);
+    if (newObject)
+        setConnections();
+
+    const auto nChildren = m_api->m_models.count() + m_api->m_subclasses.count();
+    if (nChildren == 0)
+        return;
+
+    if (!newObject) {
+        for (auto child : m_children)
+            child->resetObject(nullptr);
+        return;
+    }
+
+    for (int i : m_children.keys()) {
+        const int index = m_api->sourcePropertyIndex(i);
+        const auto property = m_object->metaObject()->property(index);
+        QObject *child = property.read(m_object).value<QObject *>();
+        m_children[i]->resetObject(child);
+    }
+}
+
+QRemoteObjectSource::~QRemoteObjectSource()
+{
+    for (auto it : m_children) {
+        // We used QPointers for m_children because we don't control the lifetime of child QObjects
+        // Since the this/source QObject's parent is the referenced QObject, it could have already
+        // been deleted
+        delete it;
+    }
+}
+
+QRemoteObjectRootSource::~QRemoteObjectRootSource()
+{
+    for (auto it : m_children) {
+        // We used QPointers for m_children because we don't control the lifetime of child QObjects
+        // Since the this/source QObject's parent is the referenced QObject, it could have already
+        // been deleted
+        delete it;
+    }
+    d->m_sourceIo->unregisterSource(this);
+    // removeListener tries to modify d->m_listeners, this is O(N²),
+    // so clear d->m_listeners prior to calling unregister (consume loop).
+    // We can do this, because we don't care about the return value of removeListener() here.
+    for (QtROIoDeviceBase *io : qExchange(d->m_listeners, {})) {
+        removeListener(io, true);
+    }
+    delete d;
+}
+
+QVariantList* QRemoteObjectSourceBase::marshalArgs(int index, void **a)
+{
+    QVariantList &list = m_marshalledArgs;
+    int N = m_api->signalParameterCount(index);
+    if (N == 1 && QMetaType(m_api->signalParameterType(index, 0)).flags().testFlag(QMetaType::PointerToQObject))
+        N = 0; // Don't try to send pointers, the will be handle by QRO_
+    if (list.size() < N)
+        list.reserve(N);
+    const int minFill = std::min(int(list.size()), N);
+    for (int i = 0; i < minFill; ++i) {
+        const int type = m_api->signalParameterType(index, i);
+        if (type == QMetaType::QVariant)
+            list[i] = *reinterpret_cast<QVariant *>(a[i + 1]);
+        else
+            list[i] = QVariant(QMetaType(type), a[i + 1]);
+    }
+    for (int i = int(list.size()); i < N; ++i) {
+        const int type = m_api->signalParameterType(index, i);
+        if (type == QMetaType::QVariant)
+            list << *reinterpret_cast<QVariant *>(a[i + 1]);
+        else
+            list << QVariant(QMetaType(type), a[i + 1]);
+    }
+    for (int i = N; i < list.size(); ++i)
+        list.removeLast();
+    return &m_marshalledArgs;
+}
+
+bool QRemoteObjectSourceBase::invoke(QMetaObject::Call c, int index, const QVariantList &args, QVariant* returnValue)
+{
+    int status = -1;
+    int flags = 0;
+    bool forAdapter = (c == QMetaObject::InvokeMetaMethod ? m_api->isAdapterMethod(index) : m_api->isAdapterProperty(index));
+    int resolvedIndex = (c == QMetaObject::InvokeMetaMethod ? m_api->sourceMethodIndex(index) : m_api->sourcePropertyIndex(index));
+    if (resolvedIndex < 0)
+        return false;
+    QVarLengthArray<void*, 10> param(args.size() + 1);
+
+    if (c == QMetaObject::InvokeMetaMethod) {
+        QMetaMethod method;
+        if (!forAdapter)
+            method = parent()->metaObject()->method(resolvedIndex);
+
+        if (returnValue) {
+            if (!forAdapter && method.isValid() && method.returnType() == QMetaType::QVariant)
+                param[0] = const_cast<void*>(reinterpret_cast<const void*>(returnValue));
+            else
+                param[0] = returnValue->data();
+        } else {
+            param[0] = nullptr;
+        }
+
+        auto argument = [&](int i) -> void * {
+            if ((forAdapter && m_api->methodParameterType(index, i) == QMetaType::QVariant) ||
+                    (method.isValid() && method.parameterType(i) == QMetaType::QVariant)) {
+                return const_cast<void*>(reinterpret_cast<const void*>(&args.at(i)));
+            }
+            return const_cast<void*>(args.at(i).data());
+        };
+
+        for (int i = 0; i < args.size(); ++i) {
+            param[i + 1] = argument(i);
+        }
+    } else if (c == QMetaObject::WriteProperty || c == QMetaObject::ReadProperty) {
+        bool isQVariant = !forAdapter && parent()->metaObject()->property(resolvedIndex).userType() == QMetaType::QVariant;
+        for (int i = 0; i < args.size(); ++i) {
+            if (isQVariant)
+                param[i] = const_cast<void*>(reinterpret_cast<const void*>(&args.at(i)));
+            else
+                param[i] = const_cast<void*>(args.at(i).data());
+        }
+        if (c == QMetaObject::WriteProperty) {
+            Q_ASSERT(param.size() == 2); // for return-value and setter value
+            // check QMetaProperty::write for an explanation of these
+            param.append(&status);
+            param.append(&flags);
+        }
+    } else {
+        // Better safe than sorry
+        return false;
+    }
+    int r = -1;
+    if (forAdapter)
+        r = m_adapter->qt_metacall(c, resolvedIndex, param.data());
+    else
+        r = parent()->qt_metacall(c, resolvedIndex, param.data());
+    return r == -1 && status == -1;
+}
+
+void QRemoteObjectSourceBase::handleMetaCall(int index, QMetaObject::Call call, void **a)
+{
+    if (d->m_listeners.empty())
+        return;
+
+    int propertyIndex = m_api->propertyIndexFromSignal(index);
+    if (propertyIndex >= 0) {
+        const int internalIndex = m_api->propertyRawIndexFromSignal(index);
+        const auto target = m_api->isAdapterProperty(internalIndex) ? m_adapter : m_object;
+        const QMetaProperty mp = target->metaObject()->property(propertyIndex);
+        qCDebug(QT_REMOTEOBJECT) << "Sending Invoke Property" << (m_api->isAdapterSignal(internalIndex) ? "via adapter" : "") << internalIndex << propertyIndex << mp.name() << mp.read(target);
+
+        d->codec->serializePropertyChangePacket(this, index);
+        propertyIndex = internalIndex;
+    }
+
+    qCDebug(QT_REMOTEOBJECT) << "# Listeners" << d->m_listeners.length();
+    qCDebug(QT_REMOTEOBJECT) << "Invoke args:" << m_object
+                             << (call == 0 ? QLatin1String("InvokeMetaMethod") : QStringLiteral("Non-invoked call: %d").arg(call))
+                             << m_api->signalSignature(index) << *marshalArgs(index, a);
+
+    d->codec->serializeInvokePacket(name(), call, index, *marshalArgs(index, a), -1, propertyIndex);
+
+    d->codec->send(d->m_listeners);
+}
+
+void QRemoteObjectRootSource::addListener(QtROIoDeviceBase *io, bool dynamic)
+{
+    d->m_listeners.append(io);
+    d->isDynamic = d->isDynamic || dynamic;
+
+    if (dynamic) {
+        d->sentTypes.clear();
+        d->codec->serializeInitDynamicPacket(this);
+        d->codec->send(io);
+    } else {
+        d->codec->serializeInitPacket(this);
+        d->codec->send(io);
+    }
+}
+
+int QRemoteObjectRootSource::removeListener(QtROIoDeviceBase *io, bool shouldSendRemove)
+{
+    d->m_listeners.removeAll(io);
+    if (shouldSendRemove)
+    {
+        d->codec->serializeRemoveObjectPacket(m_api->name());
+        d->codec->send(io);
+    }
+    return int(d->m_listeners.length());
+}
+
+int QRemoteObjectSourceBase::qt_metacall(QMetaObject::Call call, int methodId, void **a)
+{
+    methodId = QObject::qt_metacall(call, methodId, a);
+    if (methodId < 0)
+        return methodId;
+
+    if (call == QMetaObject::InvokeMetaMethod)
+        handleMetaCall(methodId, call, a);
+
+    return -1;
+}
+
+DynamicApiMap::DynamicApiMap(QObject *object, const QMetaObject *metaObject, const QString &name, const QString &typeName)
+    : m_name(name),
+      m_typeName(typeName),
+      m_metaObject(metaObject),
+      m_cachedMetamethodIndex(-1)
+{
+    m_enumOffset = metaObject->enumeratorOffset();
+    m_enumCount = metaObject->enumeratorCount() - m_enumOffset;
+
+    const int propCount = metaObject->propertyCount();
+    const int propOffset = metaObject->propertyOffset();
+    m_properties.reserve(propCount-propOffset);
+    QSet<int> invalidSignals;
+    for (int i = propOffset; i < propCount; ++i) {
+        const QMetaProperty property = metaObject->property(i);
+        const auto metaType = property.metaType();
+        if (metaType.flags().testFlag(QMetaType::PointerToQObject)) {
+            auto propertyMeta = metaType.metaObject();
+            QObject *child = property.read(object).value<QObject *>();
+            const QMetaObject *meta = child ? child->metaObject() : propertyMeta;
+            if (!meta) {
+                const int notifyIndex = metaObject->property(i).notifySignalIndex();
+                if (notifyIndex != -1)
+                    invalidSignals << notifyIndex;
+                continue;
+            }
+            if (meta->inherits(&QAbstractItemModel::staticMetaObject)) {
+                const QByteArray name = QByteArray::fromRawData(property.name(),
+                                                                qsizetype(qstrlen(property.name())));
+                const QByteArray infoName = name.toUpper() + QByteArrayLiteral("_ROLES");
+                const int infoIndex = metaObject->indexOfClassInfo(infoName.constData());
+                QByteArray roleInfo;
+                if (infoIndex >= 0) {
+                    auto ci = metaObject->classInfo(infoIndex);
+                    roleInfo = QByteArray::fromRawData(ci.value(), qsizetype(qstrlen(ci.value())));
+                }
+                m_models << ModelInfo({qobject_cast<QAbstractItemModel *>(child),
+                                       QString::fromLatin1(property.name()),
+                                       roleInfo});
+            } else {
+                QString typeName = QtRemoteObjects::getTypeNameAndMetaobjectFromClassInfo(meta);
+                if (typeName.isNull()) {
+                    typeName = QString::fromLatin1(meta->className());
+                    if (typeName.contains(QLatin1String("QQuick")))
+                        typeName.remove(QLatin1String("QQuick"));
+                    else if (int index = typeName.indexOf(QLatin1String("_QMLTYPE_")))
+                        typeName.truncate(index);
+                    // TODO better way to ensure we have consistent typenames between source/replicas?
+                    else if (typeName.endsWith(QLatin1String("Source")))
+                        typeName.chop(6);
+                }
+
+                m_subclasses << new DynamicApiMap(child, meta, QString::fromLatin1(property.name()), typeName);
+            }
+        }
+        m_properties << i;
+        const int notifyIndex = metaObject->property(i).notifySignalIndex();
+        if (notifyIndex != -1) {
+            m_signals << notifyIndex;
+            m_propertyAssociatedWithSignal.append(i-propOffset);
+            //The starting values of _signals will be the notify signals
+            //So if we are processing _signal with index i, api->sourcePropertyIndex(_propertyAssociatedWithSignal.at(i))
+            //will be the property that changed.  This is only valid if i < _propertyAssociatedWithSignal.size().
+        }
+    }
+    const int methodCount = metaObject->methodCount();
+    const int methodOffset = metaObject->methodOffset();
+    for (int i = methodOffset; i < methodCount; ++i) {
+        const QMetaMethod mm = metaObject->method(i);
+        const QMetaMethod::MethodType m = mm.methodType();
+        if (m == QMetaMethod::Signal) {
+            if (m_signals.indexOf(i) >= 0)  // Already added as a property notifier
+                continue;
+            if (invalidSignals.contains(i)) // QObject with no metatype
+                continue;
+            m_signals << i;
+        } else if (m == QMetaMethod::Slot || m == QMetaMethod::Method)
+            m_methods << i;
+    }
+
+    m_objectSignature = QtPrivate::qtro_classinfo_signature(metaObject);
+}
+
+QByteArrayList DynamicApiMap::signalParameterNames(int index) const
+{
+    const int objectIndex = m_signals.at(index);
+    checkCache(objectIndex);
+    return m_cachedMetamethod.parameterNames();
+}
+
+int DynamicApiMap::parameterCount(int objectIndex) const
+{
+    checkCache(objectIndex);
+    return m_cachedMetamethod.parameterCount();
+}
+
+int DynamicApiMap::parameterType(int objectIndex, int paramIndex) const
+{
+    checkCache(objectIndex);
+    return m_cachedMetamethod.parameterType(paramIndex);
+}
+
+const QByteArray DynamicApiMap::signature(int objectIndex) const
+{
+    checkCache(objectIndex);
+    return m_cachedMetamethod.methodSignature();
+}
+
+QMetaMethod::MethodType DynamicApiMap::methodType(int index) const
+{
+    const int objectIndex = m_methods.at(index);
+    checkCache(objectIndex);
+    return m_cachedMetamethod.methodType();
+}
+
+const QByteArray DynamicApiMap::typeName(int index) const
+{
+    const int objectIndex = m_methods.at(index);
+    checkCache(objectIndex);
+    return m_cachedMetamethod.typeName();
+}
+
+QByteArrayList DynamicApiMap::methodParameterNames(int index) const
+{
+    const int objectIndex = m_methods.at(index);
+    checkCache(objectIndex);
+    return m_cachedMetamethod.parameterNames();
+}
+
+QRemoteObjectSourceBase::Private::Private(QRemoteObjectSourceIo *io, QRemoteObjectRootSource *root)
+    : m_sourceIo(io), codec(io->m_codec.data()), isDynamic(false), root(root)
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/remoteobjects/qremoteobjectsource.h b/src/remoteobjects/qremoteobjectsource.h
new file mode 100644 (file)
index 0000000..78195ec
--- /dev/null
@@ -0,0 +1,188 @@
+/****************************************************************************
+**
+** 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 QREMOTEOBJECTSOURCE_H
+#define QREMOTEOBJECTSOURCE_H
+
+#include <QtCore/qscopedpointer.h>
+#include <QtRemoteObjects/qtremoteobjectglobal.h>
+#include <QtCore/qmetaobject.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtPrivate {
+
+//Based on compile time checks for static connect() from qobjectdefs_impl.h
+template <class ObjectType, typename Func1, typename Func2>
+static inline int qtro_property_index(Func1, Func2, const char *propName)
+{
+    typedef QtPrivate::FunctionPointer<Func1> Type1;
+    typedef QtPrivate::FunctionPointer<Func2> Type2;
+
+    //compilation error if the arguments do not match.
+    Q_STATIC_ASSERT_X(int(Type1::ArgumentCount) >= int(Type2::ArgumentCount),
+                      "Argument counts are not compatible.");
+    Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename Type1::Arguments, typename Type2::Arguments>::value),
+                      "Arguments are not compatible.");
+    Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename Type1::ReturnType, typename Type2::ReturnType>::value),
+                      "Return types are not compatible.");
+    return ObjectType::staticMetaObject.indexOfProperty(propName);
+}
+
+template <class ObjectType, typename Func1, typename Func2>
+static inline int qtro_signal_index(Func1 func, Func2, int *count, int const **types)
+{
+    typedef QtPrivate::FunctionPointer<Func1> Type1;
+    typedef QtPrivate::FunctionPointer<Func2> Type2;
+
+    //compilation error if the arguments do not match.
+    Q_STATIC_ASSERT_X(int(Type1::ArgumentCount) >= int(Type2::ArgumentCount),
+                      "Argument counts are not compatible.");
+    Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename Type1::Arguments, typename Type2::Arguments>::value),
+                      "Arguments are not compatible.");
+    Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename Type1::ReturnType, typename Type2::ReturnType>::value),
+                      "Return types are not compatible.");
+    const QMetaMethod sig = QMetaMethod::fromSignal(func);
+    *count = Type2::ArgumentCount;
+    *types = QtPrivate::ConnectionTypes<typename Type2::Arguments>::types();
+    return sig.methodIndex();
+}
+
+template <class ObjectType, typename Func1, typename Func2>
+static inline void qtro_method_test(Func1, Func2)
+{
+    typedef QtPrivate::FunctionPointer<Func1> Type1;
+    typedef QtPrivate::FunctionPointer<Func2> Type2;
+
+    //compilation error if the arguments do not match.
+    Q_STATIC_ASSERT_X(int(Type1::ArgumentCount) >= int(Type2::ArgumentCount),
+                      "Argument counts are not compatible.");
+    Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename Type1::Arguments, typename Type2::Arguments>::value),
+                      "Arguments are not compatible.");
+    Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename Type1::ReturnType, typename Type2::ReturnType>::value),
+                      "Return types are not compatible.");
+}
+
+Q_REMOTEOBJECTS_EXPORT
+int qtro_method_index_impl(const QMetaObject *staticMetaObj, const char *className,
+                           const char *methodName, int *count, const int **types);
+
+template <class ObjectType, typename Func1, typename Func2>
+static inline int qtro_method_index(Func1, Func2, const char *methodName, int *count, int const **types)
+{
+    typedef QtPrivate::FunctionPointer<Func1> Type1;
+    typedef QtPrivate::FunctionPointer<Func2> Type2;
+
+    //compilation error if the arguments do not match.
+    Q_STATIC_ASSERT_X(int(Type1::ArgumentCount) >= int(Type2::ArgumentCount),
+                      "Argument counts are not compatible.");
+    Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename Type1::Arguments, typename Type2::Arguments>::value),
+                      "Arguments are not compatible.");
+    Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename Type1::ReturnType, typename Type2::ReturnType>::value),
+                      "Return types are not compatible.");
+    *count = Type2::ArgumentCount;
+    *types = QtPrivate::ConnectionTypes<typename Type2::Arguments>::types();
+
+    return qtro_method_index_impl(&ObjectType::staticMetaObject,
+                                  ObjectType::staticMetaObject.className(), methodName, count,
+                                  types);
+}
+
+template <class ObjectType>
+static inline QByteArray qtro_enum_signature(const char *enumName)
+{
+    const auto qme = ObjectType::staticMetaObject.enumerator(ObjectType::staticMetaObject.indexOfEnumerator(enumName));
+    return QByteArrayLiteral("1::2").replace("1", qme.scope()).replace("2", qme.name());
+}
+
+QByteArray qtro_classinfo_signature(const QMetaObject *metaObject);
+
+}
+
+// TODO ModelInfo just needs roles, and no need for SubclassInfo
+class QAbstractItemModel;
+
+struct ModelInfo
+{
+    QAbstractItemModel *ptr;
+    QString name;
+    QByteArray roles;
+};
+
+class SourceApiMap
+{
+protected:
+    SourceApiMap() {}
+public:
+    virtual ~SourceApiMap() {}
+    virtual QString name() const = 0;
+    virtual QString typeName() const = 0;
+    virtual QByteArray className() const { return typeName().toLatin1().append("Source"); }
+    virtual int enumCount() const = 0;
+    virtual int propertyCount() const = 0;
+    virtual int signalCount() const = 0;
+    virtual int methodCount() const = 0;
+    virtual int sourceEnumIndex(int index) const = 0;
+    virtual int sourcePropertyIndex(int index) const = 0;
+    virtual int sourceSignalIndex(int index) const = 0;
+    virtual int sourceMethodIndex(int index) const = 0;
+    virtual int signalParameterCount(int index) const = 0;
+    virtual int signalParameterType(int sigIndex, int paramIndex) const = 0;
+    virtual const QByteArray signalSignature(int index) const = 0;
+    virtual QByteArrayList signalParameterNames(int index) const = 0;
+    virtual int methodParameterCount(int index) const = 0;
+    virtual int methodParameterType(int methodIndex, int paramIndex) const = 0;
+    virtual const QByteArray methodSignature(int index) const = 0;
+    virtual QMetaMethod::MethodType methodType(int index) const = 0;
+    virtual const QByteArray typeName(int index) const = 0;
+    virtual QByteArrayList methodParameterNames(int index) const = 0;
+    virtual int propertyIndexFromSignal(int index) const = 0;
+    virtual int propertyRawIndexFromSignal(int index) const = 0;
+    virtual QByteArray objectSignature() const = 0;
+    virtual bool isDynamic() const { return false; }
+    virtual bool isAdapterSignal(int) const { return false; }
+    virtual bool isAdapterMethod(int) const { return false; }
+    virtual bool isAdapterProperty(int) const { return false; }
+    QList<ModelInfo> m_models;
+    QList<SourceApiMap *> m_subclasses;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/remoteobjects/qremoteobjectsource_p.h b/src/remoteobjects/qremoteobjectsource_p.h
new file mode 100644 (file)
index 0000000..fe71497
--- /dev/null
@@ -0,0 +1,223 @@
+/****************************************************************************
+**
+** 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 QREMOTEOBJECTSOURCE_P_H
+#define QREMOTEOBJECTSOURCE_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 <QtCore/qlist.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qpointer.h>
+#include "qremoteobjectsource.h"
+#include "qremoteobjectpacket_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QRemoteObjectSourceIo;
+class QtROIoDeviceBase;
+
+class QRemoteObjectSourceBase : public QObject
+{
+public:
+    ~QRemoteObjectSourceBase() override;
+
+    void setConnections();
+    void resetObject(QObject *newObject);
+    int qt_metacall(QMetaObject::Call call, int methodId, void **a) final;
+    QObject *m_object, *m_adapter;
+    const SourceApiMap *m_api;
+    QVariantList m_marshalledArgs;
+    bool hasAdapter() const { return m_adapter; }
+    virtual QString name() const = 0;
+    virtual bool isRoot() const = 0;
+
+    QVariantList* marshalArgs(int index, void **a);
+    void handleMetaCall(int index, QMetaObject::Call call, void **a);
+    bool invoke(QMetaObject::Call c, int index, const QVariantList& args, QVariant* returnValue = nullptr);
+    QByteArray m_objectChecksum;
+    QMap<int, QPointer<QRemoteObjectSourceBase>> m_children;
+    struct Private {
+        Private(QRemoteObjectSourceIo *io, QRemoteObjectRootSource *root);
+        QRemoteObjectSourceIo *m_sourceIo;
+        QList<QtROIoDeviceBase*> m_listeners;
+        // Pointer to codec, not owned by Private.  We can assume it is valid.
+        QRemoteObjectPackets::CodecBase *codec;
+
+        // Types needed during recursively sending a root to a new listener
+        QSet<QString> sentTypes;
+        bool isDynamic;
+        QRemoteObjectRootSource *root;
+    };
+    Private *d;
+    static const int qobjectPropertyOffset;
+    static const int qobjectMethodOffset;
+protected:
+    explicit QRemoteObjectSourceBase(QObject *object, Private *d, const SourceApiMap *, QObject *adapter);
+};
+
+class QRemoteObjectSource : public QRemoteObjectSourceBase
+{
+public:
+    explicit QRemoteObjectSource(QObject *object, Private *d, const SourceApiMap *, QObject *adapter, const QString &parentName);
+    ~QRemoteObjectSource() override;
+
+    bool isRoot() const override { return false; }
+    QString name() const override { return m_name; }
+
+    QString m_name;
+};
+
+class QRemoteObjectRootSource : public QRemoteObjectSourceBase
+{
+public:
+    explicit QRemoteObjectRootSource(QObject *object, const SourceApiMap *,
+                                     QObject *adapter, QRemoteObjectSourceIo *sourceIo);
+    ~QRemoteObjectRootSource() override;
+
+    bool isRoot() const override { return true; }
+    QString name() const override { return m_name; }
+    void addListener(QtROIoDeviceBase *io, bool dynamic = false);
+    int removeListener(QtROIoDeviceBase *io, bool shouldSendRemove = false);
+
+    QString m_name;
+};
+
+class DynamicApiMap final : public SourceApiMap
+{
+public:
+    DynamicApiMap(QObject *object, const QMetaObject *metaObject, const QString &name, const QString &typeName);
+    ~DynamicApiMap() override {}
+    QString name() const override { return m_name; }
+    QString typeName() const override { return m_typeName; }
+    QByteArray className() const override { return QByteArray(m_metaObject->className()); }
+    int enumCount() const override { return m_enumCount; }
+    int propertyCount() const override { return m_properties.size(); }
+    int signalCount() const override { return m_signals.size(); }
+    int methodCount() const override { return m_methods.size(); }
+    int sourceEnumIndex(int index) const override
+    {
+        if (index < 0 || index >= enumCount())
+            return -1;
+        return m_enumOffset + index;
+    }
+    int sourcePropertyIndex(int index) const override
+    {
+        if (index < 0 || index >= propertyCount())
+            return -1;
+        return m_properties.at(index);
+    }
+    int sourceSignalIndex(int index) const override
+    {
+        if (index < 0 || index >= signalCount())
+            return -1;
+        return m_signals.at(index);
+    }
+    int sourceMethodIndex(int index) const override
+    {
+        if (index < 0 || index >= methodCount())
+            return -1;
+        return m_methods.at(index);
+    }
+    int signalParameterCount(int index) const override { return parameterCount(m_signals.at(index)); }
+    int signalParameterType(int sigIndex, int paramIndex) const override { return parameterType(m_signals.at(sigIndex), paramIndex); }
+    const QByteArray signalSignature(int index) const override { return signature(m_signals.at(index)); }
+    QByteArrayList signalParameterNames(int index) const override;
+
+    int methodParameterCount(int index) const override { return parameterCount(m_methods.at(index)); }
+    int methodParameterType(int methodIndex, int paramIndex) const override { return parameterType(m_methods.at(methodIndex), paramIndex); }
+    const QByteArray methodSignature(int index) const override { return signature(m_methods.at(index)); }
+    QMetaMethod::MethodType methodType(int index) const override;
+    const QByteArray typeName(int index) const override;
+    QByteArrayList methodParameterNames(int index) const override;
+
+    int propertyIndexFromSignal(int index) const override
+    {
+        if (index >= 0 && index < m_propertyAssociatedWithSignal.size())
+            return m_properties.at(m_propertyAssociatedWithSignal.at(index));
+        return -1;
+    }
+    int propertyRawIndexFromSignal(int index) const override
+    {
+        if (index >= 0 && index < m_propertyAssociatedWithSignal.size())
+            return m_propertyAssociatedWithSignal.at(index);
+        return -1;
+    }
+    QByteArray objectSignature() const override { return m_objectSignature; }
+
+    bool isDynamic() const override { return true; }
+
+    int parameterCount(int objectIndex) const;
+    int parameterType(int objectIndex, int paramIndex) const;
+    const QByteArray signature(int objectIndex) const;
+    inline void checkCache(int objectIndex) const
+    {
+        if (objectIndex != m_cachedMetamethodIndex) {
+            m_cachedMetamethodIndex = objectIndex;
+            m_cachedMetamethod = m_metaObject->method(objectIndex);
+        }
+    }
+
+    QString m_name;
+    QString m_typeName;
+    int m_enumCount;
+    int m_enumOffset;
+    QList<int> m_properties;
+    QList<int> m_signals;
+    QList<int> m_methods;
+    QList<int> m_propertyAssociatedWithSignal;
+    const QMetaObject *m_metaObject;
+    mutable QMetaMethod m_cachedMetamethod;
+    mutable int m_cachedMetamethodIndex;
+    QByteArray m_objectSignature;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/remoteobjects/qremoteobjectsourceio.cpp b/src/remoteobjects/qremoteobjectsourceio.cpp
new file mode 100644 (file)
index 0000000..13cfde2
--- /dev/null
@@ -0,0 +1,331 @@
+/****************************************************************************
+**
+** 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 "qremoteobjectsourceio_p.h"
+
+#include "qremoteobjectpacket_p.h"
+#include "qremoteobjectsource_p.h"
+#include "qremoteobjectnode_p.h"
+#include "qremoteobjectpendingcall.h"
+#include "qtremoteobjectglobal.h"
+
+#include <QtCore/qstringlist.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QtRemoteObjects;
+
+QRemoteObjectSourceIo::QRemoteObjectSourceIo(const QUrl &address, QObject *parent)
+    : QObject(parent)
+    , m_server(QtROServerFactory::instance()->isValid(address) ?
+               QtROServerFactory::instance()->create(address, this) : nullptr)
+    , m_address(address)
+{
+    if (m_server == nullptr)
+        qRODebug(this) << "Using" << m_address << "as external url.";
+}
+
+QRemoteObjectSourceIo::QRemoteObjectSourceIo(QObject *parent)
+    : QObject(parent)
+    , m_server(nullptr)
+{
+}
+
+QRemoteObjectSourceIo::~QRemoteObjectSourceIo()
+{
+    qDeleteAll(m_sourceRoots.values());
+}
+
+bool QRemoteObjectSourceIo::startListening()
+{
+    if (!m_server->listen(m_address)) {
+        qROCritical(this) << "Listen failed for URL:" << m_address;
+        qROCritical(this) << m_server->serverError();
+        return false;
+    }
+
+    qRODebug(this) << "QRemoteObjectSourceIo is Listening" << m_address;
+    connect(m_server.data(), &QConnectionAbstractServer::newConnection, this,
+            &QRemoteObjectSourceIo::handleConnection);
+    return true;
+}
+
+bool QRemoteObjectSourceIo::enableRemoting(QObject *object, const QMetaObject *meta, const QString &name, const QString &typeName)
+{
+    if (m_sourceRoots.contains(name)) {
+        qROWarning(this) << "Tried to register QRemoteObjectRootSource twice" << name;
+        return false;
+    }
+
+    return enableRemoting(object, new DynamicApiMap(object, meta, name, typeName));
+}
+
+bool QRemoteObjectSourceIo::enableRemoting(QObject *object, const SourceApiMap *api, QObject *adapter)
+{
+    const QString name = api->name();
+    if (!api->isDynamic() && m_sourceRoots.contains(name)) {
+        qROWarning(this) << "Tried to register QRemoteObjectRootSource twice" << name;
+        return false;
+    }
+
+    new QRemoteObjectRootSource(object, api, adapter, this);
+    m_codec->serializeObjectListPacket({QRemoteObjectPackets::ObjectInfo{api->name(), api->typeName(), api->objectSignature()}});
+    m_codec->send(m_connections);
+    if (const int count = m_connections.size())
+        qRODebug(this) << "Wrote new QObjectListPacket for" << api->name() << "to" << count << "connections";
+    return true;
+}
+
+bool QRemoteObjectSourceIo::disableRemoting(QObject *object)
+{
+    QRemoteObjectRootSource *source = m_objectToSourceMap.take(object);
+    if (!source)
+        return false;
+
+    delete source;
+    return true;
+}
+
+void QRemoteObjectSourceIo::registerSource(QRemoteObjectSourceBase *source)
+{
+    Q_ASSERT(source);
+    const QString &name = source->name();
+    m_sourceObjects[name] = source;
+    if (source->isRoot()) {
+        QRemoteObjectRootSource *root = static_cast<QRemoteObjectRootSource *>(source);
+        qRODebug(this) << "Registering" << name;
+        m_sourceRoots[name] = root;
+        m_objectToSourceMap[source->m_object] = root;
+        if (serverAddress().isValid()) {
+            const auto &type = source->m_api->typeName();
+            emit remoteObjectAdded(qMakePair(name, QRemoteObjectSourceLocationInfo(type, serverAddress())));
+        }
+    }
+}
+
+void QRemoteObjectSourceIo::unregisterSource(QRemoteObjectSourceBase *source)
+{
+    Q_ASSERT(source);
+    const QString &name = source->name();
+    m_sourceObjects.remove(name);
+    if (source->isRoot()) {
+        const auto type = source->m_api->typeName();
+        m_objectToSourceMap.remove(source->m_object);
+        m_sourceRoots.remove(name);
+        if (serverAddress().isValid())
+            emit remoteObjectRemoved(qMakePair(name, QRemoteObjectSourceLocationInfo(type, serverAddress())));
+    }
+}
+
+void QRemoteObjectSourceIo::onServerDisconnect(QObject *conn)
+{
+    QtROIoDeviceBase *connection = qobject_cast<QtROIoDeviceBase*>(conn);
+    m_connections.remove(connection);
+
+    qRODebug(this) << "OnServerDisconnect";
+
+    for (QRemoteObjectRootSource *root : qAsConst(m_sourceRoots))
+        root->removeListener(connection);
+
+    const QUrl location = m_registryMapping.value(connection);
+    emit serverRemoved(location);
+    m_registryMapping.remove(connection);
+    connection->close();
+    connection->deleteLater();
+}
+
+void QRemoteObjectSourceIo::onServerRead(QObject *conn)
+{
+    // Assert the invariant here conn is of type QIODevice
+    QtROIoDeviceBase *connection = qobject_cast<QtROIoDeviceBase*>(conn);
+    QRemoteObjectPacketTypeEnum packetType;
+
+    do {
+
+        if (!connection->read(packetType, m_rxName))
+            return;
+
+        using namespace QRemoteObjectPackets;
+
+        switch (packetType) {
+        case Ping:
+            m_codec->serializePongPacket(m_rxName);
+            m_codec->send(connection);
+            break;
+        case AddObject:
+        {
+            bool isDynamic;
+            m_codec->deserializeAddObjectPacket(connection->d_func()->stream(), isDynamic);
+            qRODebug(this) << "AddObject" << m_rxName << isDynamic;
+            if (m_sourceRoots.contains(m_rxName)) {
+                QRemoteObjectRootSource *root = m_sourceRoots[m_rxName];
+                root->addListener(connection, isDynamic);
+            } else {
+                qROWarning(this) << "Request to attach to non-existent RemoteObjectSource:" << m_rxName;
+            }
+            break;
+        }
+        case RemoveObject:
+        {
+            qRODebug(this) << "RemoveObject" << m_rxName;
+            if (m_sourceRoots.contains(m_rxName)) {
+                QRemoteObjectRootSource *root = m_sourceRoots[m_rxName];
+                const int count = root->removeListener(connection);
+                Q_UNUSED(count);
+                //TODO - possible to have a timer that closes connections if not reopened within a timeout?
+            } else {
+                qROWarning(this) << "Request to detach from non-existent RemoteObjectSource:" << m_rxName;
+            }
+            qRODebug(this) << "RemoveObject finished" << m_rxName;
+            break;
+        }
+        case InvokePacket:
+        {
+            int call, index, serialId, propertyId;
+            m_codec->deserializeInvokePacket(connection->d_func()->stream(), call, index, m_rxArgs, serialId, propertyId);
+            if (m_rxName == QLatin1String("Registry") && !m_registryMapping.contains(connection)) {
+                const QRemoteObjectSourceLocation loc = m_rxArgs.first().value<QRemoteObjectSourceLocation>();
+                m_registryMapping[connection] = loc.second.hostUrl;
+            }
+            if (m_sourceObjects.contains(m_rxName)) {
+                QRemoteObjectSourceBase *source = m_sourceObjects[m_rxName];
+                if (call == QMetaObject::InvokeMetaMethod) {
+                    const int resolvedIndex = source->m_api->sourceMethodIndex(index);
+                    if (resolvedIndex < 0) { //Invalid index
+                        qROWarning(this) << "Invalid method invoke packet received.  Index =" << index <<"which is out of bounds for type"<<m_rxName;
+                        //TODO - consider moving this to packet validation?
+                        break;
+                    }
+                    if (source->m_api->isAdapterMethod(index))
+                        qRODebug(this) << "Adapter (method) Invoke-->" << m_rxName << source->m_adapter->metaObject()->method(resolvedIndex).name();
+                    else {
+                        qRODebug(this) << "Source (method) Invoke-->" << m_rxName << source->m_object->metaObject()->method(resolvedIndex).methodSignature();
+                        auto method = source->m_object->metaObject()->method(resolvedIndex);
+                        const int parameterCount = method.parameterCount();
+                        for (int i = 0; i < parameterCount; i++)
+                            m_rxArgs[i] = decodeVariant(std::move(m_rxArgs[i]), method.parameterMetaType(i));
+                    }
+                    auto metaType = QMetaType::fromName(source->m_api->typeName(index).constData());
+                    if (!metaType.sizeOf())
+                        metaType = QMetaType(QMetaType::UnknownType);
+                    QVariant returnValue(metaType, nullptr);
+                    // If a Replica is used as a Source (which node->proxy() does) we can have a PendingCall return value.
+                    // In this case, we need to wait for the pending call and send that.
+                    if (source->m_api->typeName(index) == QByteArrayLiteral("QRemoteObjectPendingCall"))
+                        returnValue = QVariant::fromValue<QRemoteObjectPendingCall>(QRemoteObjectPendingCall());
+                    source->invoke(QMetaObject::InvokeMetaMethod, index, m_rxArgs, &returnValue);
+                    // send reply if wanted
+                    if (serialId >= 0) {
+                        if (returnValue.canConvert<QRemoteObjectPendingCall>()) {
+                            QRemoteObjectPendingCall call = returnValue.value<QRemoteObjectPendingCall>();
+                            // Watcher will be destroyed when connection is, or when the finished lambda is called
+                            QRemoteObjectPendingCallWatcher *watcher = new QRemoteObjectPendingCallWatcher(call, connection);
+                            QObject::connect(watcher, &QRemoteObjectPendingCallWatcher::finished, connection, [this, serialId, connection, watcher]() {
+                                if (watcher->error() == QRemoteObjectPendingCall::NoError) {
+                                    m_codec->serializeInvokeReplyPacket(this->m_rxName, serialId, encodeVariant(watcher->returnValue()));
+                                    m_codec->send(connection);
+                                }
+                                watcher->deleteLater();
+                            });
+                        } else {
+                            m_codec->serializeInvokeReplyPacket(m_rxName, serialId, encodeVariant(returnValue));
+                            m_codec->send(connection);
+                        }
+                    }
+                } else {
+                    const int resolvedIndex = source->m_api->sourcePropertyIndex(index);
+                    if (resolvedIndex < 0) {
+                        qROWarning(this) << "Invalid property invoke packet received.  Index =" << index <<"which is out of bounds for type"<<m_rxName;
+                        //TODO - consider moving this to packet validation?
+                        break;
+                    }
+                    if (source->m_api->isAdapterProperty(index))
+                        qRODebug(this) << "Adapter (write property) Invoke-->" << m_rxName << source->m_adapter->metaObject()->property(resolvedIndex).name();
+                    else
+                        qRODebug(this) << "Source (write property) Invoke-->" << m_rxName << source->m_object->metaObject()->property(resolvedIndex).name();
+                    source->invoke(QMetaObject::WriteProperty, index, m_rxArgs);
+                }
+            }
+            break;
+        }
+        default:
+            qRODebug(this) << "OnReadReady invalid type" << packetType;
+        }
+    } while (connection->bytesAvailable()); // have bytes left over, so do another iteration
+}
+
+void QRemoteObjectSourceIo::handleConnection()
+{
+    qRODebug(this) << "handleConnection" << m_connections;
+
+    QtROServerIoDevice *conn = m_server->nextPendingConnection();
+    newConnection(conn);
+}
+
+void QRemoteObjectSourceIo::newConnection(QtROIoDeviceBase *conn)
+{
+    m_connections.insert(conn);
+    connect(conn, &QtROIoDeviceBase::readyRead, this, [this, conn]() {
+        onServerRead(conn);
+    });
+    connect(conn, &QtROIoDeviceBase::disconnected, this, [this, conn]() {
+        onServerDisconnect(conn);
+    });
+
+    m_codec->serializeHandshakePacket();
+    m_codec->send(conn);
+
+    QRemoteObjectPackets::ObjectInfoList infos;
+    infos.reserve(m_sourceRoots.size());
+    for (auto remoteObject : qAsConst(m_sourceRoots)) {
+        infos << QRemoteObjectPackets::ObjectInfo{remoteObject->m_api->name(), remoteObject->m_api->typeName(), remoteObject->m_api->objectSignature()};
+    }
+    m_codec->serializeObjectListPacket(infos);
+    m_codec->send(conn);
+    qRODebug(this) << "Wrote ObjectList packet from Server" << QStringList(m_sourceRoots.keys());
+}
+
+QUrl QRemoteObjectSourceIo::serverAddress() const
+{
+    if (m_server)
+        return m_server->address();
+    return m_address;
+}
+
+QT_END_NAMESPACE
diff --git a/src/remoteobjects/qremoteobjectsourceio_p.h b/src/remoteobjects/qremoteobjectsourceio_p.h
new file mode 100644 (file)
index 0000000..37d952e
--- /dev/null
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** 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 QREMOTEOBJECTSOURCEIO_P_H
+#define QREMOTEOBJECTSOURCEIO_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 "qtremoteobjectglobal.h"
+#include "qremoteobjectpacket_p.h"
+
+#include <QtCore/qiodevice.h>
+#include <QtCore/qscopedpointer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRemoteObjectSourceBase;
+class QRemoteObjectRootSource;
+class SourceApiMap;
+class QRemoteObjectHostBase;
+
+class QRemoteObjectSourceIo : public QObject
+{
+    Q_OBJECT
+public:
+    explicit QRemoteObjectSourceIo(const QUrl &address, QObject *parent = nullptr);
+    explicit QRemoteObjectSourceIo(QObject *parent = nullptr);
+    ~QRemoteObjectSourceIo() override;
+
+    bool startListening();
+    bool enableRemoting(QObject *object, const QMetaObject *meta, const QString &name,
+                        const QString &typeName);
+    bool enableRemoting(QObject *object, const SourceApiMap *api, QObject *adapter = nullptr);
+    bool disableRemoting(QObject *object);
+    void newConnection(QtROIoDeviceBase *conn);
+
+    QUrl serverAddress() const;
+
+public Q_SLOTS:
+    void handleConnection();
+    void onServerDisconnect(QObject *obj = nullptr);
+    void onServerRead(QObject *obj);
+
+Q_SIGNALS:
+    void remoteObjectAdded(const QRemoteObjectSourceLocation &);
+    void remoteObjectRemoved(const QRemoteObjectSourceLocation &);
+    void serverRemoved(const QUrl& url);
+
+public:
+    void registerSource(QRemoteObjectSourceBase *source);
+    void unregisterSource(QRemoteObjectSourceBase *source);
+
+    QHash<QIODevice*, quint32> m_readSize;
+    QSet<QtROIoDeviceBase*> m_connections;
+    QHash<QObject *, QRemoteObjectRootSource*> m_objectToSourceMap;
+    QMap<QString, QRemoteObjectSourceBase*> m_sourceObjects;
+    QMap<QString, QRemoteObjectRootSource*> m_sourceRoots;
+    QHash<QtROIoDeviceBase*, QUrl> m_registryMapping;
+    QScopedPointer<QConnectionAbstractServer> m_server;
+    // TODO should have some sort of manager for the codec
+    QScopedPointer<QRemoteObjectPackets::CodecBase> m_codec{new QRemoteObjectPackets::QDataStreamCodec};
+    QString m_rxName;
+    QVariantList m_rxArgs;
+    QUrl m_address;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/remoteobjects/qtremoteobjectglobal.cpp b/src/remoteobjects/qtremoteobjectglobal.cpp
new file mode 100644 (file)
index 0000000..f83db9b
--- /dev/null
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** 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 "qtremoteobjectglobal.h"
+#include "qremoteobjectpacket_p.h"
+
+#include <QtCore/qdatastream.h>
+#include <QtCore/qmetaobject.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(QT_REMOTEOBJECT, "qt.remoteobjects", QtWarningMsg)
+Q_LOGGING_CATEGORY(QT_REMOTEOBJECT_MODELS, "qt.remoteobjects.models", QtWarningMsg)
+Q_LOGGING_CATEGORY(QT_REMOTEOBJECT_IO, "qt.remoteobjects.io", QtWarningMsg)
+
+/*!
+    \namespace QtRemoteObjects
+    \inmodule QtRemoteObjects
+
+    \brief The QtRemoteObjects namespace contains identifiers used in the
+    Remote Objects module, as well as some functions used from code generated
+    by the \l{Qt Remote Objects Compiler}{Replica Compiler (repc)}.
+*/
+
+/*!
+    \enum QtRemoteObjects::InitialAction
+
+    This enum type specifies the initial action when acquiring a \l Replica derived
+    from QAbstractItemModel.
+
+    \value FetchRootSize Only the size of the model is requested before the
+                         \l {QRemoteObjectReplica::}{initialized} signal is emitted,
+                         no data will be prefetched before that.
+    \value PrefetchData  Some data can be prefetched before the
+                         \l {QRemoteObjectReplica::}{initialized} signal is emitted.
+
+    \sa QRemoteObjectNode::acquireModel(), QRemoteObjectReplica::initialized()
+*/
+
+namespace QtRemoteObjects {
+
+void copyStoredProperties(const QMetaObject *mo, const void *src, void *dst)
+{
+    if (!src) {
+        qCWarning(QT_REMOTEOBJECT) << Q_FUNC_INFO << ": trying to copy from a null source";
+        return;
+    }
+    if (!dst) {
+        qCWarning(QT_REMOTEOBJECT) << Q_FUNC_INFO << ": trying to copy to a null destination";
+        return;
+    }
+
+    for (int i = 0, end = mo->propertyCount(); i != end; ++i) {
+        const QMetaProperty mp = mo->property(i);
+        mp.writeOnGadget(dst, mp.readOnGadget(src));
+    }
+}
+
+void copyStoredProperties(const QMetaObject *mo, const void *src, QDataStream &dst)
+{
+    if (!src) {
+        qCWarning(QT_REMOTEOBJECT) << Q_FUNC_INFO << ": trying to copy from a null source";
+        return;
+    }
+
+    for (int i = 0, end = mo->propertyCount(); i != end; ++i) {
+        const QMetaProperty mp = mo->property(i);
+        dst << QRemoteObjectPackets::encodeVariant(mp.readOnGadget(src));
+    }
+}
+
+void copyStoredProperties(const QMetaObject *mo, QDataStream &src, void *dst)
+{
+    if (!dst) {
+        qCWarning(QT_REMOTEOBJECT) << Q_FUNC_INFO << ": trying to copy to a null destination";
+        return;
+    }
+
+    for (int i = 0, end = mo->propertyCount(); i != end; ++i) {
+        const QMetaProperty mp = mo->property(i);
+        QVariant v;
+        src >> v;
+        mp.writeOnGadget(dst, QRemoteObjectPackets::decodeVariant(std::move(v), mp.metaType()));
+    }
+}
+
+} // namespace QtRemoteObjects
+
+QT_END_NAMESPACE
diff --git a/src/remoteobjects/qtremoteobjectglobal.h b/src/remoteobjects/qtremoteobjectglobal.h
new file mode 100644 (file)
index 0000000..600636a
--- /dev/null
@@ -0,0 +1,188 @@
+/****************************************************************************
+**
+** 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 QTREMOTEOBJECTGLOBAL_H
+#define QTREMOTEOBJECTGLOBAL_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qloggingcategory.h>
+
+QT_BEGIN_NAMESPACE
+
+struct QRemoteObjectSourceLocationInfo
+{
+    QRemoteObjectSourceLocationInfo() = default;
+    QRemoteObjectSourceLocationInfo(const QString &typeName_, const QUrl &hostUrl_)
+        : typeName(typeName_), hostUrl(hostUrl_) {}
+
+    inline bool operator==(const QRemoteObjectSourceLocationInfo &other) const Q_DECL_NOTHROW
+    {
+        return other.typeName == typeName && other.hostUrl == hostUrl;
+    }
+    inline bool operator!=(const QRemoteObjectSourceLocationInfo &other) const Q_DECL_NOTHROW
+    {
+        return !(*this == other);
+    }
+
+    QString typeName;
+    QUrl hostUrl;
+};
+
+inline QDebug operator<<(QDebug dbg, const QRemoteObjectSourceLocationInfo &info)
+{
+    dbg.nospace() << "SourceLocationInfo(" << info.typeName << ", " << info.hostUrl << ")";
+    return dbg.space();
+}
+
+inline QDataStream& operator<<(QDataStream &stream, const QRemoteObjectSourceLocationInfo &info)
+{
+    return stream << info.typeName << info.hostUrl;
+}
+
+inline QDataStream& operator>>(QDataStream &stream, QRemoteObjectSourceLocationInfo &info)
+{
+    return stream >> info.typeName >> info.hostUrl;
+}
+
+typedef QPair<QString, QRemoteObjectSourceLocationInfo> QRemoteObjectSourceLocation;
+typedef QHash<QString, QRemoteObjectSourceLocationInfo> QRemoteObjectSourceLocations;
+typedef QHash<int, QByteArray> QIntHash;
+
+QT_END_NAMESPACE
+Q_DECLARE_METATYPE(QRemoteObjectSourceLocation)
+Q_DECLARE_METATYPE(QRemoteObjectSourceLocations)
+Q_DECLARE_METATYPE(QIntHash)
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_STATIC
+#  if defined(QT_BUILD_REMOTEOBJECTS_LIB)
+#    define Q_REMOTEOBJECTS_EXPORT Q_DECL_EXPORT
+#  else
+#    define Q_REMOTEOBJECTS_EXPORT Q_DECL_IMPORT
+#  endif
+#else
+#  define Q_REMOTEOBJECTS_EXPORT
+#endif
+
+#define QCLASSINFO_REMOTEOBJECT_TYPE "RemoteObject Type"
+#define QCLASSINFO_REMOTEOBJECT_SIGNATURE "RemoteObject Signature"
+
+class QDataStream;
+
+namespace QRemoteObjectStringLiterals {
+
+// when QStringLiteral is used with the same string in different functions,
+// it creates duplicate static data. Wrapping it in inline functions prevents it.
+
+inline QString local() { return QStringLiteral("local"); }
+inline QString localabstract() { return QStringLiteral("localabstract"); }
+inline QString tcp() { return QStringLiteral("tcp"); }
+inline QString CLASS() { return QStringLiteral("Class::%1"); }
+inline QString MODEL() { return QStringLiteral("Model::%1"); }
+inline QString QAIMADAPTER() { return QStringLiteral("QAbstractItemModelAdapter"); }
+
+}
+
+Q_DECLARE_LOGGING_CATEGORY(QT_REMOTEOBJECT)
+Q_DECLARE_LOGGING_CATEGORY(QT_REMOTEOBJECT_MODELS)
+Q_DECLARE_LOGGING_CATEGORY(QT_REMOTEOBJECT_IO)
+
+namespace QtRemoteObjects {
+
+Q_NAMESPACE
+
+Q_REMOTEOBJECTS_EXPORT void copyStoredProperties(const QMetaObject *mo, const void *src, void *dst);
+Q_REMOTEOBJECTS_EXPORT void copyStoredProperties(const QMetaObject *mo, const void *src, QDataStream &dst);
+Q_REMOTEOBJECTS_EXPORT void copyStoredProperties(const QMetaObject *mo, QDataStream &src, void *dst);
+
+QString getTypeNameAndMetaobjectFromClassInfo(const QMetaObject *& meta);
+
+template <typename T>
+void copyStoredProperties(const T *src, T *dst)
+{
+    copyStoredProperties(&T::staticMetaObject, src, dst);
+}
+
+template <typename T>
+void copyStoredProperties(const T *src, QDataStream &dst)
+{
+    copyStoredProperties(&T::staticMetaObject, src, dst);
+}
+
+template <typename T>
+void copyStoredProperties(QDataStream &src, T *dst)
+{
+    copyStoredProperties(&T::staticMetaObject, src, dst);
+}
+
+template <typename E>
+constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept {
+    return static_cast<typename std::underlying_type<E>::type>(e);
+}
+
+enum QRemoteObjectPacketTypeEnum
+{
+    Invalid = 0,
+    Handshake,
+    InitPacket,
+    InitDynamicPacket,
+    AddObject,
+    RemoveObject,
+    InvokePacket,
+    InvokeReplyPacket,
+    PropertyChangePacket,
+    ObjectList,
+    Ping,
+    Pong
+};
+Q_ENUM_NS(QRemoteObjectPacketTypeEnum)
+
+enum InitialAction {
+    FetchRootSize,
+    PrefetchData
+};
+Q_ENUM_NS(InitialAction)
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QTREMOTEOBJECTSGLOBAL_H
diff --git a/src/remoteobjectsqml/CMakeLists.txt b/src/remoteobjectsqml/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7b49f62
--- /dev/null
@@ -0,0 +1,19 @@
+
+#####################################################################
+## qtremoteobjects Plugin:
+#####################################################################
+
+qt_internal_add_qml_module(RemoteObjectsQml
+    URI "QtRemoteObjects"
+    VERSION "${PROJECT_VERSION}"
+    PLUGIN_TARGET declarative_remoteobjects
+    CLASS_NAME QtRemoteObjectsPlugin
+    SOURCES
+        qremoteobjectsqml_p.h
+    PUBLIC_LIBRARIES
+        Qt::Core
+        Qt::Gui
+        Qt::Qml
+        Qt::QmlPrivate
+        Qt::RemoteObjects
+)
diff --git a/src/remoteobjectsqml/qremoteobjectsqml_p.h b/src/remoteobjectsqml/qremoteobjectsqml_p.h
new file mode 100644 (file)
index 0000000..d56a430
--- /dev/null
@@ -0,0 +1,184 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** 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 QREMOTEOBJECTSQML_P_H
+#define QREMOTEOBJECTSQML_P_H
+
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtRemoteObjects/qremoteobjectpendingcall.h>
+#include <QtRemoteObjects/qremoteobjectsettingsstore.h>
+
+#include <QtCore/qtimer.h>
+#include <QtQml/QJSValue>
+#include <QtQml/private/qjsvalue_p.h>
+#include <QtQml/qqml.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlinfo.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.
+//
+
+QT_BEGIN_NAMESPACE
+
+struct QtQmlRemoteObjectsResponse
+{
+    QJSValue promise;
+    QTimer *timer;
+};
+
+// documentation updates for this class can be made in remoteobjects-qml.qdoc
+class QtQmlRemoteObjects : public QObject
+{
+    Q_OBJECT
+    QML_NAMED_ELEMENT(QtRemoteObjects)
+    QML_SINGLETON
+    QML_ADDED_IN_VERSION(5, 14)
+
+public:
+    ~QtQmlRemoteObjects()
+    {
+        auto i = m_callbacks.begin();
+        while (i != m_callbacks.end()) {
+            delete i.key();
+            delete i.value().timer;
+            i = m_callbacks.erase(i);
+        }
+    }
+
+    Q_INVOKABLE QJSValue watch(const QRemoteObjectPendingCall &reply, int timeout = 30000)
+    {
+        if (m_accessiblePromise.isUndefined())
+            m_accessiblePromise = qmlEngine(this)->evaluate(QLatin1String(
+                    "(function() { var obj = {}; obj.promise = new Promise(function(resolve, "
+                    "reject) { obj.resolve = resolve; obj.reject = reject; }); return obj; })"));
+
+        QRemoteObjectPendingCallWatcher *watcher = new QRemoteObjectPendingCallWatcher(reply);
+
+        QJSValue promise = m_accessiblePromise.call();
+        QtQmlRemoteObjectsResponse response;
+        response.promise = promise;
+        response.timer = new QTimer();
+        response.timer->setSingleShot(true);
+        m_callbacks.insert(watcher, response);
+
+        // handle timeout
+        connect(response.timer, &QTimer::timeout, [this, watcher]() {
+            auto i = m_callbacks.find(watcher);
+            if (i == m_callbacks.end()) {
+                qmlWarning(this) << "could not find callback for watcher.";
+                return;
+            }
+
+            QJSValue v(QLatin1String("timeout"));
+            i.value().promise.property(QLatin1String("reject")).call(QJSValueList() << v);
+
+            delete i.key();
+            delete i.value().timer;
+            m_callbacks.erase(i);
+        });
+
+        // handle success
+        connect(watcher, &QRemoteObjectPendingCallWatcher::finished,
+                [this](QRemoteObjectPendingCallWatcher *self) {
+                    auto i = m_callbacks.find(self);
+                    if (i == m_callbacks.end()) {
+                        qmlWarning(this) << "could not find callback for watcher.";
+                        return;
+                    }
+                    QJSValue v = qmlEngine(this)->toScriptValue(self->returnValue());
+                    i.value().promise.property(QLatin1String("resolve")).call(QJSValueList() << v);
+
+                    delete i.key();
+                    delete i.value().timer;
+                    m_callbacks.erase(i);
+                });
+
+        response.timer->start(timeout);
+        return promise.property(QLatin1String("promise"));
+    }
+
+private:
+    QHash<QRemoteObjectPendingCallWatcher *, QtQmlRemoteObjectsResponse> m_callbacks;
+    QJSValue m_accessiblePromise;
+};
+
+struct QRemoteObjectNodeForeign
+{
+    Q_GADGET
+    QML_FOREIGN(QRemoteObjectNode)
+    QML_NAMED_ELEMENT(Node)
+    QML_ADDED_IN_VERSION(5, 12)
+};
+
+struct QRemoteObjectSettingsStoreForeign
+{
+    Q_GADGET
+    QML_FOREIGN(QRemoteObjectSettingsStore)
+    QML_NAMED_ELEMENT(SettingsStore)
+    QML_ADDED_IN_VERSION(5, 12)
+};
+
+struct QRemoteObjectHostForeign
+{
+    Q_GADGET
+    QML_FOREIGN(QRemoteObjectHost)
+    QML_NAMED_ELEMENT(Host)
+    QML_ADDED_IN_VERSION(5, 15)
+};
+
+struct QRemoteObjectAbstractPersistedStoreForeign
+{
+    Q_GADGET
+    QML_FOREIGN(QRemoteObjectAbstractPersistedStore)
+    QML_NAMED_ELEMENT(PersistedStore)
+    QML_UNCREATABLE("QRemoteObjectAbstractPersistedStore is Abstract")
+    QML_ADDED_IN_VERSION(5, 12)
+};
+
+QT_END_NAMESPACE
+
+#endif // QREMOTEOBJECTSQML_P_H
diff --git a/src/repparser/CMakeLists.txt b/src/repparser/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6dcf2a2
--- /dev/null
@@ -0,0 +1,15 @@
+
+#####################################################################
+## RepParser Module:
+#####################################################################
+
+qt_internal_add_module(RepParser
+    HEADER_MODULE
+    PUBLIC_LIBRARIES
+        Qt::Core
+)
+
+qt_internal_module_info(module RepParser)
+qt_path_join(parser_install_dir "${QT_INSTALL_DIR}" "${INSTALL_INCLUDEDIR}" "${module}")
+
+qt_copy_or_install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/parser.g" DESTINATION "${parser_install_dir}")
diff --git a/src/repparser/parser.g b/src/repparser/parser.g
new file mode 100644 (file)
index 0000000..77ed224
--- /dev/null
@@ -0,0 +1,1470 @@
+----------------------------------------------------------------------------
+--
+-- Copyright (C) 2014-2020 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$
+--
+----------------------------------------------------------------------------
+
+%parser rep_grammar
+%decl repparser.h
+%impl repparser.cpp
+
+%token_prefix Token_
+%token semicolon "[semicolon];"
+%token class "[class]class[ \\t]+(?<name>[A-Za-z_][A-Za-z0-9_]+)[ \\t]*"
+%token pod "[pod]POD[ \\t]*(?<name>[A-Za-z_][A-Za-z0-9_]+)[ \\t]*\\((?<types>[^\\)]*)\\);?[ \\t]*"
+%token pod2 "[pod2]POD[ \\t]*(?<name>[A-Za-z_][A-Za-z0-9_]+)[ \\t]*"
+%token flag "[flag][ \\t]*FLAG[ \t]*\\([ \t]*(?<name>[A-Za-z_][A-Za-z0-9_]*)[ \t]+(?<enum>[A-Za-z_][A-Za-z0-9_]*)[ \t]*\\)[ \t]*"
+%token enum "[enum][ \\t]*ENUM[ \t]+(?:(?<class>class[ \t]+))?(?<name>[A-Za-z_][A-Za-z0-9_]*)[ \t]*(?::[ \t]*(?<type>[a-zA-Z0-9 _:]*[a-zA-Z0-9_])[ \t]*)?"
+%token prop "[prop][ \\t]*PROP[ \\t]*\\((?<args>[^\\)]+)\\);?[ \\t]*"
+%token use_enum "[use_enum]USE_ENUM[ \\t]*\\((?<name>[^\\)]*)\\);?[ \\t]*"
+%token signal "[signal][ \\t]*SIGNAL[ \\t]*\\([ \\t]*(?<name>\\S+)[ \\t]*\\((?<args>[^\\)]*)\\)[ \\t]*\\);?[ \\t]*"
+%token slot "[slot][ \\t]*SLOT[ \\t]*\\((?<type>[^\\(]*)\\((?<args>[^\\)]*)\\)[ \\t]*\\);?[ \\t]*"
+%token model "[model][ \\t]*MODEL[ \\t]+(?<name>[A-Za-z_][A-Za-z0-9_]+)\\((?<args>[^\\)]+)\\)[ \\t]*;?[ \\t]*"
+%token childrep "[childrep][ \\t]*CLASS[ \\t]+(?<name>[A-Za-z_][A-Za-z0-9_]+)\\((?<type>[^\\)]+)\\)[ \\t]*;?[ \\t]*"
+%token qualifier "[qualifier][ \\t]*(?<value>const|unsigned|signed)[ \\t]*"
+%token passbyqual "[passbyqual][ \\t]*(?<value>&)[ \\t]*"
+%token symbol "[symbol][ \\t]*(?<symbol>[A-Za-z_][A-Za-z0-9_]*)[ \\t]*"
+%token value "[value][ \\t]*(?<value>-\\d+|0[xX][0-9A-Fa-f]+|\\d+)[ \\t]*"
+%token start "[start][ \\t]*\\{[ \\t]*"
+%token stop "[stop][ \\t]*\\};?[ \\t]*"
+%token comma "[comma],"
+%token equals "[equals]="
+%token comment "[comment](?<comment>[ \\t]*//[^\\n]*\\n)"
+%token mcomment "[mcomment,M](?<comment>/\\*(.*?)\\*/)"
+%token preprocessor_directive "[preprocessor_directive](?<preprocessor_directive>#[ \\t]*[^\\n]*\\n)"
+%token newline "[newline](\\r)?\\n"
+%token tstart "[tstart]<"
+%token tstop "[tstop]>[ \\t]*"
+
+%start TopLevel
+
+/:
+#ifndef REPPARSER_H
+#define REPPARSER_H
+
+#include <rep_grammar_p.h>
+#include <qregexparser.h>
+#include <QStringList>
+#include <QList>
+#include <QRegularExpression>
+
+QT_BEGIN_NAMESPACE
+class QIODevice;
+class QCryptographicHash;
+
+struct AST;
+
+struct SignedType
+{
+    SignedType(const QString &name = QString());
+    virtual ~SignedType() {}
+    void generateSignature(AST &ast);
+    virtual QString typeName() const;
+    virtual void signature_impl(const AST &ast, QCryptographicHash &checksum) = 0;
+    QString name;
+};
+
+/// A property of a Class declaration
+struct ASTProperty
+{
+    enum Modifier
+    {
+        Constant,
+        ReadOnly,
+        ReadPush,
+        ReadWrite,
+        SourceOnlySetter
+    };
+
+    ASTProperty();
+    ASTProperty(const QString &type, const QString &name, const QString &defaultValue, Modifier modifier, bool persisted,
+                bool isPointer=false);
+
+    QString type;
+    QString name;
+    QString defaultValue;
+    Modifier modifier;
+    bool persisted;
+    bool isPointer;
+};
+Q_DECLARE_TYPEINFO(ASTProperty, Q_RELOCATABLE_TYPE);
+
+struct ASTDeclaration
+{
+    enum VariableType {
+        None = 0,
+        Constant = 1,
+        Reference = 2,
+    };
+    Q_DECLARE_FLAGS(VariableTypes, VariableType)
+
+    ASTDeclaration(const QString &declarationType = QString(), const QString &declarationName = QString(), VariableTypes declarationVariableType = None)
+        : type(declarationType),
+          name(declarationName),
+          variableType(declarationVariableType)
+    {
+    }
+
+    QString asString(bool withName) const;
+
+    QString type;
+    QString name;
+    VariableTypes variableType;
+};
+Q_DECLARE_TYPEINFO(ASTDeclaration, Q_RELOCATABLE_TYPE);
+
+struct ASTFunction
+{
+    enum ParamsAsStringFormat {
+        Default,
+        Normalized
+    };
+
+    explicit ASTFunction(const QString &name = QString(), const QString &returnType = QLatin1String("void"));
+
+    QString paramsAsString(ParamsAsStringFormat format = Default) const;
+    QStringList paramNames() const;
+
+    QString returnType;
+    QString name;
+    QList<ASTDeclaration> params;
+};
+Q_DECLARE_TYPEINFO(ASTFunction, Q_RELOCATABLE_TYPE);
+
+struct ASTEnumParam
+{
+    ASTEnumParam(const QString &paramName = QString(), int paramValue = 0)
+        : name(paramName),
+          value(paramValue)
+    {
+    }
+
+    QString asString() const;
+
+    QString name;
+    int value;
+};
+Q_DECLARE_TYPEINFO(ASTEnumParam, Q_RELOCATABLE_TYPE);
+
+struct ASTEnum : public SignedType
+{
+    explicit ASTEnum(const QString &name = QString());
+    void signature_impl(const AST &ast, QCryptographicHash &checksum) override;
+    QString typeName() const override;
+
+    QString type;
+    QString scope;
+    QList<ASTEnumParam> params;
+    bool isSigned;
+    bool isScoped;
+    int max;
+    int flagIndex = -1;
+};
+Q_DECLARE_TYPEINFO(ASTEnum, Q_RELOCATABLE_TYPE);
+
+struct ASTFlag : public SignedType
+{
+    explicit ASTFlag(const QString &name = {}, const QString &_enum = {});
+    void signature_impl(const AST &ast, QCryptographicHash &checksum) override;
+    QString typeName() const override;
+
+    bool isValid() const;
+    QString _enum;
+    QString scope;
+};
+Q_DECLARE_TYPEINFO(ASTFlag, Q_RELOCATABLE_TYPE);
+
+struct ASTModelRole
+{
+    ASTModelRole(const QString &roleName = QString())
+        : name(roleName)
+    {
+    }
+
+    QString name;
+};
+Q_DECLARE_TYPEINFO(ASTModelRole, Q_RELOCATABLE_TYPE);
+
+struct ASTModel : public SignedType
+{
+    ASTModel(const QString &name, const QString &scope, int index = -1)
+        : SignedType(name), scope(scope), propertyIndex(index) {}
+    void signature_impl(const AST &ast, QCryptographicHash &checksum) override;
+    QString typeName() const override;
+
+    QList<ASTModelRole> roles;
+    QString scope;
+    int propertyIndex;
+};
+Q_DECLARE_TYPEINFO(ASTModel, Q_RELOCATABLE_TYPE);
+
+/// A Class declaration
+struct ASTClass : public SignedType
+{
+    explicit ASTClass(const QString& name = QString());
+    void signature_impl(const AST &ast, QCryptographicHash &checksum) override;
+
+    bool isValid() const;
+    bool hasPointerObjects() const;
+
+    QList<ASTProperty> properties;
+    QList<ASTFunction> signalsList;
+    QList<ASTFunction> slotsList;
+    QList<ASTEnum> enums;
+    QList<ASTFlag> flags;
+    bool hasPersisted;
+    QList<ASTModel> modelMetadata;
+    QList<int> subClassPropertyIndices;
+};
+Q_DECLARE_TYPEINFO(ASTClass, Q_RELOCATABLE_TYPE);
+
+// The attribute of a POD
+struct PODAttribute
+{
+    explicit PODAttribute(const QString &type_ = QString(), const QString &name_ = QString())
+        : type(type_),
+          name(name_)
+    {}
+    QString type;
+    QString name;
+};
+Q_DECLARE_TYPEINFO(PODAttribute, Q_RELOCATABLE_TYPE);
+
+// A POD declaration
+struct POD : public SignedType
+{
+    void signature_impl(const AST &ast, QCryptographicHash &checksum) override;
+
+    QList<PODAttribute> attributes;
+    QList<ASTEnum> enums;
+    QList<ASTFlag> flags;
+};
+Q_DECLARE_TYPEINFO(POD, Q_RELOCATABLE_TYPE);
+
+// The AST representation of a .rep file
+struct AST
+{
+    QList<ASTClass> classes;
+    QList<POD> pods;
+    QList<ASTEnum> enums;
+    QList<ASTFlag> flags;
+    QList<QString> enumUses;
+    QStringList preprocessorDirectives;
+    QHash<QString, QByteArray> typeSignatures;
+    QByteArray typeData(const QString &type, const QString &className) const;
+    QByteArray functionsData(const QList<ASTFunction> &functions, const QString &className) const;
+};
+Q_DECLARE_TYPEINFO(AST, Q_RELOCATABLE_TYPE);
+
+class RepParser: public QRegexParser<RepParser, $table>
+{
+public:
+    explicit RepParser(QIODevice &outputDevice);
+    virtual ~RepParser() {}
+
+    bool parse() override { return QRegexParser<RepParser, $table>::parse(); }
+
+    void reset() override;
+    int nextToken();
+    bool consumeRule(int ruleno);
+
+    AST ast() const;
+
+private:
+    struct TypeParser
+    {
+        void parseArguments(const QString &arguments);
+        void appendParams(ASTFunction &slot);
+        void appendPods(POD &pods);
+        void generateFunctionParameter(QString variableName, const QString &propertyType, int &variableNameIndex, ASTDeclaration::VariableTypes variableType);
+        //Type, Variable
+        QList<ASTDeclaration> arguments;
+    };
+
+    bool parseProperty(ASTClass &astClass, const QString &propertyDeclaration);
+    /// A helper function to parse modifier flag of property declaration
+    bool parseModifierFlag(const QString &flag, ASTProperty::Modifier &modifier, bool &persisted);
+
+    bool parseRoles(ASTModel &astModel, const QString &modelRoles);
+
+    AST m_ast;
+
+    ASTClass m_astClass;
+    POD m_astPod;
+    QString m_symbol;
+    QString m_argString;
+    ASTEnum m_astEnum;
+    int m_astEnumValue;
+};
+QT_END_NAMESPACE
+#endif
+:/
+
+
+/.
+#include "repparser.h"
+
+#include <QCryptographicHash>
+#include <QDebug>
+#include <QTextStream>
+
+// for normalizeTypeInternal
+#include <private/qmetaobject_p.h>
+#include <private/qmetaobject_moc_p.h>
+
+// Code copied from moc.cpp
+// We cannot depend on QMetaObject::normalizedSignature,
+// since repc is linked against Qt5Bootstrap (which doesn't offer QMetaObject) when cross-compiling
+// Thus, just use internal API which is exported in private headers, as moc does
+static QByteArray normalizeType(const QByteArray &ba)
+{
+    const char *s = ba.constData();
+    int len = ba.size();
+    char stackbuf[64];
+    char *buf = (len >= 64 ? new char[len + 1] : stackbuf);
+    char *d = buf;
+    char last = 0;
+    while (*s && is_space(*s))
+        s++;
+    while (*s) {
+        while (*s && !is_space(*s))
+            last = *d++ = *s++;
+        while (*s && is_space(*s))
+            s++;
+        if (*s && ((is_ident_char(*s) && is_ident_char(last))
+                   || ((*s == ':') && (last == '<')))) {
+            last = *d++ = ' ';
+        }
+    }
+    *d = '\0';
+    QByteArray result = normalizeTypeInternal(buf, d);
+    if (buf != stackbuf)
+        delete [] buf;
+    return result;
+}
+
+SignedType::SignedType(const QString &name) : name(name)
+{
+}
+
+void SignedType::generateSignature(AST &ast)
+{
+    QCryptographicHash checksum(QCryptographicHash::Sha1);
+    signature_impl(ast, checksum);
+    ast.typeSignatures[typeName()] = checksum.result().toHex();
+}
+
+QString SignedType::typeName() const
+{
+    return name;
+}
+
+ASTProperty::ASTProperty()
+    : modifier(ReadPush), persisted(false), isPointer(false)
+{
+}
+
+ASTProperty::ASTProperty(const QString &type, const QString &name, const QString &defaultValue, Modifier modifier, bool persisted, bool isPointer)
+    : type(type), name(name), defaultValue(defaultValue), modifier(modifier), persisted(persisted), isPointer(isPointer)
+{
+}
+
+QString ASTDeclaration::asString(bool withName) const
+{
+    QString str;
+    if (variableType & ASTDeclaration::Constant)
+        str += QLatin1String("const ");
+    str += type;
+    if (variableType & ASTDeclaration::Reference)
+        str += QLatin1String(" &");
+    if (withName)
+        str += QString::fromLatin1(" %1").arg(name);
+    return str;
+}
+
+ASTFunction::ASTFunction(const QString &name, const QString &returnType)
+    : returnType(returnType), name(name)
+{
+}
+
+QString ASTFunction::paramsAsString(ParamsAsStringFormat format) const
+{
+    QString str;
+    for (const ASTDeclaration &param : params) {
+        QString paramStr = param.asString(format != Normalized);
+        if (format == Normalized) {
+            paramStr = QString::fromLatin1(::normalizeType(paramStr.toLatin1().constData()));
+            str += paramStr + QLatin1Char(',');
+        } else {
+            str += paramStr + QLatin1String(", ");
+        }
+    }
+
+    str.chop((format == Normalized ? 1 : 2)); // chop trailing ',' or ', '
+
+    return str;
+}
+
+QStringList ASTFunction::paramNames() const
+{
+    QStringList names;
+    names.reserve(params.size());
+    for (const ASTDeclaration &param : params)
+        names << param.name;
+    return names;
+}
+
+ASTEnum::ASTEnum(const QString &name)
+    : SignedType(name), isSigned(false), isScoped(false), max(0)
+{
+}
+
+void ASTEnum::signature_impl(const AST &ast, QCryptographicHash &checksum)
+{
+    Q_UNUSED(ast)
+    checksum.addData(name.toLatin1());
+    if (isScoped)
+        checksum.addData("class", qstrlen("class"));
+    if (!type.isEmpty())
+        checksum.addData(type.toLatin1());
+    for (const ASTEnumParam &param : params) {
+        checksum.addData(param.name.toLatin1());
+        checksum.addData(QByteArray::number(param.value));
+    }
+}
+
+QString ASTEnum::typeName() const
+{
+    if (scope.isEmpty())
+        return name;
+
+    return QLatin1String("%1::%2").arg(scope, name);
+}
+
+ASTFlag::ASTFlag(const QString &name, const QString &_enum)
+    : SignedType(name), _enum(_enum)
+{
+}
+
+void ASTFlag::signature_impl(const AST &ast, QCryptographicHash &checksum)
+{
+    checksum.addData(name.toLatin1());
+    checksum.addData(ast.typeData(_enum, scope));
+}
+
+QString ASTFlag::typeName() const
+{
+    if (scope.isEmpty())
+        return name;
+
+    return QLatin1String("%1::%2").arg(scope, name);
+}
+
+bool ASTFlag::isValid() const
+{
+    return !name.isEmpty();
+}
+
+void ASTModel::signature_impl(const AST &ast, QCryptographicHash &checksum)
+{
+    Q_UNUSED(ast)
+    QByteArrayList _roles;
+    for (const auto &role : roles)
+        _roles << role.name.toLatin1();
+    std::sort(_roles.begin(), _roles.end());
+    checksum.addData(_roles.join('_'));
+}
+
+QString ASTModel::typeName() const
+{
+    return QLatin1String("%1::%2").arg(scope, name);
+}
+
+ASTClass::ASTClass(const QString &name)
+    : SignedType(name), hasPersisted(false)
+{
+}
+
+void ASTClass::signature_impl(const AST &ast, QCryptographicHash &checksum)
+{
+    checksum.addData(name.toLatin1());
+
+    // Checksum properties
+    QSet<int> classIndices{ subClassPropertyIndices.begin(),
+                            subClassPropertyIndices.end() };
+    int propertyIndex = -1;
+    int modelIndex = 0;
+    for (const ASTProperty &p : properties) {
+        propertyIndex++;
+        checksum.addData(p.name.toLatin1());
+        if (p.type == QLatin1String("QAbstractItemModel"))
+            checksum.addData(ast.typeSignatures[modelMetadata[modelIndex++].typeName()]);
+        else if (classIndices.contains(propertyIndex))
+            checksum.addData(ast.typeSignatures[p.type]);
+        else
+            checksum.addData(ast.typeData(p.type, name));
+        ASTProperty::Modifier m = p.modifier;
+        // Treat ReadOnly and SourceOnlySetter the same (interface-wise they are)
+        if (m == ASTProperty::SourceOnlySetter)
+            m = ASTProperty::ReadOnly;
+        checksum.addData(reinterpret_cast<const char *>(&m), sizeof(m));
+    }
+
+    // Checksum signals
+    checksum.addData(ast.functionsData(signalsList, name));
+
+    // Checksum slots
+    checksum.addData(ast.functionsData(slotsList, name));
+}
+
+void POD::signature_impl(const AST &ast, QCryptographicHash &checksum)
+{
+    checksum.addData(name.toLatin1());
+    for (const PODAttribute &attr : attributes) {
+        checksum.addData(attr.name.toLatin1());
+        checksum.addData(ast.typeData(attr.type, name));
+    }
+}
+
+bool ASTClass::isValid() const
+{
+    return !name.isEmpty();
+}
+
+bool ASTClass::hasPointerObjects() const
+{
+    int count = modelMetadata.size() + subClassPropertyIndices.size();
+    return count > 0;
+}
+
+QByteArray AST::typeData(const QString &type, const QString &className) const
+{
+    static const QRegularExpression re = QRegularExpression(QLatin1String("([^<>,\\s]+)"));
+    if (type.contains(QLatin1Char('<'))) { // templated type
+        QByteArray result;
+        for (const QRegularExpressionMatch &match : re.globalMatch(type))
+            result += typeData(match.captured(1), className);
+        return result;
+    }
+    // Try enum/flags within the class first
+    if (!className.isEmpty()) {
+        auto classType = QLatin1String("%1::%2").arg(className, type);
+        auto it = typeSignatures.find(classType);
+        if (it != typeSignatures.end())
+            return it.value();
+    }
+    auto it = typeSignatures.find(type);
+    if (it != typeSignatures.end())
+        return it.value();
+    const auto pos = type.lastIndexOf(QLatin1String("::"));
+    if (pos > 0)
+        return typeData(type.mid(pos + 2), className);
+    return type.toLatin1();
+}
+
+QByteArray AST::functionsData(const QList<ASTFunction> &functions, const QString &className) const
+{
+    QByteArray ret;
+    for (const ASTFunction &func : functions) {
+        ret += func.name.toLatin1();
+        for (const ASTDeclaration &param : func.params) {
+            ret += param.name.toLatin1();
+            ret += typeData(param.type, className);
+            ret += QByteArray(reinterpret_cast<const char *>(&param.variableType),
+                              sizeof(param.variableType));
+        }
+        ret += typeData(func.returnType, className);
+    }
+    return ret;
+}
+
+RepParser::RepParser(QIODevice &outputDevice)
+    : QRegexParser(), m_astEnumValue(-1)
+{
+    setBufferFromDevice(&outputDevice);
+}
+
+void RepParser::reset()
+{
+    m_ast = AST();
+    m_astClass = ASTClass();
+    m_astPod = POD();
+    m_argString.clear();
+    m_astEnum = ASTEnum();
+    //setDebug();
+}
+
+bool RepParser::parseModifierFlag(const QString &flag, ASTProperty::Modifier &modifier, bool &persisted)
+{
+    QRegularExpression regex(QStringLiteral("\\s*,\\s*"));
+    QStringList flags = flag.split(regex);
+    persisted = flags.removeAll(QStringLiteral("PERSISTED")) > 0;
+    if (flags.length() == 0)
+        return true;
+    if (flags.length() > 1) {
+        // Only valid combination is "READONLY" and "CONSTANT"
+        if (flags.length() == 2 && flags.contains(QStringLiteral("READONLY")) &&
+            flags.contains(QStringLiteral("CONSTANT"))) {
+            // If we have READONLY and CONSTANT that means CONSTANT
+            modifier = ASTProperty::Constant;
+            return true;
+        } else {
+            setErrorString(QLatin1String("Invalid property declaration: combination not allowed (%1)").arg(flag));
+            return false;
+        }
+    }
+    const QString &f = flags.at(0);
+    if (f == QLatin1String("READONLY"))
+        modifier = ASTProperty::ReadOnly;
+    else if (f == QLatin1String("CONSTANT"))
+        modifier = ASTProperty::Constant;
+    else if (f == QLatin1String("READPUSH"))
+        modifier = ASTProperty::ReadPush;
+    else if (f == QLatin1String("READWRITE"))
+        modifier = ASTProperty::ReadWrite;
+    else if (f == QLatin1String("SOURCEONLYSETTER"))
+        modifier = ASTProperty::SourceOnlySetter;
+    else {
+        setErrorString(QLatin1String("Invalid property declaration: flag %1 is unknown").arg(flag));
+        return false;
+    }
+
+    return true;
+}
+
+QString stripArgs(const QString &arguments)
+{
+    // This repc parser searches for the longest possible matches, which can be multiline.
+    // This method "cleans" the string input, removing comments and converting to a single
+    // line for subsequent parsing.
+    QStringList lines = arguments.split(QRegularExpression(QStringLiteral("\r?\n")));
+    for (auto & line : lines)
+        line.replace(QRegularExpression(QStringLiteral("//.*")),QString());
+    return lines.join(QString());
+}
+
+bool RepParser::parseProperty(ASTClass &astClass, const QString &propertyDeclaration)
+{
+    QString input = stripArgs(propertyDeclaration).trimmed();
+    const QRegularExpression whitespace(QStringLiteral("\\s"));
+
+    QString propertyType;
+    QString propertyName;
+    QString propertyDefaultValue;
+    ASTProperty::Modifier propertyModifier = ASTProperty::ReadPush;
+    bool persisted = false;
+
+    // parse type declaration which could be a nested template as well
+    bool inTemplate = false;
+    int templateDepth = 0;
+    int nameIndex = -1;
+
+    for (int i = 0; i < input.size(); ++i) {
+        const QChar inputChar(input.at(i));
+        if (inputChar == QLatin1Char('<')) {
+            propertyType += inputChar;
+            inTemplate = true;
+            ++templateDepth;
+        } else if (inputChar == QLatin1Char('>')) {
+            propertyType += inputChar;
+            --templateDepth;
+            if (templateDepth == 0)
+                inTemplate = false;
+        } else if (inputChar.isSpace()) {
+            if (!inTemplate) {
+                nameIndex = i;
+                break;
+            } else {
+                propertyType += inputChar;
+            }
+        } else {
+            propertyType += inputChar;
+        }
+    }
+
+    if (nameIndex == -1) {
+        setErrorString(QLatin1String("PROP: Invalid property declaration: %1").arg(propertyDeclaration));
+        return false;
+    }
+
+    // parse the name of the property
+    input = input.mid(nameIndex).trimmed();
+
+    const int equalSignIndex = input.indexOf(QLatin1Char('='));
+    if (equalSignIndex != -1) { // we have a default value
+        propertyName = input.left(equalSignIndex).trimmed();
+
+        input = input.mid(equalSignIndex + 1).trimmed();
+        const int lastQuoteIndex = input.lastIndexOf(QLatin1Char('"'));
+        if (lastQuoteIndex != -1) {
+            propertyDefaultValue = input.left(lastQuoteIndex + 1);
+            input = input.mid(lastQuoteIndex + 1);
+        }
+        const int whitespaceIndex = input.indexOf(whitespace);
+        if (whitespaceIndex == -1) { // no flag given
+            if (propertyDefaultValue.isEmpty())
+                propertyDefaultValue = input;
+            propertyModifier = ASTProperty::ReadPush;
+        } else { // flag given
+            if (propertyDefaultValue.isEmpty())
+                propertyDefaultValue = input.left(whitespaceIndex).trimmed();
+
+            const QString flag = input.mid(whitespaceIndex + 1).trimmed();
+            if (!parseModifierFlag(flag, propertyModifier, persisted))
+                return false;
+        }
+    } else { // there is no default value
+        const int whitespaceIndex = input.indexOf(whitespace);
+        if (whitespaceIndex == -1) { // no flag given
+            propertyName = input;
+            propertyModifier = ASTProperty::ReadPush;
+        } else { // flag given
+            propertyName = input.left(whitespaceIndex).trimmed();
+
+            const QString flag = input.mid(whitespaceIndex + 1).trimmed();
+            if (!parseModifierFlag(flag, propertyModifier, persisted))
+                return false;
+        }
+    }
+
+    astClass.properties << ASTProperty(propertyType, propertyName, propertyDefaultValue, propertyModifier, persisted);
+    if (persisted)
+        astClass.hasPersisted = true;
+    return true;
+}
+
+bool RepParser::parseRoles(ASTModel &astModel, const QString &modelRoles)
+{
+    const QString input = modelRoles.trimmed();
+
+    if (input.isEmpty())
+        return true;
+
+    const QStringList roleStrings = input.split(QChar(QLatin1Char(',')));
+    for (auto role : roleStrings)
+        astModel.roles << ASTModelRole(role.trimmed());
+    return true;
+}
+
+AST RepParser::ast() const
+{
+    return m_ast;
+}
+
+void RepParser::TypeParser::parseArguments(const QString &arguments)
+{
+    const QString strippedArgs = stripArgs(arguments);
+    int templateDepth = 0;
+    bool inTemplate = false;
+    bool inVariable = false;
+    QString propertyType;
+    QString variableName;
+    ASTDeclaration::VariableTypes variableType = ASTDeclaration::None;
+    int variableNameIndex = 0;
+    for (int i = 0; i < strippedArgs.size(); ++i) {
+        const QChar inputChar(strippedArgs.at(i));
+        if (inputChar == QLatin1Char('<')) {
+            propertyType += inputChar;
+            inTemplate = true;
+            ++templateDepth;
+        } else if (inputChar == QLatin1Char('>')) {
+            propertyType += inputChar;
+            --templateDepth;
+            if (templateDepth == 0)
+                inTemplate = false;
+        } else if (inputChar.isSpace()) {
+            if (inTemplate)
+                propertyType += inputChar;
+            else if (!propertyType.isEmpty()) {
+                if (propertyType == QLatin1String("const")) {
+                    propertyType.clear();
+                    variableType |= ASTDeclaration::Constant;
+                } else {
+                    inVariable = true;
+                }
+            }
+        } else if (inputChar == QLatin1Char('&')) {
+            variableType |= ASTDeclaration::Reference;
+        } else if (inputChar == QLatin1Char(',')) {
+            if (!inTemplate) {
+                RepParser::TypeParser::generateFunctionParameter(variableName, propertyType, variableNameIndex, variableType);
+                propertyType.clear();
+                variableName.clear();
+                variableType = ASTDeclaration::None;
+                inVariable = false;
+            } else {
+                propertyType += inputChar;
+            }
+        } else {
+            if (inVariable)
+                variableName += inputChar;
+            else
+                propertyType += inputChar;
+        }
+    }
+    if (!propertyType.isEmpty()) {
+        RepParser::TypeParser::generateFunctionParameter(variableName, propertyType, variableNameIndex, variableType);
+    }
+}
+
+void RepParser::TypeParser::generateFunctionParameter(QString variableName, const QString &propertyType, int &variableNameIndex, ASTDeclaration::VariableTypes variableType)
+{
+    if (!variableName.isEmpty())
+        variableName = variableName.trimmed();
+    else
+        variableName = QString::fromLatin1("__repc_variable_%1").arg(++variableNameIndex);
+    arguments.append(ASTDeclaration(propertyType, variableName, variableType));
+}
+
+void RepParser::TypeParser::appendParams(ASTFunction &slot)
+{
+    for (const ASTDeclaration &arg : qAsConst(arguments))
+        slot.params << arg;
+}
+
+void RepParser::TypeParser::appendPods(POD &pods)
+{
+    for (const ASTDeclaration &arg : qAsConst(arguments)) {
+        PODAttribute attr;
+        attr.type = arg.type;
+        attr.name = arg.name;
+        pods.attributes.append(qMove(attr));
+    }
+}
+
+bool RepParser::consumeRule(int ruleno)
+{
+    if (isDebug()) {
+        qDebug() << "consumeRule:" << ruleno << spell[rule_info[rule_index[ruleno]]];
+    }
+    switch (ruleno) {
+./
+
+TopLevel: Types | Newlines Types | FileComments Types | Newlines FileComments Types;
+
+FileComments: Comments;
+
+Types: Type | Type Types;
+
+Newlines: newline | newline Newlines;
+Comments: Comment | Comment Comments;
+Comment: comment | comment Newlines | mcomment | mcomment Newlines;
+Type: PreprocessorDirective | PreprocessorDirective Newlines;
+Type: Pod | Pod Newlines;
+Type: Pod2;
+Type: Class;
+Type: UseEnum | UseEnum Newlines;
+Type: Comments | Comments Newlines;
+Type: Enum;
+/.
+    case $rule_number:
+    {
+        m_astEnum.generateSignature(m_ast);
+        m_ast.enums.append(m_astEnum);
+    }
+    break;
+./
+Type: Flag | Flag Newlines;
+
+Comma: comma | comma Newlines;
+
+Equals: equals;
+
+PreprocessorDirective: preprocessor_directive;
+/.
+    case $rule_number:
+    {
+        m_ast.preprocessorDirectives.append(captured().value(QStringLiteral("preprocessor_directive")));
+    }
+    break;
+./
+
+Pod: pod;
+/.
+    case $rule_number:
+    {
+        POD pod;
+        pod.name = captured().value(QStringLiteral("name")).trimmed();
+
+        const QString argString = captured().value(QLatin1String("types")).trimmed();
+        if (argString.isEmpty()) {
+            qWarning() << "[repc] - Ignoring POD with no data members.  POD name: " << qPrintable(pod.name);
+            return true;
+        }
+        if (argString.contains(QLatin1String("ENUM"))) {
+            setErrorString(QLatin1String("ENUMs are only available in PODs using bracket syntax ('{'), not parentheses"));
+            return false;
+        }
+
+        RepParser::TypeParser parseType;
+        parseType.parseArguments(argString);
+        parseType.appendPods(pod);
+        pod.generateSignature(m_ast);
+        m_ast.pods.append(pod);
+    }
+    break;
+./
+
+Class: ClassStart Start ClassTypes Stop;
+/.
+    case $rule_number:
+./
+Class: ClassStart Start Comments Stop;
+/.
+    case $rule_number:
+./
+Class: ClassStart Start Stop;
+/.
+    case $rule_number:
+    {
+        m_astClass.generateSignature(m_ast);
+        m_ast.classes.append(m_astClass);
+    }
+    break;
+./
+
+ClassTypes: ClassType | ClassType ClassTypes;
+ClassType: DecoratedProp | DecoratedSignal | DecoratedSlot | DecoratedModel | DecoratedClass | DecoratedClassFlag | Comments;
+ClassType: Enum;
+/.
+    case $rule_number:
+    {
+        m_astEnum.scope = m_astClass.name;
+        m_astEnum.generateSignature(m_ast);
+        m_astClass.enums.append(m_astEnum);
+    }
+    break;
+./
+
+Pod2: PodStart Start PodTypes Stop;
+/.
+    case $rule_number:
+./
+Pod2: PodStart Start Comments Stop;
+/.
+    case $rule_number:
+./
+Pod2: PodStart Start Stop;
+/.
+    case $rule_number:
+    {
+        RepParser::TypeParser parseType;
+        parseType.parseArguments(m_argString);
+        parseType.appendPods(m_astPod);
+        m_astPod.generateSignature(m_ast);
+        m_ast.pods.append(m_astPod);
+    }
+    break;
+./
+
+PodTypes: PodType | PodType Newlines | PodType CaptureComma PodTypes | PodType PodTypes | PodType Newlines PodTypes;
+PodType: DecoratedPODFlag | Comments;
+PodType: Enum;
+/.
+    case $rule_number:
+    {
+        m_astEnum.generateSignature(m_ast);
+        m_astPod.enums.append(m_astEnum);
+    }
+    break;
+./
+
+PodType: Parameter;
+Parameter: DecoratedParameterType ParameterName;
+
+DecoratedParameterType: ParameterType | Qualified ParameterType | ParameterType PassByReference | Qualified ParameterType PassByReference;
+
+ParameterType: SimpleType | TemplateType;
+
+TemplateType: TemplateTypename TStart ParameterTypes TStop;
+
+TemplateTypename: Symbol;
+/.
+    case $rule_number:
+    {
+        m_argString += m_symbol;
+    }
+    break;
+./
+
+TStart: tstart;
+/.
+    case $rule_number:
+    {
+        m_argString += QLatin1Char('<');
+    }
+    break;
+./
+
+TStop: tstop;
+/.
+    case $rule_number:
+    {
+        m_argString += QLatin1Char('>');
+    }
+    break;
+./
+
+Qualified: qualifier;
+/.
+    case $rule_number:
+    {
+        m_argString += captured().value(QLatin1String("value")).trimmed() + QLatin1Char(' ');
+    }
+    break;
+./
+
+PassByReference: passbyqual;
+/.
+    case $rule_number:
+    {
+        m_argString += QLatin1Char(' ') + captured().value(QLatin1String("value")).trimmed();
+    }
+    break;
+./
+
+ParameterTypes: DecoratedParameterType | DecoratedParameterType CaptureComma ParameterTypes;
+
+CaptureComma: comma;
+/.
+    case $rule_number:
+./
+CaptureComma: comma Newlines;
+/.
+    case $rule_number:
+    {
+        m_argString += QLatin1Char(',');
+    }
+    break;
+./
+
+SimpleType: Symbol;
+/.
+    case $rule_number:
+    {
+        m_argString += m_symbol;
+    }
+    break;
+./
+
+ParameterName: Symbol;
+/.
+    case $rule_number:
+    {
+        m_argString += QLatin1Char(' ') + m_symbol;
+    }
+    break;
+./
+
+DecoratedSlot: Slot | Comments Slot | Slot Newlines | Comments Slot Newlines;
+DecoratedSignal: Signal | Comments Signal | Signal Newlines | Comments Signal Newlines;
+DecoratedProp: Prop | Comments Prop | Prop Newlines | Comments Prop Newlines;
+DecoratedModel: Model | Comments Model | Model Newlines | Comments Model Newlines;
+DecoratedClass: ChildRep | Comments ChildRep | ChildRep Newlines | Comments ChildRep Newlines;
+DecoratedEnumParam: EnumParam | Comments EnumParam | EnumParam Newlines | Comments EnumParam Newlines;
+DecoratedClassFlag: ClassFlag | Comments ClassFlag | ClassFlag Newlines | Comments ClassFlag Newlines;
+
+DecoratedPODFlag: PODFlag | Comments PODFlag | PODFlag Newlines | Comments PODFlag Newlines;
+
+Start: start | Comments start | start Newlines | Comments start Newlines;
+Stop: stop | stop Newlines;
+
+Enum: EnumStart Start EnumParams Comments Stop;
+Enum: EnumStart Start EnumParams Stop;
+
+EnumStart: enum;
+/.
+    case $rule_number:
+    {
+        const QString name = captured().value(QLatin1String("name"));
+        const QString type = captured().value(QLatin1String("type"));
+        const QString _class = captured().value(QLatin1String("class"));
+
+        // new Class declaration
+        m_astEnum = ASTEnum(name);
+        if (!_class.isEmpty())
+            m_astEnum.isScoped = true;
+        if (!type.isEmpty())
+            m_astEnum.type = type;
+        m_astEnumValue = -1;
+    }
+    break;
+./
+
+EnumParams: DecoratedEnumParam | DecoratedEnumParam Comma EnumParams;
+
+EnumParam: Symbol;
+/.
+    case $rule_number:
+    {
+        ASTEnumParam param;
+        param.name = m_symbol;
+        param.value = ++m_astEnumValue;
+        if (m_astEnum.max < param.value)
+            m_astEnum.max = param.value;
+        m_astEnum.params << param;
+    }
+    break;
+./
+
+EnumParam: Symbol Equals Value;
+/.
+    case $rule_number:
+    {
+        ASTEnumParam param;
+        param.name = m_symbol;
+        param.value = m_astEnumValue;
+        if (param.value < 0) {
+            m_astEnum.isSigned = true;
+            if (m_astEnum.max < -param.value)
+                m_astEnum.max = -param.value;
+        } else if (m_astEnum.max < param.value)
+            m_astEnum.max = param.value;
+        m_astEnum.params << param;
+    }
+    break;
+./
+
+Symbol: symbol;
+/.
+    case $rule_number:
+    {
+        m_symbol = captured().value(QStringLiteral("symbol")).trimmed();
+    }
+    break;
+./
+
+Value: value;
+/.
+    case $rule_number:
+    {
+        QString value = captured().value(QStringLiteral("value")).trimmed();
+        if (value.startsWith(QLatin1String("0x"), Qt::CaseInsensitive))
+            m_astEnumValue = value.toInt(0,16);
+        else
+            m_astEnumValue = value.toInt();
+    }
+    break;
+./
+
+ClassFlag: flag;
+/.
+    case $rule_number:
+    {
+        const QString name = captured().value(QLatin1String("name"));
+        const QString _enum = captured().value(QLatin1String("enum"));
+        int enumIndex = 0;
+        for (auto &en : m_astClass.enums) {
+            if (en.name == _enum) {
+                en.flagIndex = m_astClass.flags.count();
+                break;
+            }
+            enumIndex++;
+        }
+        if (enumIndex == m_astClass.enums.count()) {
+            setErrorString(QLatin1String("FLAG: Unknown (class) enum: %1").arg(_enum));
+            return false;
+        }
+        auto flag = ASTFlag(name, _enum);
+        flag.scope = m_astClass.name;
+        flag.generateSignature(m_ast);
+        m_astClass.flags.append(flag);
+    }
+    break;
+./
+
+PODFlag: flag;
+/.
+    case $rule_number:
+    {
+        const QString name = captured().value(QLatin1String("name"));
+        const QString _enum = captured().value(QLatin1String("enum"));
+        int enumIndex = 0;
+        for (auto &en : m_astPod.enums) {
+            if (en.name == _enum) {
+                en.flagIndex = m_astPod.flags.count();
+                break;
+            }
+            enumIndex++;
+        }
+        if (enumIndex == m_astPod.enums.count()) {
+            setErrorString(QLatin1String("FLAG: Unknown (pod) enum: %1").arg(_enum));
+            return false;
+        }
+        auto flag = ASTFlag(name, _enum);
+        flag.scope = m_astPod.name;
+        flag.generateSignature(m_ast);
+        m_astPod.flags.append(flag);
+    }
+    break;
+./
+
+Prop: prop;
+/.
+    case $rule_number:
+    {
+        const QString args = captured().value(QLatin1String("args"));
+        if (!parseProperty(m_astClass, args))
+            return false;
+    }
+    break;
+./
+
+Signal: signal;
+/.
+    case $rule_number:
+    {
+        ASTFunction signal;
+        signal.name = captured().value(QLatin1String("name")).trimmed();
+
+        const QString argString = captured().value(QLatin1String("args")).trimmed();
+        RepParser::TypeParser parseType;
+        parseType.parseArguments(argString);
+        parseType.appendParams(signal);
+        m_astClass.signalsList << signal;
+    }
+    break;
+./
+
+Slot: slot;
+/.
+    case $rule_number:
+    {
+        QString returnTypeAndName = captured().value(QLatin1String("type")).trimmed();
+        const QString argString = captured().value(QLatin1String("args")).trimmed();
+
+        // compat code with old SLOT declaration: "SLOT(func(...))"
+        const bool hasWhitespace = returnTypeAndName.indexOf(u' ') != -1;
+        if (!hasWhitespace) {
+            qWarning() << "[repc] - Adding 'void' for unspecified return type on" << qPrintable(returnTypeAndName);
+            returnTypeAndName.prepend(QLatin1String("void "));
+        }
+
+        const int startOfFunctionName = returnTypeAndName.lastIndexOf(u' ') + 1;
+
+        ASTFunction slot;
+        slot.returnType = returnTypeAndName.mid(0, startOfFunctionName-1);
+        slot.name = returnTypeAndName.mid(startOfFunctionName);
+
+        RepParser::TypeParser parseType;
+        parseType.parseArguments(argString);
+        parseType.appendParams(slot);
+        m_astClass.slotsList << slot;
+    }
+    break;
+./
+
+Model: model;
+/.
+    case $rule_number:
+    {
+        const QString name = captured().value(QLatin1String("name")).trimmed();
+        const QString argString = captured().value(QLatin1String("args")).trimmed();
+
+        ASTModel model(name, m_astClass.name, m_astClass.properties.size());
+        if (!parseRoles(model, argString))
+            return false;
+
+        model.generateSignature(m_ast);
+        m_astClass.modelMetadata << model;
+        m_astClass.properties << ASTProperty(QStringLiteral("QAbstractItemModel"), name, QStringLiteral("nullptr"), ASTProperty::SourceOnlySetter, false, true);
+    }
+    break;
+./
+
+ChildRep: childrep;
+/.
+case $rule_number:
+{
+    const QString name = captured().value(QLatin1String("name")).trimmed();
+    const QString type = captured().value(QLatin1String("type")).trimmed();
+
+    m_astClass.subClassPropertyIndices << m_astClass.properties.size();
+    m_astClass.properties << ASTProperty(type, name, QStringLiteral("nullptr"), ASTProperty::SourceOnlySetter, false, true);
+}
+break;
+./
+
+ClassStart: class Newlines;
+/.
+    case $rule_number:
+./
+ClassStart: class;
+/.
+    case $rule_number:
+    {
+        const QString name = captured().value(QLatin1String("name"));
+
+        // new Class declaration
+        m_astClass = ASTClass(name);
+    }
+    break;
+./
+
+PodStart: pod2;
+/.
+    case $rule_number:
+./
+PodStart: pod2 Newlines;
+/.
+    case $rule_number:
+    {
+        // new POD declaration
+        m_astPod = POD();
+        m_astPod.name = captured().value(QLatin1String("name")).trimmed();
+        m_argString.clear();
+    }
+    break;
+./
+
+UseEnum: use_enum;
+/.
+    case $rule_number:
+    {
+        const QString name = captured().value(QLatin1String("name"));
+
+        m_ast.enumUses.append(name);
+    }
+    break;
+./
+
+Flag: flag;
+/.
+    case $rule_number:
+    {
+        const QString name = captured().value(QLatin1String("name"));
+        const QString _enum = captured().value(QLatin1String("enum"));
+        int enumIndex = 0;
+        for (auto &en : m_ast.enums) {
+            if (en.name == _enum) {
+                en.flagIndex = m_ast.flags.count();
+                break;
+            }
+            if (en.name == _enum)
+                break;
+            enumIndex++;
+        }
+        if (enumIndex == m_ast.enums.count()) {
+            setErrorString(QLatin1String("FLAG: Unknown (global) enum: %1").arg(_enum));
+            return false;
+        }
+        auto flag = ASTFlag(name, _enum);
+        flag.generateSignature(m_ast);
+        m_ast.flags.append(flag);
+    }
+    break;
+./
+
+--Error conditions/messages
+ClassType: ClassStart;
+/.
+    case $rule_number:
+    {
+        setErrorString(QStringLiteral("class: Cannot be nested"));
+        return false;
+    }
+    break;
+./
+ClassType: Pod;
+/.
+    case $rule_number:
+    {
+        setErrorString(QStringLiteral("POD: Can only be used in global scope"));
+        return false;
+    }
+    break;
+./
+ClassType: UseEnum;
+/.
+    case $rule_number:
+    {
+        setErrorString(QStringLiteral("USE_ENUM: Can only be used in global scope"));
+        return false;
+    }
+    break;
+./
+Type: Signal;
+/.
+    case $rule_number:
+    {
+        setErrorString(QStringLiteral("SIGNAL: Can only be used in class scope"));
+        return false;
+    }
+    break;
+./
+Type: Slot;
+/.
+    case $rule_number:
+    {
+        setErrorString(QStringLiteral("SLOT: Can only be used in class scope"));
+        return false;
+    }
+    break;
+./
+Type: Prop;
+/.
+    case $rule_number:
+    {
+        setErrorString(QStringLiteral("PROP: Can only be used in class scope"));
+        return false;
+    }
+    break;
+./
+Type: Model;
+/.
+    case $rule_number:
+    {
+        setErrorString(QStringLiteral("MODEL: Can only be used in class scope"));
+        return false;
+    }
+    break;
+./
+
+Type: ChildRep;
+/.
+    case $rule_number:
+    {
+        setErrorString(QStringLiteral("CLASS: Can only be used in class scope"));
+        return false;
+    }
+    break;
+./
+
+/.
+    } // switch
+    return true;
+}
+./
diff --git a/src/repparser/qregexparser.h b/src/repparser/qregexparser.h
new file mode 100644 (file)
index 0000000..2ffbfbe
--- /dev/null
@@ -0,0 +1,396 @@
+/****************************************************************************
+** Copyright (C) 2017-2020 Ford Motor Company.
+** All rights reserved.
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** 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 QREGEXPARSER_H
+#define QREGEXPARSER_H
+
+#include <QtCore/qshareddata.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qregularexpression.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qtextstream.h>
+#include <QtCore/qdebug.h>
+
+struct MatchCandidate {
+    MatchCandidate(const QString &n, const QString &t, int i) : name(n), matchText(t), index(i) {}
+    QString name;
+    QString matchText;
+    int index;
+};
+
+QT_BEGIN_NAMESPACE
+
+template <typename _Parser, typename _Table>
+class QRegexParser: protected _Table
+{
+public:
+    QRegexParser(int maxMatchLen=4096);
+    virtual ~QRegexParser();
+
+    virtual bool parse();
+
+    virtual void reset() {}
+
+    inline QVariant &sym(int index);
+
+    void setBuffer(const QString &buffer);
+
+    void setBufferFromDevice(QIODevice *device);
+
+    void setDebug();
+
+    QString errorString() const
+    {
+        return m_errorString;
+    }
+
+    void setErrorString(const QString &error)
+    {
+        m_errorString = error;
+        qWarning() << m_errorString;
+    }
+
+    inline const QMap<QString, QString>& captured() const
+    {
+        return m_captured;
+    }
+
+    inline bool isDebug() const
+    {
+        return m_debug;
+    }
+
+    inline int lineNumber() const
+    {
+        return m_lineno;
+    }
+
+private:
+    int nextToken();
+
+    inline bool consumeRule(int rule)
+    {
+        return static_cast<_Parser*> (this)->consumeRule(rule);
+    }
+
+    enum { DefaultStackSize = 128 };
+
+    struct Data: public QSharedData
+    {
+        Data(): stackSize (DefaultStackSize), tos (0) {}
+
+        QVarLengthArray<int, DefaultStackSize> stateStack;
+        QVarLengthArray<QVariant, DefaultStackSize> parseStack;
+        int stackSize;
+        int tos;
+
+        void reallocateStack() {
+            stackSize <<= 1;
+            stateStack.resize(stackSize);
+            parseStack.resize(stackSize);
+        }
+    };
+
+    inline QString escapeString(QString s)
+    {
+        return s.replace(QLatin1Char('\n'), QLatin1String("\\n")).replace(QLatin1Char('\t'), QLatin1String("\\t"));
+    }
+
+    QSharedDataPointer<Data> d;
+
+    QList<QRegularExpression> m_regexes;
+    QMap<QChar, QList<int> > regexCandidates;
+    QList<int> m_tokens;
+    QString m_buffer, m_lastMatchText;
+    int m_loc, m_lastNewlinePosition;
+    int m_lineno;
+    int m_debug;
+    QStringList m_tokenNames;
+    QMap<QString, QString> m_captured;
+    int m_maxMatchLen;
+    QString m_errorString;
+    QList<QMap<int, QString>> m_names; //storage for match names
+};
+
+template <typename _Parser, typename _Table>
+inline QVariant &QRegexParser<_Parser, _Table>::sym(int n)
+{
+    return d->parseStack [d->tos + n - 1];
+}
+
+template <typename _Parser, typename _Table>
+QRegexParser<_Parser, _Table>::~QRegexParser()
+{
+}
+
+template <typename _Parser, typename _Table>
+bool QRegexParser<_Parser, _Table>::parse()
+{
+    m_errorString.clear();
+    reset();
+    const int INITIAL_STATE = 0;
+
+    d->tos = 0;
+    d->reallocateStack();
+
+    int act = d->stateStack[++d->tos] = INITIAL_STATE;
+    int token = -1;
+
+    Q_FOREVER {
+        if (token == -1 && - _Table::TERMINAL_COUNT != _Table::action_index[act])
+            token = nextToken();
+
+        act = _Table::t_action(act, token);
+
+        if (d->stateStack[d->tos] == _Table::ACCEPT_STATE)
+            return true;
+
+        else if (act > 0) {
+            if (++d->tos == d->stackSize)
+                d->reallocateStack();
+
+            d->parseStack[d->tos] = d->parseStack[d->tos - 1];
+            d->stateStack[d->tos] = act;
+            token = -1;
+        }
+
+        else if (act < 0) {
+            int r = - act - 1;
+            d->tos -= _Table::rhs[r];
+            act = d->stateStack[d->tos++];
+            if (!consumeRule(r))
+                return false;
+            act = d->stateStack[d->tos] = _Table::nt_action(act, _Table::lhs[r] - _Table::TERMINAL_COUNT);
+        }
+
+        else break;
+    }
+
+    setErrorString(QStringLiteral("Unknown token encountered"));
+    return false;
+}
+
+template <typename _Parser, typename _Table>
+QRegexParser<_Parser, _Table>::QRegexParser(int maxMatchLen) : d(new Data()), m_loc(0), m_lastNewlinePosition(0), m_lineno(1), m_debug(0), m_maxMatchLen(maxMatchLen)
+{
+    QRegularExpression re(QStringLiteral("\\[([_a-zA-Z][_0-9a-zA-Z]*)(,\\s*M)?\\](.+)$"));
+    re.optimize();
+    QMap<QString, int> token_lookup;
+    QMap<int, QString> names;
+    for (int i = 1; i < _Table::lhs[0]; i++) {
+        const QString text = QLatin1String(_Table::spell[i]);
+        names.clear();
+        QRegularExpressionMatch match = re.match(text, 0, QRegularExpression::NormalMatch, QRegularExpression::DontCheckSubjectStringMatchOption);
+        if (match.hasMatch()) {
+            const QString token = match.captured(1);
+            const bool multiline = match.captured(2).length() > 0;
+            const QString pattern = match.captured(3);
+            m_tokenNames.append(token);
+            int index = i;
+            if (token_lookup.contains(token))
+                index = token_lookup[token];
+            else
+                token_lookup[token] = i;
+            QRegularExpression pat(pattern);
+            if (multiline)
+                pat.setPatternOptions(QRegularExpression::DotMatchesEverythingOption);
+
+            if (!pat.isValid())
+                qCritical() << "Pattern error for token #" << i << "for" << text << "pattern =" << pat << ":" << pat.errorString();
+            else {
+                pat.optimize();
+                int counter = 0;
+                const auto namedCaptureGroups = pat.namedCaptureGroups();
+                for (const QString &name : namedCaptureGroups) {
+                    if (!name.isEmpty())
+                        names.insert(counter, name);
+                    ++counter;
+                }
+                m_names.append(names);
+                m_regexes.append(pat);
+                if (token.startsWith(QLatin1String("ignore")))
+                    m_tokens.append(-1);
+                else
+                    m_tokens.append(index);
+            }
+        } else {
+            qCritical() << "Error parsing regex at token #" << i << "for" << text << "Invalid syntax";
+        }
+    }
+}
+
+template <typename _Parser, typename _Table>
+void QRegexParser<_Parser, _Table>::setBuffer(const QString &buffer)
+{
+    m_buffer = buffer;
+}
+
+template <typename _Parser, typename _Table>
+void QRegexParser<_Parser, _Table>::setBufferFromDevice(QIODevice *device)
+{
+    QTextStream in(device);
+    m_buffer = in.readAll();
+}
+
+template <typename _Parser, typename _Table>
+void QRegexParser<_Parser, _Table>::setDebug()
+{
+    m_debug = true;
+    for (int r = 0; r < _Table::RULE_COUNT; ++r)
+    {
+        int ridx = _Table::rule_index[r];
+        int _rhs = _Table::rhs[r];
+        qDebug("%3d) %s ::=", r + 1, _Table::spell[_Table::rule_info[ridx]]);
+        ++ridx;
+        for (int i = ridx; i < ridx + _rhs; ++i)
+        {
+            int symbol = _Table::rule_info[i];
+            if (symbol > 0 && symbol < _Table::lhs[0])
+                qDebug("     token_%s (pattern = %s)",qPrintable(m_tokenNames[symbol-1]),qPrintable(m_regexes[symbol-1].pattern()));
+            else if (const char *name = _Table::spell[symbol])
+                qDebug("     %s", name);
+            else
+                qDebug("     #%d", symbol);
+        }
+        qDebug();
+    }
+}
+
+template <typename _Parser, typename _Table>
+int QRegexParser<_Parser, _Table>::nextToken()
+{
+    const QStringView buffer { m_buffer };
+    static const QRegularExpression newline(QLatin1String("(\\n)"));
+    int token = -1;
+    while (token < 0)
+    {
+        if (m_loc == buffer.size())
+            return _Table::EOF_SYMBOL;
+
+        //Check m_lastMatchText for newlines and update m_lineno
+        //This isn't necessary, but being able to provide the line # and character #
+        //where the match is failing sure makes building/debugging grammars easier.
+        QRegularExpressionMatchIterator  matches = newline.globalMatch(m_lastMatchText);
+        while (matches.hasNext()) {
+            m_lineno++;
+            QRegularExpressionMatch match = matches.next();
+            if (!matches.hasNext())
+                m_lastNewlinePosition += match.capturedEnd();
+        }
+
+        if (m_debug) {
+            qDebug();
+            qDebug() << "nextToken loop, line =" << m_lineno
+                << "line position =" << m_loc - m_lastNewlinePosition
+                << "next 5 characters =" << escapeString(buffer.mid(m_loc, 5).toString());
+        }
+        int best = -1, maxLen = -1;
+        QRegularExpressionMatch bestRegex;
+
+        //Find the longest match.
+        //If more than one are the same (longest) length, return the first one in
+        //the order defined.
+        QList<MatchCandidate> candidates;
+        //We used PCRE's PartialMatch to eliminate most of the regexes by the first
+        //character, so we keep a regexCandidates map with the list of possible regexes
+        //based on initial characters found so far.
+        const QChar nextChar = buffer.at(m_loc);
+        //Populate the list if we haven't seeen this character before
+        if (!regexCandidates.contains(nextChar)) {
+            const QStringView tmp = buffer.mid(m_loc,1);
+            int i = 0;
+            regexCandidates[nextChar] = QList<int>();
+            for (const QRegularExpression &re : qAsConst(m_regexes))
+            {
+                QRegularExpressionMatch match = re.match(tmp, 0, QRegularExpression::PartialPreferFirstMatch, QRegularExpression::DontCheckSubjectStringMatchOption);
+                //qDebug() << nextChar << tmp << match.hasMatch() << match.hasPartialMatch() << re.pattern();
+                if (match.hasMatch() || match.hasPartialMatch())
+                    regexCandidates[nextChar] << i;
+                i++;
+            }
+        }
+        const auto indices = regexCandidates.value(nextChar);
+        for (int i : indices)
+        {
+            //Seems like I should be able to run the regex on the entire string, but performance is horrible
+            //unless I use a substring.
+            //QRegularExpressionMatch match = m_regexes[i].match(m_buffer, m_loc, QRegularExpression::NormalMatch, QRegularExpression::AnchorAtOffsetMatchOption);
+            QRegularExpressionMatch match = m_regexes.at(i).match(buffer.mid(m_loc, m_maxMatchLen), 0, QRegularExpression::NormalMatch, QRegularExpression::AnchorAtOffsetMatchOption | QRegularExpression::DontCheckSubjectStringMatchOption);
+            if (match.hasMatch()) {
+                if (m_debug)
+                    candidates << MatchCandidate(m_tokenNames[i], match.captured(), i);
+                if (match.capturedLength() > maxLen) {
+                    best = i;
+                    maxLen = match.capturedLength();
+                    bestRegex = match;
+                }
+            }
+        }
+        if (best < 0) {
+            setErrorString(QLatin1String("Error generating tokens from file, next characters >%1<").arg(buffer.mid(m_loc, 15)));
+            return -1;
+        } else {
+            const QMap<int, QString> &map = m_names.at(best);
+            if (!map.isEmpty())
+                m_captured.clear();
+            for (auto iter = map.cbegin(), end = map.cend(); iter != end; ++iter)
+                m_captured.insert(iter.value(), bestRegex.captured(iter.key()));
+            if (m_debug) {
+                qDebug() << "Match candidates:";
+                for (const MatchCandidate &m : qAsConst(candidates)) {
+                    QLatin1String result = m.index == best ? QLatin1String(" * ") : QLatin1String("   ");
+                    qDebug() << qPrintable(result) << qPrintable(m.name) << qPrintable(escapeString(m.matchText));
+                }
+            }
+            m_loc += maxLen;
+            if (m_tokens.at(best) >= 0)
+                token = m_tokens.at(best);
+            m_lastMatchText = bestRegex.captured(0);
+        }
+    }
+    return token;
+}
+
+QT_END_NAMESPACE
+
+#endif // QREGEXPARSER_H
diff --git a/sync.profile b/sync.profile
new file mode 100644 (file)
index 0000000..2a12d4c
--- /dev/null
@@ -0,0 +1,5 @@
+%modules = ( # path to module name map
+    "QtRemoteObjects" => "$basedir/src/remoteobjects",
+    "QtRemoteObjectsQml" => "$basedir/src/remoteobjectsqml",
+    "QtRepParser" => "$basedir/src/repparser",
+);
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ae5e2f0
--- /dev/null
@@ -0,0 +1,6 @@
+
+if(QT_BUILD_STANDALONE_TESTS)
+    # Add qt_find_package calls for extra dependencies that need to be found when building
+    # the standalone tests here.
+endif()
+qt_build_tests()
diff --git a/tests/auto/CMakeLists.txt b/tests/auto/CMakeLists.txt
new file mode 100644 (file)
index 0000000..0ac483a
--- /dev/null
@@ -0,0 +1,27 @@
+
+add_subdirectory(benchmarks)
+add_subdirectory(cmake)
+add_subdirectory(modelreplica)
+add_subdirectory(modelview)
+add_subdirectory(pods)
+add_subdirectory(proxy)
+add_subdirectory(rep_from_header)
+add_subdirectory(repc)
+add_subdirectory(repcodegenerator)
+add_subdirectory(repparser)
+add_subdirectory(subclassreplica)
+if(QT_FEATURE_ssl)
+    add_subdirectory(external_IODevice)
+endif()
+if(TARGET Qt::Qml)
+    add_subdirectory(qml)
+endif()
+if(QT_FEATURE_process)
+    add_subdirectory(integration_multiprocess)
+    add_subdirectory(proxy_multiprocess)
+    add_subdirectory(integration_external)
+    add_subdirectory(restart)
+    add_subdirectory(reconnect)
+endif()
+add_subdirectory(localsockettestserver)
+add_subdirectory(integration)
diff --git a/tests/auto/benchmarks/CMakeLists.txt b/tests/auto/benchmarks/CMakeLists.txt
new file mode 100644 (file)
index 0000000..cde6e5d
--- /dev/null
@@ -0,0 +1,25 @@
+
+#####################################################################
+## tst_benchmarkstest Test:
+#####################################################################
+
+qt_internal_add_test(tst_benchmarkstest
+    SOURCES
+        tst_benchmarkstest.cpp
+    DEFINES
+        SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/\\\"
+    PUBLIC_LIBRARIES
+        Qt::Network
+        Qt::RemoteObjects
+)
+qt6_add_repc_sources(tst_benchmarkstest
+    ../repfiles/localdatacenter.rep
+    ../repfiles/tcpdatacenter.rep
+)
+qt6_add_repc_replicas(tst_benchmarkstest
+        ../repfiles/localdatacenter.rep
+        ../repfiles/tcpdatacenter.rep
+)
+
+#### Keys ignored in scope 1:.:.:benchmarks.pro:<TRUE>:
+# TEMPLATE = "app"
diff --git a/tests/auto/benchmarks/tst_benchmarkstest.cpp b/tests/auto/benchmarks/tst_benchmarkstest.cpp
new file mode 100644 (file)
index 0000000..d943a3e
--- /dev/null
@@ -0,0 +1,395 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include <QString>
+#include <QDataStream>
+#include <QLocalSocket>
+#include <QLocalServer>
+#include <QtTest>
+#include <QtRemoteObjects/QAbstractItemModelReplica>
+#include <QtRemoteObjects/QRemoteObjectNode>
+#include "rep_localdatacenter_replica.h"
+#include "rep_localdatacenter_source.h"
+
+class BenchmarksModel : public QAbstractListModel
+{
+    // QAbstractItemModel interface
+public:
+    int rowCount(const QModelIndex &parent) const override;
+    QVariant data(const QModelIndex &index, int role) const override;
+    QHash<int, QByteArray> roleNames() const override;
+};
+
+int BenchmarksModel::rowCount(const QModelIndex &parent) const
+{
+    Q_UNUSED(parent)
+    return 100000;
+}
+
+QVariant BenchmarksModel::data(const QModelIndex &index, int role) const
+{
+    switch (role) {
+    case Qt::DisplayRole:
+        return QStringLiteral("Benchmark data %1").arg(index.row());
+    case Qt::BackgroundRole:
+        return index.row() % 2 ? QStringLiteral("red") : QStringLiteral("green");
+    }
+    return QVariant();
+}
+
+QHash<int, QByteArray> BenchmarksModel::roleNames() const
+{
+    static QHash<int,QByteArray> roleNames = {
+        {Qt::DisplayRole, "_text"},
+        {Qt::BackgroundRole, "_color"}
+    };
+    return roleNames;
+}
+
+class BenchmarksTest : public QObject
+{
+    Q_OBJECT
+
+public:
+    BenchmarksTest();
+private:
+    QRemoteObjectHost m_basicServer;
+    QRemoteObjectNode m_basicClient;
+    QScopedPointer<LocalDataCenterSimpleSource> dataCenterLocal;
+    BenchmarksModel m_sourceModel;
+
+private Q_SLOTS:
+    void initTestCase();
+    void benchPropertyChangesInt();
+    void benchQDataStreamInt();
+    void benchQLocalSocketInt();
+    void benchQLocalSocketQDataStreamInt();
+    void benchModelLinearAccess();
+    void benchModelRandomAccess();
+};
+
+BenchmarksTest::BenchmarksTest()
+{
+}
+
+void BenchmarksTest::initTestCase() {
+    m_basicServer.setHostUrl(QUrl(QStringLiteral("local:benchmark_replica")));
+    dataCenterLocal.reset(new LocalDataCenterSimpleSource);
+    dataCenterLocal->setData1(5);
+    const bool remoted = m_basicServer.enableRemoting(dataCenterLocal.data());
+    Q_ASSERT(remoted);
+    Q_UNUSED(remoted)
+
+    m_basicClient.connectToNode(QUrl(QStringLiteral("local:benchmark_replica")));
+    Q_ASSERT(m_basicClient.lastError() == QRemoteObjectNode::NoError);
+
+    m_basicServer.enableRemoting(&m_sourceModel, QStringLiteral("BenchmarkRemoteModel"),
+                                 m_sourceModel.roleNames().keys().toVector());
+}
+
+void BenchmarksTest::benchPropertyChangesInt()
+{
+    QScopedPointer<LocalDataCenterReplica> center;
+    center.reset(m_basicClient.acquire<LocalDataCenterReplica>());
+    if (!center->isInitialized()) {
+        QEventLoop loop;
+        connect(center.data(), &LocalDataCenterReplica::initialized, &loop, &QEventLoop::quit);
+        loop.exec();
+    }
+    QEventLoop loop;
+    int lastValue = 0;
+    connect(center.data(), &LocalDataCenterReplica::data1Changed, [&lastValue, &center, &loop]() {
+        const bool res = (lastValue++ == center->data1());
+        Q_ASSERT(res);
+        Q_UNUSED(res)
+        if (lastValue == 50000)
+            loop.quit();
+    });
+    QBENCHMARK {
+        for (int i = 0; i < 50000; ++i) {
+            dataCenterLocal->setData1(i);
+        }
+        loop.exec();
+    }
+}
+// This ONLY tests the optimal case of a non resizing QByteArray
+void BenchmarksTest::benchQDataStreamInt()
+{
+    QByteArray buffer;
+    QDataStream stream(&buffer, QIODevice::WriteOnly);
+    QDataStream rStream(&buffer, QIODevice::ReadOnly);
+    int readout = 0;
+    QBENCHMARK {
+        for (int i = 0; i < 50000; ++i) {
+            stream << i;
+        }
+        for (int i = 0; i < 50000; ++i) {
+            rStream >> readout;
+            Q_ASSERT(i == readout);
+        }
+    }
+}
+
+void BenchmarksTest::benchQLocalSocketInt()
+{
+    const QString socketName = QStringLiteral("benchLocalSocket");
+    QLocalServer server;
+    QLocalServer::removeServer(socketName);
+    server.listen(socketName);
+    QLocalSocket client;
+    client.connectToServer(socketName);
+    QEventLoop loop;
+    QScopedPointer<QLocalSocket> serverSock;
+    if (!server.hasPendingConnections()) {
+        connect(&server, &QLocalServer::newConnection, &loop, &QEventLoop::quit);
+        loop.exec();
+    }
+    Q_ASSERT(server.hasPendingConnections());
+    serverSock.reset(server.nextPendingConnection());
+    int lastValue = 0;
+    connect(&client, &QLocalSocket::readyRead, [&loop, &lastValue, &client]() {
+        int readout = 0;
+        while (client.bytesAvailable() && lastValue < 50000) {
+            client.read(reinterpret_cast<char*>(&readout), sizeof(int));
+            const bool res = (lastValue++ == readout);
+            Q_ASSERT(res);
+            Q_UNUSED(res)
+        }
+        if (lastValue >= 50000)
+            loop.quit();
+    });
+    QBENCHMARK {
+        for (int i = 0; i < 50000; ++i) {
+            const int res = int(serverSock->write(reinterpret_cast<char*>(&i), sizeof(int)));
+            Q_ASSERT(res == sizeof(int));
+            Q_UNUSED(res)
+        }
+        loop.exec();
+    }
+
+#ifdef Q_OS_WIN
+    // Work-around QTBUG-38185: immediately close socket
+    client.abort();
+#endif
+}
+
+void BenchmarksTest::benchQLocalSocketQDataStreamInt()
+{
+    const QString socketName = QStringLiteral("benchLocalSocket");
+    QLocalServer server;
+    QLocalServer::removeServer(socketName);
+    server.listen(socketName);
+    QLocalSocket client;
+    client.connectToServer(socketName);
+    QDataStream readStream(&client);
+    QEventLoop loop;
+    QScopedPointer<QLocalSocket> serverSock;
+    if (!server.hasPendingConnections()) {
+        connect(&server, &QLocalServer::newConnection, &loop, &QEventLoop::quit);
+        loop.exec();
+    }
+    Q_ASSERT(server.hasPendingConnections());
+    serverSock.reset(server.nextPendingConnection());
+    QDataStream writeStream(serverSock.data());
+    int lastValue = 0;
+    connect(&client, &QIODevice::readyRead, [&loop, &lastValue, &readStream]() {
+        int readout = 0;
+        while (readStream.device()->bytesAvailable() && lastValue < 50000) {
+            readStream >> readout;
+            const bool res = (lastValue++ == readout);
+            Q_ASSERT(res);
+            Q_UNUSED(res)
+        }
+        if (lastValue >= 50000)
+            loop.quit();
+    });
+    QBENCHMARK {
+        for (int i = 0; i < 50000; ++i) {
+            writeStream << i;
+        }
+        loop.exec();
+    }
+
+#ifdef Q_OS_WIN
+    // Work-around QTBUG-38185: immediately close socket
+    client.abort();
+#endif
+}
+
+void BenchmarksTest::benchModelLinearAccess()
+{
+    // Simulate an user browse through item them stops.
+    // We're measuring the time needed needed to deliver the visible chunk of data
+    // which are the last 50 items
+    QBENCHMARK {
+        QRemoteObjectNode localClient;
+        localClient.connectToNode(QUrl(QStringLiteral("local:benchmark_replica")));
+        QScopedPointer<QAbstractItemModelReplica> model(localClient.acquireModel(QStringLiteral("BenchmarkRemoteModel")));
+        QEventLoop loop;
+        QHash<int, QPair<QString, QString>> dataToWait;
+        connect(model.data(), &QAbstractItemModelReplica::dataChanged, [&model, &loop, &dataToWait](const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList<int> &roles) {
+            for (int row = topLeft.row(); row <= bottomRight.row(); ++row) {
+                // we're assuming that the view will try use the sent data,
+                // therefore we're not optimizing the code
+                auto it = dataToWait.find(row);
+                if (it == dataToWait.end()) {
+                    // simulate some work with the received data
+                    QThread::usleep(10);
+                    continue;
+                }
+                for (int role : roles) {
+                    QVariant data = model->data(model->index(row, 0), role);
+                    switch (role) {
+                    case Qt::DisplayRole:
+                        it->first = data.toString();
+                        break;
+                    case Qt::BackgroundRole:
+                        it->second = data.toString();
+                        break;
+                    }
+                }
+
+                if (it->first == QStringLiteral("Benchmark data %1").arg(row) &&
+                        it->second == (row % 2 ? QStringLiteral("red") : QStringLiteral("green"))) {
+                    dataToWait.erase(it);
+                    if (dataToWait.isEmpty())
+                        break;
+                }
+            }
+            if (dataToWait.isEmpty())
+                loop.quit();
+        });
+
+        auto beginBenchmark = [&model, &dataToWait] {
+            for (int row = 0; row < 1000; ++row) {
+                if (row >= 950)
+                    dataToWait.insert(row, QPair<QString, QString>());
+                model->data(model->index(row, 0), Qt::DisplayRole);
+                model->data(model->index(row, 0), Qt::BackgroundRole);
+
+                // Views (e.g. QTreeView) are accessing other roles
+                model->data(model->index(row, 0), Qt::FontRole);
+                model->data(model->index(row, 0), Qt::DecorationRole);
+                model->data(model->index(row, 0), Qt::SizeHintRole);
+            }
+
+        };
+        connect(model.data(), &QAbstractItemModelReplica::initialized, [&model, &loop, &beginBenchmark] {
+            if (model->isInitialized()) {
+                beginBenchmark();
+            } else {
+                Q_ASSERT(false);
+                loop.quit();
+            }
+        });
+        if (model->isInitialized())
+            beginBenchmark();
+
+        QTimer::singleShot(5000, &loop, &QEventLoop::quit);
+        loop.exec();
+        QVERIFY(dataToWait.isEmpty());
+    }
+}
+
+void BenchmarksTest::benchModelRandomAccess()
+{
+    QBENCHMARK {
+        QRemoteObjectNode localClient;
+        localClient.connectToNode(QUrl(QStringLiteral("local:benchmark_replica")));
+        QScopedPointer<QAbstractItemModelReplica> model(localClient.acquireModel(QStringLiteral("BenchmarkRemoteModel")));
+        model->setRootCacheSize(5000); // we need to make room for all 5000 rows that we'll use
+        QEventLoop loop;
+        QHash<int, QPair<QString, QString>> dataToWait;
+        connect(model.data(), &QAbstractItemModelReplica::dataChanged, [&model, &loop, &dataToWait](const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList<int> &roles) {
+            for (int row = topLeft.row(); row <= bottomRight.row(); ++row) {
+                // we're assuming that the view will try use the sent data,
+                // therefore we're not optimizing the code
+                auto it = dataToWait.find(row);
+                if (it == dataToWait.end()) {
+                    QThread::yieldCurrentThread(); // instead to wait
+                    continue;
+                }
+                for (int role : roles) {
+                    QVariant data = model->data(model->index(row, 0), role);
+                    switch (role) {
+                    case Qt::DisplayRole:
+                        it->first = data.toString();
+                        break;
+                    case Qt::BackgroundRole:
+                        it->second = data.toString();
+                        break;
+                    }
+                }
+
+                if (it->first == QStringLiteral("Benchmark data %1").arg(row) &&
+                        it->second == (row % 2 ? QStringLiteral("red") : QStringLiteral("green"))) {
+                    dataToWait.erase(it);
+                    if (dataToWait.isEmpty())
+                        break;
+                }
+            }
+            if (dataToWait.isEmpty())
+                loop.quit();
+        });
+
+        auto beginBenchmark = [&model, &dataToWait] {
+            for (int chunck = 0; chunck < 100; ++chunck) {
+                int row = chunck * 950;
+                for (int r = 0; r < 50; ++r) {
+                    dataToWait.insert(r + row, QPair<QString, QString>());
+                    model->data(model->index(r + row, 0), Qt::DisplayRole);
+                    model->data(model->index(r + row, 0), Qt::BackgroundRole);
+
+                    // Views (e.g. QTreeView) are accessing other roles
+                    model->data(model->index(r + row, 0), Qt::FontRole);
+                    model->data(model->index(r + row, 0), Qt::DecorationRole);
+                    model->data(model->index(r + row, 0), Qt::SizeHintRole);
+                }
+            }
+
+        };
+        connect(model.data(), &QAbstractItemModelReplica::initialized, [&model, &loop, &beginBenchmark] {
+            if (model->isInitialized()) {
+                beginBenchmark();
+            } else {
+                Q_ASSERT(false);
+                loop.quit();
+            }
+        });
+        if (model->isInitialized())
+            beginBenchmark();
+
+        QTimer::singleShot(5000, &loop, &QEventLoop::quit);
+        loop.exec();
+        QVERIFY(dataToWait.isEmpty());
+    }
+}
+
+QTEST_MAIN(BenchmarksTest)
+
+#include "tst_benchmarkstest.moc"
diff --git a/tests/auto/bic/data/QtRemoteObjects.5.13.0.linux-gcc-amd64.txt b/tests/auto/bic/data/QtRemoteObjects.5.13.0.linux-gcc-amd64.txt
new file mode 100644 (file)
index 0000000..f65afd8
--- /dev/null
@@ -0,0 +1,6368 @@
+Class std::__failure_type
+   size=1 align=1
+   base size=0 base align=1
+std::__failure_type (0x0x7f234e2095a0) 0 empty
+
+Class std::__do_is_destructible_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__do_is_destructible_impl (0x0x7f234e267d20) 0 empty
+
+Class std::__do_is_nt_destructible_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__do_is_nt_destructible_impl (0x0x7f234e267f60) 0 empty
+
+Class std::__do_is_default_constructible_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__do_is_default_constructible_impl (0x0x7f234e2911e0) 0 empty
+
+Class std::__do_is_static_castable_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__do_is_static_castable_impl (0x0x7f234e291420) 0 empty
+
+Class std::__do_is_direct_constructible_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__do_is_direct_constructible_impl (0x0x7f234e2915a0) 0 empty
+
+Class std::__do_is_nary_constructible_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__do_is_nary_constructible_impl (0x0x7f234e291960) 0 empty
+
+Class std::__do_is_implicitly_default_constructible_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__do_is_implicitly_default_constructible_impl (0x0x7f234e2cfa80) 0 empty
+
+Class std::__do_common_type_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__do_common_type_impl (0x0x7f234df4f180) 0 empty
+
+Class std::__do_member_type_wrapper
+   size=1 align=1
+   base size=0 base align=1
+std::__do_member_type_wrapper (0x0x7f234df4f240) 0 empty
+
+Class std::__invoke_memfun_ref
+   size=1 align=1
+   base size=0 base align=1
+std::__invoke_memfun_ref (0x0x7f234df4f600) 0 empty
+
+Class std::__invoke_memfun_deref
+   size=1 align=1
+   base size=0 base align=1
+std::__invoke_memfun_deref (0x0x7f234df4f660) 0 empty
+
+Class std::__invoke_memobj_ref
+   size=1 align=1
+   base size=0 base align=1
+std::__invoke_memobj_ref (0x0x7f234df4f6c0) 0 empty
+
+Class std::__invoke_memobj_deref
+   size=1 align=1
+   base size=0 base align=1
+std::__invoke_memobj_deref (0x0x7f234df4f720) 0 empty
+
+Class std::__invoke_other
+   size=1 align=1
+   base size=0 base align=1
+std::__invoke_other (0x0x7f234df4f780) 0 empty
+
+Class std::__result_of_memfun_ref_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__result_of_memfun_ref_impl (0x0x7f234df4f840) 0 empty
+
+Class std::__result_of_memfun_deref_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__result_of_memfun_deref_impl (0x0x7f234df4f900) 0 empty
+
+Class std::__result_of_memobj_ref_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__result_of_memobj_ref_impl (0x0x7f234df4f9c0) 0 empty
+
+Class std::__result_of_memobj_deref_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__result_of_memobj_deref_impl (0x0x7f234df4fa80) 0 empty
+
+Class std::__result_of_other_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__result_of_other_impl (0x0x7f234df4fde0) 0 empty
+
+Class std::__swappable_details::__do_is_swappable_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__swappable_details::__do_is_swappable_impl (0x0x7f234df8f180) 0 empty
+
+Class std::__swappable_details::__do_is_nothrow_swappable_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__swappable_details::__do_is_nothrow_swappable_impl (0x0x7f234df8f1e0) 0 empty
+
+Class std::__nonesuch
+   size=1 align=1
+   base size=0 base align=1
+std::__nonesuch (0x0x7f234df8f780) 0 empty
+
+Class std::piecewise_construct_t
+   size=1 align=1
+   base size=0 base align=1
+std::piecewise_construct_t (0x0x7f234df8fde0) 0 empty
+
+Class std::__nonesuch_no_braces
+   size=1 align=1
+   base size=1 base align=1
+std::__nonesuch_no_braces (0x0x7f234dfa71a0) 0 empty
+  std::__nonesuch (0x0x7f234dfd2300) 0 empty
+
+Class std::__true_type
+   size=1 align=1
+   base size=0 base align=1
+std::__true_type (0x0x7f234e01fc60) 0 empty
+
+Class std::__false_type
+   size=1 align=1
+   base size=0 base align=1
+std::__false_type (0x0x7f234e01fcc0) 0 empty
+
+Class std::input_iterator_tag
+   size=1 align=1
+   base size=0 base align=1
+std::input_iterator_tag (0x0x7f234e07a9c0) 0 empty
+
+Class std::output_iterator_tag
+   size=1 align=1
+   base size=0 base align=1
+std::output_iterator_tag (0x0x7f234e07aa20) 0 empty
+
+Class std::forward_iterator_tag
+   size=1 align=1
+   base size=1 base align=1
+std::forward_iterator_tag (0x0x7f234dfa7680) 0 empty
+  std::input_iterator_tag (0x0x7f234e07aa80) 0 empty
+
+Class std::bidirectional_iterator_tag
+   size=1 align=1
+   base size=1 base align=1
+std::bidirectional_iterator_tag (0x0x7f234dfa76e8) 0 empty
+  std::forward_iterator_tag (0x0x7f234dfa7750) 0 empty
+    std::input_iterator_tag (0x0x7f234e07aae0) 0 empty
+
+Class std::random_access_iterator_tag
+   size=1 align=1
+   base size=1 base align=1
+std::random_access_iterator_tag (0x0x7f234dfa77b8) 0 empty
+  std::bidirectional_iterator_tag (0x0x7f234dfa7820) 0 empty
+    std::forward_iterator_tag (0x0x7f234dfa7888) 0 empty
+      std::input_iterator_tag (0x0x7f234e07ab40) 0 empty
+
+Class __gnu_cxx::__ops::_Iter_less_iter
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__ops::_Iter_less_iter (0x0x7f234e12d660) 0 empty
+
+Class __gnu_cxx::__ops::_Iter_less_val
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__ops::_Iter_less_val (0x0x7f234e12d780) 0 empty
+
+Class __gnu_cxx::__ops::_Val_less_iter
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__ops::_Val_less_iter (0x0x7f234e12da80) 0 empty
+
+Class __gnu_cxx::__ops::_Iter_equal_to_iter
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__ops::_Iter_equal_to_iter (0x0x7f234e12dd80) 0 empty
+
+Class __gnu_cxx::__ops::_Iter_equal_to_val
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__ops::_Iter_equal_to_val (0x0x7f234e12dea0) 0 empty
+
+Class __locale_struct
+   size=232 align=8
+   base size=232 base align=8
+__locale_struct (0x0x7f234ddeb1e0) 0
+
+Class timeval
+   size=16 align=8
+   base size=16 base align=8
+timeval (0x0x7f234ddeb4e0) 0
+
+Class timespec
+   size=16 align=8
+   base size=16 base align=8
+timespec (0x0x7f234ddeb540) 0
+
+Class __pthread_rwlock_arch_t
+   size=56 align=8
+   base size=56 base align=8
+__pthread_rwlock_arch_t (0x0x7f234ddeb600) 0
+
+Class __pthread_internal_list
+   size=16 align=8
+   base size=16 base align=8
+__pthread_internal_list (0x0x7f234ddeb660) 0
+
+Class __pthread_mutex_s
+   size=40 align=8
+   base size=40 base align=8
+__pthread_mutex_s (0x0x7f234ddeb6c0) 0
+
+Class __pthread_cond_s
+   size=48 align=8
+   base size=48 base align=8
+__pthread_cond_s (0x0x7f234ddeb720) 0
+
+Class pthread_attr_t
+   size=56 align=8
+   base size=56 base align=8
+pthread_attr_t (0x0x7f234ddeb9c0) 0
+
+Class random_data
+   size=48 align=8
+   base size=48 base align=8
+random_data (0x0x7f234ddebc60) 0
+
+Class drand48_data
+   size=24 align=8
+   base size=24 base align=8
+drand48_data (0x0x7f234ddebcc0) 0
+
+Vtable for std::exception
+std::exception::_ZTVSt9exception: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt9exception)
+16    (int (*)(...))std::exception::~exception
+24    (int (*)(...))std::exception::~exception
+32    (int (*)(...))std::exception::what
+
+Class std::exception
+   size=8 align=8
+   base size=8 base align=8
+std::exception (0x0x7f234deb4a80) 0 nearly-empty
+    vptr=((& std::exception::_ZTVSt9exception) + 16)
+
+Vtable for std::bad_exception
+std::bad_exception::_ZTVSt13bad_exception: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt13bad_exception)
+16    (int (*)(...))std::bad_exception::~bad_exception
+24    (int (*)(...))std::bad_exception::~bad_exception
+32    (int (*)(...))std::bad_exception::what
+
+Class std::bad_exception
+   size=8 align=8
+   base size=8 base align=8
+std::bad_exception (0x0x7f234dfa7bc8) 0 nearly-empty
+    vptr=((& std::bad_exception::_ZTVSt13bad_exception) + 16)
+  std::exception (0x0x7f234deb4c60) 0 nearly-empty
+      primary-for std::bad_exception (0x0x7f234dfa7bc8)
+
+Vtable for std::type_info
+std::type_info::_ZTVSt9type_info: 8 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt9type_info)
+16    (int (*)(...))std::type_info::~type_info
+24    (int (*)(...))std::type_info::~type_info
+32    (int (*)(...))std::type_info::__is_pointer_p
+40    (int (*)(...))std::type_info::__is_function_p
+48    (int (*)(...))std::type_info::__do_catch
+56    (int (*)(...))std::type_info::__do_upcast
+
+Class std::type_info
+   size=16 align=8
+   base size=16 base align=8
+std::type_info (0x0x7f234deb4e40) 0
+    vptr=((& std::type_info::_ZTVSt9type_info) + 16)
+
+Vtable for std::bad_cast
+std::bad_cast::_ZTVSt8bad_cast: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt8bad_cast)
+16    (int (*)(...))std::bad_cast::~bad_cast
+24    (int (*)(...))std::bad_cast::~bad_cast
+32    (int (*)(...))std::bad_cast::what
+
+Class std::bad_cast
+   size=8 align=8
+   base size=8 base align=8
+std::bad_cast (0x0x7f234dfa7c30) 0 nearly-empty
+    vptr=((& std::bad_cast::_ZTVSt8bad_cast) + 16)
+  std::exception (0x0x7f234deeb240) 0 nearly-empty
+      primary-for std::bad_cast (0x0x7f234dfa7c30)
+
+Vtable for std::bad_typeid
+std::bad_typeid::_ZTVSt10bad_typeid: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt10bad_typeid)
+16    (int (*)(...))std::bad_typeid::~bad_typeid
+24    (int (*)(...))std::bad_typeid::~bad_typeid
+32    (int (*)(...))std::bad_typeid::what
+
+Class std::bad_typeid
+   size=8 align=8
+   base size=8 base align=8
+std::bad_typeid (0x0x7f234dfa7c98) 0 nearly-empty
+    vptr=((& std::bad_typeid::_ZTVSt10bad_typeid) + 16)
+  std::exception (0x0x7f234deeb420) 0 nearly-empty
+      primary-for std::bad_typeid (0x0x7f234dfa7c98)
+
+Class std::__exception_ptr::exception_ptr
+   size=8 align=8
+   base size=8 base align=8
+std::__exception_ptr::exception_ptr (0x0x7f234deeb600) 0
+
+Vtable for std::nested_exception
+std::nested_exception::_ZTVSt16nested_exception: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt16nested_exception)
+16    (int (*)(...))std::nested_exception::~nested_exception
+24    (int (*)(...))std::nested_exception::~nested_exception
+
+Class std::nested_exception
+   size=16 align=8
+   base size=16 base align=8
+std::nested_exception (0x0x7f234deebba0) 0
+    vptr=((& std::nested_exception::_ZTVSt16nested_exception) + 16)
+
+Vtable for std::bad_alloc
+std::bad_alloc::_ZTVSt9bad_alloc: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt9bad_alloc)
+16    (int (*)(...))std::bad_alloc::~bad_alloc
+24    (int (*)(...))std::bad_alloc::~bad_alloc
+32    (int (*)(...))std::bad_alloc::what
+
+Class std::bad_alloc
+   size=8 align=8
+   base size=8 base align=8
+std::bad_alloc (0x0x7f234dfa7d00) 0 nearly-empty
+    vptr=((& std::bad_alloc::_ZTVSt9bad_alloc) + 16)
+  std::exception (0x0x7f234df1a2a0) 0 nearly-empty
+      primary-for std::bad_alloc (0x0x7f234dfa7d00)
+
+Vtable for std::bad_array_new_length
+std::bad_array_new_length::_ZTVSt20bad_array_new_length: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt20bad_array_new_length)
+16    (int (*)(...))std::bad_array_new_length::~bad_array_new_length
+24    (int (*)(...))std::bad_array_new_length::~bad_array_new_length
+32    (int (*)(...))std::bad_array_new_length::what
+
+Class std::bad_array_new_length
+   size=8 align=8
+   base size=8 base align=8
+std::bad_array_new_length (0x0x7f234dfa7d68) 0 nearly-empty
+    vptr=((& std::bad_array_new_length::_ZTVSt20bad_array_new_length) + 16)
+  std::bad_alloc (0x0x7f234dfa7dd0) 0 nearly-empty
+      primary-for std::bad_array_new_length (0x0x7f234dfa7d68)
+    std::exception (0x0x7f234df1a480) 0 nearly-empty
+        primary-for std::bad_alloc (0x0x7f234dfa7dd0)
+
+Class std::nothrow_t
+   size=1 align=1
+   base size=0 base align=1
+std::nothrow_t (0x0x7f234df1a660) 0 empty
+
+Class std::__allocator_traits_base
+   size=1 align=1
+   base size=0 base align=1
+std::__allocator_traits_base (0x0x7f234df1a840) 0 empty
+
+Class std::__numeric_limits_base
+   size=1 align=1
+   base size=0 base align=1
+std::__numeric_limits_base (0x0x7f234db97d20) 0 empty
+
+Class qIsNull(double)::U
+   size=8 align=8
+   base size=8 base align=8
+qIsNull(double)::U (0x0x7f234d9737e0) 0
+
+Class qIsNull(float)::U
+   size=4 align=4
+   base size=4 base align=4
+qIsNull(float)::U (0x0x7f234d9738a0) 0
+
+Class QSysInfo
+   size=1 align=1
+   base size=0 base align=1
+QSysInfo (0x0x7f234d834240) 0 empty
+
+Class QMessageLogContext
+   size=32 align=8
+   base size=32 base align=8
+QMessageLogContext (0x0x7f234d834360) 0
+
+Class QMessageLogger
+   size=32 align=8
+   base size=32 base align=8
+QMessageLogger (0x0x7f234d8346c0) 0
+
+Class QFlag
+   size=4 align=4
+   base size=4 base align=4
+QFlag (0x0x7f234d834c00) 0
+
+Class QIncompatibleFlag
+   size=4 align=4
+   base size=4 base align=4
+QIncompatibleFlag (0x0x7f234d8ad3c0) 0
+
+Class std::__atomic_flag_base
+   size=1 align=1
+   base size=1 base align=1
+std::__atomic_flag_base (0x0x7f234d5437e0) 0
+
+Class std::atomic_flag
+   size=1 align=1
+   base size=1 base align=1
+std::atomic_flag (0x0x7f234d8e5c30) 0
+  std::__atomic_flag_base (0x0x7f234d543840) 0
+
+Class QAtomicInt
+   size=4 align=4
+   base size=4 base align=4
+QAtomicInt (0x0x7f234d7273a8) 0
+  QAtomicInteger<int> (0x0x7f234d727410) 0
+    QBasicAtomicInteger<int> (0x0x7f234d4787e0) 0
+
+Class QInternal
+   size=1 align=1
+   base size=0 base align=1
+QInternal (0x0x7f234d090ae0) 0 empty
+
+Class QtPrivate::QSlotObjectBase
+   size=16 align=8
+   base size=16 base align=8
+QtPrivate::QSlotObjectBase (0x0x7f234d1010c0) 0
+
+Class QGenericArgument
+   size=16 align=8
+   base size=16 base align=8
+QGenericArgument (0x0x7f234d1017e0) 0
+
+Class QGenericReturnArgument
+   size=16 align=8
+   base size=16 base align=8
+QGenericReturnArgument (0x0x7f234d240f70) 0
+  QGenericArgument (0x0x7f234d101a80) 0
+
+Class QMetaObject
+   size=48 align=8
+   base size=48 base align=8
+QMetaObject (0x0x7f234d101ea0) 0
+
+Class QMetaObject::Connection
+   size=8 align=8
+   base size=8 base align=8
+QMetaObject::Connection (0x0x7f234cd60300) 0
+
+Class QLatin1Char
+   size=1 align=1
+   base size=1 base align=1
+QLatin1Char (0x0x7f234cdc6de0) 0
+
+Class QChar
+   size=2 align=2
+   base size=2 base align=2
+QChar (0x0x7f234cde60c0) 0
+
+Class QtPrivate::RefCount
+   size=4 align=4
+   base size=4 base align=4
+QtPrivate::RefCount (0x0x7f234ce96ea0) 0
+
+Class QArrayData
+   size=24 align=8
+   base size=24 base align=8
+QArrayData (0x0x7f234ceb8240) 0
+
+Class QtPrivate::QContainerImplHelper
+   size=1 align=1
+   base size=0 base align=1
+QtPrivate::QContainerImplHelper (0x0x7f234cf1b540) 0 empty
+
+Class lconv
+   size=96 align=8
+   base size=96 base align=8
+lconv (0x0x7f234cbccd80) 0
+
+Vtable for __cxxabiv1::__forced_unwind
+__cxxabiv1::__forced_unwind::_ZTVN10__cxxabiv115__forced_unwindE: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTIN10__cxxabiv115__forced_unwindE)
+16    0
+24    0
+32    (int (*)(...))__cxa_pure_virtual
+
+Class __cxxabiv1::__forced_unwind
+   size=8 align=8
+   base size=8 base align=8
+__cxxabiv1::__forced_unwind (0x0x7f234cbcce40) 0 nearly-empty
+    vptr=((& __cxxabiv1::__forced_unwind::_ZTVN10__cxxabiv115__forced_unwindE) + 16)
+
+Class sched_param
+   size=4 align=4
+   base size=4 base align=4
+sched_param (0x0x7f234cc8ff60) 0
+
+Class timex
+   size=208 align=8
+   base size=208 base align=8
+timex (0x0x7f234ccc0060) 0
+
+Class tm
+   size=56 align=8
+   base size=56 base align=8
+tm (0x0x7f234ccc00c0) 0
+
+Class itimerspec
+   size=32 align=8
+   base size=32 base align=8
+itimerspec (0x0x7f234ccc0120) 0
+
+Class _pthread_cleanup_buffer
+   size=32 align=8
+   base size=32 base align=8
+_pthread_cleanup_buffer (0x0x7f234ccc0180) 0
+
+Class __pthread_cleanup_frame
+   size=24 align=8
+   base size=24 base align=8
+__pthread_cleanup_frame (0x0x7f234ccc02a0) 0
+
+Class __pthread_cleanup_class
+   size=24 align=8
+   base size=24 base align=8
+__pthread_cleanup_class (0x0x7f234ccc0300) 0
+
+Class _IO_marker
+   size=24 align=8
+   base size=24 base align=8
+_IO_marker (0x0x7f234ca022a0) 0
+
+Class _IO_FILE
+   size=216 align=8
+   base size=216 base align=8
+_IO_FILE (0x0x7f234ca02300) 0
+
+Class std::_Hash_impl
+   size=1 align=1
+   base size=0 base align=1
+std::_Hash_impl (0x0x7f234c7b7360) 0 empty
+
+Class std::_Fnv_hash_impl
+   size=1 align=1
+   base size=0 base align=1
+std::_Fnv_hash_impl (0x0x7f234c7b74e0) 0 empty
+
+Class std::locale
+   size=8 align=8
+   base size=8 base align=8
+std::locale (0x0x7f234c933660) 0
+
+Vtable for std::locale::facet
+std::locale::facet::_ZTVNSt6locale5facetE: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTINSt6locale5facetE)
+16    (int (*)(...))std::locale::facet::~facet
+24    (int (*)(...))std::locale::facet::~facet
+
+Class std::locale::facet
+   size=16 align=8
+   base size=12 base align=8
+std::locale::facet (0x0x7f234c933a20) 0
+    vptr=((& std::locale::facet::_ZTVNSt6locale5facetE) + 16)
+
+Class std::locale::id
+   size=8 align=8
+   base size=8 base align=8
+std::locale::id (0x0x7f234c933cc0) 0
+
+Class std::locale::_Impl
+   size=40 align=8
+   base size=40 base align=8
+std::locale::_Impl (0x0x7f234c933ea0) 0
+
+Class std::__cow_string
+   size=8 align=8
+   base size=8 base align=8
+std::__cow_string (0x0x7f234c588ea0) 0
+
+Vtable for std::logic_error
+std::logic_error::_ZTVSt11logic_error: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt11logic_error)
+16    (int (*)(...))std::logic_error::~logic_error
+24    (int (*)(...))std::logic_error::~logic_error
+32    (int (*)(...))std::logic_error::what
+
+Class std::logic_error
+   size=16 align=8
+   base size=16 base align=8
+std::logic_error (0x0x7f234c7b8958) 0
+    vptr=((& std::logic_error::_ZTVSt11logic_error) + 16)
+  std::exception (0x0x7f234c588f60) 0 nearly-empty
+      primary-for std::logic_error (0x0x7f234c7b8958)
+
+Vtable for std::domain_error
+std::domain_error::_ZTVSt12domain_error: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt12domain_error)
+16    (int (*)(...))std::domain_error::~domain_error
+24    (int (*)(...))std::domain_error::~domain_error
+32    (int (*)(...))std::logic_error::what
+
+Class std::domain_error
+   size=16 align=8
+   base size=16 base align=8
+std::domain_error (0x0x7f234c7b89c0) 0
+    vptr=((& std::domain_error::_ZTVSt12domain_error) + 16)
+  std::logic_error (0x0x7f234c5d9000) 0
+      primary-for std::domain_error (0x0x7f234c7b89c0)
+    std::exception (0x0x7f234c5da000) 0 nearly-empty
+        primary-for std::logic_error (0x0x7f234c5d9000)
+
+Vtable for std::invalid_argument
+std::invalid_argument::_ZTVSt16invalid_argument: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt16invalid_argument)
+16    (int (*)(...))std::invalid_argument::~invalid_argument
+24    (int (*)(...))std::invalid_argument::~invalid_argument
+32    (int (*)(...))std::logic_error::what
+
+Class std::invalid_argument
+   size=16 align=8
+   base size=16 base align=8
+std::invalid_argument (0x0x7f234c5d9068) 0
+    vptr=((& std::invalid_argument::_ZTVSt16invalid_argument) + 16)
+  std::logic_error (0x0x7f234c5d90d0) 0
+      primary-for std::invalid_argument (0x0x7f234c5d9068)
+    std::exception (0x0x7f234c5da060) 0 nearly-empty
+        primary-for std::logic_error (0x0x7f234c5d90d0)
+
+Vtable for std::length_error
+std::length_error::_ZTVSt12length_error: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt12length_error)
+16    (int (*)(...))std::length_error::~length_error
+24    (int (*)(...))std::length_error::~length_error
+32    (int (*)(...))std::logic_error::what
+
+Class std::length_error
+   size=16 align=8
+   base size=16 base align=8
+std::length_error (0x0x7f234c5d9138) 0
+    vptr=((& std::length_error::_ZTVSt12length_error) + 16)
+  std::logic_error (0x0x7f234c5d91a0) 0
+      primary-for std::length_error (0x0x7f234c5d9138)
+    std::exception (0x0x7f234c5da0c0) 0 nearly-empty
+        primary-for std::logic_error (0x0x7f234c5d91a0)
+
+Vtable for std::out_of_range
+std::out_of_range::_ZTVSt12out_of_range: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt12out_of_range)
+16    (int (*)(...))std::out_of_range::~out_of_range
+24    (int (*)(...))std::out_of_range::~out_of_range
+32    (int (*)(...))std::logic_error::what
+
+Class std::out_of_range
+   size=16 align=8
+   base size=16 base align=8
+std::out_of_range (0x0x7f234c5d9208) 0
+    vptr=((& std::out_of_range::_ZTVSt12out_of_range) + 16)
+  std::logic_error (0x0x7f234c5d9270) 0
+      primary-for std::out_of_range (0x0x7f234c5d9208)
+    std::exception (0x0x7f234c5da120) 0 nearly-empty
+        primary-for std::logic_error (0x0x7f234c5d9270)
+
+Vtable for std::runtime_error
+std::runtime_error::_ZTVSt13runtime_error: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt13runtime_error)
+16    (int (*)(...))std::runtime_error::~runtime_error
+24    (int (*)(...))std::runtime_error::~runtime_error
+32    (int (*)(...))std::runtime_error::what
+
+Class std::runtime_error
+   size=16 align=8
+   base size=16 base align=8
+std::runtime_error (0x0x7f234c5d92d8) 0
+    vptr=((& std::runtime_error::_ZTVSt13runtime_error) + 16)
+  std::exception (0x0x7f234c5da180) 0 nearly-empty
+      primary-for std::runtime_error (0x0x7f234c5d92d8)
+
+Vtable for std::range_error
+std::range_error::_ZTVSt11range_error: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt11range_error)
+16    (int (*)(...))std::range_error::~range_error
+24    (int (*)(...))std::range_error::~range_error
+32    (int (*)(...))std::runtime_error::what
+
+Class std::range_error
+   size=16 align=8
+   base size=16 base align=8
+std::range_error (0x0x7f234c5d9340) 0
+    vptr=((& std::range_error::_ZTVSt11range_error) + 16)
+  std::runtime_error (0x0x7f234c5d93a8) 0
+      primary-for std::range_error (0x0x7f234c5d9340)
+    std::exception (0x0x7f234c5da1e0) 0 nearly-empty
+        primary-for std::runtime_error (0x0x7f234c5d93a8)
+
+Vtable for std::overflow_error
+std::overflow_error::_ZTVSt14overflow_error: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt14overflow_error)
+16    (int (*)(...))std::overflow_error::~overflow_error
+24    (int (*)(...))std::overflow_error::~overflow_error
+32    (int (*)(...))std::runtime_error::what
+
+Class std::overflow_error
+   size=16 align=8
+   base size=16 base align=8
+std::overflow_error (0x0x7f234c5d9410) 0
+    vptr=((& std::overflow_error::_ZTVSt14overflow_error) + 16)
+  std::runtime_error (0x0x7f234c5d9478) 0
+      primary-for std::overflow_error (0x0x7f234c5d9410)
+    std::exception (0x0x7f234c5da240) 0 nearly-empty
+        primary-for std::runtime_error (0x0x7f234c5d9478)
+
+Vtable for std::underflow_error
+std::underflow_error::_ZTVSt15underflow_error: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt15underflow_error)
+16    (int (*)(...))std::underflow_error::~underflow_error
+24    (int (*)(...))std::underflow_error::~underflow_error
+32    (int (*)(...))std::runtime_error::what
+
+Class std::underflow_error
+   size=16 align=8
+   base size=16 base align=8
+std::underflow_error (0x0x7f234c5d94e0) 0
+    vptr=((& std::underflow_error::_ZTVSt15underflow_error) + 16)
+  std::runtime_error (0x0x7f234c5d9548) 0
+      primary-for std::underflow_error (0x0x7f234c5d94e0)
+    std::exception (0x0x7f234c5da2a0) 0 nearly-empty
+        primary-for std::runtime_error (0x0x7f234c5d9548)
+
+Vtable for std::_V2::error_category
+std::_V2::error_category::_ZTVNSt3_V214error_categoryE: 10 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTINSt3_V214error_categoryE)
+16    0
+24    0
+32    (int (*)(...))__cxa_pure_virtual
+40    (int (*)(...))std::_V2::error_category::_M_message
+48    (int (*)(...))__cxa_pure_virtual
+56    (int (*)(...))std::_V2::error_category::default_error_condition
+64    (int (*)(...))std::_V2::error_category::equivalent
+72    (int (*)(...))std::_V2::error_category::equivalent
+
+Class std::_V2::error_category
+   size=8 align=8
+   base size=8 base align=8
+std::_V2::error_category (0x0x7f234c5da420) 0 nearly-empty
+    vptr=((& std::_V2::error_category::_ZTVNSt3_V214error_categoryE) + 16)
+
+Class std::error_code
+   size=16 align=8
+   base size=16 base align=8
+std::error_code (0x0x7f234c5da780) 0
+
+Class std::error_condition
+   size=16 align=8
+   base size=16 base align=8
+std::error_condition (0x0x7f234c623000) 0
+
+Vtable for std::system_error
+std::system_error::_ZTVSt12system_error: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt12system_error)
+16    (int (*)(...))std::system_error::~system_error
+24    (int (*)(...))std::system_error::~system_error
+32    (int (*)(...))std::runtime_error::what
+
+Class std::system_error
+   size=32 align=8
+   base size=32 base align=8
+std::system_error (0x0x7f234c5d9958) 0
+    vptr=((& std::system_error::_ZTVSt12system_error) + 16)
+  std::runtime_error (0x0x7f234c5d99c0) 0
+      primary-for std::system_error (0x0x7f234c5d9958)
+    std::exception (0x0x7f234c623ba0) 0 nearly-empty
+        primary-for std::runtime_error (0x0x7f234c5d99c0)
+
+Vtable for std::ios_base::failure
+std::ios_base::failure::_ZTVNSt8ios_base7failureB5cxx11E: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTINSt8ios_base7failureB5cxx11E)
+16    (int (*)(...))std::ios_base::failure::~failure
+24    (int (*)(...))std::ios_base::failure::~failure
+32    (int (*)(...))std::ios_base::failure::what
+
+Class std::ios_base::failure
+   size=32 align=8
+   base size=32 base align=8
+std::ios_base::failure (0x0x7f234c5d9c30) 0
+    vptr=((& std::ios_base::failure::_ZTVNSt8ios_base7failureB5cxx11E) + 16)
+  std::system_error (0x0x7f234c5d9c98) 0
+      primary-for std::ios_base::failure (0x0x7f234c5d9c30)
+    std::runtime_error (0x0x7f234c5d9d00) 0
+        primary-for std::system_error (0x0x7f234c5d9c98)
+      std::exception (0x0x7f234c680180) 0 nearly-empty
+          primary-for std::runtime_error (0x0x7f234c5d9d00)
+
+Class std::ios_base::_Callback_list
+   size=24 align=8
+   base size=24 base align=8
+std::ios_base::_Callback_list (0x0x7f234c6801e0) 0
+
+Class std::ios_base::_Words
+   size=16 align=8
+   base size=16 base align=8
+std::ios_base::_Words (0x0x7f234c680240) 0
+
+Class std::ios_base::Init
+   size=1 align=1
+   base size=0 base align=1
+std::ios_base::Init (0x0x7f234c6802a0) 0 empty
+
+Vtable for std::ios_base
+std::ios_base::_ZTVSt8ios_base: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt8ios_base)
+16    (int (*)(...))std::ios_base::~ios_base
+24    (int (*)(...))std::ios_base::~ios_base
+
+Class std::ios_base
+   size=216 align=8
+   base size=216 base align=8
+std::ios_base (0x0x7f234c680120) 0
+    vptr=((& std::ios_base::_ZTVSt8ios_base) + 16)
+
+Class std::ctype_base
+   size=1 align=1
+   base size=0 base align=1
+std::ctype_base (0x0x7f234c34cba0) 0 empty
+
+Class std::__num_base
+   size=1 align=1
+   base size=0 base align=1
+std::__num_base (0x0x7f234c3f4d80) 0 empty
+
+VTT for std::basic_ostream<char>
+std::basic_ostream<char>::_ZTTSo: 2 entries
+0     ((& std::basic_ostream<char>::_ZTVSo) + 24)
+8     ((& std::basic_ostream<char>::_ZTVSo) + 64)
+
+VTT for std::basic_ostream<wchar_t>
+std::basic_ostream<wchar_t>::_ZTTSt13basic_ostreamIwSt11char_traitsIwEE: 2 entries
+0     ((& std::basic_ostream<wchar_t>::_ZTVSt13basic_ostreamIwSt11char_traitsIwEE) + 24)
+8     ((& std::basic_ostream<wchar_t>::_ZTVSt13basic_ostreamIwSt11char_traitsIwEE) + 64)
+
+VTT for std::basic_istream<char>
+std::basic_istream<char>::_ZTTSi: 2 entries
+0     ((& std::basic_istream<char>::_ZTVSi) + 24)
+8     ((& std::basic_istream<char>::_ZTVSi) + 64)
+
+VTT for std::basic_istream<wchar_t>
+std::basic_istream<wchar_t>::_ZTTSt13basic_istreamIwSt11char_traitsIwEE: 2 entries
+0     ((& std::basic_istream<wchar_t>::_ZTVSt13basic_istreamIwSt11char_traitsIwEE) + 24)
+8     ((& std::basic_istream<wchar_t>::_ZTVSt13basic_istreamIwSt11char_traitsIwEE) + 64)
+
+Construction vtable for std::basic_istream<char> (0x0x7f234bfc9410 instance) in std::basic_iostream<char>
+std::basic_iostream<char>::_ZTCSd0_Si: 10 entries
+0     24
+8     (int (*)(...))0
+16    (int (*)(...))(& _ZTISi)
+24    0
+32    0
+40    18446744073709551592
+48    (int (*)(...))-24
+56    (int (*)(...))(& _ZTISi)
+64    0
+72    0
+
+Construction vtable for std::basic_ostream<char> (0x0x7f234bfc94e0 instance) in std::basic_iostream<char>
+std::basic_iostream<char>::_ZTCSd16_So: 10 entries
+0     8
+8     (int (*)(...))0
+16    (int (*)(...))(& _ZTISo)
+24    0
+32    0
+40    18446744073709551608
+48    (int (*)(...))-8
+56    (int (*)(...))(& _ZTISo)
+64    0
+72    0
+
+VTT for std::basic_iostream<char>
+std::basic_iostream<char>::_ZTTSd: 7 entries
+0     ((& std::basic_iostream<char>::_ZTVSd) + 24)
+8     ((& std::basic_iostream<char>::_ZTCSd0_Si) + 24)
+16    ((& std::basic_iostream<char>::_ZTCSd0_Si) + 64)
+24    ((& std::basic_iostream<char>::_ZTCSd16_So) + 24)
+32    ((& std::basic_iostream<char>::_ZTCSd16_So) + 64)
+40    ((& std::basic_iostream<char>::_ZTVSd) + 104)
+48    ((& std::basic_iostream<char>::_ZTVSd) + 64)
+
+Construction vtable for std::basic_istream<wchar_t> (0x0x7f234c00b1a0 instance) in std::basic_iostream<wchar_t>
+std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE0_St13basic_istreamIwS1_E: 10 entries
+0     24
+8     (int (*)(...))0
+16    (int (*)(...))(& _ZTISt13basic_istreamIwSt11char_traitsIwEE)
+24    0
+32    0
+40    18446744073709551592
+48    (int (*)(...))-24
+56    (int (*)(...))(& _ZTISt13basic_istreamIwSt11char_traitsIwEE)
+64    0
+72    0
+
+Construction vtable for std::basic_ostream<wchar_t> (0x0x7f234c00b270 instance) in std::basic_iostream<wchar_t>
+std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE16_St13basic_ostreamIwS1_E: 10 entries
+0     8
+8     (int (*)(...))0
+16    (int (*)(...))(& _ZTISt13basic_ostreamIwSt11char_traitsIwEE)
+24    0
+32    0
+40    18446744073709551608
+48    (int (*)(...))-8
+56    (int (*)(...))(& _ZTISt13basic_ostreamIwSt11char_traitsIwEE)
+64    0
+72    0
+
+VTT for std::basic_iostream<wchar_t>
+std::basic_iostream<wchar_t>::_ZTTSt14basic_iostreamIwSt11char_traitsIwEE: 7 entries
+0     ((& std::basic_iostream<wchar_t>::_ZTVSt14basic_iostreamIwSt11char_traitsIwEE) + 24)
+8     ((& std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE0_St13basic_istreamIwS1_E) + 24)
+16    ((& std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE0_St13basic_istreamIwS1_E) + 64)
+24    ((& std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE16_St13basic_ostreamIwS1_E) + 24)
+32    ((& std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE16_St13basic_ostreamIwS1_E) + 64)
+40    ((& std::basic_iostream<wchar_t>::_ZTVSt14basic_iostreamIwSt11char_traitsIwEE) + 104)
+48    ((& std::basic_iostream<wchar_t>::_ZTVSt14basic_iostreamIwSt11char_traitsIwEE) + 64)
+
+Class QByteArrayDataPtr
+   size=8 align=8
+   base size=8 base align=8
+QByteArrayDataPtr (0x0x7f234c02b720) 0
+
+Class QByteArray
+   size=8 align=8
+   base size=8 base align=8
+QByteArray (0x0x7f234c02b780) 0
+
+Class QByteRef
+   size=16 align=8
+   base size=12 base align=8
+QByteRef (0x0x7f234bd47b40) 0
+
+Class QStringDataPtr
+   size=8 align=8
+   base size=8 base align=8
+QStringDataPtr (0x0x7f234bdec9c0) 0
+
+Class QStringView
+   size=16 align=8
+   base size=16 base align=8
+QStringView (0x0x7f234bdece40) 0
+
+Class QLatin1String
+   size=16 align=8
+   base size=16 base align=8
+QLatin1String (0x0x7f234bebdc00) 0
+
+Class QString::Null
+   size=1 align=1
+   base size=0 base align=1
+QString::Null (0x0x7f234bb4d660) 0 empty
+
+Class QString
+   size=8 align=8
+   base size=8 base align=8
+QString (0x0x7f234bb4d600) 0
+
+Class QCharRef
+   size=16 align=8
+   base size=12 base align=8
+QCharRef (0x0x7f234b9317e0) 0
+
+Class QStringRef
+   size=16 align=8
+   base size=16 base align=8
+QStringRef (0x0x7f234bad2060) 0
+
+Class QtPrivate::QHashCombine
+   size=1 align=1
+   base size=0 base align=1
+QtPrivate::QHashCombine (0x0x7f234b8eb360) 0 empty
+
+Class QtPrivate::QHashCombineCommutative
+   size=1 align=1
+   base size=0 base align=1
+QtPrivate::QHashCombineCommutative (0x0x7f234b8eb420) 0 empty
+
+Class std::_Bit_reference
+   size=16 align=8
+   base size=16 base align=8
+std::_Bit_reference (0x0x7f234b59a900) 0
+
+Class std::_Bit_iterator_base
+   size=16 align=8
+   base size=12 base align=8
+std::_Bit_iterator_base (0x0x7f234b8bf5b0) 0
+  std::iterator<std::random_access_iterator_tag, bool> (0x0x7f234b5bd060) 0 empty
+
+Class std::_Bit_iterator
+   size=16 align=8
+   base size=12 base align=8
+std::_Bit_iterator (0x0x7f234b8bf6e8) 0
+  std::_Bit_iterator_base (0x0x7f234b8bf750) 0
+    std::iterator<std::random_access_iterator_tag, bool> (0x0x7f234b5bd6c0) 0 empty
+
+Class std::_Bit_const_iterator
+   size=16 align=8
+   base size=12 base align=8
+std::_Bit_const_iterator (0x0x7f234b8bf7b8) 0
+  std::_Bit_iterator_base (0x0x7f234b8bf820) 0
+    std::iterator<std::random_access_iterator_tag, bool> (0x0x7f234b5bdea0) 0 empty
+
+Class std::__detail::_List_node_base
+   size=16 align=8
+   base size=16 base align=8
+std::__detail::_List_node_base (0x0x7f234b3d5540) 0
+
+Class QListData::NotArrayCompatibleLayout
+   size=1 align=1
+   base size=0 base align=1
+QListData::NotArrayCompatibleLayout (0x0x7f234b4a1300) 0 empty
+
+Class QListData::NotIndirectLayout
+   size=1 align=1
+   base size=0 base align=1
+QListData::NotIndirectLayout (0x0x7f234b4a1360) 0 empty
+
+Class QListData::ArrayCompatibleLayout
+   size=1 align=1
+   base size=1 base align=1
+QListData::ArrayCompatibleLayout (0x0x7f234b3aa270) 0 empty
+  QListData::NotIndirectLayout (0x0x7f234b4a13c0) 0 empty
+
+Class QListData::InlineWithPaddingLayout
+   size=1 align=1
+   base size=1 base align=1
+QListData::InlineWithPaddingLayout (0x0x7f234b32ee70) 0 empty
+  QListData::NotArrayCompatibleLayout (0x0x7f234b4a1420) 0 empty
+  QListData::NotIndirectLayout (0x0x7f234b4a1480) 0 empty
+
+Class QListData::IndirectLayout
+   size=1 align=1
+   base size=1 base align=1
+QListData::IndirectLayout (0x0x7f234b3aa2d8) 0 empty
+  QListData::NotArrayCompatibleLayout (0x0x7f234b4a14e0) 0 empty
+
+Class QListData::Data
+   size=24 align=8
+   base size=24 base align=8
+QListData::Data (0x0x7f234b4a1540) 0
+
+Class QListData
+   size=8 align=8
+   base size=8 base align=8
+QListData (0x0x7f234b4a12a0) 0
+
+Class QRegExp
+   size=8 align=8
+   base size=8 base align=8
+QRegExp (0x0x7f234b18e720) 0
+
+Class QStringMatcher::Data
+   size=272 align=8
+   base size=272 base align=8
+QStringMatcher::Data (0x0x7f234b26cd80) 0
+
+Class QStringMatcher
+   size=1048 align=8
+   base size=1048 base align=8
+QStringMatcher (0x0x7f234b26cd20) 0
+
+Class QStringList
+   size=8 align=8
+   base size=8 base align=8
+QStringList (0x0x7f234b2bb000) 0
+  QList<QString> (0x0x7f234b2bb068) 0
+    QListSpecialMethods<QString> (0x0x7f234b2bc000) 0 empty
+
+Class QScopedPointerPodDeleter
+   size=1 align=1
+   base size=0 base align=1
+QScopedPointerPodDeleter (0x0x7f234af29b40) 0 empty
+
+Class std::_Rb_tree_node_base
+   size=32 align=8
+   base size=32 base align=8
+std::_Rb_tree_node_base (0x0x7f234afbec60) 0
+
+Class std::_Rb_tree_header
+   size=40 align=8
+   base size=40 base align=8
+std::_Rb_tree_header (0x0x7f234afe1000) 0
+
+Class std::__erased_type
+   size=1 align=1
+   base size=0 base align=1
+std::__erased_type (0x0x7f234adb85a0) 0 empty
+
+Class std::allocator_arg_t
+   size=1 align=1
+   base size=0 base align=1
+std::allocator_arg_t (0x0x7f234adb8600) 0 empty
+
+Class std::__uses_alloc_base
+   size=1 align=1
+   base size=0 base align=1
+std::__uses_alloc_base (0x0x7f234adb8780) 0 empty
+
+Class std::__uses_alloc0::_Sink
+   size=1 align=1
+   base size=0 base align=1
+std::__uses_alloc0::_Sink (0x0x7f234adb8840) 0 empty
+
+Class std::__uses_alloc0
+   size=1 align=1
+   base size=1 base align=1
+std::__uses_alloc0 (0x0x7f234ad4b3a8) 0
+  std::__uses_alloc_base (0x0x7f234adb87e0) 0 empty
+
+Class std::_Swallow_assign
+   size=1 align=1
+   base size=0 base align=1
+std::_Swallow_assign (0x0x7f234aa9dba0) 0 empty
+
+Class QtPrivate::AbstractDebugStreamFunction
+   size=16 align=8
+   base size=16 base align=8
+QtPrivate::AbstractDebugStreamFunction (0x0x7f234ab63060) 0
+
+Class QtPrivate::AbstractComparatorFunction
+   size=24 align=8
+   base size=24 base align=8
+QtPrivate::AbstractComparatorFunction (0x0x7f234ab633c0) 0
+
+Class QtPrivate::AbstractConverterFunction
+   size=8 align=8
+   base size=8 base align=8
+QtPrivate::AbstractConverterFunction (0x0x7f234ab63900) 0
+
+Class QMetaType
+   size=80 align=8
+   base size=80 base align=8
+QMetaType (0x0x7f234ab63e40) 0
+
+Class QtMetaTypePrivate::VariantData
+   size=24 align=8
+   base size=20 base align=8
+QtMetaTypePrivate::VariantData (0x0x7f234abee060) 0
+
+Class QtMetaTypePrivate::VectorBoolElements
+   size=1 align=1
+   base size=0 base align=1
+QtMetaTypePrivate::VectorBoolElements (0x0x7f234abee720) 0 empty
+
+Class QtMetaTypePrivate::QSequentialIterableImpl
+   size=104 align=8
+   base size=104 base align=8
+QtMetaTypePrivate::QSequentialIterableImpl (0x0x7f234ac855a0) 0
+
+Class QtMetaTypePrivate::QAssociativeIterableImpl
+   size=112 align=8
+   base size=112 base align=8
+QtMetaTypePrivate::QAssociativeIterableImpl (0x0x7f234a8dcc60) 0
+
+Class QtMetaTypePrivate::QPairVariantInterfaceImpl
+   size=40 align=8
+   base size=40 base align=8
+QtMetaTypePrivate::QPairVariantInterfaceImpl (0x0x7f234a9551e0) 0
+
+Class std::chrono::_V2::system_clock
+   size=1 align=1
+   base size=0 base align=1
+std::chrono::_V2::system_clock (0x0x7f234a7a4000) 0 empty
+
+Class std::chrono::_V2::steady_clock
+   size=1 align=1
+   base size=0 base align=1
+std::chrono::_V2::steady_clock (0x0x7f234a49ea80) 0 empty
+
+Vtable for QObjectData
+QObjectData::_ZTV11QObjectData: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI11QObjectData)
+16    (int (*)(...))__cxa_pure_virtual
+24    (int (*)(...))__cxa_pure_virtual
+
+Class QObjectData
+   size=48 align=8
+   base size=48 base align=8
+QObjectData (0x0x7f234a49eae0) 0
+    vptr=((& QObjectData::_ZTV11QObjectData) + 16)
+
+Class QObject::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QObject::QPrivateSignal (0x0x7f234a49ecc0) 0 empty
+
+Vtable for QObject
+QObject::_ZTV7QObject: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI7QObject)
+16    (int (*)(...))QObject::metaObject
+24    (int (*)(...))QObject::qt_metacast
+32    (int (*)(...))QObject::qt_metacall
+40    (int (*)(...))QObject::~QObject
+48    (int (*)(...))QObject::~QObject
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QObject
+   size=16 align=8
+   base size=16 base align=8
+QObject (0x0x7f234a49ec60) 0
+    vptr=((& QObject::_ZTV7QObject) + 16)
+
+Vtable for QObjectUserData
+QObjectUserData::_ZTV15QObjectUserData: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI15QObjectUserData)
+16    (int (*)(...))QObjectUserData::~QObjectUserData
+24    (int (*)(...))QObjectUserData::~QObjectUserData
+
+Class QObjectUserData
+   size=8 align=8
+   base size=8 base align=8
+QObjectUserData (0x0x7f234a578ae0) 0 nearly-empty
+    vptr=((& QObjectUserData::_ZTV15QObjectUserData) + 16)
+
+Class QSignalBlocker
+   size=16 align=8
+   base size=10 base align=8
+QSignalBlocker (0x0x7f234a578c60) 0
+
+Class QAbstractAnimation::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QAbstractAnimation::QPrivateSignal (0x0x7f234a599540) 0 empty
+
+Vtable for QAbstractAnimation
+QAbstractAnimation::_ZTV18QAbstractAnimation: 18 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI18QAbstractAnimation)
+16    (int (*)(...))QAbstractAnimation::metaObject
+24    (int (*)(...))QAbstractAnimation::qt_metacast
+32    (int (*)(...))QAbstractAnimation::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QAbstractAnimation::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))__cxa_pure_virtual
+120   (int (*)(...))__cxa_pure_virtual
+128   (int (*)(...))QAbstractAnimation::updateState
+136   (int (*)(...))QAbstractAnimation::updateDirection
+
+Class QAbstractAnimation
+   size=16 align=8
+   base size=16 base align=8
+QAbstractAnimation (0x0x7f234a57d5b0) 0
+    vptr=((& QAbstractAnimation::_ZTV18QAbstractAnimation) + 16)
+  QObject (0x0x7f234a5994e0) 0
+      primary-for QAbstractAnimation (0x0x7f234a57d5b0)
+
+Class QAnimationDriver::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QAnimationDriver::QPrivateSignal (0x0x7f234a599900) 0 empty
+
+Vtable for QAnimationDriver
+QAnimationDriver::_ZTV16QAnimationDriver: 18 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI16QAnimationDriver)
+16    (int (*)(...))QAnimationDriver::metaObject
+24    (int (*)(...))QAnimationDriver::qt_metacast
+32    (int (*)(...))QAnimationDriver::qt_metacall
+40    (int (*)(...))QAnimationDriver::~QAnimationDriver
+48    (int (*)(...))QAnimationDriver::~QAnimationDriver
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QAnimationDriver::advance
+120   (int (*)(...))QAnimationDriver::elapsed
+128   (int (*)(...))QAnimationDriver::start
+136   (int (*)(...))QAnimationDriver::stop
+
+Class QAnimationDriver
+   size=16 align=8
+   base size=16 base align=8
+QAnimationDriver (0x0x7f234a57d618) 0
+    vptr=((& QAnimationDriver::_ZTV16QAnimationDriver) + 16)
+  QObject (0x0x7f234a5998a0) 0
+      primary-for QAnimationDriver (0x0x7f234a57d618)
+
+Class QEventLoop::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QEventLoop::QPrivateSignal (0x0x7f234a599b40) 0 empty
+
+Vtable for QEventLoop
+QEventLoop::_ZTV10QEventLoop: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI10QEventLoop)
+16    (int (*)(...))QEventLoop::metaObject
+24    (int (*)(...))QEventLoop::qt_metacast
+32    (int (*)(...))QEventLoop::qt_metacall
+40    (int (*)(...))QEventLoop::~QEventLoop
+48    (int (*)(...))QEventLoop::~QEventLoop
+56    (int (*)(...))QEventLoop::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QEventLoop
+   size=16 align=8
+   base size=16 base align=8
+QEventLoop (0x0x7f234a57d680) 0
+    vptr=((& QEventLoop::_ZTV10QEventLoop) + 16)
+  QObject (0x0x7f234a599ae0) 0
+      primary-for QEventLoop (0x0x7f234a57d680)
+
+Class QEventLoopLocker
+   size=8 align=8
+   base size=8 base align=8
+QEventLoopLocker (0x0x7f234a5ef420) 0
+
+Class QAbstractEventDispatcher::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QAbstractEventDispatcher::QPrivateSignal (0x0x7f234a5ef4e0) 0 empty
+
+Class QAbstractEventDispatcher::TimerInfo
+   size=12 align=4
+   base size=12 base align=4
+QAbstractEventDispatcher::TimerInfo (0x0x7f234a5ef540) 0
+
+Vtable for QAbstractEventDispatcher
+QAbstractEventDispatcher::_ZTV24QAbstractEventDispatcher: 28 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI24QAbstractEventDispatcher)
+16    (int (*)(...))QAbstractEventDispatcher::metaObject
+24    (int (*)(...))QAbstractEventDispatcher::qt_metacast
+32    (int (*)(...))QAbstractEventDispatcher::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))__cxa_pure_virtual
+120   (int (*)(...))__cxa_pure_virtual
+128   (int (*)(...))__cxa_pure_virtual
+136   (int (*)(...))__cxa_pure_virtual
+144   (int (*)(...))__cxa_pure_virtual
+152   (int (*)(...))__cxa_pure_virtual
+160   (int (*)(...))__cxa_pure_virtual
+168   (int (*)(...))__cxa_pure_virtual
+176   (int (*)(...))__cxa_pure_virtual
+184   (int (*)(...))__cxa_pure_virtual
+192   (int (*)(...))__cxa_pure_virtual
+200   (int (*)(...))__cxa_pure_virtual
+208   (int (*)(...))QAbstractEventDispatcher::startingUp
+216   (int (*)(...))QAbstractEventDispatcher::closingDown
+
+Class QAbstractEventDispatcher
+   size=16 align=8
+   base size=16 base align=8
+QAbstractEventDispatcher (0x0x7f234a57d7b8) 0
+    vptr=((& QAbstractEventDispatcher::_ZTV24QAbstractEventDispatcher) + 16)
+  QObject (0x0x7f234a5ef480) 0
+      primary-for QAbstractEventDispatcher (0x0x7f234a57d7b8)
+
+Vtable for std::bad_function_call
+std::bad_function_call::_ZTVSt17bad_function_call: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt17bad_function_call)
+16    (int (*)(...))std::bad_function_call::~bad_function_call
+24    (int (*)(...))std::bad_function_call::~bad_function_call
+32    (int (*)(...))std::bad_function_call::what
+
+Class std::bad_function_call
+   size=8 align=8
+   base size=8 base align=8
+std::bad_function_call (0x0x7f234a297138) 0 nearly-empty
+    vptr=((& std::bad_function_call::_ZTVSt17bad_function_call) + 16)
+  std::exception (0x0x7f234a27fba0) 0 nearly-empty
+      primary-for std::bad_function_call (0x0x7f234a297138)
+
+Class std::_Nocopy_types
+   size=16 align=8
+   base size=16 base align=8
+std::_Nocopy_types (0x0x7f234a27fc60) 0
+
+Class std::_Any_data
+   size=16 align=8
+   base size=16 base align=8
+std::_Any_data (0x0x7f234a27fcc0) 0
+
+Class std::_Function_base
+   size=24 align=8
+   base size=24 base align=8
+std::_Function_base (0x0x7f234a2b5000) 0
+
+Class QMapNodeBase
+   size=24 align=8
+   base size=24 base align=8
+QMapNodeBase (0x0x7f234a06bf60) 0
+
+Class QMapDataBase
+   size=40 align=8
+   base size=40 base align=8
+QMapDataBase (0x0x7f234a0b7c00) 0
+
+Class QHashData::Node
+   size=16 align=8
+   base size=16 base align=8
+QHashData::Node (0x0x7f234a1a75a0) 0
+
+Class QHashData
+   size=48 align=8
+   base size=44 base align=8
+QHashData (0x0x7f234a1a7540) 0
+
+Class QHashDummyValue
+   size=1 align=1
+   base size=0 base align=1
+QHashDummyValue (0x0x7f234a1a7840) 0 empty
+
+Class QVariant::PrivateShared
+   size=16 align=8
+   base size=12 base align=8
+QVariant::PrivateShared (0x0x7f2349eafde0) 0
+
+Class QVariant::Private::Data
+   size=8 align=8
+   base size=8 base align=8
+QVariant::Private::Data (0x0x7f2349eafea0) 0
+
+Class QVariant::Private
+   size=16 align=8
+   base size=12 base align=8
+QVariant::Private (0x0x7f2349eafe40) 0
+
+Class QVariant::Handler
+   size=72 align=8
+   base size=72 base align=8
+QVariant::Handler (0x0x7f2349eaff00) 0
+
+Class QVariant
+   size=16 align=8
+   base size=16 base align=8
+QVariant (0x0x7f2349eafd80) 0
+
+Class QVariantComparisonHelper
+   size=8 align=8
+   base size=8 base align=8
+QVariantComparisonHelper (0x0x7f2349c2b1e0) 0
+
+Class QSequentialIterable::const_iterator
+   size=112 align=8
+   base size=112 base align=8
+QSequentialIterable::const_iterator (0x0x7f2349c6d840) 0
+
+Class QSequentialIterable
+   size=104 align=8
+   base size=104 base align=8
+QSequentialIterable (0x0x7f2349c6d7e0) 0
+
+Class QAssociativeIterable::const_iterator
+   size=120 align=8
+   base size=120 base align=8
+QAssociativeIterable::const_iterator (0x0x7f2349c6d960) 0
+
+Class QAssociativeIterable
+   size=112 align=8
+   base size=112 base align=8
+QAssociativeIterable (0x0x7f2349c6d900) 0
+
+Class QModelIndex
+   size=24 align=8
+   base size=24 base align=8
+QModelIndex (0x0x7f2349d37ae0) 0
+
+Class QPersistentModelIndex
+   size=8 align=8
+   base size=8 base align=8
+QPersistentModelIndex (0x0x7f2349daa720) 0
+
+Class QAbstractItemModel::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QAbstractItemModel::QPrivateSignal (0x0x7f2349a7b540) 0 empty
+
+Vtable for QAbstractItemModel
+QAbstractItemModel::_ZTV18QAbstractItemModel: 48 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI18QAbstractItemModel)
+16    (int (*)(...))QAbstractItemModel::metaObject
+24    (int (*)(...))QAbstractItemModel::qt_metacast
+32    (int (*)(...))QAbstractItemModel::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))__cxa_pure_virtual
+120   (int (*)(...))__cxa_pure_virtual
+128   (int (*)(...))QAbstractItemModel::sibling
+136   (int (*)(...))__cxa_pure_virtual
+144   (int (*)(...))__cxa_pure_virtual
+152   (int (*)(...))QAbstractItemModel::hasChildren
+160   (int (*)(...))__cxa_pure_virtual
+168   (int (*)(...))QAbstractItemModel::setData
+176   (int (*)(...))QAbstractItemModel::headerData
+184   (int (*)(...))QAbstractItemModel::setHeaderData
+192   (int (*)(...))QAbstractItemModel::itemData
+200   (int (*)(...))QAbstractItemModel::setItemData
+208   (int (*)(...))QAbstractItemModel::mimeTypes
+216   (int (*)(...))QAbstractItemModel::mimeData
+224   (int (*)(...))QAbstractItemModel::canDropMimeData
+232   (int (*)(...))QAbstractItemModel::dropMimeData
+240   (int (*)(...))QAbstractItemModel::supportedDropActions
+248   (int (*)(...))QAbstractItemModel::supportedDragActions
+256   (int (*)(...))QAbstractItemModel::insertRows
+264   (int (*)(...))QAbstractItemModel::insertColumns
+272   (int (*)(...))QAbstractItemModel::removeRows
+280   (int (*)(...))QAbstractItemModel::removeColumns
+288   (int (*)(...))QAbstractItemModel::moveRows
+296   (int (*)(...))QAbstractItemModel::moveColumns
+304   (int (*)(...))QAbstractItemModel::fetchMore
+312   (int (*)(...))QAbstractItemModel::canFetchMore
+320   (int (*)(...))QAbstractItemModel::flags
+328   (int (*)(...))QAbstractItemModel::sort
+336   (int (*)(...))QAbstractItemModel::buddy
+344   (int (*)(...))QAbstractItemModel::match
+352   (int (*)(...))QAbstractItemModel::span
+360   (int (*)(...))QAbstractItemModel::roleNames
+368   (int (*)(...))QAbstractItemModel::submit
+376   (int (*)(...))QAbstractItemModel::revert
+
+Class QAbstractItemModel
+   size=16 align=8
+   base size=16 base align=8
+QAbstractItemModel (0x0x7f2349a6cd00) 0
+    vptr=((& QAbstractItemModel::_ZTV18QAbstractItemModel) + 16)
+  QObject (0x0x7f2349a7b4e0) 0
+      primary-for QAbstractItemModel (0x0x7f2349a6cd00)
+
+Class QAbstractTableModel::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QAbstractTableModel::QPrivateSignal (0x0x7f2349b32900) 0 empty
+
+Vtable for QAbstractTableModel
+QAbstractTableModel::_ZTV19QAbstractTableModel: 48 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI19QAbstractTableModel)
+16    (int (*)(...))QAbstractTableModel::metaObject
+24    (int (*)(...))QAbstractTableModel::qt_metacast
+32    (int (*)(...))QAbstractTableModel::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QAbstractTableModel::index
+120   (int (*)(...))QAbstractTableModel::parent
+128   (int (*)(...))QAbstractTableModel::sibling
+136   (int (*)(...))__cxa_pure_virtual
+144   (int (*)(...))__cxa_pure_virtual
+152   (int (*)(...))QAbstractTableModel::hasChildren
+160   (int (*)(...))__cxa_pure_virtual
+168   (int (*)(...))QAbstractItemModel::setData
+176   (int (*)(...))QAbstractItemModel::headerData
+184   (int (*)(...))QAbstractItemModel::setHeaderData
+192   (int (*)(...))QAbstractItemModel::itemData
+200   (int (*)(...))QAbstractItemModel::setItemData
+208   (int (*)(...))QAbstractItemModel::mimeTypes
+216   (int (*)(...))QAbstractItemModel::mimeData
+224   (int (*)(...))QAbstractItemModel::canDropMimeData
+232   (int (*)(...))QAbstractTableModel::dropMimeData
+240   (int (*)(...))QAbstractItemModel::supportedDropActions
+248   (int (*)(...))QAbstractItemModel::supportedDragActions
+256   (int (*)(...))QAbstractItemModel::insertRows
+264   (int (*)(...))QAbstractItemModel::insertColumns
+272   (int (*)(...))QAbstractItemModel::removeRows
+280   (int (*)(...))QAbstractItemModel::removeColumns
+288   (int (*)(...))QAbstractItemModel::moveRows
+296   (int (*)(...))QAbstractItemModel::moveColumns
+304   (int (*)(...))QAbstractItemModel::fetchMore
+312   (int (*)(...))QAbstractItemModel::canFetchMore
+320   (int (*)(...))QAbstractTableModel::flags
+328   (int (*)(...))QAbstractItemModel::sort
+336   (int (*)(...))QAbstractItemModel::buddy
+344   (int (*)(...))QAbstractItemModel::match
+352   (int (*)(...))QAbstractItemModel::span
+360   (int (*)(...))QAbstractItemModel::roleNames
+368   (int (*)(...))QAbstractItemModel::submit
+376   (int (*)(...))QAbstractItemModel::revert
+
+Class QAbstractTableModel
+   size=16 align=8
+   base size=16 base align=8
+QAbstractTableModel (0x0x7f2349ac2340) 0
+    vptr=((& QAbstractTableModel::_ZTV19QAbstractTableModel) + 16)
+  QAbstractItemModel (0x0x7f2349ac23a8) 0
+      primary-for QAbstractTableModel (0x0x7f2349ac2340)
+    QObject (0x0x7f2349b328a0) 0
+        primary-for QAbstractItemModel (0x0x7f2349ac23a8)
+
+Class QAbstractListModel::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QAbstractListModel::QPrivateSignal (0x0x7f2349b32a80) 0 empty
+
+Vtable for QAbstractListModel
+QAbstractListModel::_ZTV18QAbstractListModel: 48 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI18QAbstractListModel)
+16    (int (*)(...))QAbstractListModel::metaObject
+24    (int (*)(...))QAbstractListModel::qt_metacast
+32    (int (*)(...))QAbstractListModel::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QAbstractListModel::index
+120   (int (*)(...))QAbstractListModel::parent
+128   (int (*)(...))QAbstractListModel::sibling
+136   (int (*)(...))__cxa_pure_virtual
+144   (int (*)(...))QAbstractListModel::columnCount
+152   (int (*)(...))QAbstractListModel::hasChildren
+160   (int (*)(...))__cxa_pure_virtual
+168   (int (*)(...))QAbstractItemModel::setData
+176   (int (*)(...))QAbstractItemModel::headerData
+184   (int (*)(...))QAbstractItemModel::setHeaderData
+192   (int (*)(...))QAbstractItemModel::itemData
+200   (int (*)(...))QAbstractItemModel::setItemData
+208   (int (*)(...))QAbstractItemModel::mimeTypes
+216   (int (*)(...))QAbstractItemModel::mimeData
+224   (int (*)(...))QAbstractItemModel::canDropMimeData
+232   (int (*)(...))QAbstractListModel::dropMimeData
+240   (int (*)(...))QAbstractItemModel::supportedDropActions
+248   (int (*)(...))QAbstractItemModel::supportedDragActions
+256   (int (*)(...))QAbstractItemModel::insertRows
+264   (int (*)(...))QAbstractItemModel::insertColumns
+272   (int (*)(...))QAbstractItemModel::removeRows
+280   (int (*)(...))QAbstractItemModel::removeColumns
+288   (int (*)(...))QAbstractItemModel::moveRows
+296   (int (*)(...))QAbstractItemModel::moveColumns
+304   (int (*)(...))QAbstractItemModel::fetchMore
+312   (int (*)(...))QAbstractItemModel::canFetchMore
+320   (int (*)(...))QAbstractListModel::flags
+328   (int (*)(...))QAbstractItemModel::sort
+336   (int (*)(...))QAbstractItemModel::buddy
+344   (int (*)(...))QAbstractItemModel::match
+352   (int (*)(...))QAbstractItemModel::span
+360   (int (*)(...))QAbstractItemModel::roleNames
+368   (int (*)(...))QAbstractItemModel::submit
+376   (int (*)(...))QAbstractItemModel::revert
+
+Class QAbstractListModel
+   size=16 align=8
+   base size=16 base align=8
+QAbstractListModel (0x0x7f2349ac2410) 0
+    vptr=((& QAbstractListModel::_ZTV18QAbstractListModel) + 16)
+  QAbstractItemModel (0x0x7f2349ac2478) 0
+      primary-for QAbstractListModel (0x0x7f2349ac2410)
+    QObject (0x0x7f2349b32a20) 0
+        primary-for QAbstractItemModel (0x0x7f2349ac2478)
+
+Vtable for QAbstractNativeEventFilter
+QAbstractNativeEventFilter::_ZTV26QAbstractNativeEventFilter: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI26QAbstractNativeEventFilter)
+16    0
+24    0
+32    (int (*)(...))__cxa_pure_virtual
+
+Class QAbstractNativeEventFilter
+   size=16 align=8
+   base size=16 base align=8
+QAbstractNativeEventFilter (0x0x7f2349b771e0) 0
+    vptr=((& QAbstractNativeEventFilter::_ZTV26QAbstractNativeEventFilter) + 16)
+
+Class QAbstractProxyModel::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QAbstractProxyModel::QPrivateSignal (0x0x7f2349b772a0) 0 empty
+
+Vtable for QAbstractProxyModel
+QAbstractProxyModel::_ZTV19QAbstractProxyModel: 53 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI19QAbstractProxyModel)
+16    (int (*)(...))QAbstractProxyModel::metaObject
+24    (int (*)(...))QAbstractProxyModel::qt_metacast
+32    (int (*)(...))QAbstractProxyModel::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))__cxa_pure_virtual
+120   (int (*)(...))__cxa_pure_virtual
+128   (int (*)(...))QAbstractProxyModel::sibling
+136   (int (*)(...))__cxa_pure_virtual
+144   (int (*)(...))__cxa_pure_virtual
+152   (int (*)(...))QAbstractProxyModel::hasChildren
+160   (int (*)(...))QAbstractProxyModel::data
+168   (int (*)(...))QAbstractProxyModel::setData
+176   (int (*)(...))QAbstractProxyModel::headerData
+184   (int (*)(...))QAbstractProxyModel::setHeaderData
+192   (int (*)(...))QAbstractProxyModel::itemData
+200   (int (*)(...))QAbstractProxyModel::setItemData
+208   (int (*)(...))QAbstractProxyModel::mimeTypes
+216   (int (*)(...))QAbstractProxyModel::mimeData
+224   (int (*)(...))QAbstractProxyModel::canDropMimeData
+232   (int (*)(...))QAbstractProxyModel::dropMimeData
+240   (int (*)(...))QAbstractProxyModel::supportedDropActions
+248   (int (*)(...))QAbstractProxyModel::supportedDragActions
+256   (int (*)(...))QAbstractItemModel::insertRows
+264   (int (*)(...))QAbstractItemModel::insertColumns
+272   (int (*)(...))QAbstractItemModel::removeRows
+280   (int (*)(...))QAbstractItemModel::removeColumns
+288   (int (*)(...))QAbstractItemModel::moveRows
+296   (int (*)(...))QAbstractItemModel::moveColumns
+304   (int (*)(...))QAbstractProxyModel::fetchMore
+312   (int (*)(...))QAbstractProxyModel::canFetchMore
+320   (int (*)(...))QAbstractProxyModel::flags
+328   (int (*)(...))QAbstractProxyModel::sort
+336   (int (*)(...))QAbstractProxyModel::buddy
+344   (int (*)(...))QAbstractItemModel::match
+352   (int (*)(...))QAbstractProxyModel::span
+360   (int (*)(...))QAbstractItemModel::roleNames
+368   (int (*)(...))QAbstractProxyModel::submit
+376   (int (*)(...))QAbstractProxyModel::revert
+384   (int (*)(...))QAbstractProxyModel::setSourceModel
+392   (int (*)(...))__cxa_pure_virtual
+400   (int (*)(...))__cxa_pure_virtual
+408   (int (*)(...))QAbstractProxyModel::mapSelectionToSource
+416   (int (*)(...))QAbstractProxyModel::mapSelectionFromSource
+
+Class QAbstractProxyModel
+   size=16 align=8
+   base size=16 base align=8
+QAbstractProxyModel (0x0x7f2349ac2548) 0
+    vptr=((& QAbstractProxyModel::_ZTV19QAbstractProxyModel) + 16)
+  QAbstractItemModel (0x0x7f2349ac25b0) 0
+      primary-for QAbstractProxyModel (0x0x7f2349ac2548)
+    QObject (0x0x7f2349b77240) 0
+        primary-for QAbstractItemModel (0x0x7f2349ac25b0)
+
+Class QAbstractState::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QAbstractState::QPrivateSignal (0x0x7f2349b774e0) 0 empty
+
+Vtable for QAbstractState
+QAbstractState::_ZTV14QAbstractState: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI14QAbstractState)
+16    (int (*)(...))QAbstractState::metaObject
+24    (int (*)(...))QAbstractState::qt_metacast
+32    (int (*)(...))QAbstractState::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QAbstractState::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))__cxa_pure_virtual
+120   (int (*)(...))__cxa_pure_virtual
+
+Class QAbstractState
+   size=16 align=8
+   base size=16 base align=8
+QAbstractState (0x0x7f2349ac2618) 0
+    vptr=((& QAbstractState::_ZTV14QAbstractState) + 16)
+  QObject (0x0x7f2349b77480) 0
+      primary-for QAbstractState (0x0x7f2349ac2618)
+
+Class QAbstractTransition::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QAbstractTransition::QPrivateSignal (0x0x7f2349b77720) 0 empty
+
+Vtable for QAbstractTransition
+QAbstractTransition::_ZTV19QAbstractTransition: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI19QAbstractTransition)
+16    (int (*)(...))QAbstractTransition::metaObject
+24    (int (*)(...))QAbstractTransition::qt_metacast
+32    (int (*)(...))QAbstractTransition::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QAbstractTransition::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))__cxa_pure_virtual
+120   (int (*)(...))__cxa_pure_virtual
+
+Class QAbstractTransition
+   size=16 align=8
+   base size=16 base align=8
+QAbstractTransition (0x0x7f2349ac2680) 0
+    vptr=((& QAbstractTransition::_ZTV19QAbstractTransition) + 16)
+  QObject (0x0x7f2349b776c0) 0
+      primary-for QAbstractTransition (0x0x7f2349ac2680)
+
+Class QAnimationGroup::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QAnimationGroup::QPrivateSignal (0x0x7f2349b77a20) 0 empty
+
+Vtable for QAnimationGroup
+QAnimationGroup::_ZTV15QAnimationGroup: 18 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI15QAnimationGroup)
+16    (int (*)(...))QAnimationGroup::metaObject
+24    (int (*)(...))QAnimationGroup::qt_metacast
+32    (int (*)(...))QAnimationGroup::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QAnimationGroup::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))__cxa_pure_virtual
+120   (int (*)(...))__cxa_pure_virtual
+128   (int (*)(...))QAbstractAnimation::updateState
+136   (int (*)(...))QAbstractAnimation::updateDirection
+
+Class QAnimationGroup
+   size=16 align=8
+   base size=16 base align=8
+QAnimationGroup (0x0x7f2349ac26e8) 0
+    vptr=((& QAnimationGroup::_ZTV15QAnimationGroup) + 16)
+  QAbstractAnimation (0x0x7f2349ac2750) 0
+      primary-for QAnimationGroup (0x0x7f2349ac26e8)
+    QObject (0x0x7f2349b779c0) 0
+        primary-for QAbstractAnimation (0x0x7f2349ac2750)
+
+Class QBasicTimer
+   size=4 align=4
+   base size=4 base align=4
+QBasicTimer (0x0x7f234981fd80) 0
+
+Class QBitArray
+   size=8 align=8
+   base size=8 base align=8
+QBitArray (0x0x7f234987d180) 0
+
+Class QBitRef
+   size=16 align=8
+   base size=12 base align=8
+QBitRef (0x0x7f23498de600) 0
+
+Class QIODevice::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QIODevice::QPrivateSignal (0x0x7f23499289c0) 0 empty
+
+Vtable for QIODevice
+QIODevice::_ZTV9QIODevice: 30 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI9QIODevice)
+16    (int (*)(...))QIODevice::metaObject
+24    (int (*)(...))QIODevice::qt_metacast
+32    (int (*)(...))QIODevice::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QIODevice::isSequential
+120   (int (*)(...))QIODevice::open
+128   (int (*)(...))QIODevice::close
+136   (int (*)(...))QIODevice::pos
+144   (int (*)(...))QIODevice::size
+152   (int (*)(...))QIODevice::seek
+160   (int (*)(...))QIODevice::atEnd
+168   (int (*)(...))QIODevice::reset
+176   (int (*)(...))QIODevice::bytesAvailable
+184   (int (*)(...))QIODevice::bytesToWrite
+192   (int (*)(...))QIODevice::canReadLine
+200   (int (*)(...))QIODevice::waitForReadyRead
+208   (int (*)(...))QIODevice::waitForBytesWritten
+216   (int (*)(...))__cxa_pure_virtual
+224   (int (*)(...))QIODevice::readLineData
+232   (int (*)(...))__cxa_pure_virtual
+
+Class QIODevice
+   size=16 align=8
+   base size=16 base align=8
+QIODevice (0x0x7f2349921c98) 0
+    vptr=((& QIODevice::_ZTV9QIODevice) + 16)
+  QObject (0x0x7f2349928960) 0
+      primary-for QIODevice (0x0x7f2349921c98)
+
+Class QBuffer::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QBuffer::QPrivateSignal (0x0x7f2349973360) 0 empty
+
+Vtable for QBuffer
+QBuffer::_ZTV7QBuffer: 30 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI7QBuffer)
+16    (int (*)(...))QBuffer::metaObject
+24    (int (*)(...))QBuffer::qt_metacast
+32    (int (*)(...))QBuffer::qt_metacall
+40    (int (*)(...))QBuffer::~QBuffer
+48    (int (*)(...))QBuffer::~QBuffer
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QBuffer::connectNotify
+104   (int (*)(...))QBuffer::disconnectNotify
+112   (int (*)(...))QIODevice::isSequential
+120   (int (*)(...))QBuffer::open
+128   (int (*)(...))QBuffer::close
+136   (int (*)(...))QBuffer::pos
+144   (int (*)(...))QBuffer::size
+152   (int (*)(...))QBuffer::seek
+160   (int (*)(...))QBuffer::atEnd
+168   (int (*)(...))QIODevice::reset
+176   (int (*)(...))QIODevice::bytesAvailable
+184   (int (*)(...))QIODevice::bytesToWrite
+192   (int (*)(...))QBuffer::canReadLine
+200   (int (*)(...))QIODevice::waitForReadyRead
+208   (int (*)(...))QIODevice::waitForBytesWritten
+216   (int (*)(...))QBuffer::readData
+224   (int (*)(...))QIODevice::readLineData
+232   (int (*)(...))QBuffer::writeData
+
+Class QBuffer
+   size=16 align=8
+   base size=16 base align=8
+QBuffer (0x0x7f2349921dd0) 0
+    vptr=((& QBuffer::_ZTV7QBuffer) + 16)
+  QIODevice (0x0x7f2349921e38) 0
+      primary-for QBuffer (0x0x7f2349921dd0)
+    QObject (0x0x7f2349973300) 0
+        primary-for QIODevice (0x0x7f2349921e38)
+
+Class QByteArrayMatcher::Data
+   size=272 align=8
+   base size=272 base align=8
+QByteArrayMatcher::Data (0x0x7f2349973600) 0
+
+Class QByteArrayMatcher
+   size=1040 align=8
+   base size=1040 base align=8
+QByteArrayMatcher (0x0x7f23499735a0) 0
+
+Class QStaticByteArrayMatcherBase::Skiptable
+   size=256 align=1
+   base size=256 base align=1
+QStaticByteArrayMatcherBase::Skiptable (0x0x7f2349973780) 0
+
+Class QStaticByteArrayMatcherBase
+   size=256 align=16
+   base size=256 base align=16
+QStaticByteArrayMatcherBase (0x0x7f2349973720) 0
+
+Class QSharedData
+   size=4 align=4
+   base size=4 base align=4
+QSharedData (0x0x7f23499bf660) 0
+
+Class QDate
+   size=8 align=8
+   base size=8 base align=8
+QDate (0x0x7f2349a00600) 0
+
+Class QTime
+   size=4 align=4
+   base size=4 base align=4
+QTime (0x0x7f2349656ea0) 0
+
+Class QDateTime::ShortData
+   size=8 align=8
+   base size=8 base align=8
+QDateTime::ShortData (0x0x7f23496bfb40) 0
+
+Class QDateTime::Data
+   size=8 align=8
+   base size=8 base align=8
+QDateTime::Data (0x0x7f23496bfba0) 0
+
+Class QDateTime
+   size=8 align=8
+   base size=8 base align=8
+QDateTime (0x0x7f23496bfae0) 0
+
+Class QLocale
+   size=8 align=8
+   base size=8 base align=8
+QLocale (0x0x7f23497b12a0) 0
+
+Vtable for QTextStream
+QTextStream::_ZTV11QTextStream: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI11QTextStream)
+16    (int (*)(...))QTextStream::~QTextStream
+24    (int (*)(...))QTextStream::~QTextStream
+
+Class QTextStream
+   size=16 align=8
+   base size=16 base align=8
+QTextStream (0x0x7f23494ad840) 0
+    vptr=((& QTextStream::_ZTV11QTextStream) + 16)
+
+Class QTextStreamManipulator
+   size=40 align=8
+   base size=38 base align=8
+QTextStreamManipulator (0x0x7f2349514120) 0
+
+Class QContiguousCacheData
+   size=24 align=4
+   base size=24 base align=4
+QContiguousCacheData (0x0x7f2349587c00) 0
+
+Class QtSharedPointer::NormalDeleter
+   size=1 align=1
+   base size=0 base align=1
+QtSharedPointer::NormalDeleter (0x0x7f23495d28a0) 0 empty
+
+Class QtSharedPointer::ExternalRefCountData
+   size=16 align=8
+   base size=16 base align=8
+QtSharedPointer::ExternalRefCountData (0x0x7f23495d2a20) 0
+
+Class QDebug::Stream
+   size=80 align=8
+   base size=76 base align=8
+QDebug::Stream (0x0x7f234928d660) 0
+
+Class QDebug
+   size=8 align=8
+   base size=8 base align=8
+QDebug (0x0x7f234928d600) 0
+
+Class QDebugStateSaver
+   size=8 align=8
+   base size=8 base align=8
+QDebugStateSaver (0x0x7f234902e6c0) 0
+
+Class QNoDebug
+   size=1 align=1
+   base size=0 base align=1
+QNoDebug (0x0x7f234902e780) 0 empty
+
+Class QCborError
+   size=4 align=4
+   base size=4 base align=4
+QCborError (0x0x7f23490ada80) 0
+
+Class QRegularExpression
+   size=8 align=8
+   base size=8 base align=8
+QRegularExpression (0x0x7f23490e0240) 0
+
+Class QRegularExpressionMatch
+   size=8 align=8
+   base size=8 base align=8
+QRegularExpressionMatch (0x0x7f2349191120) 0
+
+Class QRegularExpressionMatchIterator
+   size=8 align=8
+   base size=8 base align=8
+QRegularExpressionMatchIterator (0x0x7f23491ceea0) 0
+
+Class QUrl
+   size=8 align=8
+   base size=8 base align=8
+QUrl (0x0x7f2348e51900) 0
+
+Class QUuid
+   size=16 align=4
+   base size=16 base align=4
+QUuid (0x0x7f2348f948a0) 0
+
+Class QCborParserError
+   size=16 align=8
+   base size=12 base align=8
+QCborParserError (0x0x7f2348c1c420) 0
+
+Class QCborValue
+   size=24 align=8
+   base size=20 base align=8
+QCborValue (0x0x7f2348c1c4e0) 0
+
+Class QCborValueRef
+   size=16 align=8
+   base size=16 base align=8
+QCborValueRef (0x0x7f2348a954e0) 0
+
+Class QCborArray::Iterator
+   size=16 align=8
+   base size=16 base align=8
+QCborArray::Iterator (0x0x7f2348b02f00) 0
+
+Class QCborArray::ConstIterator
+   size=16 align=8
+   base size=16 base align=8
+QCborArray::ConstIterator (0x0x7f2348b02f60) 0
+
+Class QCborArray
+   size=8 align=8
+   base size=8 base align=8
+QCborArray (0x0x7f2348b02ea0) 0
+
+Class QCborMap::Iterator
+   size=16 align=8
+   base size=16 base align=8
+QCborMap::Iterator (0x0x7f234881c960) 0
+
+Class QCborMap::ConstIterator
+   size=16 align=8
+   base size=16 base align=8
+QCborMap::ConstIterator (0x0x7f234881c9c0) 0
+
+Class QCborMap
+   size=8 align=8
+   base size=8 base align=8
+QCborMap (0x0x7f234881c900) 0
+
+Class qfloat16
+   size=2 align=2
+   base size=2 base align=2
+qfloat16 (0x0x7f234862e120) 0
+
+Class QCborStreamWriter
+   size=8 align=8
+   base size=8 base align=8
+QCborStreamWriter (0x0x7f23486f00c0) 0
+
+Class QCborStreamReader
+   size=24 align=8
+   base size=20 base align=8
+QCborStreamReader (0x0x7f23486f0de0) 0
+
+Class QCollatorSortKey
+   size=8 align=8
+   base size=8 base align=8
+QCollatorSortKey (0x0x7f2348786f00) 0
+
+Class QCollator
+   size=8 align=8
+   base size=8 base align=8
+QCollator (0x0x7f23487b0120) 0
+
+Class QCommandLineOption
+   size=8 align=8
+   base size=8 base align=8
+QCommandLineOption (0x0x7f234849c6c0) 0
+
+Vtable for QEvent
+QEvent::_ZTV6QEvent: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI6QEvent)
+16    (int (*)(...))QEvent::~QEvent
+24    (int (*)(...))QEvent::~QEvent
+
+Class QEvent
+   size=24 align=8
+   base size=20 base align=8
+QEvent (0x0x7f23484f3de0) 0
+    vptr=((& QEvent::_ZTV6QEvent) + 16)
+
+Vtable for QTimerEvent
+QTimerEvent::_ZTV11QTimerEvent: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI11QTimerEvent)
+16    (int (*)(...))QTimerEvent::~QTimerEvent
+24    (int (*)(...))QTimerEvent::~QTimerEvent
+
+Class QTimerEvent
+   size=24 align=8
+   base size=24 base align=8
+QTimerEvent (0x0x7f234853b000) 0
+    vptr=((& QTimerEvent::_ZTV11QTimerEvent) + 16)
+  QEvent (0x0x7f23485371e0) 0
+      primary-for QTimerEvent (0x0x7f234853b000)
+
+Vtable for QChildEvent
+QChildEvent::_ZTV11QChildEvent: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI11QChildEvent)
+16    (int (*)(...))QChildEvent::~QChildEvent
+24    (int (*)(...))QChildEvent::~QChildEvent
+
+Class QChildEvent
+   size=32 align=8
+   base size=32 base align=8
+QChildEvent (0x0x7f234853b068) 0
+    vptr=((& QChildEvent::_ZTV11QChildEvent) + 16)
+  QEvent (0x0x7f23485372a0) 0
+      primary-for QChildEvent (0x0x7f234853b068)
+
+Vtable for QDynamicPropertyChangeEvent
+QDynamicPropertyChangeEvent::_ZTV27QDynamicPropertyChangeEvent: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI27QDynamicPropertyChangeEvent)
+16    (int (*)(...))QDynamicPropertyChangeEvent::~QDynamicPropertyChangeEvent
+24    (int (*)(...))QDynamicPropertyChangeEvent::~QDynamicPropertyChangeEvent
+
+Class QDynamicPropertyChangeEvent
+   size=32 align=8
+   base size=32 base align=8
+QDynamicPropertyChangeEvent (0x0x7f234853b5b0) 0
+    vptr=((& QDynamicPropertyChangeEvent::_ZTV27QDynamicPropertyChangeEvent) + 16)
+  QEvent (0x0x7f2348537900) 0
+      primary-for QDynamicPropertyChangeEvent (0x0x7f234853b5b0)
+
+Vtable for QDeferredDeleteEvent
+QDeferredDeleteEvent::_ZTV20QDeferredDeleteEvent: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI20QDeferredDeleteEvent)
+16    (int (*)(...))QDeferredDeleteEvent::~QDeferredDeleteEvent
+24    (int (*)(...))QDeferredDeleteEvent::~QDeferredDeleteEvent
+
+Class QDeferredDeleteEvent
+   size=24 align=8
+   base size=24 base align=8
+QDeferredDeleteEvent (0x0x7f234853b618) 0
+    vptr=((& QDeferredDeleteEvent::_ZTV20QDeferredDeleteEvent) + 16)
+  QEvent (0x0x7f23485379c0) 0
+      primary-for QDeferredDeleteEvent (0x0x7f234853b618)
+
+Class QCoreApplication::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QCoreApplication::QPrivateSignal (0x0x7f2348537ae0) 0 empty
+
+Vtable for QCoreApplication
+QCoreApplication::_ZTV16QCoreApplication: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI16QCoreApplication)
+16    (int (*)(...))QCoreApplication::metaObject
+24    (int (*)(...))QCoreApplication::qt_metacast
+32    (int (*)(...))QCoreApplication::qt_metacall
+40    (int (*)(...))QCoreApplication::~QCoreApplication
+48    (int (*)(...))QCoreApplication::~QCoreApplication
+56    (int (*)(...))QCoreApplication::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QCoreApplication::notify
+120   (int (*)(...))QCoreApplication::compressEvent
+
+Class QCoreApplication
+   size=16 align=8
+   base size=16 base align=8
+QCoreApplication (0x0x7f234853b680) 0
+    vptr=((& QCoreApplication::_ZTV16QCoreApplication) + 16)
+  QObject (0x0x7f2348537a80) 0
+      primary-for QCoreApplication (0x0x7f234853b680)
+
+Class QCommandLineParser
+   size=8 align=8
+   base size=8 base align=8
+QCommandLineParser (0x0x7f2348537d20) 0
+
+Class QConcatenateTablesProxyModel::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QConcatenateTablesProxyModel::QPrivateSignal (0x0x7f2348537ea0) 0 empty
+
+Vtable for QConcatenateTablesProxyModel
+QConcatenateTablesProxyModel::_ZTV28QConcatenateTablesProxyModel: 48 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI28QConcatenateTablesProxyModel)
+16    (int (*)(...))QConcatenateTablesProxyModel::metaObject
+24    (int (*)(...))QConcatenateTablesProxyModel::qt_metacast
+32    (int (*)(...))QConcatenateTablesProxyModel::qt_metacall
+40    (int (*)(...))QConcatenateTablesProxyModel::~QConcatenateTablesProxyModel
+48    (int (*)(...))QConcatenateTablesProxyModel::~QConcatenateTablesProxyModel
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QConcatenateTablesProxyModel::index
+120   (int (*)(...))QConcatenateTablesProxyModel::parent
+128   (int (*)(...))QAbstractItemModel::sibling
+136   (int (*)(...))QConcatenateTablesProxyModel::rowCount
+144   (int (*)(...))QConcatenateTablesProxyModel::columnCount
+152   (int (*)(...))QAbstractItemModel::hasChildren
+160   (int (*)(...))QConcatenateTablesProxyModel::data
+168   (int (*)(...))QConcatenateTablesProxyModel::setData
+176   (int (*)(...))QConcatenateTablesProxyModel::headerData
+184   (int (*)(...))QAbstractItemModel::setHeaderData
+192   (int (*)(...))QConcatenateTablesProxyModel::itemData
+200   (int (*)(...))QConcatenateTablesProxyModel::setItemData
+208   (int (*)(...))QConcatenateTablesProxyModel::mimeTypes
+216   (int (*)(...))QConcatenateTablesProxyModel::mimeData
+224   (int (*)(...))QConcatenateTablesProxyModel::canDropMimeData
+232   (int (*)(...))QConcatenateTablesProxyModel::dropMimeData
+240   (int (*)(...))QAbstractItemModel::supportedDropActions
+248   (int (*)(...))QAbstractItemModel::supportedDragActions
+256   (int (*)(...))QAbstractItemModel::insertRows
+264   (int (*)(...))QAbstractItemModel::insertColumns
+272   (int (*)(...))QAbstractItemModel::removeRows
+280   (int (*)(...))QAbstractItemModel::removeColumns
+288   (int (*)(...))QAbstractItemModel::moveRows
+296   (int (*)(...))QAbstractItemModel::moveColumns
+304   (int (*)(...))QAbstractItemModel::fetchMore
+312   (int (*)(...))QAbstractItemModel::canFetchMore
+320   (int (*)(...))QConcatenateTablesProxyModel::flags
+328   (int (*)(...))QAbstractItemModel::sort
+336   (int (*)(...))QAbstractItemModel::buddy
+344   (int (*)(...))QAbstractItemModel::match
+352   (int (*)(...))QConcatenateTablesProxyModel::span
+360   (int (*)(...))QAbstractItemModel::roleNames
+368   (int (*)(...))QAbstractItemModel::submit
+376   (int (*)(...))QAbstractItemModel::revert
+
+Class QConcatenateTablesProxyModel
+   size=16 align=8
+   base size=16 base align=8
+QConcatenateTablesProxyModel (0x0x7f234853b6e8) 0
+    vptr=((& QConcatenateTablesProxyModel::_ZTV28QConcatenateTablesProxyModel) + 16)
+  QAbstractItemModel (0x0x7f234853b750) 0
+      primary-for QConcatenateTablesProxyModel (0x0x7f234853b6e8)
+    QObject (0x0x7f2348537e40) 0
+        primary-for QAbstractItemModel (0x0x7f234853b750)
+
+Class QCryptographicHash
+   size=8 align=8
+   base size=8 base align=8
+QCryptographicHash (0x0x7f234859d0c0) 0
+
+Class QDataStream
+   size=32 align=8
+   base size=32 base align=8
+QDataStream (0x0x7f234859d1e0) 0
+
+Class QtPrivate::StreamStateSaver
+   size=16 align=8
+   base size=12 base align=8
+QtPrivate::StreamStateSaver (0x0x7f234859d360) 0
+
+Class QElapsedTimer
+   size=16 align=8
+   base size=16 base align=8
+QElapsedTimer (0x0x7f23485f9a80) 0
+
+Class QDeadlineTimer
+   size=16 align=8
+   base size=16 base align=8
+QDeadlineTimer (0x0x7f234822b1e0) 0
+
+Class QFileDevice::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QFileDevice::QPrivateSignal (0x0x7f2348349f00) 0 empty
+
+Vtable for QFileDevice
+QFileDevice::_ZTV11QFileDevice: 34 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI11QFileDevice)
+16    (int (*)(...))QFileDevice::metaObject
+24    (int (*)(...))QFileDevice::qt_metacast
+32    (int (*)(...))QFileDevice::qt_metacall
+40    (int (*)(...))QFileDevice::~QFileDevice
+48    (int (*)(...))QFileDevice::~QFileDevice
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QFileDevice::isSequential
+120   (int (*)(...))QIODevice::open
+128   (int (*)(...))QFileDevice::close
+136   (int (*)(...))QFileDevice::pos
+144   (int (*)(...))QFileDevice::size
+152   (int (*)(...))QFileDevice::seek
+160   (int (*)(...))QFileDevice::atEnd
+168   (int (*)(...))QIODevice::reset
+176   (int (*)(...))QIODevice::bytesAvailable
+184   (int (*)(...))QIODevice::bytesToWrite
+192   (int (*)(...))QIODevice::canReadLine
+200   (int (*)(...))QIODevice::waitForReadyRead
+208   (int (*)(...))QIODevice::waitForBytesWritten
+216   (int (*)(...))QFileDevice::readData
+224   (int (*)(...))QFileDevice::readLineData
+232   (int (*)(...))QFileDevice::writeData
+240   (int (*)(...))QFileDevice::fileName
+248   (int (*)(...))QFileDevice::resize
+256   (int (*)(...))QFileDevice::permissions
+264   (int (*)(...))QFileDevice::setPermissions
+
+Class QFileDevice
+   size=16 align=8
+   base size=16 base align=8
+QFileDevice (0x0x7f2348353958) 0
+    vptr=((& QFileDevice::_ZTV11QFileDevice) + 16)
+  QIODevice (0x0x7f23483539c0) 0
+      primary-for QFileDevice (0x0x7f2348353958)
+    QObject (0x0x7f2348349ea0) 0
+        primary-for QIODevice (0x0x7f23483539c0)
+
+Class QFile::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QFile::QPrivateSignal (0x0x7f2348380840) 0 empty
+
+Vtable for QFile
+QFile::_ZTV5QFile: 34 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI5QFile)
+16    (int (*)(...))QFile::metaObject
+24    (int (*)(...))QFile::qt_metacast
+32    (int (*)(...))QFile::qt_metacall
+40    (int (*)(...))QFile::~QFile
+48    (int (*)(...))QFile::~QFile
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QFileDevice::isSequential
+120   (int (*)(...))QFile::open
+128   (int (*)(...))QFileDevice::close
+136   (int (*)(...))QFileDevice::pos
+144   (int (*)(...))QFile::size
+152   (int (*)(...))QFileDevice::seek
+160   (int (*)(...))QFileDevice::atEnd
+168   (int (*)(...))QIODevice::reset
+176   (int (*)(...))QIODevice::bytesAvailable
+184   (int (*)(...))QIODevice::bytesToWrite
+192   (int (*)(...))QIODevice::canReadLine
+200   (int (*)(...))QIODevice::waitForReadyRead
+208   (int (*)(...))QIODevice::waitForBytesWritten
+216   (int (*)(...))QFileDevice::readData
+224   (int (*)(...))QFileDevice::readLineData
+232   (int (*)(...))QFileDevice::writeData
+240   (int (*)(...))QFile::fileName
+248   (int (*)(...))QFile::resize
+256   (int (*)(...))QFile::permissions
+264   (int (*)(...))QFile::setPermissions
+
+Class QFile
+   size=16 align=8
+   base size=16 base align=8
+QFile (0x0x7f2348353af8) 0
+    vptr=((& QFile::_ZTV5QFile) + 16)
+  QFileDevice (0x0x7f2348353b60) 0
+      primary-for QFile (0x0x7f2348353af8)
+    QIODevice (0x0x7f2348353bc8) 0
+        primary-for QFileDevice (0x0x7f2348353b60)
+      QObject (0x0x7f23483807e0) 0
+          primary-for QIODevice (0x0x7f2348353bc8)
+
+Class QFileInfo
+   size=8 align=8
+   base size=8 base align=8
+QFileInfo (0x0x7f2348380ea0) 0
+
+Class QDir
+   size=8 align=8
+   base size=8 base align=8
+QDir (0x0x7f23480352a0) 0
+
+Class QDirIterator
+   size=8 align=8
+   base size=8 base align=8
+QDirIterator (0x0x7f23480df600) 0
+
+Class QEasingCurve
+   size=8 align=8
+   base size=8 base align=8
+QEasingCurve (0x0x7f23480dfd80) 0
+
+Class QEventTransition::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QEventTransition::QPrivateSignal (0x0x7f2347dd6ea0) 0 empty
+
+Vtable for QEventTransition
+QEventTransition::_ZTV16QEventTransition: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI16QEventTransition)
+16    (int (*)(...))QEventTransition::metaObject
+24    (int (*)(...))QEventTransition::qt_metacast
+32    (int (*)(...))QEventTransition::qt_metacall
+40    (int (*)(...))QEventTransition::~QEventTransition
+48    (int (*)(...))QEventTransition::~QEventTransition
+56    (int (*)(...))QEventTransition::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QEventTransition::eventTest
+120   (int (*)(...))QEventTransition::onTransition
+
+Class QEventTransition
+   size=16 align=8
+   base size=16 base align=8
+QEventTransition (0x0x7f23481e0e38) 0
+    vptr=((& QEventTransition::_ZTV16QEventTransition) + 16)
+  QAbstractTransition (0x0x7f23481e0ea0) 0
+      primary-for QEventTransition (0x0x7f23481e0e38)
+    QObject (0x0x7f2347dd6e40) 0
+        primary-for QAbstractTransition (0x0x7f23481e0ea0)
+
+Vtable for QException
+QException::_ZTV10QException: 7 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI10QException)
+16    (int (*)(...))QException::~QException
+24    (int (*)(...))QException::~QException
+32    (int (*)(...))std::exception::what
+40    (int (*)(...))QException::raise
+48    (int (*)(...))QException::clone
+
+Class QException
+   size=8 align=8
+   base size=8 base align=8
+QException (0x0x7f23481e0f08) 0 nearly-empty
+    vptr=((& QException::_ZTV10QException) + 16)
+  std::exception (0x0x7f2347e0e0c0) 0 nearly-empty
+      primary-for QException (0x0x7f23481e0f08)
+
+Vtable for QUnhandledException
+QUnhandledException::_ZTV19QUnhandledException: 7 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI19QUnhandledException)
+16    (int (*)(...))QUnhandledException::~QUnhandledException
+24    (int (*)(...))QUnhandledException::~QUnhandledException
+32    (int (*)(...))std::exception::what
+40    (int (*)(...))QUnhandledException::raise
+48    (int (*)(...))QUnhandledException::clone
+
+Class QUnhandledException
+   size=8 align=8
+   base size=8 base align=8
+QUnhandledException (0x0x7f23481e0f70) 0 nearly-empty
+    vptr=((& QUnhandledException::_ZTV19QUnhandledException) + 16)
+  QException (0x0x7f2347e13000) 0 nearly-empty
+      primary-for QUnhandledException (0x0x7f23481e0f70)
+    std::exception (0x0x7f2347e0e120) 0 nearly-empty
+        primary-for QException (0x0x7f2347e13000)
+
+Class QtPrivate::ExceptionHolder
+   size=8 align=8
+   base size=8 base align=8
+QtPrivate::ExceptionHolder (0x0x7f2347e0e180) 0
+
+Class QtPrivate::ExceptionStore
+   size=8 align=8
+   base size=8 base align=8
+QtPrivate::ExceptionStore (0x0x7f2347e0e240) 0
+
+Vtable for QFactoryInterface
+QFactoryInterface::_ZTV17QFactoryInterface: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI17QFactoryInterface)
+16    0
+24    0
+32    (int (*)(...))__cxa_pure_virtual
+
+Class QFactoryInterface
+   size=8 align=8
+   base size=8 base align=8
+QFactoryInterface (0x0x7f2347e0e2a0) 0 nearly-empty
+    vptr=((& QFactoryInterface::_ZTV17QFactoryInterface) + 16)
+
+Class QFileSelector::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QFileSelector::QPrivateSignal (0x0x7f2347e0e4e0) 0 empty
+
+Vtable for QFileSelector
+QFileSelector::_ZTV13QFileSelector: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI13QFileSelector)
+16    (int (*)(...))QFileSelector::metaObject
+24    (int (*)(...))QFileSelector::qt_metacast
+32    (int (*)(...))QFileSelector::qt_metacall
+40    (int (*)(...))QFileSelector::~QFileSelector
+48    (int (*)(...))QFileSelector::~QFileSelector
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QFileSelector
+   size=16 align=8
+   base size=16 base align=8
+QFileSelector (0x0x7f2347e13068) 0
+    vptr=((& QFileSelector::_ZTV13QFileSelector) + 16)
+  QObject (0x0x7f2347e0e480) 0
+      primary-for QFileSelector (0x0x7f2347e13068)
+
+Class QFileSystemWatcher::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QFileSystemWatcher::QPrivateSignal (0x0x7f2347e0e720) 0 empty
+
+Vtable for QFileSystemWatcher
+QFileSystemWatcher::_ZTV18QFileSystemWatcher: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI18QFileSystemWatcher)
+16    (int (*)(...))QFileSystemWatcher::metaObject
+24    (int (*)(...))QFileSystemWatcher::qt_metacast
+32    (int (*)(...))QFileSystemWatcher::qt_metacall
+40    (int (*)(...))QFileSystemWatcher::~QFileSystemWatcher
+48    (int (*)(...))QFileSystemWatcher::~QFileSystemWatcher
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QFileSystemWatcher
+   size=16 align=8
+   base size=16 base align=8
+QFileSystemWatcher (0x0x7f2347e130d0) 0
+    vptr=((& QFileSystemWatcher::_ZTV18QFileSystemWatcher) + 16)
+  QObject (0x0x7f2347e0e6c0) 0
+      primary-for QFileSystemWatcher (0x0x7f2347e130d0)
+
+Class QFinalState::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QFinalState::QPrivateSignal (0x0x7f2347e0e960) 0 empty
+
+Vtable for QFinalState
+QFinalState::_ZTV11QFinalState: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI11QFinalState)
+16    (int (*)(...))QFinalState::metaObject
+24    (int (*)(...))QFinalState::qt_metacast
+32    (int (*)(...))QFinalState::qt_metacall
+40    (int (*)(...))QFinalState::~QFinalState
+48    (int (*)(...))QFinalState::~QFinalState
+56    (int (*)(...))QFinalState::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QFinalState::onEntry
+120   (int (*)(...))QFinalState::onExit
+
+Class QFinalState
+   size=16 align=8
+   base size=16 base align=8
+QFinalState (0x0x7f2347e13138) 0
+    vptr=((& QFinalState::_ZTV11QFinalState) + 16)
+  QAbstractState (0x0x7f2347e131a0) 0
+      primary-for QFinalState (0x0x7f2347e13138)
+    QObject (0x0x7f2347e0e900) 0
+        primary-for QAbstractState (0x0x7f2347e131a0)
+
+Vtable for QRunnable
+QRunnable::_ZTV9QRunnable: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI9QRunnable)
+16    (int (*)(...))__cxa_pure_virtual
+24    0
+32    0
+
+Class QRunnable
+   size=16 align=8
+   base size=12 base align=8
+QRunnable (0x0x7f2347e0eb40) 0
+    vptr=((& QRunnable::_ZTV9QRunnable) + 16)
+
+Class QBasicMutex
+   size=8 align=8
+   base size=8 base align=8
+QBasicMutex (0x0x7f2347e0ede0) 0
+
+Class QMutex
+   size=8 align=8
+   base size=8 base align=8
+QMutex (0x0x7f2347e13270) 0
+  QBasicMutex (0x0x7f2347ebea80) 0
+
+Class QMutexLocker
+   size=8 align=8
+   base size=8 base align=8
+QMutexLocker (0x0x7f2347ebecc0) 0
+
+Class QtPrivate::ResultItem
+   size=16 align=8
+   base size=16 base align=8
+QtPrivate::ResultItem (0x0x7f2347ee2180) 0
+
+Class QtPrivate::ResultIteratorBase
+   size=16 align=8
+   base size=12 base align=8
+QtPrivate::ResultIteratorBase (0x0x7f2347ee2780) 0
+
+Vtable for QtPrivate::ResultStoreBase
+QtPrivate::ResultStoreBase::_ZTVN9QtPrivate15ResultStoreBaseE: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTIN9QtPrivate15ResultStoreBaseE)
+16    (int (*)(...))QtPrivate::ResultStoreBase::~ResultStoreBase
+24    (int (*)(...))QtPrivate::ResultStoreBase::~ResultStoreBase
+
+Class QtPrivate::ResultStoreBase
+   size=48 align=8
+   base size=44 base align=8
+QtPrivate::ResultStoreBase (0x0x7f2347ee2960) 0
+    vptr=((& QtPrivate::ResultStoreBase::_ZTVN9QtPrivate15ResultStoreBaseE) + 16)
+
+Vtable for QFutureInterfaceBase
+QFutureInterfaceBase::_ZTV20QFutureInterfaceBase: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI20QFutureInterfaceBase)
+16    (int (*)(...))QFutureInterfaceBase::~QFutureInterfaceBase
+24    (int (*)(...))QFutureInterfaceBase::~QFutureInterfaceBase
+
+Class QFutureInterfaceBase
+   size=16 align=8
+   base size=16 base align=8
+QFutureInterfaceBase (0x0x7f2347f6f180) 0
+    vptr=((& QFutureInterfaceBase::_ZTV20QFutureInterfaceBase) + 16)
+
+Class QFutureWatcherBase::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QFutureWatcherBase::QPrivateSignal (0x0x7f2347c1b480) 0 empty
+
+Vtable for QFutureWatcherBase
+QFutureWatcherBase::_ZTV18QFutureWatcherBase: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI18QFutureWatcherBase)
+16    (int (*)(...))QFutureWatcherBase::metaObject
+24    (int (*)(...))QFutureWatcherBase::qt_metacast
+32    (int (*)(...))QFutureWatcherBase::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QFutureWatcherBase::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QFutureWatcherBase::connectNotify
+104   (int (*)(...))QFutureWatcherBase::disconnectNotify
+112   (int (*)(...))__cxa_pure_virtual
+120   (int (*)(...))__cxa_pure_virtual
+
+Class QFutureWatcherBase
+   size=16 align=8
+   base size=16 base align=8
+QFutureWatcherBase (0x0x7f2347fa4888) 0
+    vptr=((& QFutureWatcherBase::_ZTV18QFutureWatcherBase) + 16)
+  QObject (0x0x7f2347c1b420) 0
+      primary-for QFutureWatcherBase (0x0x7f2347fa4888)
+
+Class QHistoryState::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QHistoryState::QPrivateSignal (0x0x7f2347c437e0) 0 empty
+
+Vtable for QHistoryState
+QHistoryState::_ZTV13QHistoryState: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI13QHistoryState)
+16    (int (*)(...))QHistoryState::metaObject
+24    (int (*)(...))QHistoryState::qt_metacast
+32    (int (*)(...))QHistoryState::qt_metacall
+40    (int (*)(...))QHistoryState::~QHistoryState
+48    (int (*)(...))QHistoryState::~QHistoryState
+56    (int (*)(...))QHistoryState::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QHistoryState::onEntry
+120   (int (*)(...))QHistoryState::onExit
+
+Class QHistoryState
+   size=16 align=8
+   base size=16 base align=8
+QHistoryState (0x0x7f2347c4d0d0) 0
+    vptr=((& QHistoryState::_ZTV13QHistoryState) + 16)
+  QAbstractState (0x0x7f2347c4d138) 0
+      primary-for QHistoryState (0x0x7f2347c4d0d0)
+    QObject (0x0x7f2347c43780) 0
+        primary-for QAbstractState (0x0x7f2347c4d138)
+
+Class QIdentityProxyModel::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QIdentityProxyModel::QPrivateSignal (0x0x7f2347c43ae0) 0 empty
+
+Vtable for QIdentityProxyModel
+QIdentityProxyModel::_ZTV19QIdentityProxyModel: 53 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI19QIdentityProxyModel)
+16    (int (*)(...))QIdentityProxyModel::metaObject
+24    (int (*)(...))QIdentityProxyModel::qt_metacast
+32    (int (*)(...))QIdentityProxyModel::qt_metacall
+40    (int (*)(...))QIdentityProxyModel::~QIdentityProxyModel
+48    (int (*)(...))QIdentityProxyModel::~QIdentityProxyModel
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QIdentityProxyModel::index
+120   (int (*)(...))QIdentityProxyModel::parent
+128   (int (*)(...))QIdentityProxyModel::sibling
+136   (int (*)(...))QIdentityProxyModel::rowCount
+144   (int (*)(...))QIdentityProxyModel::columnCount
+152   (int (*)(...))QAbstractProxyModel::hasChildren
+160   (int (*)(...))QAbstractProxyModel::data
+168   (int (*)(...))QAbstractProxyModel::setData
+176   (int (*)(...))QIdentityProxyModel::headerData
+184   (int (*)(...))QAbstractProxyModel::setHeaderData
+192   (int (*)(...))QAbstractProxyModel::itemData
+200   (int (*)(...))QAbstractProxyModel::setItemData
+208   (int (*)(...))QAbstractProxyModel::mimeTypes
+216   (int (*)(...))QAbstractProxyModel::mimeData
+224   (int (*)(...))QAbstractProxyModel::canDropMimeData
+232   (int (*)(...))QIdentityProxyModel::dropMimeData
+240   (int (*)(...))QAbstractProxyModel::supportedDropActions
+248   (int (*)(...))QAbstractProxyModel::supportedDragActions
+256   (int (*)(...))QIdentityProxyModel::insertRows
+264   (int (*)(...))QIdentityProxyModel::insertColumns
+272   (int (*)(...))QIdentityProxyModel::removeRows
+280   (int (*)(...))QIdentityProxyModel::removeColumns
+288   (int (*)(...))QAbstractItemModel::moveRows
+296   (int (*)(...))QAbstractItemModel::moveColumns
+304   (int (*)(...))QAbstractProxyModel::fetchMore
+312   (int (*)(...))QAbstractProxyModel::canFetchMore
+320   (int (*)(...))QAbstractProxyModel::flags
+328   (int (*)(...))QAbstractProxyModel::sort
+336   (int (*)(...))QAbstractProxyModel::buddy
+344   (int (*)(...))QIdentityProxyModel::match
+352   (int (*)(...))QAbstractProxyModel::span
+360   (int (*)(...))QAbstractItemModel::roleNames
+368   (int (*)(...))QAbstractProxyModel::submit
+376   (int (*)(...))QAbstractProxyModel::revert
+384   (int (*)(...))QIdentityProxyModel::setSourceModel
+392   (int (*)(...))QIdentityProxyModel::mapToSource
+400   (int (*)(...))QIdentityProxyModel::mapFromSource
+408   (int (*)(...))QIdentityProxyModel::mapSelectionToSource
+416   (int (*)(...))QIdentityProxyModel::mapSelectionFromSource
+
+Class QIdentityProxyModel
+   size=16 align=8
+   base size=16 base align=8
+QIdentityProxyModel (0x0x7f2347c4d1a0) 0
+    vptr=((& QIdentityProxyModel::_ZTV19QIdentityProxyModel) + 16)
+  QAbstractProxyModel (0x0x7f2347c4d208) 0
+      primary-for QIdentityProxyModel (0x0x7f2347c4d1a0)
+    QAbstractItemModel (0x0x7f2347c4d270) 0
+        primary-for QAbstractProxyModel (0x0x7f2347c4d208)
+      QObject (0x0x7f2347c43a80) 0
+          primary-for QAbstractItemModel (0x0x7f2347c4d270)
+
+Class QItemSelectionRange
+   size=16 align=8
+   base size=16 base align=8
+QItemSelectionRange (0x0x7f2347c43cc0) 0
+
+Class QItemSelectionModel::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QItemSelectionModel::QPrivateSignal (0x0x7f2347d2b600) 0 empty
+
+Vtable for QItemSelectionModel
+QItemSelectionModel::_ZTV19QItemSelectionModel: 20 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI19QItemSelectionModel)
+16    (int (*)(...))QItemSelectionModel::metaObject
+24    (int (*)(...))QItemSelectionModel::qt_metacast
+32    (int (*)(...))QItemSelectionModel::qt_metacall
+40    (int (*)(...))QItemSelectionModel::~QItemSelectionModel
+48    (int (*)(...))QItemSelectionModel::~QItemSelectionModel
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QItemSelectionModel::setCurrentIndex
+120   (int (*)(...))QItemSelectionModel::select
+128   (int (*)(...))QItemSelectionModel::select
+136   (int (*)(...))QItemSelectionModel::clear
+144   (int (*)(...))QItemSelectionModel::reset
+152   (int (*)(...))QItemSelectionModel::clearCurrentIndex
+
+Class QItemSelectionModel
+   size=16 align=8
+   base size=16 base align=8
+QItemSelectionModel (0x0x7f2347d20bc8) 0
+    vptr=((& QItemSelectionModel::_ZTV19QItemSelectionModel) + 16)
+  QObject (0x0x7f2347d2b5a0) 0
+      primary-for QItemSelectionModel (0x0x7f2347d20bc8)
+
+Class QItemSelection
+   size=8 align=8
+   base size=8 base align=8
+QItemSelection (0x0x7f2347d20d68) 0
+  QList<QItemSelectionRange> (0x0x7f2347d20dd0) 0
+    QListSpecialMethods<QItemSelectionRange> (0x0x7f2347d73120) 0 empty
+
+Class QJsonValue
+   size=24 align=8
+   base size=20 base align=8
+QJsonValue (0x0x7f23479d7a20) 0
+
+Class QJsonValueRef
+   size=16 align=8
+   base size=12 base align=8
+QJsonValueRef (0x0x7f2347b29c00) 0
+
+Class QJsonValuePtr
+   size=24 align=8
+   base size=24 base align=8
+QJsonValuePtr (0x0x7f2347b62ba0) 0
+
+Class QJsonValueRefPtr
+   size=16 align=8
+   base size=16 base align=8
+QJsonValueRefPtr (0x0x7f2347b62e40) 0
+
+Class QJsonArray::iterator
+   size=16 align=8
+   base size=12 base align=8
+QJsonArray::iterator (0x0x7f23477db1e0) 0
+
+Class QJsonArray::const_iterator
+   size=16 align=8
+   base size=12 base align=8
+QJsonArray::const_iterator (0x0x7f23477db240) 0
+
+Class QJsonArray
+   size=16 align=8
+   base size=16 base align=8
+QJsonArray (0x0x7f23477db180) 0
+
+Class QJsonParseError
+   size=8 align=4
+   base size=8 base align=4
+QJsonParseError (0x0x7f2347907120) 0
+
+Class QJsonDocument
+   size=8 align=8
+   base size=8 base align=8
+QJsonDocument (0x0x7f2347907180) 0
+
+Class QJsonObject::iterator
+   size=16 align=8
+   base size=12 base align=8
+QJsonObject::iterator (0x0x7f234795c960) 0
+
+Class QJsonObject::const_iterator
+   size=16 align=8
+   base size=12 base align=8
+QJsonObject::const_iterator (0x0x7f234795c9c0) 0
+
+Class QJsonObject
+   size=16 align=8
+   base size=16 base align=8
+QJsonObject (0x0x7f234795c900) 0
+
+Class QLibrary::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QLibrary::QPrivateSignal (0x0x7f234766bd20) 0 empty
+
+Vtable for QLibrary
+QLibrary::_ZTV8QLibrary: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI8QLibrary)
+16    (int (*)(...))QLibrary::metaObject
+24    (int (*)(...))QLibrary::qt_metacast
+32    (int (*)(...))QLibrary::qt_metacall
+40    (int (*)(...))QLibrary::~QLibrary
+48    (int (*)(...))QLibrary::~QLibrary
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QLibrary
+   size=32 align=8
+   base size=25 base align=8
+QLibrary (0x0x7f234766ae38) 0
+    vptr=((& QLibrary::_ZTV8QLibrary) + 16)
+  QObject (0x0x7f234766bcc0) 0
+      primary-for QLibrary (0x0x7f234766ae38)
+
+Class QVersionNumber::SegmentStorage
+   size=8 align=8
+   base size=8 base align=8
+QVersionNumber::SegmentStorage (0x0x7f234769dba0) 0
+
+Class QVersionNumber
+   size=8 align=8
+   base size=8 base align=8
+QVersionNumber (0x0x7f234769d6c0) 0
+
+Class QLibraryInfo
+   size=1 align=1
+   base size=0 base align=1
+QLibraryInfo (0x0x7f234776e300) 0 empty
+
+Class QPoint
+   size=8 align=4
+   base size=8 base align=4
+QPoint (0x0x7f234776e360) 0
+
+Class QPointF
+   size=16 align=8
+   base size=16 base align=8
+QPointF (0x0x7f23473e3180) 0
+
+Class QLine
+   size=16 align=4
+   base size=16 base align=4
+QLine (0x0x7f2347456300) 0
+
+Class QLineF
+   size=32 align=8
+   base size=32 base align=8
+QLineF (0x0x7f23474be6c0) 0
+
+Class QLinkedListData
+   size=32 align=8
+   base size=25 base align=8
+QLinkedListData (0x0x7f2347539960) 0
+
+Class QLockFile
+   size=8 align=8
+   base size=8 base align=8
+QLockFile (0x0x7f23471dcae0) 0
+
+Class QLoggingCategory::AtomicBools
+   size=4 align=1
+   base size=4 base align=1
+QLoggingCategory::AtomicBools (0x0x7f23471dcd20) 0
+
+Class QLoggingCategory
+   size=24 align=8
+   base size=24 base align=8
+QLoggingCategory (0x0x7f23471dccc0) 0
+
+Class QMargins
+   size=16 align=4
+   base size=16 base align=4
+QMargins (0x0x7f234724b180) 0
+
+Class QMarginsF
+   size=32 align=8
+   base size=32 base align=8
+QMarginsF (0x0x7f23472c70c0) 0
+
+Class QMessageAuthenticationCode
+   size=8 align=8
+   base size=8 base align=8
+QMessageAuthenticationCode (0x0x7f234707a8a0) 0
+
+Class QMetaMethod
+   size=16 align=8
+   base size=12 base align=8
+QMetaMethod (0x0x7f234707a900) 0
+
+Class QMetaEnum
+   size=16 align=8
+   base size=12 base align=8
+QMetaEnum (0x0x7f2347105180) 0
+
+Class QMetaProperty
+   size=32 align=8
+   base size=32 base align=8
+QMetaProperty (0x0x7f2346d483c0) 0
+
+Class QMetaClassInfo
+   size=16 align=8
+   base size=12 base align=8
+QMetaClassInfo (0x0x7f2346d484e0) 0
+
+Class QMimeData::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QMimeData::QPrivateSignal (0x0x7f2346d88a80) 0 empty
+
+Vtable for QMimeData
+QMimeData::_ZTV9QMimeData: 17 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI9QMimeData)
+16    (int (*)(...))QMimeData::metaObject
+24    (int (*)(...))QMimeData::qt_metacast
+32    (int (*)(...))QMimeData::qt_metacall
+40    (int (*)(...))QMimeData::~QMimeData
+48    (int (*)(...))QMimeData::~QMimeData
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QMimeData::hasFormat
+120   (int (*)(...))QMimeData::formats
+128   (int (*)(...))QMimeData::retrieveData
+
+Class QMimeData
+   size=16 align=8
+   base size=16 base align=8
+QMimeData (0x0x7f2346d8ca90) 0
+    vptr=((& QMimeData::_ZTV9QMimeData) + 16)
+  QObject (0x0x7f2346d88a20) 0
+      primary-for QMimeData (0x0x7f2346d8ca90)
+
+Class QMimeType
+   size=8 align=8
+   base size=8 base align=8
+QMimeType (0x0x7f2346d88c60) 0
+
+Class QMimeDatabase
+   size=8 align=8
+   base size=8 base align=8
+QMimeDatabase (0x0x7f2346de2d80) 0
+
+Class QObjectCleanupHandler::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QObjectCleanupHandler::QPrivateSignal (0x0x7f2346de2e40) 0 empty
+
+Vtable for QObjectCleanupHandler
+QObjectCleanupHandler::_ZTV21QObjectCleanupHandler: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI21QObjectCleanupHandler)
+16    (int (*)(...))QObjectCleanupHandler::metaObject
+24    (int (*)(...))QObjectCleanupHandler::qt_metacast
+32    (int (*)(...))QObjectCleanupHandler::qt_metacall
+40    (int (*)(...))QObjectCleanupHandler::~QObjectCleanupHandler
+48    (int (*)(...))QObjectCleanupHandler::~QObjectCleanupHandler
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QObjectCleanupHandler
+   size=24 align=8
+   base size=24 base align=8
+QObjectCleanupHandler (0x0x7f2346de8dd0) 0
+    vptr=((& QObjectCleanupHandler::_ZTV21QObjectCleanupHandler) + 16)
+  QObject (0x0x7f2346de2de0) 0
+      primary-for QObjectCleanupHandler (0x0x7f2346de8dd0)
+
+Class QOperatingSystemVersion
+   size=16 align=4
+   base size=16 base align=4
+QOperatingSystemVersion (0x0x7f2346de2f60) 0
+
+Class QParallelAnimationGroup::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QParallelAnimationGroup::QPrivateSignal (0x0x7f2346e71720) 0 empty
+
+Vtable for QParallelAnimationGroup
+QParallelAnimationGroup::_ZTV23QParallelAnimationGroup: 18 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI23QParallelAnimationGroup)
+16    (int (*)(...))QParallelAnimationGroup::metaObject
+24    (int (*)(...))QParallelAnimationGroup::qt_metacast
+32    (int (*)(...))QParallelAnimationGroup::qt_metacall
+40    (int (*)(...))QParallelAnimationGroup::~QParallelAnimationGroup
+48    (int (*)(...))QParallelAnimationGroup::~QParallelAnimationGroup
+56    (int (*)(...))QParallelAnimationGroup::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QParallelAnimationGroup::duration
+120   (int (*)(...))QParallelAnimationGroup::updateCurrentTime
+128   (int (*)(...))QParallelAnimationGroup::updateState
+136   (int (*)(...))QParallelAnimationGroup::updateDirection
+
+Class QParallelAnimationGroup
+   size=16 align=8
+   base size=16 base align=8
+QParallelAnimationGroup (0x0x7f2346e75680) 0
+    vptr=((& QParallelAnimationGroup::_ZTV23QParallelAnimationGroup) + 16)
+  QAnimationGroup (0x0x7f2346e756e8) 0
+      primary-for QParallelAnimationGroup (0x0x7f2346e75680)
+    QAbstractAnimation (0x0x7f2346e75750) 0
+        primary-for QAnimationGroup (0x0x7f2346e756e8)
+      QObject (0x0x7f2346e716c0) 0
+          primary-for QAbstractAnimation (0x0x7f2346e75750)
+
+Class QPauseAnimation::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QPauseAnimation::QPrivateSignal (0x0x7f2346e71960) 0 empty
+
+Vtable for QPauseAnimation
+QPauseAnimation::_ZTV15QPauseAnimation: 18 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI15QPauseAnimation)
+16    (int (*)(...))QPauseAnimation::metaObject
+24    (int (*)(...))QPauseAnimation::qt_metacast
+32    (int (*)(...))QPauseAnimation::qt_metacall
+40    (int (*)(...))QPauseAnimation::~QPauseAnimation
+48    (int (*)(...))QPauseAnimation::~QPauseAnimation
+56    (int (*)(...))QPauseAnimation::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QPauseAnimation::duration
+120   (int (*)(...))QPauseAnimation::updateCurrentTime
+128   (int (*)(...))QAbstractAnimation::updateState
+136   (int (*)(...))QAbstractAnimation::updateDirection
+
+Class QPauseAnimation
+   size=16 align=8
+   base size=16 base align=8
+QPauseAnimation (0x0x7f2346e757b8) 0
+    vptr=((& QPauseAnimation::_ZTV15QPauseAnimation) + 16)
+  QAbstractAnimation (0x0x7f2346e75820) 0
+      primary-for QPauseAnimation (0x0x7f2346e757b8)
+    QObject (0x0x7f2346e71900) 0
+        primary-for QAbstractAnimation (0x0x7f2346e75820)
+
+Class QStaticPlugin
+   size=16 align=8
+   base size=16 base align=8
+QStaticPlugin (0x0x7f2346ea35a0) 0
+
+Class QPluginLoader::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QPluginLoader::QPrivateSignal (0x0x7f2346eea720) 0 empty
+
+Vtable for QPluginLoader
+QPluginLoader::_ZTV13QPluginLoader: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI13QPluginLoader)
+16    (int (*)(...))QPluginLoader::metaObject
+24    (int (*)(...))QPluginLoader::qt_metacast
+32    (int (*)(...))QPluginLoader::qt_metacall
+40    (int (*)(...))QPluginLoader::~QPluginLoader
+48    (int (*)(...))QPluginLoader::~QPluginLoader
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QPluginLoader
+   size=32 align=8
+   base size=25 base align=8
+QPluginLoader (0x0x7f2346edeb60) 0
+    vptr=((& QPluginLoader::_ZTV13QPluginLoader) + 16)
+  QObject (0x0x7f2346eea6c0) 0
+      primary-for QPluginLoader (0x0x7f2346edeb60)
+
+Class QProcessEnvironment
+   size=8 align=8
+   base size=8 base align=8
+QProcessEnvironment (0x0x7f2346eea840) 0
+
+Class QProcess::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QProcess::QPrivateSignal (0x0x7f2346b45ea0) 0 empty
+
+Vtable for QProcess
+QProcess::_ZTV8QProcess: 31 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI8QProcess)
+16    (int (*)(...))QProcess::metaObject
+24    (int (*)(...))QProcess::qt_metacast
+32    (int (*)(...))QProcess::qt_metacall
+40    (int (*)(...))QProcess::~QProcess
+48    (int (*)(...))QProcess::~QProcess
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QProcess::isSequential
+120   (int (*)(...))QProcess::open
+128   (int (*)(...))QProcess::close
+136   (int (*)(...))QIODevice::pos
+144   (int (*)(...))QIODevice::size
+152   (int (*)(...))QIODevice::seek
+160   (int (*)(...))QProcess::atEnd
+168   (int (*)(...))QIODevice::reset
+176   (int (*)(...))QProcess::bytesAvailable
+184   (int (*)(...))QProcess::bytesToWrite
+192   (int (*)(...))QProcess::canReadLine
+200   (int (*)(...))QProcess::waitForReadyRead
+208   (int (*)(...))QProcess::waitForBytesWritten
+216   (int (*)(...))QProcess::readData
+224   (int (*)(...))QIODevice::readLineData
+232   (int (*)(...))QProcess::writeData
+240   (int (*)(...))QProcess::setupChildProcess
+
+Class QProcess
+   size=16 align=8
+   base size=16 base align=8
+QProcess (0x0x7f2346b4f7b8) 0
+    vptr=((& QProcess::_ZTV8QProcess) + 16)
+  QIODevice (0x0x7f2346b4f820) 0
+      primary-for QProcess (0x0x7f2346b4f7b8)
+    QObject (0x0x7f2346b45e40) 0
+        primary-for QIODevice (0x0x7f2346b4f820)
+
+Class QVariantAnimation::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QVariantAnimation::QPrivateSignal (0x0x7f2346b885a0) 0 empty
+
+Vtable for QVariantAnimation
+QVariantAnimation::_ZTV17QVariantAnimation: 20 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI17QVariantAnimation)
+16    (int (*)(...))QVariantAnimation::metaObject
+24    (int (*)(...))QVariantAnimation::qt_metacast
+32    (int (*)(...))QVariantAnimation::qt_metacall
+40    (int (*)(...))QVariantAnimation::~QVariantAnimation
+48    (int (*)(...))QVariantAnimation::~QVariantAnimation
+56    (int (*)(...))QVariantAnimation::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QVariantAnimation::duration
+120   (int (*)(...))QVariantAnimation::updateCurrentTime
+128   (int (*)(...))QVariantAnimation::updateState
+136   (int (*)(...))QAbstractAnimation::updateDirection
+144   (int (*)(...))QVariantAnimation::updateCurrentValue
+152   (int (*)(...))QVariantAnimation::interpolated
+
+Class QVariantAnimation
+   size=16 align=8
+   base size=16 base align=8
+QVariantAnimation (0x0x7f2346b4f888) 0
+    vptr=((& QVariantAnimation::_ZTV17QVariantAnimation) + 16)
+  QAbstractAnimation (0x0x7f2346b4f8f0) 0
+      primary-for QVariantAnimation (0x0x7f2346b4f888)
+    QObject (0x0x7f2346b88540) 0
+        primary-for QAbstractAnimation (0x0x7f2346b4f8f0)
+
+Class QPropertyAnimation::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QPropertyAnimation::QPrivateSignal (0x0x7f2346b88840) 0 empty
+
+Vtable for QPropertyAnimation
+QPropertyAnimation::_ZTV18QPropertyAnimation: 20 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI18QPropertyAnimation)
+16    (int (*)(...))QPropertyAnimation::metaObject
+24    (int (*)(...))QPropertyAnimation::qt_metacast
+32    (int (*)(...))QPropertyAnimation::qt_metacall
+40    (int (*)(...))QPropertyAnimation::~QPropertyAnimation
+48    (int (*)(...))QPropertyAnimation::~QPropertyAnimation
+56    (int (*)(...))QPropertyAnimation::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QVariantAnimation::duration
+120   (int (*)(...))QVariantAnimation::updateCurrentTime
+128   (int (*)(...))QPropertyAnimation::updateState
+136   (int (*)(...))QAbstractAnimation::updateDirection
+144   (int (*)(...))QPropertyAnimation::updateCurrentValue
+152   (int (*)(...))QVariantAnimation::interpolated
+
+Class QPropertyAnimation
+   size=16 align=8
+   base size=16 base align=8
+QPropertyAnimation (0x0x7f2346b4f9c0) 0
+    vptr=((& QPropertyAnimation::_ZTV18QPropertyAnimation) + 16)
+  QVariantAnimation (0x0x7f2346b4fa28) 0
+      primary-for QPropertyAnimation (0x0x7f2346b4f9c0)
+    QAbstractAnimation (0x0x7f2346b4fa90) 0
+        primary-for QVariantAnimation (0x0x7f2346b4fa28)
+      QObject (0x0x7f2346b887e0) 0
+          primary-for QAbstractAnimation (0x0x7f2346b4fa90)
+
+Class std::random_device
+   size=5000 align=8
+   base size=5000 base align=8
+std::random_device (0x0x7f2346c07f60) 0
+
+Class std::bernoulli_distribution::param_type
+   size=8 align=8
+   base size=8 base align=8
+std::bernoulli_distribution::param_type (0x0x7f2346d07cc0) 0
+
+Class std::bernoulli_distribution
+   size=8 align=8
+   base size=8 base align=8
+std::bernoulli_distribution (0x0x7f2346d07c60) 0
+
+Class std::seed_seq
+   size=24 align=8
+   base size=24 base align=8
+std::seed_seq (0x0x7f2346b06a20) 0
+
+Class QRandomGenerator::Storage
+   size=2504 align=8
+   base size=2504 base align=8
+QRandomGenerator::Storage (0x0x7f23469316c0) 0
+
+Class QRandomGenerator
+   size=2512 align=8
+   base size=2512 base align=8
+QRandomGenerator (0x0x7f2346931660) 0
+
+Class QRandomGenerator64
+   size=2512 align=8
+   base size=2512 base align=8
+QRandomGenerator64 (0x0x7f234652e750) 0
+  QRandomGenerator (0x0x7f23465531e0) 0
+
+Class QReadWriteLock
+   size=8 align=8
+   base size=8 base align=8
+QReadWriteLock (0x0x7f2346553d80) 0
+
+Class QReadLocker
+   size=8 align=8
+   base size=8 base align=8
+QReadLocker (0x0x7f23465d9060) 0
+
+Class QWriteLocker
+   size=8 align=8
+   base size=8 base align=8
+QWriteLocker (0x0x7f23465d9540) 0
+
+Class QSize
+   size=8 align=4
+   base size=8 base align=4
+QSize (0x0x7f23465d9a20) 0
+
+Class QSizeF
+   size=16 align=8
+   base size=16 base align=8
+QSizeF (0x0x7f2346648840) 0
+
+Class QRect
+   size=16 align=4
+   base size=16 base align=4
+QRect (0x0x7f23466bf7e0) 0
+
+Class QRectF
+   size=32 align=8
+   base size=32 base align=8
+QRectF (0x0x7f2346372840) 0
+
+Class QResource
+   size=8 align=8
+   base size=8 base align=8
+QResource (0x0x7f2346432960) 0
+
+Class QSaveFile::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QSaveFile::QPrivateSignal (0x0x7f2346432c00) 0 empty
+
+Vtable for QSaveFile
+QSaveFile::_ZTV9QSaveFile: 34 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI9QSaveFile)
+16    (int (*)(...))QSaveFile::metaObject
+24    (int (*)(...))QSaveFile::qt_metacast
+32    (int (*)(...))QSaveFile::qt_metacall
+40    (int (*)(...))QSaveFile::~QSaveFile
+48    (int (*)(...))QSaveFile::~QSaveFile
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QFileDevice::isSequential
+120   (int (*)(...))QSaveFile::open
+128   (int (*)(...))QSaveFile::close
+136   (int (*)(...))QFileDevice::pos
+144   (int (*)(...))QFileDevice::size
+152   (int (*)(...))QFileDevice::seek
+160   (int (*)(...))QFileDevice::atEnd
+168   (int (*)(...))QIODevice::reset
+176   (int (*)(...))QIODevice::bytesAvailable
+184   (int (*)(...))QIODevice::bytesToWrite
+192   (int (*)(...))QIODevice::canReadLine
+200   (int (*)(...))QIODevice::waitForReadyRead
+208   (int (*)(...))QIODevice::waitForBytesWritten
+216   (int (*)(...))QFileDevice::readData
+224   (int (*)(...))QFileDevice::readLineData
+232   (int (*)(...))QSaveFile::writeData
+240   (int (*)(...))QSaveFile::fileName
+248   (int (*)(...))QFileDevice::resize
+256   (int (*)(...))QFileDevice::permissions
+264   (int (*)(...))QFileDevice::setPermissions
+
+Class QSaveFile
+   size=16 align=8
+   base size=16 base align=8
+QSaveFile (0x0x7f23463fc138) 0
+    vptr=((& QSaveFile::_ZTV9QSaveFile) + 16)
+  QFileDevice (0x0x7f23463fc1a0) 0
+      primary-for QSaveFile (0x0x7f23463fc138)
+    QIODevice (0x0x7f23463fc208) 0
+        primary-for QFileDevice (0x0x7f23463fc1a0)
+      QObject (0x0x7f2346432ba0) 0
+          primary-for QIODevice (0x0x7f23463fc208)
+
+Class QSemaphore
+   size=8 align=8
+   base size=8 base align=8
+QSemaphore (0x0x7f2346489240) 0
+
+Class QSemaphoreReleaser
+   size=16 align=8
+   base size=12 base align=8
+QSemaphoreReleaser (0x0x7f23464893c0) 0
+
+Class QSequentialAnimationGroup::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QSequentialAnimationGroup::QPrivateSignal (0x0x7f2346196660) 0 empty
+
+Vtable for QSequentialAnimationGroup
+QSequentialAnimationGroup::_ZTV25QSequentialAnimationGroup: 18 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI25QSequentialAnimationGroup)
+16    (int (*)(...))QSequentialAnimationGroup::metaObject
+24    (int (*)(...))QSequentialAnimationGroup::qt_metacast
+32    (int (*)(...))QSequentialAnimationGroup::qt_metacall
+40    (int (*)(...))QSequentialAnimationGroup::~QSequentialAnimationGroup
+48    (int (*)(...))QSequentialAnimationGroup::~QSequentialAnimationGroup
+56    (int (*)(...))QSequentialAnimationGroup::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QSequentialAnimationGroup::duration
+120   (int (*)(...))QSequentialAnimationGroup::updateCurrentTime
+128   (int (*)(...))QSequentialAnimationGroup::updateState
+136   (int (*)(...))QSequentialAnimationGroup::updateDirection
+
+Class QSequentialAnimationGroup
+   size=16 align=8
+   base size=16 base align=8
+QSequentialAnimationGroup (0x0x7f2346190f08) 0
+    vptr=((& QSequentialAnimationGroup::_ZTV25QSequentialAnimationGroup) + 16)
+  QAnimationGroup (0x0x7f2346190f70) 0
+      primary-for QSequentialAnimationGroup (0x0x7f2346190f08)
+    QAbstractAnimation (0x0x7f234619e000) 0
+        primary-for QAnimationGroup (0x0x7f2346190f70)
+      QObject (0x0x7f2346196600) 0
+          primary-for QAbstractAnimation (0x0x7f234619e000)
+
+Class QSettings::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QSettings::QPrivateSignal (0x0x7f23461968a0) 0 empty
+
+Vtable for QSettings
+QSettings::_ZTV9QSettings: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI9QSettings)
+16    (int (*)(...))QSettings::metaObject
+24    (int (*)(...))QSettings::qt_metacast
+32    (int (*)(...))QSettings::qt_metacall
+40    (int (*)(...))QSettings::~QSettings
+48    (int (*)(...))QSettings::~QSettings
+56    (int (*)(...))QSettings::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QSettings
+   size=16 align=8
+   base size=16 base align=8
+QSettings (0x0x7f234619e068) 0
+    vptr=((& QSettings::_ZTV9QSettings) + 16)
+  QObject (0x0x7f2346196840) 0
+      primary-for QSettings (0x0x7f234619e068)
+
+Class QSharedMemory::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QSharedMemory::QPrivateSignal (0x0x7f2346196d20) 0 empty
+
+Vtable for QSharedMemory
+QSharedMemory::_ZTV13QSharedMemory: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI13QSharedMemory)
+16    (int (*)(...))QSharedMemory::metaObject
+24    (int (*)(...))QSharedMemory::qt_metacast
+32    (int (*)(...))QSharedMemory::qt_metacall
+40    (int (*)(...))QSharedMemory::~QSharedMemory
+48    (int (*)(...))QSharedMemory::~QSharedMemory
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QSharedMemory
+   size=16 align=8
+   base size=16 base align=8
+QSharedMemory (0x0x7f234619e0d0) 0
+    vptr=((& QSharedMemory::_ZTV13QSharedMemory) + 16)
+  QObject (0x0x7f2346196cc0) 0
+      primary-for QSharedMemory (0x0x7f234619e0d0)
+
+Class QSignalMapper::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QSignalMapper::QPrivateSignal (0x0x7f2346196f60) 0 empty
+
+Vtable for QSignalMapper
+QSignalMapper::_ZTV13QSignalMapper: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI13QSignalMapper)
+16    (int (*)(...))QSignalMapper::metaObject
+24    (int (*)(...))QSignalMapper::qt_metacast
+32    (int (*)(...))QSignalMapper::qt_metacall
+40    (int (*)(...))QSignalMapper::~QSignalMapper
+48    (int (*)(...))QSignalMapper::~QSignalMapper
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QSignalMapper
+   size=16 align=8
+   base size=16 base align=8
+QSignalMapper (0x0x7f234619e138) 0
+    vptr=((& QSignalMapper::_ZTV13QSignalMapper) + 16)
+  QObject (0x0x7f2346196f00) 0
+      primary-for QSignalMapper (0x0x7f234619e138)
+
+Class QSignalTransition::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QSignalTransition::QPrivateSignal (0x0x7f23461ee1e0) 0 empty
+
+Vtable for QSignalTransition
+QSignalTransition::_ZTV17QSignalTransition: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI17QSignalTransition)
+16    (int (*)(...))QSignalTransition::metaObject
+24    (int (*)(...))QSignalTransition::qt_metacast
+32    (int (*)(...))QSignalTransition::qt_metacall
+40    (int (*)(...))QSignalTransition::~QSignalTransition
+48    (int (*)(...))QSignalTransition::~QSignalTransition
+56    (int (*)(...))QSignalTransition::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QSignalTransition::eventTest
+120   (int (*)(...))QSignalTransition::onTransition
+
+Class QSignalTransition
+   size=16 align=8
+   base size=16 base align=8
+QSignalTransition (0x0x7f234619e1a0) 0
+    vptr=((& QSignalTransition::_ZTV17QSignalTransition) + 16)
+  QAbstractTransition (0x0x7f234619e208) 0
+      primary-for QSignalTransition (0x0x7f234619e1a0)
+    QObject (0x0x7f23461ee180) 0
+        primary-for QAbstractTransition (0x0x7f234619e208)
+
+Class QSocketNotifier::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QSocketNotifier::QPrivateSignal (0x0x7f23461ee480) 0 empty
+
+Vtable for QSocketNotifier
+QSocketNotifier::_ZTV15QSocketNotifier: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI15QSocketNotifier)
+16    (int (*)(...))QSocketNotifier::metaObject
+24    (int (*)(...))QSocketNotifier::qt_metacast
+32    (int (*)(...))QSocketNotifier::qt_metacall
+40    (int (*)(...))QSocketNotifier::~QSocketNotifier
+48    (int (*)(...))QSocketNotifier::~QSocketNotifier
+56    (int (*)(...))QSocketNotifier::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QSocketNotifier
+   size=16 align=8
+   base size=16 base align=8
+QSocketNotifier (0x0x7f234619e270) 0
+    vptr=((& QSocketNotifier::_ZTV15QSocketNotifier) + 16)
+  QObject (0x0x7f23461ee420) 0
+      primary-for QSocketNotifier (0x0x7f234619e270)
+
+Class QSortFilterProxyModel::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QSortFilterProxyModel::QPrivateSignal (0x0x7f23461ee6c0) 0 empty
+
+Vtable for QSortFilterProxyModel
+QSortFilterProxyModel::_ZTV21QSortFilterProxyModel: 56 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI21QSortFilterProxyModel)
+16    (int (*)(...))QSortFilterProxyModel::metaObject
+24    (int (*)(...))QSortFilterProxyModel::qt_metacast
+32    (int (*)(...))QSortFilterProxyModel::qt_metacall
+40    (int (*)(...))QSortFilterProxyModel::~QSortFilterProxyModel
+48    (int (*)(...))QSortFilterProxyModel::~QSortFilterProxyModel
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QSortFilterProxyModel::index
+120   (int (*)(...))QSortFilterProxyModel::parent
+128   (int (*)(...))QSortFilterProxyModel::sibling
+136   (int (*)(...))QSortFilterProxyModel::rowCount
+144   (int (*)(...))QSortFilterProxyModel::columnCount
+152   (int (*)(...))QSortFilterProxyModel::hasChildren
+160   (int (*)(...))QSortFilterProxyModel::data
+168   (int (*)(...))QSortFilterProxyModel::setData
+176   (int (*)(...))QSortFilterProxyModel::headerData
+184   (int (*)(...))QSortFilterProxyModel::setHeaderData
+192   (int (*)(...))QAbstractProxyModel::itemData
+200   (int (*)(...))QAbstractProxyModel::setItemData
+208   (int (*)(...))QSortFilterProxyModel::mimeTypes
+216   (int (*)(...))QSortFilterProxyModel::mimeData
+224   (int (*)(...))QAbstractProxyModel::canDropMimeData
+232   (int (*)(...))QSortFilterProxyModel::dropMimeData
+240   (int (*)(...))QSortFilterProxyModel::supportedDropActions
+248   (int (*)(...))QAbstractProxyModel::supportedDragActions
+256   (int (*)(...))QSortFilterProxyModel::insertRows
+264   (int (*)(...))QSortFilterProxyModel::insertColumns
+272   (int (*)(...))QSortFilterProxyModel::removeRows
+280   (int (*)(...))QSortFilterProxyModel::removeColumns
+288   (int (*)(...))QAbstractItemModel::moveRows
+296   (int (*)(...))QAbstractItemModel::moveColumns
+304   (int (*)(...))QSortFilterProxyModel::fetchMore
+312   (int (*)(...))QSortFilterProxyModel::canFetchMore
+320   (int (*)(...))QSortFilterProxyModel::flags
+328   (int (*)(...))QSortFilterProxyModel::sort
+336   (int (*)(...))QSortFilterProxyModel::buddy
+344   (int (*)(...))QSortFilterProxyModel::match
+352   (int (*)(...))QSortFilterProxyModel::span
+360   (int (*)(...))QAbstractItemModel::roleNames
+368   (int (*)(...))QAbstractProxyModel::submit
+376   (int (*)(...))QAbstractProxyModel::revert
+384   (int (*)(...))QSortFilterProxyModel::setSourceModel
+392   (int (*)(...))QSortFilterProxyModel::mapToSource
+400   (int (*)(...))QSortFilterProxyModel::mapFromSource
+408   (int (*)(...))QSortFilterProxyModel::mapSelectionToSource
+416   (int (*)(...))QSortFilterProxyModel::mapSelectionFromSource
+424   (int (*)(...))QSortFilterProxyModel::filterAcceptsRow
+432   (int (*)(...))QSortFilterProxyModel::filterAcceptsColumn
+440   (int (*)(...))QSortFilterProxyModel::lessThan
+
+Class QSortFilterProxyModel
+   size=16 align=8
+   base size=16 base align=8
+QSortFilterProxyModel (0x0x7f234619e2d8) 0
+    vptr=((& QSortFilterProxyModel::_ZTV21QSortFilterProxyModel) + 16)
+  QAbstractProxyModel (0x0x7f234619e340) 0
+      primary-for QSortFilterProxyModel (0x0x7f234619e2d8)
+    QAbstractItemModel (0x0x7f234619e3a8) 0
+        primary-for QAbstractProxyModel (0x0x7f234619e340)
+      QObject (0x0x7f23461ee660) 0
+          primary-for QAbstractItemModel (0x0x7f234619e3a8)
+
+Class QStandardPaths
+   size=1 align=1
+   base size=0 base align=1
+QStandardPaths (0x0x7f23461eeae0) 0 empty
+
+Class QState::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QState::QPrivateSignal (0x0x7f234625e420) 0 empty
+
+Vtable for QState
+QState::_ZTV6QState: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI6QState)
+16    (int (*)(...))QState::metaObject
+24    (int (*)(...))QState::qt_metacast
+32    (int (*)(...))QState::qt_metacall
+40    (int (*)(...))QState::~QState
+48    (int (*)(...))QState::~QState
+56    (int (*)(...))QState::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QState::onEntry
+120   (int (*)(...))QState::onExit
+
+Class QState
+   size=16 align=8
+   base size=16 base align=8
+QState (0x0x7f234619e548) 0
+    vptr=((& QState::_ZTV6QState) + 16)
+  QAbstractState (0x0x7f234619e5b0) 0
+      primary-for QState (0x0x7f234619e548)
+    QObject (0x0x7f234625e3c0) 0
+        primary-for QAbstractState (0x0x7f234619e5b0)
+
+Class QStateMachine::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QStateMachine::QPrivateSignal (0x0x7f234625e8a0) 0 empty
+
+Vtable for QStateMachine::SignalEvent
+QStateMachine::SignalEvent::_ZTVN13QStateMachine11SignalEventE: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTIN13QStateMachine11SignalEventE)
+16    (int (*)(...))QStateMachine::SignalEvent::~SignalEvent
+24    (int (*)(...))QStateMachine::SignalEvent::~SignalEvent
+
+Class QStateMachine::SignalEvent
+   size=48 align=8
+   base size=48 base align=8
+QStateMachine::SignalEvent (0x0x7f234619e750) 0
+    vptr=((& QStateMachine::SignalEvent::_ZTVN13QStateMachine11SignalEventE) + 16)
+  QEvent (0x0x7f234625e900) 0
+      primary-for QStateMachine::SignalEvent (0x0x7f234619e750)
+
+Vtable for QStateMachine::WrappedEvent
+QStateMachine::WrappedEvent::_ZTVN13QStateMachine12WrappedEventE: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTIN13QStateMachine12WrappedEventE)
+16    (int (*)(...))QStateMachine::WrappedEvent::~WrappedEvent
+24    (int (*)(...))QStateMachine::WrappedEvent::~WrappedEvent
+
+Class QStateMachine::WrappedEvent
+   size=40 align=8
+   base size=40 base align=8
+QStateMachine::WrappedEvent (0x0x7f234619e7b8) 0
+    vptr=((& QStateMachine::WrappedEvent::_ZTVN13QStateMachine12WrappedEventE) + 16)
+  QEvent (0x0x7f234625e960) 0
+      primary-for QStateMachine::WrappedEvent (0x0x7f234619e7b8)
+
+Vtable for QStateMachine
+QStateMachine::_ZTV13QStateMachine: 20 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI13QStateMachine)
+16    (int (*)(...))QStateMachine::metaObject
+24    (int (*)(...))QStateMachine::qt_metacast
+32    (int (*)(...))QStateMachine::qt_metacall
+40    (int (*)(...))QStateMachine::~QStateMachine
+48    (int (*)(...))QStateMachine::~QStateMachine
+56    (int (*)(...))QStateMachine::event
+64    (int (*)(...))QStateMachine::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QStateMachine::onEntry
+120   (int (*)(...))QStateMachine::onExit
+128   (int (*)(...))QStateMachine::beginSelectTransitions
+136   (int (*)(...))QStateMachine::endSelectTransitions
+144   (int (*)(...))QStateMachine::beginMicrostep
+152   (int (*)(...))QStateMachine::endMicrostep
+
+Class QStateMachine
+   size=16 align=8
+   base size=16 base align=8
+QStateMachine (0x0x7f234619e618) 0
+    vptr=((& QStateMachine::_ZTV13QStateMachine) + 16)
+  QState (0x0x7f234619e680) 0
+      primary-for QStateMachine (0x0x7f234619e618)
+    QAbstractState (0x0x7f234619e6e8) 0
+        primary-for QState (0x0x7f234619e680)
+      QObject (0x0x7f234625e840) 0
+          primary-for QAbstractState (0x0x7f234619e6e8)
+
+Class QStorageInfo
+   size=8 align=8
+   base size=8 base align=8
+QStorageInfo (0x0x7f234625ed20) 0
+
+Class QAbstractConcatenable
+   size=1 align=1
+   base size=0 base align=1
+QAbstractConcatenable (0x0x7f2345f15d20) 0 empty
+
+Class QStringListModel::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QStringListModel::QPrivateSignal (0x0x7f2345fcb0c0) 0 empty
+
+Vtable for QStringListModel
+QStringListModel::_ZTV16QStringListModel: 48 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI16QStringListModel)
+16    (int (*)(...))QStringListModel::metaObject
+24    (int (*)(...))QStringListModel::qt_metacast
+32    (int (*)(...))QStringListModel::qt_metacall
+40    (int (*)(...))QStringListModel::~QStringListModel
+48    (int (*)(...))QStringListModel::~QStringListModel
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QAbstractListModel::index
+120   (int (*)(...))QAbstractListModel::parent
+128   (int (*)(...))QStringListModel::sibling
+136   (int (*)(...))QStringListModel::rowCount
+144   (int (*)(...))QAbstractListModel::columnCount
+152   (int (*)(...))QAbstractListModel::hasChildren
+160   (int (*)(...))QStringListModel::data
+168   (int (*)(...))QStringListModel::setData
+176   (int (*)(...))QAbstractItemModel::headerData
+184   (int (*)(...))QAbstractItemModel::setHeaderData
+192   (int (*)(...))QStringListModel::itemData
+200   (int (*)(...))QStringListModel::setItemData
+208   (int (*)(...))QAbstractItemModel::mimeTypes
+216   (int (*)(...))QAbstractItemModel::mimeData
+224   (int (*)(...))QAbstractItemModel::canDropMimeData
+232   (int (*)(...))QAbstractListModel::dropMimeData
+240   (int (*)(...))QStringListModel::supportedDropActions
+248   (int (*)(...))QAbstractItemModel::supportedDragActions
+256   (int (*)(...))QStringListModel::insertRows
+264   (int (*)(...))QAbstractItemModel::insertColumns
+272   (int (*)(...))QStringListModel::removeRows
+280   (int (*)(...))QAbstractItemModel::removeColumns
+288   (int (*)(...))QStringListModel::moveRows
+296   (int (*)(...))QAbstractItemModel::moveColumns
+304   (int (*)(...))QAbstractItemModel::fetchMore
+312   (int (*)(...))QAbstractItemModel::canFetchMore
+320   (int (*)(...))QStringListModel::flags
+328   (int (*)(...))QStringListModel::sort
+336   (int (*)(...))QAbstractItemModel::buddy
+344   (int (*)(...))QAbstractItemModel::match
+352   (int (*)(...))QAbstractItemModel::span
+360   (int (*)(...))QAbstractItemModel::roleNames
+368   (int (*)(...))QAbstractItemModel::submit
+376   (int (*)(...))QAbstractItemModel::revert
+
+Class QStringListModel
+   size=24 align=8
+   base size=24 base align=8
+QStringListModel (0x0x7f2345fa48f0) 0
+    vptr=((& QStringListModel::_ZTV16QStringListModel) + 16)
+  QAbstractListModel (0x0x7f2345fa4958) 0
+      primary-for QStringListModel (0x0x7f2345fa48f0)
+    QAbstractItemModel (0x0x7f2345fa49c0) 0
+        primary-for QAbstractListModel (0x0x7f2345fa4958)
+      QObject (0x0x7f2345fcb060) 0
+          primary-for QAbstractItemModel (0x0x7f2345fa49c0)
+
+Class QSystemSemaphore
+   size=8 align=8
+   base size=8 base align=8
+QSystemSemaphore (0x0x7f2345fcb1e0) 0
+
+Class QTemporaryDir
+   size=8 align=8
+   base size=8 base align=8
+QTemporaryDir (0x0x7f2345fcb2a0) 0
+
+Class QTemporaryFile::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QTemporaryFile::QPrivateSignal (0x0x7f2345fcb3c0) 0 empty
+
+Vtable for QTemporaryFile
+QTemporaryFile::_ZTV14QTemporaryFile: 34 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI14QTemporaryFile)
+16    (int (*)(...))QTemporaryFile::metaObject
+24    (int (*)(...))QTemporaryFile::qt_metacast
+32    (int (*)(...))QTemporaryFile::qt_metacall
+40    (int (*)(...))QTemporaryFile::~QTemporaryFile
+48    (int (*)(...))QTemporaryFile::~QTemporaryFile
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QFileDevice::isSequential
+120   (int (*)(...))QTemporaryFile::open
+128   (int (*)(...))QFileDevice::close
+136   (int (*)(...))QFileDevice::pos
+144   (int (*)(...))QFile::size
+152   (int (*)(...))QFileDevice::seek
+160   (int (*)(...))QFileDevice::atEnd
+168   (int (*)(...))QIODevice::reset
+176   (int (*)(...))QIODevice::bytesAvailable
+184   (int (*)(...))QIODevice::bytesToWrite
+192   (int (*)(...))QIODevice::canReadLine
+200   (int (*)(...))QIODevice::waitForReadyRead
+208   (int (*)(...))QIODevice::waitForBytesWritten
+216   (int (*)(...))QFileDevice::readData
+224   (int (*)(...))QFileDevice::readLineData
+232   (int (*)(...))QFileDevice::writeData
+240   (int (*)(...))QTemporaryFile::fileName
+248   (int (*)(...))QFile::resize
+256   (int (*)(...))QFile::permissions
+264   (int (*)(...))QFile::setPermissions
+
+Class QTemporaryFile
+   size=16 align=8
+   base size=16 base align=8
+QTemporaryFile (0x0x7f2345fa4a28) 0
+    vptr=((& QTemporaryFile::_ZTV14QTemporaryFile) + 16)
+  QFile (0x0x7f2345fa4a90) 0
+      primary-for QTemporaryFile (0x0x7f2345fa4a28)
+    QFileDevice (0x0x7f2345fa4af8) 0
+        primary-for QFile (0x0x7f2345fa4a90)
+      QIODevice (0x0x7f2345fa4b60) 0
+          primary-for QFileDevice (0x0x7f2345fa4af8)
+        QObject (0x0x7f2345fcb360) 0
+            primary-for QIODevice (0x0x7f2345fa4b60)
+
+Class QTextBoundaryFinder
+   size=48 align=8
+   base size=48 base align=8
+QTextBoundaryFinder (0x0x7f2345fcb720) 0
+
+Class QTextCodec::ConverterState
+   size=32 align=8
+   base size=32 base align=8
+QTextCodec::ConverterState (0x0x7f2345fcbf60) 0
+
+Vtable for QTextCodec
+QTextCodec::_ZTV10QTextCodec: 9 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI10QTextCodec)
+16    (int (*)(...))__cxa_pure_virtual
+24    (int (*)(...))QTextCodec::aliases
+32    (int (*)(...))__cxa_pure_virtual
+40    (int (*)(...))__cxa_pure_virtual
+48    (int (*)(...))__cxa_pure_virtual
+56    0
+64    0
+
+Class QTextCodec
+   size=8 align=8
+   base size=8 base align=8
+QTextCodec (0x0x7f2345fcbf00) 0 nearly-empty
+    vptr=((& QTextCodec::_ZTV10QTextCodec) + 16)
+
+Class QTextEncoder
+   size=40 align=8
+   base size=40 base align=8
+QTextEncoder (0x0x7f2346048960) 0
+
+Class QTextDecoder
+   size=40 align=8
+   base size=40 base align=8
+QTextDecoder (0x0x7f2346048b40) 0
+
+Class std::__mutex_base
+   size=40 align=8
+   base size=40 base align=8
+std::__mutex_base (0x0x7f2346048d20) 0
+
+Class std::mutex
+   size=40 align=8
+   base size=40 base align=8
+std::mutex (0x0x7f2345fa4d68) 0
+  std::__mutex_base (0x0x7f2346048d80) 0
+
+Class std::defer_lock_t
+   size=1 align=1
+   base size=0 base align=1
+std::defer_lock_t (0x0x7f2346048f60) 0 empty
+
+Class std::try_to_lock_t
+   size=1 align=1
+   base size=0 base align=1
+std::try_to_lock_t (0x0x7f23460a1000) 0 empty
+
+Class std::adopt_lock_t
+   size=1 align=1
+   base size=0 base align=1
+std::adopt_lock_t (0x0x7f23460a1060) 0 empty
+
+Class std::__recursive_mutex_base
+   size=40 align=8
+   base size=40 base align=8
+std::__recursive_mutex_base (0x0x7f23460a1a80) 0
+
+Class std::recursive_mutex
+   size=40 align=8
+   base size=40 base align=8
+std::recursive_mutex (0x0x7f2345fa4dd0) 0
+  std::__recursive_mutex_base (0x0x7f23460a1ae0) 0
+
+Class std::timed_mutex
+   size=40 align=8
+   base size=40 base align=8
+std::timed_mutex (0x0x7f2346095cb0) 0
+  std::__mutex_base (0x0x7f23460a1ea0) 0
+  std::__timed_mutex_impl<std::timed_mutex> (0x0x7f23460a1f00) 0 empty
+
+Class std::recursive_timed_mutex
+   size=40 align=8
+   base size=40 base align=8
+std::recursive_timed_mutex (0x0x7f2345cf0000) 0
+  std::__recursive_mutex_base (0x0x7f2345ce82a0) 0
+  std::__timed_mutex_impl<std::recursive_timed_mutex> (0x0x7f2345ce8300) 0 empty
+
+Class std::once_flag
+   size=4 align=4
+   base size=4 base align=4
+std::once_flag (0x0x7f2345ce8a20) 0
+
+Vtable for __gnu_cxx::__concurrence_lock_error
+__gnu_cxx::__concurrence_lock_error::_ZTVN9__gnu_cxx24__concurrence_lock_errorE: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTIN9__gnu_cxx24__concurrence_lock_errorE)
+16    (int (*)(...))__gnu_cxx::__concurrence_lock_error::~__concurrence_lock_error
+24    (int (*)(...))__gnu_cxx::__concurrence_lock_error::~__concurrence_lock_error
+32    (int (*)(...))__gnu_cxx::__concurrence_lock_error::what
+
+Class __gnu_cxx::__concurrence_lock_error
+   size=8 align=8
+   base size=8 base align=8
+__gnu_cxx::__concurrence_lock_error (0x0x7f2345fa4f08) 0 nearly-empty
+    vptr=((& __gnu_cxx::__concurrence_lock_error::_ZTVN9__gnu_cxx24__concurrence_lock_errorE) + 16)
+  std::exception (0x0x7f2345ce8f60) 0 nearly-empty
+      primary-for __gnu_cxx::__concurrence_lock_error (0x0x7f2345fa4f08)
+
+Vtable for __gnu_cxx::__concurrence_unlock_error
+__gnu_cxx::__concurrence_unlock_error::_ZTVN9__gnu_cxx26__concurrence_unlock_errorE: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTIN9__gnu_cxx26__concurrence_unlock_errorE)
+16    (int (*)(...))__gnu_cxx::__concurrence_unlock_error::~__concurrence_unlock_error
+24    (int (*)(...))__gnu_cxx::__concurrence_unlock_error::~__concurrence_unlock_error
+32    (int (*)(...))__gnu_cxx::__concurrence_unlock_error::what
+
+Class __gnu_cxx::__concurrence_unlock_error
+   size=8 align=8
+   base size=8 base align=8
+__gnu_cxx::__concurrence_unlock_error (0x0x7f2345fa4f70) 0 nearly-empty
+    vptr=((& __gnu_cxx::__concurrence_unlock_error::_ZTVN9__gnu_cxx26__concurrence_unlock_errorE) + 16)
+  std::exception (0x0x7f2345d1e0c0) 0 nearly-empty
+      primary-for __gnu_cxx::__concurrence_unlock_error (0x0x7f2345fa4f70)
+
+Vtable for __gnu_cxx::__concurrence_broadcast_error
+__gnu_cxx::__concurrence_broadcast_error::_ZTVN9__gnu_cxx29__concurrence_broadcast_errorE: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTIN9__gnu_cxx29__concurrence_broadcast_errorE)
+16    (int (*)(...))__gnu_cxx::__concurrence_broadcast_error::~__concurrence_broadcast_error
+24    (int (*)(...))__gnu_cxx::__concurrence_broadcast_error::~__concurrence_broadcast_error
+32    (int (*)(...))__gnu_cxx::__concurrence_broadcast_error::what
+
+Class __gnu_cxx::__concurrence_broadcast_error
+   size=8 align=8
+   base size=8 base align=8
+__gnu_cxx::__concurrence_broadcast_error (0x0x7f2345d25000) 0 nearly-empty
+    vptr=((& __gnu_cxx::__concurrence_broadcast_error::_ZTVN9__gnu_cxx29__concurrence_broadcast_errorE) + 16)
+  std::exception (0x0x7f2345d1e1e0) 0 nearly-empty
+      primary-for __gnu_cxx::__concurrence_broadcast_error (0x0x7f2345d25000)
+
+Vtable for __gnu_cxx::__concurrence_wait_error
+__gnu_cxx::__concurrence_wait_error::_ZTVN9__gnu_cxx24__concurrence_wait_errorE: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTIN9__gnu_cxx24__concurrence_wait_errorE)
+16    (int (*)(...))__gnu_cxx::__concurrence_wait_error::~__concurrence_wait_error
+24    (int (*)(...))__gnu_cxx::__concurrence_wait_error::~__concurrence_wait_error
+32    (int (*)(...))__gnu_cxx::__concurrence_wait_error::what
+
+Class __gnu_cxx::__concurrence_wait_error
+   size=8 align=8
+   base size=8 base align=8
+__gnu_cxx::__concurrence_wait_error (0x0x7f2345d250d0) 0 nearly-empty
+    vptr=((& __gnu_cxx::__concurrence_wait_error::_ZTVN9__gnu_cxx24__concurrence_wait_errorE) + 16)
+  std::exception (0x0x7f2345d1e300) 0 nearly-empty
+      primary-for __gnu_cxx::__concurrence_wait_error (0x0x7f2345d250d0)
+
+Class __gnu_cxx::__mutex
+   size=40 align=8
+   base size=40 base align=8
+__gnu_cxx::__mutex (0x0x7f2345d46360) 0
+
+Class __gnu_cxx::__recursive_mutex
+   size=40 align=8
+   base size=40 base align=8
+__gnu_cxx::__recursive_mutex (0x0x7f2345d46660) 0
+
+Class __gnu_cxx::__scoped_lock
+   size=8 align=8
+   base size=8 base align=8
+__gnu_cxx::__scoped_lock (0x0x7f2345d46960) 0
+
+Class __gnu_cxx::__cond
+   size=48 align=8
+   base size=48 base align=8
+__gnu_cxx::__cond (0x0x7f2345d46cc0) 0
+
+Vtable for std::bad_weak_ptr
+std::bad_weak_ptr::_ZTVSt12bad_weak_ptr: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt12bad_weak_ptr)
+16    (int (*)(...))std::bad_weak_ptr::~bad_weak_ptr
+24    (int (*)(...))std::bad_weak_ptr::~bad_weak_ptr
+32    (int (*)(...))std::bad_weak_ptr::what
+
+Class std::bad_weak_ptr
+   size=8 align=8
+   base size=8 base align=8
+std::bad_weak_ptr (0x0x7f2345d25138) 0 nearly-empty
+    vptr=((& std::bad_weak_ptr::_ZTVSt12bad_weak_ptr) + 16)
+  std::exception (0x0x7f2345dc2ea0) 0 nearly-empty
+      primary-for std::bad_weak_ptr (0x0x7f2345d25138)
+
+Class std::_Sp_make_shared_tag
+   size=1 align=1
+   base size=0 base align=1
+std::_Sp_make_shared_tag (0x0x7f2345e24e40) 0 empty
+
+Class std::__sp_array_delete
+   size=1 align=1
+   base size=0 base align=1
+std::__sp_array_delete (0x0x7f2345e522a0) 0 empty
+
+Class std::_Sp_locker
+   size=2 align=1
+   base size=2 base align=1
+std::_Sp_locker (0x0x7f2345b9a120) 0
+
+Vtable for std::thread::_State
+std::thread::_State::_ZTVNSt6thread6_StateE: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTINSt6thread6_StateE)
+16    0
+24    0
+32    (int (*)(...))__cxa_pure_virtual
+
+Class std::thread::_State
+   size=8 align=8
+   base size=8 base align=8
+std::thread::_State (0x0x7f2345bc55a0) 0 nearly-empty
+    vptr=((& std::thread::_State::_ZTVNSt6thread6_StateE) + 16)
+
+Class std::thread::id
+   size=8 align=8
+   base size=8 base align=8
+std::thread::id (0x0x7f2345bc5600) 0
+
+Class std::thread
+   size=8 align=8
+   base size=8 base align=8
+std::thread (0x0x7f2345bc5540) 0
+
+Class std::condition_variable
+   size=48 align=8
+   base size=48 base align=8
+std::condition_variable (0x0x7f2345a569c0) 0
+
+Class std::__at_thread_exit_elt
+   size=16 align=8
+   base size=16 base align=8
+std::__at_thread_exit_elt (0x0x7f2345a56d80) 0
+
+Class std::_V2::condition_variable_any
+   size=64 align=8
+   base size=64 base align=8
+std::_V2::condition_variable_any (0x0x7f2345a56de0) 0
+
+Class std::__atomic_futex_unsigned_base
+   size=1 align=1
+   base size=0 base align=1
+std::__atomic_futex_unsigned_base (0x0x7f2345812120) 0 empty
+
+Vtable for std::future_error
+std::future_error::_ZTVSt12future_error: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt12future_error)
+16    (int (*)(...))std::future_error::~future_error
+24    (int (*)(...))std::future_error::~future_error
+32    (int (*)(...))std::future_error::what
+
+Class std::future_error
+   size=32 align=8
+   base size=32 base align=8
+std::future_error (0x0x7f23457f89c0) 0
+    vptr=((& std::future_error::_ZTVSt12future_error) + 16)
+  std::logic_error (0x0x7f23457f8a28) 0
+      primary-for std::future_error (0x0x7f23457f89c0)
+    std::exception (0x0x7f2345812840) 0 nearly-empty
+        primary-for std::logic_error (0x0x7f23457f8a28)
+
+Class std::__future_base::_Result_base::_Deleter
+   size=1 align=1
+   base size=0 base align=1
+std::__future_base::_Result_base::_Deleter (0x0x7f2345812f60) 0 empty
+
+Vtable for std::__future_base::_Result_base
+std::__future_base::_Result_base::_ZTVNSt13__future_base12_Result_baseE: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTINSt13__future_base12_Result_baseE)
+16    (int (*)(...))__cxa_pure_virtual
+24    0
+32    0
+
+Class std::__future_base::_Result_base
+   size=16 align=8
+   base size=16 base align=8
+std::__future_base::_Result_base (0x0x7f2345812f00) 0
+    vptr=((& std::__future_base::_Result_base::_ZTVNSt13__future_base12_Result_baseE) + 16)
+
+Class std::__future_base::_State_baseV2::__exception_ptr_tag
+   size=1 align=1
+   base size=0 base align=1
+std::__future_base::_State_baseV2::__exception_ptr_tag (0x0x7f234561c6c0) 0 empty
+
+Class std::__future_base::_State_baseV2::_Make_ready
+   size=32 align=8
+   base size=32 base align=8
+std::__future_base::_State_baseV2::_Make_ready (0x0x7f234561f270) 0
+  std::__at_thread_exit_elt (0x0x7f234561c780) 0
+
+Vtable for std::__future_base::_State_baseV2
+std::__future_base::_State_baseV2::_ZTVNSt13__future_base13_State_baseV2E: 6 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTINSt13__future_base13_State_baseV2E)
+16    (int (*)(...))std::__future_base::_State_baseV2::~_State_baseV2
+24    (int (*)(...))std::__future_base::_State_baseV2::~_State_baseV2
+32    (int (*)(...))std::__future_base::_State_baseV2::_M_complete_async
+40    (int (*)(...))std::__future_base::_State_baseV2::_M_is_deferred_future
+
+Class std::__future_base::_State_baseV2
+   size=32 align=8
+   base size=28 base align=8
+std::__future_base::_State_baseV2 (0x0x7f2345846120) 0
+    vptr=((& std::__future_base::_State_baseV2::_ZTVNSt13__future_base13_State_baseV2E) + 16)
+
+Class std::__future_base
+   size=1 align=1
+   base size=0 base align=1
+std::__future_base (0x0x7f2345812ea0) 0 empty
+
+Vtable for std::__future_base::_Async_state_commonV2
+std::__future_base::_Async_state_commonV2::_ZTVNSt13__future_base21_Async_state_commonV2E: 6 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTINSt13__future_base21_Async_state_commonV2E)
+16    (int (*)(...))std::__future_base::_Async_state_commonV2::~_Async_state_commonV2
+24    (int (*)(...))std::__future_base::_Async_state_commonV2::~_Async_state_commonV2
+32    (int (*)(...))std::__future_base::_Async_state_commonV2::_M_complete_async
+40    (int (*)(...))std::__future_base::_State_baseV2::_M_is_deferred_future
+
+Class std::__future_base::_Async_state_commonV2
+   size=48 align=8
+   base size=44 base align=8
+std::__future_base::_Async_state_commonV2 (0x0x7f2344d7ef70) 0
+    vptr=((& std::__future_base::_Async_state_commonV2::_ZTVNSt13__future_base21_Async_state_commonV2E) + 16)
+  std::__future_base::_State_baseV2 (0x0x7f2344dcc780) 0
+      primary-for std::__future_base::_Async_state_commonV2 (0x0x7f2344d7ef70)
+
+Class QThread::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QThread::QPrivateSignal (0x0x7f2344df9060) 0 empty
+
+Vtable for QThread
+QThread::_ZTV7QThread: 15 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI7QThread)
+16    (int (*)(...))QThread::metaObject
+24    (int (*)(...))QThread::qt_metacast
+32    (int (*)(...))QThread::qt_metacall
+40    (int (*)(...))QThread::~QThread
+48    (int (*)(...))QThread::~QThread
+56    (int (*)(...))QThread::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QThread::run
+
+Class QThread
+   size=16 align=8
+   base size=16 base align=8
+QThread (0x0x7f2344de02d8) 0
+    vptr=((& QThread::_ZTV7QThread) + 16)
+  QObject (0x0x7f2344df9000) 0
+      primary-for QThread (0x0x7f2344de02d8)
+
+Class QThreadPool::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QThreadPool::QPrivateSignal (0x0x7f2344df9420) 0 empty
+
+Vtable for QThreadPool
+QThreadPool::_ZTV11QThreadPool: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI11QThreadPool)
+16    (int (*)(...))QThreadPool::metaObject
+24    (int (*)(...))QThreadPool::qt_metacast
+32    (int (*)(...))QThreadPool::qt_metacall
+40    (int (*)(...))QThreadPool::~QThreadPool
+48    (int (*)(...))QThreadPool::~QThreadPool
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QThreadPool
+   size=16 align=8
+   base size=16 base align=8
+QThreadPool (0x0x7f2344de0340) 0
+    vptr=((& QThreadPool::_ZTV11QThreadPool) + 16)
+  QObject (0x0x7f2344df93c0) 0
+      primary-for QThreadPool (0x0x7f2344de0340)
+
+Class QThreadStorageData
+   size=4 align=4
+   base size=4 base align=4
+QThreadStorageData (0x0x7f2344df9600) 0
+
+Class QTimeLine::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QTimeLine::QPrivateSignal (0x0x7f2344df9cc0) 0 empty
+
+Vtable for QTimeLine
+QTimeLine::_ZTV9QTimeLine: 15 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI9QTimeLine)
+16    (int (*)(...))QTimeLine::metaObject
+24    (int (*)(...))QTimeLine::qt_metacast
+32    (int (*)(...))QTimeLine::qt_metacall
+40    (int (*)(...))QTimeLine::~QTimeLine
+48    (int (*)(...))QTimeLine::~QTimeLine
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QTimeLine::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QTimeLine::valueForTime
+
+Class QTimeLine
+   size=16 align=8
+   base size=16 base align=8
+QTimeLine (0x0x7f2344de03a8) 0
+    vptr=((& QTimeLine::_ZTV9QTimeLine) + 16)
+  QObject (0x0x7f2344df9c60) 0
+      primary-for QTimeLine (0x0x7f2344de03a8)
+
+Class QTimer::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QTimer::QPrivateSignal (0x0x7f2344df9f00) 0 empty
+
+Vtable for QTimer
+QTimer::_ZTV6QTimer: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI6QTimer)
+16    (int (*)(...))QTimer::metaObject
+24    (int (*)(...))QTimer::qt_metacast
+32    (int (*)(...))QTimer::qt_metacall
+40    (int (*)(...))QTimer::~QTimer
+48    (int (*)(...))QTimer::~QTimer
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QTimer::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QTimer
+   size=32 align=8
+   base size=29 base align=8
+QTimer (0x0x7f2344de0410) 0
+    vptr=((& QTimer::_ZTV6QTimer) + 16)
+  QObject (0x0x7f2344df9ea0) 0
+      primary-for QTimer (0x0x7f2344de0410)
+
+Class QTimeZone::OffsetData
+   size=32 align=8
+   base size=28 base align=8
+QTimeZone::OffsetData (0x0x7f2344e7f8a0) 0
+
+Class QTimeZone
+   size=8 align=8
+   base size=8 base align=8
+QTimeZone (0x0x7f2344e7f840) 0
+
+Class QTranslator::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QTranslator::QPrivateSignal (0x0x7f2344b24960) 0 empty
+
+Vtable for QTranslator
+QTranslator::_ZTV11QTranslator: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI11QTranslator)
+16    (int (*)(...))QTranslator::metaObject
+24    (int (*)(...))QTranslator::qt_metacast
+32    (int (*)(...))QTranslator::qt_metacall
+40    (int (*)(...))QTranslator::~QTranslator
+48    (int (*)(...))QTranslator::~QTranslator
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QTranslator::translate
+120   (int (*)(...))QTranslator::isEmpty
+
+Class QTranslator
+   size=16 align=8
+   base size=16 base align=8
+QTranslator (0x0x7f2344b21af8) 0
+    vptr=((& QTranslator::_ZTV11QTranslator) + 16)
+  QObject (0x0x7f2344b24900) 0
+      primary-for QTranslator (0x0x7f2344b21af8)
+
+Class QTransposeProxyModel::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QTransposeProxyModel::QPrivateSignal (0x0x7f2344b24ba0) 0 empty
+
+Vtable for QTransposeProxyModel
+QTransposeProxyModel::_ZTV20QTransposeProxyModel: 53 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI20QTransposeProxyModel)
+16    (int (*)(...))QTransposeProxyModel::metaObject
+24    (int (*)(...))QTransposeProxyModel::qt_metacast
+32    (int (*)(...))QTransposeProxyModel::qt_metacall
+40    (int (*)(...))QTransposeProxyModel::~QTransposeProxyModel
+48    (int (*)(...))QTransposeProxyModel::~QTransposeProxyModel
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QTransposeProxyModel::index
+120   (int (*)(...))QTransposeProxyModel::parent
+128   (int (*)(...))QAbstractProxyModel::sibling
+136   (int (*)(...))QTransposeProxyModel::rowCount
+144   (int (*)(...))QTransposeProxyModel::columnCount
+152   (int (*)(...))QAbstractProxyModel::hasChildren
+160   (int (*)(...))QAbstractProxyModel::data
+168   (int (*)(...))QAbstractProxyModel::setData
+176   (int (*)(...))QTransposeProxyModel::headerData
+184   (int (*)(...))QTransposeProxyModel::setHeaderData
+192   (int (*)(...))QTransposeProxyModel::itemData
+200   (int (*)(...))QTransposeProxyModel::setItemData
+208   (int (*)(...))QAbstractProxyModel::mimeTypes
+216   (int (*)(...))QAbstractProxyModel::mimeData
+224   (int (*)(...))QAbstractProxyModel::canDropMimeData
+232   (int (*)(...))QAbstractProxyModel::dropMimeData
+240   (int (*)(...))QAbstractProxyModel::supportedDropActions
+248   (int (*)(...))QAbstractProxyModel::supportedDragActions
+256   (int (*)(...))QTransposeProxyModel::insertRows
+264   (int (*)(...))QTransposeProxyModel::insertColumns
+272   (int (*)(...))QTransposeProxyModel::removeRows
+280   (int (*)(...))QTransposeProxyModel::removeColumns
+288   (int (*)(...))QTransposeProxyModel::moveRows
+296   (int (*)(...))QTransposeProxyModel::moveColumns
+304   (int (*)(...))QAbstractProxyModel::fetchMore
+312   (int (*)(...))QAbstractProxyModel::canFetchMore
+320   (int (*)(...))QAbstractProxyModel::flags
+328   (int (*)(...))QTransposeProxyModel::sort
+336   (int (*)(...))QAbstractProxyModel::buddy
+344   (int (*)(...))QAbstractItemModel::match
+352   (int (*)(...))QTransposeProxyModel::span
+360   (int (*)(...))QAbstractItemModel::roleNames
+368   (int (*)(...))QAbstractProxyModel::submit
+376   (int (*)(...))QAbstractProxyModel::revert
+384   (int (*)(...))QTransposeProxyModel::setSourceModel
+392   (int (*)(...))QTransposeProxyModel::mapToSource
+400   (int (*)(...))QTransposeProxyModel::mapFromSource
+408   (int (*)(...))QAbstractProxyModel::mapSelectionToSource
+416   (int (*)(...))QAbstractProxyModel::mapSelectionFromSource
+
+Class QTransposeProxyModel
+   size=16 align=8
+   base size=16 base align=8
+QTransposeProxyModel (0x0x7f2344b21b60) 0
+    vptr=((& QTransposeProxyModel::_ZTV20QTransposeProxyModel) + 16)
+  QAbstractProxyModel (0x0x7f2344b21bc8) 0
+      primary-for QTransposeProxyModel (0x0x7f2344b21b60)
+    QAbstractItemModel (0x0x7f2344b21c30) 0
+        primary-for QAbstractProxyModel (0x0x7f2344b21bc8)
+      QObject (0x0x7f2344b24b40) 0
+          primary-for QAbstractItemModel (0x0x7f2344b21c30)
+
+Class QUrlQuery
+   size=8 align=8
+   base size=8 base align=8
+QUrlQuery (0x0x7f2344b24d80) 0
+
+Class QWaitCondition
+   size=8 align=8
+   base size=8 base align=8
+QWaitCondition (0x0x7f2344bc6780) 0
+
+Class QXmlStreamStringRef
+   size=16 align=8
+   base size=16 base align=8
+QXmlStreamStringRef (0x0x7f2344bc68a0) 0
+
+Class QXmlStreamAttribute
+   size=80 align=8
+   base size=73 base align=8
+QXmlStreamAttribute (0x0x7f2344c55c60) 0
+
+Class QXmlStreamAttributes
+   size=8 align=8
+   base size=8 base align=8
+QXmlStreamAttributes (0x0x7f23448d32d8) 0
+  QVector<QXmlStreamAttribute> (0x0x7f23448d23c0) 0
+
+Class QXmlStreamNamespaceDeclaration
+   size=40 align=8
+   base size=40 base align=8
+QXmlStreamNamespaceDeclaration (0x0x7f23448d26c0) 0
+
+Class QXmlStreamNotationDeclaration
+   size=56 align=8
+   base size=56 base align=8
+QXmlStreamNotationDeclaration (0x0x7f2344956660) 0
+
+Class QXmlStreamEntityDeclaration
+   size=88 align=8
+   base size=88 base align=8
+QXmlStreamEntityDeclaration (0x0x7f23449b4660) 0
+
+Vtable for QXmlStreamEntityResolver
+QXmlStreamEntityResolver::_ZTV24QXmlStreamEntityResolver: 6 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI24QXmlStreamEntityResolver)
+16    (int (*)(...))QXmlStreamEntityResolver::~QXmlStreamEntityResolver
+24    (int (*)(...))QXmlStreamEntityResolver::~QXmlStreamEntityResolver
+32    (int (*)(...))QXmlStreamEntityResolver::resolveEntity
+40    (int (*)(...))QXmlStreamEntityResolver::resolveUndeclaredEntity
+
+Class QXmlStreamEntityResolver
+   size=8 align=8
+   base size=8 base align=8
+QXmlStreamEntityResolver (0x0x7f2344a1e720) 0 nearly-empty
+    vptr=((& QXmlStreamEntityResolver::_ZTV24QXmlStreamEntityResolver) + 16)
+
+Class QXmlStreamReader
+   size=8 align=8
+   base size=8 base align=8
+QXmlStreamReader (0x0x7f2344a1e780) 0
+
+Class QXmlStreamWriter
+   size=8 align=8
+   base size=8 base align=8
+QXmlStreamWriter (0x0x7f2344a7a660) 0
+
+Class QNetworkRequest
+   size=8 align=8
+   base size=8 base align=8
+QNetworkRequest (0x0x7f2344a7a840) 0
+
+Class QNetworkCacheMetaData
+   size=8 align=8
+   base size=8 base align=8
+QNetworkCacheMetaData (0x0x7f23447001e0) 0
+
+Class QAbstractNetworkCache::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QAbstractNetworkCache::QPrivateSignal (0x0x7f234475f780) 0 empty
+
+Vtable for QAbstractNetworkCache
+QAbstractNetworkCache::_ZTV21QAbstractNetworkCache: 22 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI21QAbstractNetworkCache)
+16    (int (*)(...))QAbstractNetworkCache::metaObject
+24    (int (*)(...))QAbstractNetworkCache::qt_metacast
+32    (int (*)(...))QAbstractNetworkCache::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))__cxa_pure_virtual
+120   (int (*)(...))__cxa_pure_virtual
+128   (int (*)(...))__cxa_pure_virtual
+136   (int (*)(...))__cxa_pure_virtual
+144   (int (*)(...))__cxa_pure_virtual
+152   (int (*)(...))__cxa_pure_virtual
+160   (int (*)(...))__cxa_pure_virtual
+168   (int (*)(...))__cxa_pure_virtual
+
+Class QAbstractNetworkCache
+   size=16 align=8
+   base size=16 base align=8
+QAbstractNetworkCache (0x0x7f234474fb60) 0
+    vptr=((& QAbstractNetworkCache::_ZTV21QAbstractNetworkCache) + 16)
+  QObject (0x0x7f234475f720) 0
+      primary-for QAbstractNetworkCache (0x0x7f234474fb60)
+
+Class QAbstractSocket::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QAbstractSocket::QPrivateSignal (0x0x7f234475f9c0) 0 empty
+
+Vtable for QAbstractSocket
+QAbstractSocket::_ZTV15QAbstractSocket: 41 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI15QAbstractSocket)
+16    (int (*)(...))QAbstractSocket::metaObject
+24    (int (*)(...))QAbstractSocket::qt_metacast
+32    (int (*)(...))QAbstractSocket::qt_metacall
+40    (int (*)(...))QAbstractSocket::~QAbstractSocket
+48    (int (*)(...))QAbstractSocket::~QAbstractSocket
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QAbstractSocket::isSequential
+120   (int (*)(...))QIODevice::open
+128   (int (*)(...))QAbstractSocket::close
+136   (int (*)(...))QIODevice::pos
+144   (int (*)(...))QIODevice::size
+152   (int (*)(...))QIODevice::seek
+160   (int (*)(...))QAbstractSocket::atEnd
+168   (int (*)(...))QIODevice::reset
+176   (int (*)(...))QAbstractSocket::bytesAvailable
+184   (int (*)(...))QAbstractSocket::bytesToWrite
+192   (int (*)(...))QAbstractSocket::canReadLine
+200   (int (*)(...))QAbstractSocket::waitForReadyRead
+208   (int (*)(...))QAbstractSocket::waitForBytesWritten
+216   (int (*)(...))QAbstractSocket::readData
+224   (int (*)(...))QAbstractSocket::readLineData
+232   (int (*)(...))QAbstractSocket::writeData
+240   (int (*)(...))QAbstractSocket::resume
+248   (int (*)(...))QAbstractSocket::connectToHost
+256   (int (*)(...))QAbstractSocket::connectToHost
+264   (int (*)(...))QAbstractSocket::disconnectFromHost
+272   (int (*)(...))QAbstractSocket::setReadBufferSize
+280   (int (*)(...))QAbstractSocket::socketDescriptor
+288   (int (*)(...))QAbstractSocket::setSocketDescriptor
+296   (int (*)(...))QAbstractSocket::setSocketOption
+304   (int (*)(...))QAbstractSocket::socketOption
+312   (int (*)(...))QAbstractSocket::waitForConnected
+320   (int (*)(...))QAbstractSocket::waitForDisconnected
+
+Class QAbstractSocket
+   size=16 align=8
+   base size=16 base align=8
+QAbstractSocket (0x0x7f234474fbc8) 0
+    vptr=((& QAbstractSocket::_ZTV15QAbstractSocket) + 16)
+  QIODevice (0x0x7f234474fc30) 0
+      primary-for QAbstractSocket (0x0x7f234474fbc8)
+    QObject (0x0x7f234475f960) 0
+        primary-for QIODevice (0x0x7f234474fc30)
+
+Class QAuthenticator
+   size=8 align=8
+   base size=8 base align=8
+QAuthenticator (0x0x7f2344805120) 0
+
+Class QDnsDomainNameRecord
+   size=8 align=8
+   base size=8 base align=8
+QDnsDomainNameRecord (0x0x7f23448051e0) 0
+
+Class QDnsHostAddressRecord
+   size=8 align=8
+   base size=8 base align=8
+QDnsHostAddressRecord (0x0x7f234485b360) 0
+
+Class QDnsMailExchangeRecord
+   size=8 align=8
+   base size=8 base align=8
+QDnsMailExchangeRecord (0x0x7f23448a54e0) 0
+
+Class QDnsServiceRecord
+   size=8 align=8
+   base size=8 base align=8
+QDnsServiceRecord (0x0x7f23443f55a0) 0
+
+Class QDnsTextRecord
+   size=8 align=8
+   base size=8 base align=8
+QDnsTextRecord (0x0x7f234443f840) 0
+
+Class QDnsLookup::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QDnsLookup::QPrivateSignal (0x0x7f2344480d80) 0 empty
+
+Vtable for QDnsLookup
+QDnsLookup::_ZTV10QDnsLookup: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI10QDnsLookup)
+16    (int (*)(...))QDnsLookup::metaObject
+24    (int (*)(...))QDnsLookup::qt_metacast
+32    (int (*)(...))QDnsLookup::qt_metacall
+40    (int (*)(...))QDnsLookup::~QDnsLookup
+48    (int (*)(...))QDnsLookup::~QDnsLookup
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QDnsLookup
+   size=16 align=8
+   base size=16 base align=8
+QDnsLookup (0x0x7f2344496208) 0
+    vptr=((& QDnsLookup::_ZTV10QDnsLookup) + 16)
+  QObject (0x0x7f2344480d20) 0
+      primary-for QDnsLookup (0x0x7f2344496208)
+
+Class QTcpSocket::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QTcpSocket::QPrivateSignal (0x0x7f23444b1180) 0 empty
+
+Vtable for QTcpSocket
+QTcpSocket::_ZTV10QTcpSocket: 41 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI10QTcpSocket)
+16    (int (*)(...))QTcpSocket::metaObject
+24    (int (*)(...))QTcpSocket::qt_metacast
+32    (int (*)(...))QTcpSocket::qt_metacall
+40    (int (*)(...))QTcpSocket::~QTcpSocket
+48    (int (*)(...))QTcpSocket::~QTcpSocket
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QAbstractSocket::isSequential
+120   (int (*)(...))QIODevice::open
+128   (int (*)(...))QAbstractSocket::close
+136   (int (*)(...))QIODevice::pos
+144   (int (*)(...))QIODevice::size
+152   (int (*)(...))QIODevice::seek
+160   (int (*)(...))QAbstractSocket::atEnd
+168   (int (*)(...))QIODevice::reset
+176   (int (*)(...))QAbstractSocket::bytesAvailable
+184   (int (*)(...))QAbstractSocket::bytesToWrite
+192   (int (*)(...))QAbstractSocket::canReadLine
+200   (int (*)(...))QAbstractSocket::waitForReadyRead
+208   (int (*)(...))QAbstractSocket::waitForBytesWritten
+216   (int (*)(...))QAbstractSocket::readData
+224   (int (*)(...))QAbstractSocket::readLineData
+232   (int (*)(...))QAbstractSocket::writeData
+240   (int (*)(...))QAbstractSocket::resume
+248   (int (*)(...))QAbstractSocket::connectToHost
+256   (int (*)(...))QAbstractSocket::connectToHost
+264   (int (*)(...))QAbstractSocket::disconnectFromHost
+272   (int (*)(...))QAbstractSocket::setReadBufferSize
+280   (int (*)(...))QAbstractSocket::socketDescriptor
+288   (int (*)(...))QAbstractSocket::setSocketDescriptor
+296   (int (*)(...))QAbstractSocket::setSocketOption
+304   (int (*)(...))QAbstractSocket::socketOption
+312   (int (*)(...))QAbstractSocket::waitForConnected
+320   (int (*)(...))QAbstractSocket::waitForDisconnected
+
+Class QTcpSocket
+   size=16 align=8
+   base size=16 base align=8
+QTcpSocket (0x0x7f2344496270) 0
+    vptr=((& QTcpSocket::_ZTV10QTcpSocket) + 16)
+  QAbstractSocket (0x0x7f23444962d8) 0
+      primary-for QTcpSocket (0x0x7f2344496270)
+    QIODevice (0x0x7f2344496340) 0
+        primary-for QAbstractSocket (0x0x7f23444962d8)
+      QObject (0x0x7f23444b1120) 0
+          primary-for QIODevice (0x0x7f2344496340)
+
+Class QSslCertificate
+   size=8 align=8
+   base size=8 base align=8
+QSslCertificate (0x0x7f23444b1a20) 0
+
+Class QSslError
+   size=8 align=8
+   base size=8 base align=8
+QSslError (0x0x7f23445511e0) 0
+
+Class QSslSocket::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QSslSocket::QPrivateSignal (0x0x7f23442193c0) 0 empty
+
+Vtable for QSslSocket
+QSslSocket::_ZTV10QSslSocket: 41 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI10QSslSocket)
+16    (int (*)(...))QSslSocket::metaObject
+24    (int (*)(...))QSslSocket::qt_metacast
+32    (int (*)(...))QSslSocket::qt_metacall
+40    (int (*)(...))QSslSocket::~QSslSocket
+48    (int (*)(...))QSslSocket::~QSslSocket
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QAbstractSocket::isSequential
+120   (int (*)(...))QIODevice::open
+128   (int (*)(...))QSslSocket::close
+136   (int (*)(...))QIODevice::pos
+144   (int (*)(...))QIODevice::size
+152   (int (*)(...))QIODevice::seek
+160   (int (*)(...))QSslSocket::atEnd
+168   (int (*)(...))QIODevice::reset
+176   (int (*)(...))QSslSocket::bytesAvailable
+184   (int (*)(...))QSslSocket::bytesToWrite
+192   (int (*)(...))QSslSocket::canReadLine
+200   (int (*)(...))QSslSocket::waitForReadyRead
+208   (int (*)(...))QSslSocket::waitForBytesWritten
+216   (int (*)(...))QSslSocket::readData
+224   (int (*)(...))QAbstractSocket::readLineData
+232   (int (*)(...))QSslSocket::writeData
+240   (int (*)(...))QSslSocket::resume
+248   (int (*)(...))QSslSocket::connectToHost
+256   (int (*)(...))QAbstractSocket::connectToHost
+264   (int (*)(...))QSslSocket::disconnectFromHost
+272   (int (*)(...))QSslSocket::setReadBufferSize
+280   (int (*)(...))QAbstractSocket::socketDescriptor
+288   (int (*)(...))QSslSocket::setSocketDescriptor
+296   (int (*)(...))QSslSocket::setSocketOption
+304   (int (*)(...))QSslSocket::socketOption
+312   (int (*)(...))QSslSocket::waitForConnected
+320   (int (*)(...))QSslSocket::waitForDisconnected
+
+Class QSslSocket
+   size=16 align=8
+   base size=16 base align=8
+QSslSocket (0x0x7f234420e680) 0
+    vptr=((& QSslSocket::_ZTV10QSslSocket) + 16)
+  QTcpSocket (0x0x7f234420e6e8) 0
+      primary-for QSslSocket (0x0x7f234420e680)
+    QAbstractSocket (0x0x7f234420e750) 0
+        primary-for QTcpSocket (0x0x7f234420e6e8)
+      QIODevice (0x0x7f234420e7b8) 0
+          primary-for QAbstractSocket (0x0x7f234420e750)
+        QObject (0x0x7f2344219360) 0
+            primary-for QIODevice (0x0x7f234420e7b8)
+
+Class QDtlsClientVerifier::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QDtlsClientVerifier::QPrivateSignal (0x0x7f2344219600) 0 empty
+
+Class QDtlsClientVerifier::GeneratorParameters
+   size=16 align=8
+   base size=16 base align=8
+QDtlsClientVerifier::GeneratorParameters (0x0x7f2344219660) 0
+
+Vtable for QDtlsClientVerifier
+QDtlsClientVerifier::_ZTV19QDtlsClientVerifier: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI19QDtlsClientVerifier)
+16    (int (*)(...))QDtlsClientVerifier::metaObject
+24    (int (*)(...))QDtlsClientVerifier::qt_metacast
+32    (int (*)(...))QDtlsClientVerifier::qt_metacall
+40    (int (*)(...))QDtlsClientVerifier::~QDtlsClientVerifier
+48    (int (*)(...))QDtlsClientVerifier::~QDtlsClientVerifier
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QDtlsClientVerifier
+   size=16 align=8
+   base size=16 base align=8
+QDtlsClientVerifier (0x0x7f234420e820) 0
+    vptr=((& QDtlsClientVerifier::_ZTV19QDtlsClientVerifier) + 16)
+  QObject (0x0x7f23442195a0) 0
+      primary-for QDtlsClientVerifier (0x0x7f234420e820)
+
+Class QDtls::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QDtls::QPrivateSignal (0x0x7f23442198a0) 0 empty
+
+Vtable for QDtls
+QDtls::_ZTV5QDtls: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI5QDtls)
+16    (int (*)(...))QDtls::metaObject
+24    (int (*)(...))QDtls::qt_metacast
+32    (int (*)(...))QDtls::qt_metacall
+40    (int (*)(...))QDtls::~QDtls
+48    (int (*)(...))QDtls::~QDtls
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QDtls
+   size=16 align=8
+   base size=16 base align=8
+QDtls (0x0x7f234420e888) 0
+    vptr=((& QDtls::_ZTV5QDtls) + 16)
+  QObject (0x0x7f2344219840) 0
+      primary-for QDtls (0x0x7f234420e888)
+
+Class QIPv6Address
+   size=16 align=1
+   base size=16 base align=1
+QIPv6Address (0x0x7f2344219ae0) 0
+
+Class QHostAddress
+   size=8 align=8
+   base size=8 base align=8
+QHostAddress (0x0x7f2344219c00) 0
+
+Class QHostInfo
+   size=8 align=8
+   base size=8 base align=8
+QHostInfo (0x0x7f234431f9c0) 0
+
+Class QHstsPolicy
+   size=8 align=8
+   base size=8 base align=8
+QHstsPolicy (0x0x7f2343fef7e0) 0
+
+Class QHttpPart
+   size=8 align=8
+   base size=8 base align=8
+QHttpPart (0x0x7f234407e420) 0
+
+Class QHttpMultiPart::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QHttpMultiPart::QPrivateSignal (0x0x7f23440cf5a0) 0 empty
+
+Vtable for QHttpMultiPart
+QHttpMultiPart::_ZTV14QHttpMultiPart: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI14QHttpMultiPart)
+16    (int (*)(...))QHttpMultiPart::metaObject
+24    (int (*)(...))QHttpMultiPart::qt_metacast
+32    (int (*)(...))QHttpMultiPart::qt_metacall
+40    (int (*)(...))QHttpMultiPart::~QHttpMultiPart
+48    (int (*)(...))QHttpMultiPart::~QHttpMultiPart
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QHttpMultiPart
+   size=16 align=8
+   base size=16 base align=8
+QHttpMultiPart (0x0x7f23440cc680) 0
+    vptr=((& QHttpMultiPart::_ZTV14QHttpMultiPart) + 16)
+  QObject (0x0x7f23440cf540) 0
+      primary-for QHttpMultiPart (0x0x7f23440cc680)
+
+Class QLocalServer::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QLocalServer::QPrivateSignal (0x0x7f23440cf7e0) 0 empty
+
+Vtable for QLocalServer
+QLocalServer::_ZTV12QLocalServer: 17 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI12QLocalServer)
+16    (int (*)(...))QLocalServer::metaObject
+24    (int (*)(...))QLocalServer::qt_metacast
+32    (int (*)(...))QLocalServer::qt_metacall
+40    (int (*)(...))QLocalServer::~QLocalServer
+48    (int (*)(...))QLocalServer::~QLocalServer
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QLocalServer::hasPendingConnections
+120   (int (*)(...))QLocalServer::nextPendingConnection
+128   (int (*)(...))QLocalServer::incomingConnection
+
+Class QLocalServer
+   size=16 align=8
+   base size=16 base align=8
+QLocalServer (0x0x7f23440cc6e8) 0
+    vptr=((& QLocalServer::_ZTV12QLocalServer) + 16)
+  QObject (0x0x7f23440cf780) 0
+      primary-for QLocalServer (0x0x7f23440cc6e8)
+
+Class QLocalSocket::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QLocalSocket::QPrivateSignal (0x0x7f234411c2a0) 0 empty
+
+Vtable for QLocalSocket
+QLocalSocket::_ZTV12QLocalSocket: 30 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI12QLocalSocket)
+16    (int (*)(...))QLocalSocket::metaObject
+24    (int (*)(...))QLocalSocket::qt_metacast
+32    (int (*)(...))QLocalSocket::qt_metacall
+40    (int (*)(...))QLocalSocket::~QLocalSocket
+48    (int (*)(...))QLocalSocket::~QLocalSocket
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QLocalSocket::isSequential
+120   (int (*)(...))QLocalSocket::open
+128   (int (*)(...))QLocalSocket::close
+136   (int (*)(...))QIODevice::pos
+144   (int (*)(...))QIODevice::size
+152   (int (*)(...))QIODevice::seek
+160   (int (*)(...))QIODevice::atEnd
+168   (int (*)(...))QIODevice::reset
+176   (int (*)(...))QLocalSocket::bytesAvailable
+184   (int (*)(...))QLocalSocket::bytesToWrite
+192   (int (*)(...))QLocalSocket::canReadLine
+200   (int (*)(...))QLocalSocket::waitForReadyRead
+208   (int (*)(...))QLocalSocket::waitForBytesWritten
+216   (int (*)(...))QLocalSocket::readData
+224   (int (*)(...))QIODevice::readLineData
+232   (int (*)(...))QLocalSocket::writeData
+
+Class QLocalSocket
+   size=16 align=8
+   base size=16 base align=8
+QLocalSocket (0x0x7f23440cc888) 0
+    vptr=((& QLocalSocket::_ZTV12QLocalSocket) + 16)
+  QIODevice (0x0x7f23440cc8f0) 0
+      primary-for QLocalSocket (0x0x7f23440cc888)
+    QObject (0x0x7f234411c240) 0
+        primary-for QIODevice (0x0x7f23440cc8f0)
+
+Class QSslConfiguration
+   size=8 align=8
+   base size=8 base align=8
+QSslConfiguration (0x0x7f234411c480) 0
+
+Class QSslPreSharedKeyAuthenticator
+   size=8 align=8
+   base size=8 base align=8
+QSslPreSharedKeyAuthenticator (0x0x7f23441add20) 0
+
+Class QNetworkAccessManager::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QNetworkAccessManager::QPrivateSignal (0x0x7f2343e29300) 0 empty
+
+Vtable for QNetworkAccessManager
+QNetworkAccessManager::_ZTV21QNetworkAccessManager: 15 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI21QNetworkAccessManager)
+16    (int (*)(...))QNetworkAccessManager::metaObject
+24    (int (*)(...))QNetworkAccessManager::qt_metacast
+32    (int (*)(...))QNetworkAccessManager::qt_metacall
+40    (int (*)(...))QNetworkAccessManager::~QNetworkAccessManager
+48    (int (*)(...))QNetworkAccessManager::~QNetworkAccessManager
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QNetworkAccessManager::createRequest
+
+Class QNetworkAccessManager
+   size=16 align=8
+   base size=16 base align=8
+QNetworkAccessManager (0x0x7f2343e168f0) 0
+    vptr=((& QNetworkAccessManager::_ZTV21QNetworkAccessManager) + 16)
+  QObject (0x0x7f2343e292a0) 0
+      primary-for QNetworkAccessManager (0x0x7f2343e168f0)
+
+Class QNetworkConfiguration
+   size=8 align=8
+   base size=8 base align=8
+QNetworkConfiguration (0x0x7f2343e295a0) 0
+
+Class QNetworkConfigurationManager::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QNetworkConfigurationManager::QPrivateSignal (0x0x7f2343ea49c0) 0 empty
+
+Vtable for QNetworkConfigurationManager
+QNetworkConfigurationManager::_ZTV28QNetworkConfigurationManager: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI28QNetworkConfigurationManager)
+16    (int (*)(...))QNetworkConfigurationManager::metaObject
+24    (int (*)(...))QNetworkConfigurationManager::qt_metacast
+32    (int (*)(...))QNetworkConfigurationManager::qt_metacall
+40    (int (*)(...))QNetworkConfigurationManager::~QNetworkConfigurationManager
+48    (int (*)(...))QNetworkConfigurationManager::~QNetworkConfigurationManager
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QNetworkConfigurationManager
+   size=16 align=8
+   base size=16 base align=8
+QNetworkConfigurationManager (0x0x7f2343e93d00) 0
+    vptr=((& QNetworkConfigurationManager::_ZTV28QNetworkConfigurationManager) + 16)
+  QObject (0x0x7f2343ea4960) 0
+      primary-for QNetworkConfigurationManager (0x0x7f2343e93d00)
+
+Class QNetworkCookie
+   size=8 align=8
+   base size=8 base align=8
+QNetworkCookie (0x0x7f2343ef5540) 0
+
+Class QNetworkCookieJar::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QNetworkCookieJar::QPrivateSignal (0x0x7f2343f6d060) 0 empty
+
+Vtable for QNetworkCookieJar
+QNetworkCookieJar::_ZTV17QNetworkCookieJar: 20 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI17QNetworkCookieJar)
+16    (int (*)(...))QNetworkCookieJar::metaObject
+24    (int (*)(...))QNetworkCookieJar::qt_metacast
+32    (int (*)(...))QNetworkCookieJar::qt_metacall
+40    (int (*)(...))QNetworkCookieJar::~QNetworkCookieJar
+48    (int (*)(...))QNetworkCookieJar::~QNetworkCookieJar
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QNetworkCookieJar::cookiesForUrl
+120   (int (*)(...))QNetworkCookieJar::setCookiesFromUrl
+128   (int (*)(...))QNetworkCookieJar::insertCookie
+136   (int (*)(...))QNetworkCookieJar::updateCookie
+144   (int (*)(...))QNetworkCookieJar::deleteCookie
+152   (int (*)(...))QNetworkCookieJar::validateCookie
+
+Class QNetworkCookieJar
+   size=16 align=8
+   base size=16 base align=8
+QNetworkCookieJar (0x0x7f2343f59750) 0
+    vptr=((& QNetworkCookieJar::_ZTV17QNetworkCookieJar) + 16)
+  QObject (0x0x7f2343f6d000) 0
+      primary-for QNetworkCookieJar (0x0x7f2343f59750)
+
+Class QNetworkDatagram
+   size=8 align=8
+   base size=8 base align=8
+QNetworkDatagram (0x0x7f2343f6d240) 0
+
+Class QNetworkDiskCache::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QNetworkDiskCache::QPrivateSignal (0x0x7f2343c24d80) 0 empty
+
+Vtable for QNetworkDiskCache
+QNetworkDiskCache::_ZTV17QNetworkDiskCache: 23 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI17QNetworkDiskCache)
+16    (int (*)(...))QNetworkDiskCache::metaObject
+24    (int (*)(...))QNetworkDiskCache::qt_metacast
+32    (int (*)(...))QNetworkDiskCache::qt_metacall
+40    (int (*)(...))QNetworkDiskCache::~QNetworkDiskCache
+48    (int (*)(...))QNetworkDiskCache::~QNetworkDiskCache
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QNetworkDiskCache::metaData
+120   (int (*)(...))QNetworkDiskCache::updateMetaData
+128   (int (*)(...))QNetworkDiskCache::data
+136   (int (*)(...))QNetworkDiskCache::remove
+144   (int (*)(...))QNetworkDiskCache::cacheSize
+152   (int (*)(...))QNetworkDiskCache::prepare
+160   (int (*)(...))QNetworkDiskCache::insert
+168   (int (*)(...))QNetworkDiskCache::clear
+176   (int (*)(...))QNetworkDiskCache::expire
+
+Class QNetworkDiskCache
+   size=16 align=8
+   base size=16 base align=8
+QNetworkDiskCache (0x0x7f2343c32618) 0
+    vptr=((& QNetworkDiskCache::_ZTV17QNetworkDiskCache) + 16)
+  QAbstractNetworkCache (0x0x7f2343c32680) 0
+      primary-for QNetworkDiskCache (0x0x7f2343c32618)
+    QObject (0x0x7f2343c24d20) 0
+        primary-for QAbstractNetworkCache (0x0x7f2343c32680)
+
+Class QNetworkAddressEntry
+   size=8 align=8
+   base size=8 base align=8
+QNetworkAddressEntry (0x0x7f2343c24f60) 0
+
+Class QNetworkInterface
+   size=8 align=8
+   base size=8 base align=8
+QNetworkInterface (0x0x7f2343cf8f00) 0
+
+Class QNetworkProxyQuery
+   size=8 align=8
+   base size=8 base align=8
+QNetworkProxyQuery (0x0x7f2343d76de0) 0
+
+Class QNetworkProxy
+   size=8 align=8
+   base size=8 base align=8
+QNetworkProxy (0x0x7f2343a09300) 0
+
+Vtable for QNetworkProxyFactory
+QNetworkProxyFactory::_ZTV20QNetworkProxyFactory: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI20QNetworkProxyFactory)
+16    0
+24    0
+32    (int (*)(...))__cxa_pure_virtual
+
+Class QNetworkProxyFactory
+   size=8 align=8
+   base size=8 base align=8
+QNetworkProxyFactory (0x0x7f2343a99060) 0 nearly-empty
+    vptr=((& QNetworkProxyFactory::_ZTV20QNetworkProxyFactory) + 16)
+
+Class QNetworkReply::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QNetworkReply::QPrivateSignal (0x0x7f2343a99300) 0 empty
+
+Vtable for QNetworkReply
+QNetworkReply::_ZTV13QNetworkReply: 36 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI13QNetworkReply)
+16    (int (*)(...))QNetworkReply::metaObject
+24    (int (*)(...))QNetworkReply::qt_metacast
+32    (int (*)(...))QNetworkReply::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QNetworkReply::isSequential
+120   (int (*)(...))QIODevice::open
+128   (int (*)(...))QNetworkReply::close
+136   (int (*)(...))QIODevice::pos
+144   (int (*)(...))QIODevice::size
+152   (int (*)(...))QIODevice::seek
+160   (int (*)(...))QIODevice::atEnd
+168   (int (*)(...))QIODevice::reset
+176   (int (*)(...))QIODevice::bytesAvailable
+184   (int (*)(...))QIODevice::bytesToWrite
+192   (int (*)(...))QIODevice::canReadLine
+200   (int (*)(...))QIODevice::waitForReadyRead
+208   (int (*)(...))QIODevice::waitForBytesWritten
+216   (int (*)(...))__cxa_pure_virtual
+224   (int (*)(...))QIODevice::readLineData
+232   (int (*)(...))QNetworkReply::writeData
+240   (int (*)(...))QNetworkReply::setReadBufferSize
+248   (int (*)(...))__cxa_pure_virtual
+256   (int (*)(...))QNetworkReply::ignoreSslErrors
+264   (int (*)(...))QNetworkReply::sslConfigurationImplementation
+272   (int (*)(...))QNetworkReply::setSslConfigurationImplementation
+280   (int (*)(...))QNetworkReply::ignoreSslErrorsImplementation
+
+Class QNetworkReply
+   size=16 align=8
+   base size=16 base align=8
+QNetworkReply (0x0x7f2343a6e208) 0
+    vptr=((& QNetworkReply::_ZTV13QNetworkReply) + 16)
+  QIODevice (0x0x7f2343a6e270) 0
+      primary-for QNetworkReply (0x0x7f2343a6e208)
+    QObject (0x0x7f2343a992a0) 0
+        primary-for QIODevice (0x0x7f2343a6e270)
+
+Class QNetworkSession::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QNetworkSession::QPrivateSignal (0x0x7f2343a997e0) 0 empty
+
+Vtable for QNetworkSession
+QNetworkSession::_ZTV15QNetworkSession: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI15QNetworkSession)
+16    (int (*)(...))QNetworkSession::metaObject
+24    (int (*)(...))QNetworkSession::qt_metacast
+32    (int (*)(...))QNetworkSession::qt_metacall
+40    (int (*)(...))QNetworkSession::~QNetworkSession
+48    (int (*)(...))QNetworkSession::~QNetworkSession
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QNetworkSession::connectNotify
+104   (int (*)(...))QNetworkSession::disconnectNotify
+
+Class QNetworkSession
+   size=24 align=8
+   base size=24 base align=8
+QNetworkSession (0x0x7f2343a6e2d8) 0
+    vptr=((& QNetworkSession::_ZTV15QNetworkSession) + 16)
+  QObject (0x0x7f2343a99780) 0
+      primary-for QNetworkSession (0x0x7f2343a6e2d8)
+
+Class QOcspResponse
+   size=8 align=8
+   base size=8 base align=8
+QOcspResponse (0x0x7f2343b04060) 0
+
+Class QTcpServer::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QTcpServer::QPrivateSignal (0x0x7f2343b558a0) 0 empty
+
+Vtable for QTcpServer
+QTcpServer::_ZTV10QTcpServer: 17 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI10QTcpServer)
+16    (int (*)(...))QTcpServer::metaObject
+24    (int (*)(...))QTcpServer::qt_metacast
+32    (int (*)(...))QTcpServer::qt_metacall
+40    (int (*)(...))QTcpServer::~QTcpServer
+48    (int (*)(...))QTcpServer::~QTcpServer
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QTcpServer::hasPendingConnections
+120   (int (*)(...))QTcpServer::nextPendingConnection
+128   (int (*)(...))QTcpServer::incomingConnection
+
+Class QTcpServer
+   size=16 align=8
+   base size=16 base align=8
+QTcpServer (0x0x7f2343b49b60) 0
+    vptr=((& QTcpServer::_ZTV10QTcpServer) + 16)
+  QObject (0x0x7f2343b55840) 0
+      primary-for QTcpServer (0x0x7f2343b49b60)
+
+Class QSslCertificateExtension
+   size=8 align=8
+   base size=8 base align=8
+QSslCertificateExtension (0x0x7f2343b55a80) 0
+
+Class QSslCipher
+   size=8 align=8
+   base size=8 base align=8
+QSslCipher (0x0x7f2343bbb840) 0
+
+Class QSslDiffieHellmanParameters
+   size=8 align=8
+   base size=8 base align=8
+QSslDiffieHellmanParameters (0x0x7f234387a900) 0
+
+Class QSslEllipticCurve
+   size=4 align=4
+   base size=4 base align=4
+QSslEllipticCurve (0x0x7f234393f660) 0
+
+Class QSslKey
+   size=8 align=8
+   base size=8 base align=8
+QSslKey (0x0x7f23439a5000) 0
+
+Class QUdpSocket::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QUdpSocket::QPrivateSignal (0x0x7f23435fb300) 0 empty
+
+Vtable for QUdpSocket
+QUdpSocket::_ZTV10QUdpSocket: 41 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI10QUdpSocket)
+16    (int (*)(...))QUdpSocket::metaObject
+24    (int (*)(...))QUdpSocket::qt_metacast
+32    (int (*)(...))QUdpSocket::qt_metacall
+40    (int (*)(...))QUdpSocket::~QUdpSocket
+48    (int (*)(...))QUdpSocket::~QUdpSocket
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QAbstractSocket::isSequential
+120   (int (*)(...))QIODevice::open
+128   (int (*)(...))QAbstractSocket::close
+136   (int (*)(...))QIODevice::pos
+144   (int (*)(...))QIODevice::size
+152   (int (*)(...))QIODevice::seek
+160   (int (*)(...))QAbstractSocket::atEnd
+168   (int (*)(...))QIODevice::reset
+176   (int (*)(...))QAbstractSocket::bytesAvailable
+184   (int (*)(...))QAbstractSocket::bytesToWrite
+192   (int (*)(...))QAbstractSocket::canReadLine
+200   (int (*)(...))QAbstractSocket::waitForReadyRead
+208   (int (*)(...))QAbstractSocket::waitForBytesWritten
+216   (int (*)(...))QAbstractSocket::readData
+224   (int (*)(...))QAbstractSocket::readLineData
+232   (int (*)(...))QAbstractSocket::writeData
+240   (int (*)(...))QAbstractSocket::resume
+248   (int (*)(...))QAbstractSocket::connectToHost
+256   (int (*)(...))QAbstractSocket::connectToHost
+264   (int (*)(...))QAbstractSocket::disconnectFromHost
+272   (int (*)(...))QAbstractSocket::setReadBufferSize
+280   (int (*)(...))QAbstractSocket::socketDescriptor
+288   (int (*)(...))QAbstractSocket::setSocketDescriptor
+296   (int (*)(...))QAbstractSocket::setSocketOption
+304   (int (*)(...))QAbstractSocket::socketOption
+312   (int (*)(...))QAbstractSocket::waitForConnected
+320   (int (*)(...))QAbstractSocket::waitForDisconnected
+
+Class QUdpSocket
+   size=16 align=8
+   base size=16 base align=8
+QUdpSocket (0x0x7f23435fc0d0) 0
+    vptr=((& QUdpSocket::_ZTV10QUdpSocket) + 16)
+  QAbstractSocket (0x0x7f23435fc138) 0
+      primary-for QUdpSocket (0x0x7f23435fc0d0)
+    QIODevice (0x0x7f23435fc1a0) 0
+        primary-for QAbstractSocket (0x0x7f23435fc138)
+      QObject (0x0x7f23435fb2a0) 0
+          primary-for QIODevice (0x0x7f23435fc1a0)
+
+Class QRemoteObjectSourceLocationInfo
+   size=16 align=8
+   base size=16 base align=8
+QRemoteObjectSourceLocationInfo (0x0x7f23435fb540) 0
+
+Class QAbstractItemModelReplica::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QAbstractItemModelReplica::QPrivateSignal (0x0x7f23436e85a0) 0 empty
+
+Vtable for QAbstractItemModelReplica
+QAbstractItemModelReplica::_ZTV25QAbstractItemModelReplica: 48 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI25QAbstractItemModelReplica)
+16    (int (*)(...))QAbstractItemModelReplica::metaObject
+24    (int (*)(...))QAbstractItemModelReplica::qt_metacast
+32    (int (*)(...))QAbstractItemModelReplica::qt_metacall
+40    (int (*)(...))QAbstractItemModelReplica::~QAbstractItemModelReplica
+48    (int (*)(...))QAbstractItemModelReplica::~QAbstractItemModelReplica
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QAbstractItemModelReplica::index
+120   (int (*)(...))QAbstractItemModelReplica::parent
+128   (int (*)(...))QAbstractItemModel::sibling
+136   (int (*)(...))QAbstractItemModelReplica::rowCount
+144   (int (*)(...))QAbstractItemModelReplica::columnCount
+152   (int (*)(...))QAbstractItemModelReplica::hasChildren
+160   (int (*)(...))QAbstractItemModelReplica::data
+168   (int (*)(...))QAbstractItemModelReplica::setData
+176   (int (*)(...))QAbstractItemModelReplica::headerData
+184   (int (*)(...))QAbstractItemModel::setHeaderData
+192   (int (*)(...))QAbstractItemModel::itemData
+200   (int (*)(...))QAbstractItemModel::setItemData
+208   (int (*)(...))QAbstractItemModel::mimeTypes
+216   (int (*)(...))QAbstractItemModel::mimeData
+224   (int (*)(...))QAbstractItemModel::canDropMimeData
+232   (int (*)(...))QAbstractItemModel::dropMimeData
+240   (int (*)(...))QAbstractItemModel::supportedDropActions
+248   (int (*)(...))QAbstractItemModel::supportedDragActions
+256   (int (*)(...))QAbstractItemModel::insertRows
+264   (int (*)(...))QAbstractItemModel::insertColumns
+272   (int (*)(...))QAbstractItemModel::removeRows
+280   (int (*)(...))QAbstractItemModel::removeColumns
+288   (int (*)(...))QAbstractItemModel::moveRows
+296   (int (*)(...))QAbstractItemModel::moveColumns
+304   (int (*)(...))QAbstractItemModel::fetchMore
+312   (int (*)(...))QAbstractItemModel::canFetchMore
+320   (int (*)(...))QAbstractItemModelReplica::flags
+328   (int (*)(...))QAbstractItemModel::sort
+336   (int (*)(...))QAbstractItemModel::buddy
+344   (int (*)(...))QAbstractItemModel::match
+352   (int (*)(...))QAbstractItemModel::span
+360   (int (*)(...))QAbstractItemModelReplica::roleNames
+368   (int (*)(...))QAbstractItemModel::submit
+376   (int (*)(...))QAbstractItemModel::revert
+
+Class QAbstractItemModelReplica
+   size=24 align=8
+   base size=24 base align=8
+QAbstractItemModelReplica (0x0x7f23436438f0) 0
+    vptr=((& QAbstractItemModelReplica::_ZTV25QAbstractItemModelReplica) + 16)
+  QAbstractItemModel (0x0x7f2343643958) 0
+      primary-for QAbstractItemModelReplica (0x0x7f23436438f0)
+    QObject (0x0x7f23436e8540) 0
+        primary-for QAbstractItemModel (0x0x7f2343643958)
+
+Class ModelIndex
+   size=8 align=4
+   base size=8 base align=4
+ModelIndex (0x0x7f23436e8720) 0
+
+Class IndexValuePair
+   size=40 align=8
+   base size=40 base align=8
+IndexValuePair (0x0x7f2343726000) 0
+
+Class DataEntries
+   size=8 align=8
+   base size=8 base align=8
+DataEntries (0x0x7f23437aa840) 0
+
+Class MetaAndDataEntries
+   size=24 align=8
+   base size=24 base align=8
+MetaAndDataEntries (0x0x7f23437b8d68) 0
+  DataEntries (0x0x7f23433d32a0) 0
+
+Class QRemoteObjectReplica::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QRemoteObjectReplica::QPrivateSignal (0x0x7f23434d85a0) 0 empty
+
+Vtable for QRemoteObjectReplica
+QRemoteObjectReplica::_ZTV20QRemoteObjectReplica: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI20QRemoteObjectReplica)
+16    (int (*)(...))QRemoteObjectReplica::metaObject
+24    (int (*)(...))QRemoteObjectReplica::qt_metacast
+32    (int (*)(...))QRemoteObjectReplica::qt_metacall
+40    (int (*)(...))QRemoteObjectReplica::~QRemoteObjectReplica
+48    (int (*)(...))QRemoteObjectReplica::~QRemoteObjectReplica
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QRemoteObjectReplica::setNode
+120   (int (*)(...))QRemoteObjectReplica::initialize
+
+Class QRemoteObjectReplica
+   size=32 align=8
+   base size=32 base align=8
+QRemoteObjectReplica (0x0x7f2343435f70) 0
+    vptr=((& QRemoteObjectReplica::_ZTV20QRemoteObjectReplica) + 16)
+  QObject (0x0x7f23434d8540) 0
+      primary-for QRemoteObjectReplica (0x0x7f2343435f70)
+
+Vtable for QRemoteObjectDynamicReplica
+QRemoteObjectDynamicReplica::_ZTV27QRemoteObjectDynamicReplica: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI27QRemoteObjectDynamicReplica)
+16    (int (*)(...))QRemoteObjectDynamicReplica::metaObject
+24    (int (*)(...))QRemoteObjectDynamicReplica::qt_metacast
+32    (int (*)(...))QRemoteObjectDynamicReplica::qt_metacall
+40    (int (*)(...))QRemoteObjectDynamicReplica::~QRemoteObjectDynamicReplica
+48    (int (*)(...))QRemoteObjectDynamicReplica::~QRemoteObjectDynamicReplica
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QRemoteObjectReplica::setNode
+120   (int (*)(...))QRemoteObjectReplica::initialize
+
+Class QRemoteObjectDynamicReplica
+   size=32 align=8
+   base size=32 base align=8
+QRemoteObjectDynamicReplica (0x0x7f234351f000) 0
+    vptr=((& QRemoteObjectDynamicReplica::_ZTV27QRemoteObjectDynamicReplica) + 16)
+  QRemoteObjectReplica (0x0x7f234351f068) 0
+      primary-for QRemoteObjectDynamicReplica (0x0x7f234351f000)
+    QObject (0x0x7f23434d87e0) 0
+        primary-for QRemoteObjectReplica (0x0x7f234351f068)
+
+Class QRemoteObjectRegistry::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QRemoteObjectRegistry::QPrivateSignal (0x0x7f23434d88a0) 0 empty
+
+Vtable for QRemoteObjectRegistry
+QRemoteObjectRegistry::_ZTV21QRemoteObjectRegistry: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI21QRemoteObjectRegistry)
+16    (int (*)(...))QRemoteObjectRegistry::metaObject
+24    (int (*)(...))QRemoteObjectRegistry::qt_metacast
+32    (int (*)(...))QRemoteObjectRegistry::qt_metacall
+40    (int (*)(...))QRemoteObjectRegistry::~QRemoteObjectRegistry
+48    (int (*)(...))QRemoteObjectRegistry::~QRemoteObjectRegistry
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QRemoteObjectReplica::setNode
+120   (int (*)(...))QRemoteObjectRegistry::initialize
+
+Class QRemoteObjectRegistry
+   size=32 align=8
+   base size=32 base align=8
+QRemoteObjectRegistry (0x0x7f234351f0d0) 0
+    vptr=((& QRemoteObjectRegistry::_ZTV21QRemoteObjectRegistry) + 16)
+  QRemoteObjectReplica (0x0x7f234351f138) 0
+      primary-for QRemoteObjectRegistry (0x0x7f234351f0d0)
+    QObject (0x0x7f23434d8840) 0
+        primary-for QRemoteObjectReplica (0x0x7f234351f138)
+
+Class QRemoteObjectAbstractPersistedStore::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QRemoteObjectAbstractPersistedStore::QPrivateSignal (0x0x7f23434d8ae0) 0 empty
+
+Vtable for QRemoteObjectAbstractPersistedStore
+QRemoteObjectAbstractPersistedStore::_ZTV35QRemoteObjectAbstractPersistedStore: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI35QRemoteObjectAbstractPersistedStore)
+16    (int (*)(...))QRemoteObjectAbstractPersistedStore::metaObject
+24    (int (*)(...))QRemoteObjectAbstractPersistedStore::qt_metacast
+32    (int (*)(...))QRemoteObjectAbstractPersistedStore::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))__cxa_pure_virtual
+120   (int (*)(...))__cxa_pure_virtual
+
+Class QRemoteObjectAbstractPersistedStore
+   size=16 align=8
+   base size=16 base align=8
+QRemoteObjectAbstractPersistedStore (0x0x7f234351f1a0) 0
+    vptr=((& QRemoteObjectAbstractPersistedStore::_ZTV35QRemoteObjectAbstractPersistedStore) + 16)
+  QObject (0x0x7f23434d8a80) 0
+      primary-for QRemoteObjectAbstractPersistedStore (0x0x7f234351f1a0)
+
+Class QRemoteObjectNode::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QRemoteObjectNode::QPrivateSignal (0x0x7f23434d8d80) 0 empty
+
+Vtable for QRemoteObjectNode
+QRemoteObjectNode::_ZTV17QRemoteObjectNode: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI17QRemoteObjectNode)
+16    (int (*)(...))QRemoteObjectNode::metaObject
+24    (int (*)(...))QRemoteObjectNode::qt_metacast
+32    (int (*)(...))QRemoteObjectNode::qt_metacall
+40    (int (*)(...))QRemoteObjectNode::~QRemoteObjectNode
+48    (int (*)(...))QRemoteObjectNode::~QRemoteObjectNode
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QRemoteObjectNode::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QRemoteObjectNode::setName
+120   (int (*)(...))QRemoteObjectNode::setRegistryUrl
+
+Class QRemoteObjectNode
+   size=16 align=8
+   base size=16 base align=8
+QRemoteObjectNode (0x0x7f234351f208) 0
+    vptr=((& QRemoteObjectNode::_ZTV17QRemoteObjectNode) + 16)
+  QObject (0x0x7f23434d8d20) 0
+      primary-for QRemoteObjectNode (0x0x7f234351f208)
+
+Class QRemoteObjectHostBase::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QRemoteObjectHostBase::QPrivateSignal (0x0x7f234355a180) 0 empty
+
+Vtable for QRemoteObjectHostBase
+QRemoteObjectHostBase::_ZTV21QRemoteObjectHostBase: 18 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI21QRemoteObjectHostBase)
+16    (int (*)(...))QRemoteObjectHostBase::metaObject
+24    (int (*)(...))QRemoteObjectHostBase::qt_metacast
+32    (int (*)(...))QRemoteObjectHostBase::qt_metacall
+40    (int (*)(...))QRemoteObjectHostBase::~QRemoteObjectHostBase
+48    (int (*)(...))QRemoteObjectHostBase::~QRemoteObjectHostBase
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QRemoteObjectNode::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QRemoteObjectHostBase::setName
+120   (int (*)(...))QRemoteObjectNode::setRegistryUrl
+128   (int (*)(...))QRemoteObjectHostBase::hostUrl
+136   (int (*)(...))QRemoteObjectHostBase::setHostUrl
+
+Class QRemoteObjectHostBase
+   size=16 align=8
+   base size=16 base align=8
+QRemoteObjectHostBase (0x0x7f234351f270) 0
+    vptr=((& QRemoteObjectHostBase::_ZTV21QRemoteObjectHostBase) + 16)
+  QRemoteObjectNode (0x0x7f234351f2d8) 0
+      primary-for QRemoteObjectHostBase (0x0x7f234351f270)
+    QObject (0x0x7f234355a120) 0
+        primary-for QRemoteObjectNode (0x0x7f234351f2d8)
+
+Class QRemoteObjectHost::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QRemoteObjectHost::QPrivateSignal (0x0x7f23431e73c0) 0 empty
+
+Vtable for QRemoteObjectHost
+QRemoteObjectHost::_ZTV17QRemoteObjectHost: 18 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI17QRemoteObjectHost)
+16    (int (*)(...))QRemoteObjectHost::metaObject
+24    (int (*)(...))QRemoteObjectHost::qt_metacast
+32    (int (*)(...))QRemoteObjectHost::qt_metacall
+40    (int (*)(...))QRemoteObjectHost::~QRemoteObjectHost
+48    (int (*)(...))QRemoteObjectHost::~QRemoteObjectHost
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QRemoteObjectNode::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QRemoteObjectHostBase::setName
+120   (int (*)(...))QRemoteObjectNode::setRegistryUrl
+128   (int (*)(...))QRemoteObjectHost::hostUrl
+136   (int (*)(...))QRemoteObjectHost::setHostUrl
+
+Class QRemoteObjectHost
+   size=16 align=8
+   base size=16 base align=8
+QRemoteObjectHost (0x0x7f23431cfb60) 0
+    vptr=((& QRemoteObjectHost::_ZTV17QRemoteObjectHost) + 16)
+  QRemoteObjectHostBase (0x0x7f23431cfbc8) 0
+      primary-for QRemoteObjectHost (0x0x7f23431cfb60)
+    QRemoteObjectNode (0x0x7f23431cfc30) 0
+        primary-for QRemoteObjectHostBase (0x0x7f23431cfbc8)
+      QObject (0x0x7f23431e7360) 0
+          primary-for QRemoteObjectNode (0x0x7f23431cfc30)
+
+Class QRemoteObjectRegistryHost::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QRemoteObjectRegistryHost::QPrivateSignal (0x0x7f23431e7600) 0 empty
+
+Vtable for QRemoteObjectRegistryHost
+QRemoteObjectRegistryHost::_ZTV25QRemoteObjectRegistryHost: 18 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI25QRemoteObjectRegistryHost)
+16    (int (*)(...))QRemoteObjectRegistryHost::metaObject
+24    (int (*)(...))QRemoteObjectRegistryHost::qt_metacast
+32    (int (*)(...))QRemoteObjectRegistryHost::qt_metacall
+40    (int (*)(...))QRemoteObjectRegistryHost::~QRemoteObjectRegistryHost
+48    (int (*)(...))QRemoteObjectRegistryHost::~QRemoteObjectRegistryHost
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QRemoteObjectNode::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QRemoteObjectHostBase::setName
+120   (int (*)(...))QRemoteObjectRegistryHost::setRegistryUrl
+128   (int (*)(...))QRemoteObjectHostBase::hostUrl
+136   (int (*)(...))QRemoteObjectHostBase::setHostUrl
+
+Class QRemoteObjectRegistryHost
+   size=16 align=8
+   base size=16 base align=8
+QRemoteObjectRegistryHost (0x0x7f23431cfc98) 0
+    vptr=((& QRemoteObjectRegistryHost::_ZTV25QRemoteObjectRegistryHost) + 16)
+  QRemoteObjectHostBase (0x0x7f23431cfd00) 0
+      primary-for QRemoteObjectRegistryHost (0x0x7f23431cfc98)
+    QRemoteObjectNode (0x0x7f23431cfd68) 0
+        primary-for QRemoteObjectHostBase (0x0x7f23431cfd00)
+      QObject (0x0x7f23431e75a0) 0
+          primary-for QRemoteObjectNode (0x0x7f23431cfd68)
+
+Class QRemoteObjectPendingCall
+   size=8 align=8
+   base size=8 base align=8
+QRemoteObjectPendingCall (0x0x7f23431e77e0) 0
+
+Class QRemoteObjectPendingCallWatcher::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QRemoteObjectPendingCallWatcher::QPrivateSignal (0x0x7f23431e7b40) 0 empty
+
+Vtable for QRemoteObjectPendingCallWatcher
+QRemoteObjectPendingCallWatcher::_ZTV31QRemoteObjectPendingCallWatcher: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI31QRemoteObjectPendingCallWatcher)
+16    (int (*)(...))QRemoteObjectPendingCallWatcher::metaObject
+24    (int (*)(...))QRemoteObjectPendingCallWatcher::qt_metacast
+32    (int (*)(...))QRemoteObjectPendingCallWatcher::qt_metacall
+40    (int (*)(...))QRemoteObjectPendingCallWatcher::~QRemoteObjectPendingCallWatcher
+48    (int (*)(...))QRemoteObjectPendingCallWatcher::~QRemoteObjectPendingCallWatcher
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QRemoteObjectPendingCallWatcher
+   size=24 align=8
+   base size=24 base align=8
+QRemoteObjectPendingCallWatcher (0x0x7f23432220e0) 0
+    vptr=((& QRemoteObjectPendingCallWatcher::_ZTV31QRemoteObjectPendingCallWatcher) + 16)
+  QObject (0x0x7f23431e7a80) 0
+      primary-for QRemoteObjectPendingCallWatcher (0x0x7f23432220e0)
+  QRemoteObjectPendingCall (0x0x7f23431e7ae0) 16
+
+Class QRemoteObjectSettingsStore::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QRemoteObjectSettingsStore::QPrivateSignal (0x0x7f2343236060) 0 empty
+
+Vtable for QRemoteObjectSettingsStore
+QRemoteObjectSettingsStore::_ZTV26QRemoteObjectSettingsStore: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI26QRemoteObjectSettingsStore)
+16    (int (*)(...))QRemoteObjectSettingsStore::metaObject
+24    (int (*)(...))QRemoteObjectSettingsStore::qt_metacast
+32    (int (*)(...))QRemoteObjectSettingsStore::qt_metacall
+40    (int (*)(...))QRemoteObjectSettingsStore::~QRemoteObjectSettingsStore
+48    (int (*)(...))QRemoteObjectSettingsStore::~QRemoteObjectSettingsStore
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QRemoteObjectSettingsStore::saveProperties
+120   (int (*)(...))QRemoteObjectSettingsStore::restoreProperties
+
+Class QRemoteObjectSettingsStore
+   size=16 align=8
+   base size=16 base align=8
+QRemoteObjectSettingsStore (0x0x7f2343235000) 0
+    vptr=((& QRemoteObjectSettingsStore::_ZTV26QRemoteObjectSettingsStore) + 16)
+  QRemoteObjectAbstractPersistedStore (0x0x7f2343235068) 0
+      primary-for QRemoteObjectSettingsStore (0x0x7f2343235000)
+    QObject (0x0x7f2343236000) 0
+        primary-for QRemoteObjectAbstractPersistedStore (0x0x7f2343235068)
+
+Class QtPrivate::QMetaObjectPrivate
+   size=56 align=4
+   base size=56 base align=4
+QtPrivate::QMetaObjectPrivate (0x0x7f23432365a0) 0
+
+Class ModelInfo
+   size=24 align=8
+   base size=24 base align=8
+ModelInfo (0x0x7f23432842a0) 0
+
+Vtable for SourceApiMap
+SourceApiMap::_ZTV12SourceApiMap: 32 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI12SourceApiMap)
+16    0
+24    0
+32    (int (*)(...))__cxa_pure_virtual
+40    (int (*)(...))__cxa_pure_virtual
+48    (int (*)(...))SourceApiMap::className
+56    (int (*)(...))__cxa_pure_virtual
+64    (int (*)(...))__cxa_pure_virtual
+72    (int (*)(...))__cxa_pure_virtual
+80    (int (*)(...))__cxa_pure_virtual
+88    (int (*)(...))__cxa_pure_virtual
+96    (int (*)(...))__cxa_pure_virtual
+104   (int (*)(...))__cxa_pure_virtual
+112   (int (*)(...))__cxa_pure_virtual
+120   (int (*)(...))__cxa_pure_virtual
+128   (int (*)(...))__cxa_pure_virtual
+136   (int (*)(...))__cxa_pure_virtual
+144   (int (*)(...))__cxa_pure_virtual
+152   (int (*)(...))__cxa_pure_virtual
+160   (int (*)(...))__cxa_pure_virtual
+168   (int (*)(...))__cxa_pure_virtual
+176   (int (*)(...))__cxa_pure_virtual
+184   (int (*)(...))__cxa_pure_virtual
+192   (int (*)(...))__cxa_pure_virtual
+200   (int (*)(...))__cxa_pure_virtual
+208   (int (*)(...))__cxa_pure_virtual
+216   (int (*)(...))__cxa_pure_virtual
+224   (int (*)(...))SourceApiMap::isDynamic
+232   (int (*)(...))SourceApiMap::isAdapterSignal
+240   (int (*)(...))SourceApiMap::isAdapterMethod
+248   (int (*)(...))SourceApiMap::isAdapterProperty
+
+Class SourceApiMap
+   size=24 align=8
+   base size=24 base align=8
+SourceApiMap (0x0x7f2343284300) 0
+    vptr=((& SourceApiMap::_ZTV12SourceApiMap) + 16)
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f234331bcc0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f2343339060) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f2343339240) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f23433395a0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f2343339780) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f2343339ae0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f2343339cc0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f234337b060) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f234337b240) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f234337b5a0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7f234337b780) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7f234337bae0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7f234337bcc0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7f23433af060) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7f23433af240) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7f23433af5a0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f2342fe0a80) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f2342fe0de0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f2342fe0f60) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f2343011300) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f2343011480) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f23430117e0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f2343011960) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f2343011cc0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f2343011e40) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f23430411e0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7f2343041360) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7f23430416c0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7f2343041840) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7f2343041ba0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7f2343041d20) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7f234306e0c0) 0 empty
+
diff --git a/tests/auto/bic/data/QtRemoteObjects.5.14.0.linux-gcc-amd64.txt b/tests/auto/bic/data/QtRemoteObjects.5.14.0.linux-gcc-amd64.txt
new file mode 100644 (file)
index 0000000..e2cdb5d
--- /dev/null
@@ -0,0 +1,6412 @@
+Class std::__failure_type
+   size=1 align=1
+   base size=0 base align=1
+std::__failure_type (0x0x7f3bffb14720) 0 empty
+
+Class std::__do_is_destructible_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__do_is_destructible_impl (0x0x7f3bffb77ea0) 0 empty
+
+Class std::__do_is_nt_destructible_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__do_is_nt_destructible_impl (0x0x7f3bffba4120) 0 empty
+
+Class std::__do_is_default_constructible_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__do_is_default_constructible_impl (0x0x7f3bffba4360) 0 empty
+
+Class std::__do_is_static_castable_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__do_is_static_castable_impl (0x0x7f3bffba45a0) 0 empty
+
+Class std::__do_is_direct_constructible_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__do_is_direct_constructible_impl (0x0x7f3bffba4720) 0 empty
+
+Class std::__do_is_nary_constructible_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__do_is_nary_constructible_impl (0x0x7f3bffba4ae0) 0 empty
+
+Class std::__do_is_implicitly_default_constructible_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__do_is_implicitly_default_constructible_impl (0x0x7f3bffbe0c00) 0 empty
+
+Class std::__do_common_type_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__do_common_type_impl (0x0x7f3bff862300) 0 empty
+
+Class std::__do_member_type_wrapper
+   size=1 align=1
+   base size=0 base align=1
+std::__do_member_type_wrapper (0x0x7f3bff8623c0) 0 empty
+
+Class std::__invoke_memfun_ref
+   size=1 align=1
+   base size=0 base align=1
+std::__invoke_memfun_ref (0x0x7f3bff862780) 0 empty
+
+Class std::__invoke_memfun_deref
+   size=1 align=1
+   base size=0 base align=1
+std::__invoke_memfun_deref (0x0x7f3bff8627e0) 0 empty
+
+Class std::__invoke_memobj_ref
+   size=1 align=1
+   base size=0 base align=1
+std::__invoke_memobj_ref (0x0x7f3bff862840) 0 empty
+
+Class std::__invoke_memobj_deref
+   size=1 align=1
+   base size=0 base align=1
+std::__invoke_memobj_deref (0x0x7f3bff8628a0) 0 empty
+
+Class std::__invoke_other
+   size=1 align=1
+   base size=0 base align=1
+std::__invoke_other (0x0x7f3bff862900) 0 empty
+
+Class std::__result_of_memfun_ref_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__result_of_memfun_ref_impl (0x0x7f3bff8629c0) 0 empty
+
+Class std::__result_of_memfun_deref_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__result_of_memfun_deref_impl (0x0x7f3bff862a80) 0 empty
+
+Class std::__result_of_memobj_ref_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__result_of_memobj_ref_impl (0x0x7f3bff862b40) 0 empty
+
+Class std::__result_of_memobj_deref_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__result_of_memobj_deref_impl (0x0x7f3bff862c00) 0 empty
+
+Class std::__result_of_other_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__result_of_other_impl (0x0x7f3bff862f60) 0 empty
+
+Class std::__swappable_details::__do_is_swappable_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__swappable_details::__do_is_swappable_impl (0x0x7f3bff89f300) 0 empty
+
+Class std::__swappable_details::__do_is_nothrow_swappable_impl
+   size=1 align=1
+   base size=0 base align=1
+std::__swappable_details::__do_is_nothrow_swappable_impl (0x0x7f3bff89f360) 0 empty
+
+Class std::__nonesuch
+   size=1 align=1
+   base size=0 base align=1
+std::__nonesuch (0x0x7f3bff89f900) 0 empty
+
+Class std::piecewise_construct_t
+   size=1 align=1
+   base size=0 base align=1
+std::piecewise_construct_t (0x0x7f3bff89ff60) 0 empty
+
+Class std::__nonesuch_no_braces
+   size=1 align=1
+   base size=1 base align=1
+std::__nonesuch_no_braces (0x0x7f3bff8ba270) 0 empty
+  std::__nonesuch (0x0x7f3bff8e3480) 0 empty
+
+Class std::__true_type
+   size=1 align=1
+   base size=0 base align=1
+std::__true_type (0x0x7f3bff92fde0) 0 empty
+
+Class std::__false_type
+   size=1 align=1
+   base size=0 base align=1
+std::__false_type (0x0x7f3bff92fe40) 0 empty
+
+Class std::input_iterator_tag
+   size=1 align=1
+   base size=0 base align=1
+std::input_iterator_tag (0x0x7f3bff992b40) 0 empty
+
+Class std::output_iterator_tag
+   size=1 align=1
+   base size=0 base align=1
+std::output_iterator_tag (0x0x7f3bff992ba0) 0 empty
+
+Class std::forward_iterator_tag
+   size=1 align=1
+   base size=1 base align=1
+std::forward_iterator_tag (0x0x7f3bff8ba750) 0 empty
+  std::input_iterator_tag (0x0x7f3bff992c00) 0 empty
+
+Class std::bidirectional_iterator_tag
+   size=1 align=1
+   base size=1 base align=1
+std::bidirectional_iterator_tag (0x0x7f3bff8ba7b8) 0 empty
+  std::forward_iterator_tag (0x0x7f3bff8ba820) 0 empty
+    std::input_iterator_tag (0x0x7f3bff992c60) 0 empty
+
+Class std::random_access_iterator_tag
+   size=1 align=1
+   base size=1 base align=1
+std::random_access_iterator_tag (0x0x7f3bff8ba888) 0 empty
+  std::bidirectional_iterator_tag (0x0x7f3bff8ba8f0) 0 empty
+    std::forward_iterator_tag (0x0x7f3bff8ba958) 0 empty
+      std::input_iterator_tag (0x0x7f3bff992cc0) 0 empty
+
+Class __gnu_cxx::__ops::_Iter_less_iter
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__ops::_Iter_less_iter (0x0x7f3bffa417e0) 0 empty
+
+Class __gnu_cxx::__ops::_Iter_less_val
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__ops::_Iter_less_val (0x0x7f3bffa41900) 0 empty
+
+Class __gnu_cxx::__ops::_Val_less_iter
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__ops::_Val_less_iter (0x0x7f3bffa41c00) 0 empty
+
+Class __gnu_cxx::__ops::_Iter_equal_to_iter
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__ops::_Iter_equal_to_iter (0x0x7f3bffa41f00) 0 empty
+
+Class __gnu_cxx::__ops::_Iter_equal_to_val
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__ops::_Iter_equal_to_val (0x0x7f3bff670060) 0 empty
+
+Class __locale_struct
+   size=232 align=8
+   base size=232 base align=8
+__locale_struct (0x0x7f3bff6fc360) 0
+
+Class timeval
+   size=16 align=8
+   base size=16 base align=8
+timeval (0x0x7f3bff6fc660) 0
+
+Class timespec
+   size=16 align=8
+   base size=16 base align=8
+timespec (0x0x7f3bff6fc6c0) 0
+
+Class __pthread_rwlock_arch_t
+   size=56 align=8
+   base size=56 base align=8
+__pthread_rwlock_arch_t (0x0x7f3bff6fc780) 0
+
+Class __pthread_internal_list
+   size=16 align=8
+   base size=16 base align=8
+__pthread_internal_list (0x0x7f3bff6fc7e0) 0
+
+Class __pthread_mutex_s
+   size=40 align=8
+   base size=40 base align=8
+__pthread_mutex_s (0x0x7f3bff6fc840) 0
+
+Class __pthread_cond_s
+   size=48 align=8
+   base size=48 base align=8
+__pthread_cond_s (0x0x7f3bff6fc8a0) 0
+
+Class pthread_attr_t
+   size=56 align=8
+   base size=56 base align=8
+pthread_attr_t (0x0x7f3bff6fcb40) 0
+
+Class random_data
+   size=48 align=8
+   base size=48 base align=8
+random_data (0x0x7f3bff6fcde0) 0
+
+Class drand48_data
+   size=24 align=8
+   base size=24 base align=8
+drand48_data (0x0x7f3bff6fce40) 0
+
+Vtable for std::exception
+std::exception::_ZTVSt9exception: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt9exception)
+16    (int (*)(...))std::exception::~exception
+24    (int (*)(...))std::exception::~exception
+32    (int (*)(...))std::exception::what
+
+Class std::exception
+   size=8 align=8
+   base size=8 base align=8
+std::exception (0x0x7f3bff755c00) 0 nearly-empty
+    vptr=((& std::exception::_ZTVSt9exception) + 16)
+
+Vtable for std::bad_exception
+std::bad_exception::_ZTVSt13bad_exception: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt13bad_exception)
+16    (int (*)(...))std::bad_exception::~bad_exception
+24    (int (*)(...))std::bad_exception::~bad_exception
+32    (int (*)(...))std::bad_exception::what
+
+Class std::bad_exception
+   size=8 align=8
+   base size=8 base align=8
+std::bad_exception (0x0x7f3bff8bac98) 0 nearly-empty
+    vptr=((& std::bad_exception::_ZTVSt13bad_exception) + 16)
+  std::exception (0x0x7f3bff755de0) 0 nearly-empty
+      primary-for std::bad_exception (0x0x7f3bff8bac98)
+
+Vtable for std::type_info
+std::type_info::_ZTVSt9type_info: 8 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt9type_info)
+16    (int (*)(...))std::type_info::~type_info
+24    (int (*)(...))std::type_info::~type_info
+32    (int (*)(...))std::type_info::__is_pointer_p
+40    (int (*)(...))std::type_info::__is_function_p
+48    (int (*)(...))std::type_info::__do_catch
+56    (int (*)(...))std::type_info::__do_upcast
+
+Class std::type_info
+   size=16 align=8
+   base size=16 base align=8
+std::type_info (0x0x7f3bff7f8000) 0
+    vptr=((& std::type_info::_ZTVSt9type_info) + 16)
+
+Vtable for std::bad_cast
+std::bad_cast::_ZTVSt8bad_cast: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt8bad_cast)
+16    (int (*)(...))std::bad_cast::~bad_cast
+24    (int (*)(...))std::bad_cast::~bad_cast
+32    (int (*)(...))std::bad_cast::what
+
+Class std::bad_cast
+   size=8 align=8
+   base size=8 base align=8
+std::bad_cast (0x0x7f3bff8bad00) 0 nearly-empty
+    vptr=((& std::bad_cast::_ZTVSt8bad_cast) + 16)
+  std::exception (0x0x7f3bff7f83c0) 0 nearly-empty
+      primary-for std::bad_cast (0x0x7f3bff8bad00)
+
+Vtable for std::bad_typeid
+std::bad_typeid::_ZTVSt10bad_typeid: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt10bad_typeid)
+16    (int (*)(...))std::bad_typeid::~bad_typeid
+24    (int (*)(...))std::bad_typeid::~bad_typeid
+32    (int (*)(...))std::bad_typeid::what
+
+Class std::bad_typeid
+   size=8 align=8
+   base size=8 base align=8
+std::bad_typeid (0x0x7f3bff8bad68) 0 nearly-empty
+    vptr=((& std::bad_typeid::_ZTVSt10bad_typeid) + 16)
+  std::exception (0x0x7f3bff7f85a0) 0 nearly-empty
+      primary-for std::bad_typeid (0x0x7f3bff8bad68)
+
+Class std::__exception_ptr::exception_ptr
+   size=8 align=8
+   base size=8 base align=8
+std::__exception_ptr::exception_ptr (0x0x7f3bff7f8780) 0
+
+Vtable for std::nested_exception
+std::nested_exception::_ZTVSt16nested_exception: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt16nested_exception)
+16    (int (*)(...))std::nested_exception::~nested_exception
+24    (int (*)(...))std::nested_exception::~nested_exception
+
+Class std::nested_exception
+   size=16 align=8
+   base size=16 base align=8
+std::nested_exception (0x0x7f3bff7f8d20) 0
+    vptr=((& std::nested_exception::_ZTVSt16nested_exception) + 16)
+
+Vtable for std::bad_alloc
+std::bad_alloc::_ZTVSt9bad_alloc: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt9bad_alloc)
+16    (int (*)(...))std::bad_alloc::~bad_alloc
+24    (int (*)(...))std::bad_alloc::~bad_alloc
+32    (int (*)(...))std::bad_alloc::what
+
+Class std::bad_alloc
+   size=8 align=8
+   base size=8 base align=8
+std::bad_alloc (0x0x7f3bff8badd0) 0 nearly-empty
+    vptr=((& std::bad_alloc::_ZTVSt9bad_alloc) + 16)
+  std::exception (0x0x7f3bff82d420) 0 nearly-empty
+      primary-for std::bad_alloc (0x0x7f3bff8badd0)
+
+Vtable for std::bad_array_new_length
+std::bad_array_new_length::_ZTVSt20bad_array_new_length: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt20bad_array_new_length)
+16    (int (*)(...))std::bad_array_new_length::~bad_array_new_length
+24    (int (*)(...))std::bad_array_new_length::~bad_array_new_length
+32    (int (*)(...))std::bad_array_new_length::what
+
+Class std::bad_array_new_length
+   size=8 align=8
+   base size=8 base align=8
+std::bad_array_new_length (0x0x7f3bff8bae38) 0 nearly-empty
+    vptr=((& std::bad_array_new_length::_ZTVSt20bad_array_new_length) + 16)
+  std::bad_alloc (0x0x7f3bff8baea0) 0 nearly-empty
+      primary-for std::bad_array_new_length (0x0x7f3bff8bae38)
+    std::exception (0x0x7f3bff82d600) 0 nearly-empty
+        primary-for std::bad_alloc (0x0x7f3bff8baea0)
+
+Class std::nothrow_t
+   size=1 align=1
+   base size=0 base align=1
+std::nothrow_t (0x0x7f3bff82d7e0) 0 empty
+
+Class std::__allocator_traits_base
+   size=1 align=1
+   base size=0 base align=1
+std::__allocator_traits_base (0x0x7f3bff82d9c0) 0 empty
+
+Class std::__numeric_limits_base
+   size=1 align=1
+   base size=0 base align=1
+std::__numeric_limits_base (0x0x7f3bff4abea0) 0 empty
+
+Class QSysInfo
+   size=1 align=1
+   base size=0 base align=1
+QSysInfo (0x0x7f3bff145420) 0 empty
+
+Class QMessageLogContext
+   size=32 align=8
+   base size=32 base align=8
+QMessageLogContext (0x0x7f3bff145540) 0
+
+Class QMessageLogger
+   size=32 align=8
+   base size=32 base align=8
+QMessageLogger (0x0x7f3bff145720) 0
+
+Class QFlag
+   size=4 align=4
+   base size=4 base align=4
+QFlag (0x0x7f3bff145de0) 0
+
+Class QIncompatibleFlag
+   size=4 align=4
+   base size=4 base align=4
+QIncompatibleFlag (0x0x7f3bff1c05a0) 0
+
+Class std::__atomic_flag_base
+   size=1 align=1
+   base size=1 base align=1
+std::__atomic_flag_base (0x0x7f3bfee56a80) 0
+
+Class std::atomic_flag
+   size=1 align=1
+   base size=1 base align=1
+std::atomic_flag (0x0x7f3bff1f6d00) 0
+  std::__atomic_flag_base (0x0x7f3bfee56ae0) 0
+
+Class QAtomicInt
+   size=4 align=4
+   base size=4 base align=4
+QAtomicInt (0x0x7f3bff002478) 0
+  QAtomicInteger<int> (0x0x7f3bff0024e0) 0
+    QBasicAtomicInteger<int> (0x0x7f3bfed8cd20) 0
+
+Class QInternal
+   size=1 align=1
+   base size=0 base align=1
+QInternal (0x0x7f3bfe9e08a0) 0 empty
+
+Class QtPrivate::QSlotObjectBase
+   size=16 align=8
+   base size=16 base align=8
+QtPrivate::QSlotObjectBase (0x0x7f3bfea10e40) 0
+
+Class QGenericArgument
+   size=16 align=8
+   base size=16 base align=8
+QGenericArgument (0x0x7f3bfe65d5a0) 0
+
+Class QGenericReturnArgument
+   size=16 align=8
+   base size=16 base align=8
+QGenericReturnArgument (0x0x7f3bfe666138) 0
+  QGenericArgument (0x0x7f3bfe65d840) 0
+
+Class QMetaObject::SuperData
+   size=8 align=8
+   base size=8 base align=8
+QMetaObject::SuperData (0x0x7f3bfe65dcc0) 0
+
+Class QMetaObject
+   size=48 align=8
+   base size=48 base align=8
+QMetaObject (0x0x7f3bfe65dc60) 0
+
+Class QMetaObject::Connection
+   size=8 align=8
+   base size=8 base align=8
+QMetaObject::Connection (0x0x7f3bfe6b25a0) 0
+
+Class QLatin1Char
+   size=1 align=1
+   base size=1 base align=1
+QLatin1Char (0x0x7f3bfe7350c0) 0
+
+Class QChar
+   size=2 align=2
+   base size=2 base align=2
+QChar (0x0x7f3bfe7357e0) 0
+
+Class QtPrivate::RefCount
+   size=4 align=4
+   base size=4 base align=4
+QtPrivate::RefCount (0x0x7f3bfe804600) 0
+
+Class QArrayData
+   size=24 align=8
+   base size=24 base align=8
+QArrayData (0x0x7f3bfe804960) 0
+
+Class QtPrivate::QContainerImplHelper
+   size=1 align=1
+   base size=0 base align=1
+QtPrivate::QContainerImplHelper (0x0x7f3bfe461c60) 0 empty
+
+Class lconv
+   size=96 align=8
+   base size=96 base align=8
+lconv (0x0x7f3bfe5574e0) 0
+
+Vtable for __cxxabiv1::__forced_unwind
+__cxxabiv1::__forced_unwind::_ZTVN10__cxxabiv115__forced_unwindE: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTIN10__cxxabiv115__forced_unwindE)
+16    0
+24    0
+32    (int (*)(...))__cxa_pure_virtual
+
+Class __cxxabiv1::__forced_unwind
+   size=8 align=8
+   base size=8 base align=8
+__cxxabiv1::__forced_unwind (0x0x7f3bfe5575a0) 0 nearly-empty
+    vptr=((& __cxxabiv1::__forced_unwind::_ZTVN10__cxxabiv115__forced_unwindE) + 16)
+
+Class sched_param
+   size=4 align=4
+   base size=4 base align=4
+sched_param (0x0x7f3bfe60c6c0) 0
+
+Class timex
+   size=208 align=8
+   base size=208 base align=8
+timex (0x0x7f3bfe60c780) 0
+
+Class tm
+   size=56 align=8
+   base size=56 base align=8
+tm (0x0x7f3bfe60c7e0) 0
+
+Class itimerspec
+   size=32 align=8
+   base size=32 base align=8
+itimerspec (0x0x7f3bfe60c840) 0
+
+Class _pthread_cleanup_buffer
+   size=32 align=8
+   base size=32 base align=8
+_pthread_cleanup_buffer (0x0x7f3bfe60c8a0) 0
+
+Class __pthread_cleanup_frame
+   size=24 align=8
+   base size=24 base align=8
+__pthread_cleanup_frame (0x0x7f3bfe60c9c0) 0
+
+Class __pthread_cleanup_class
+   size=24 align=8
+   base size=24 base align=8
+__pthread_cleanup_class (0x0x7f3bfe60ca20) 0
+
+Class _IO_marker
+   size=24 align=8
+   base size=24 base align=8
+_IO_marker (0x0x7f3bfe34d9c0) 0
+
+Class _IO_FILE
+   size=216 align=8
+   base size=216 base align=8
+_IO_FILE (0x0x7f3bfe34da20) 0
+
+Class std::_Hash_impl
+   size=1 align=1
+   base size=0 base align=1
+std::_Hash_impl (0x0x7f3bfe106a80) 0 empty
+
+Class std::_Fnv_hash_impl
+   size=1 align=1
+   base size=0 base align=1
+std::_Fnv_hash_impl (0x0x7f3bfe106c00) 0 empty
+
+Class std::locale
+   size=8 align=8
+   base size=8 base align=8
+std::locale (0x0x7f3bfde7bd80) 0
+
+Vtable for std::locale::facet
+std::locale::facet::_ZTVNSt6locale5facetE: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTINSt6locale5facetE)
+16    (int (*)(...))std::locale::facet::~facet
+24    (int (*)(...))std::locale::facet::~facet
+
+Class std::locale::facet
+   size=16 align=8
+   base size=12 base align=8
+std::locale::facet (0x0x7f3bfdec7180) 0
+    vptr=((& std::locale::facet::_ZTVNSt6locale5facetE) + 16)
+
+Class std::locale::id
+   size=8 align=8
+   base size=8 base align=8
+std::locale::id (0x0x7f3bfdec7420) 0
+
+Class std::locale::_Impl
+   size=40 align=8
+   base size=40 base align=8
+std::locale::_Impl (0x0x7f3bfdec7600) 0
+
+Class std::__cow_string
+   size=8 align=8
+   base size=8 base align=8
+std::__cow_string (0x0x7f3bfdf14600) 0
+
+Vtable for std::logic_error
+std::logic_error::_ZTVSt11logic_error: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt11logic_error)
+16    (int (*)(...))std::logic_error::~logic_error
+24    (int (*)(...))std::logic_error::~logic_error
+32    (int (*)(...))std::logic_error::what
+
+Class std::logic_error
+   size=16 align=8
+   base size=16 base align=8
+std::logic_error (0x0x7f3bfdf250d0) 0
+    vptr=((& std::logic_error::_ZTVSt11logic_error) + 16)
+  std::exception (0x0x7f3bfdf146c0) 0 nearly-empty
+      primary-for std::logic_error (0x0x7f3bfdf250d0)
+
+Vtable for std::domain_error
+std::domain_error::_ZTVSt12domain_error: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt12domain_error)
+16    (int (*)(...))std::domain_error::~domain_error
+24    (int (*)(...))std::domain_error::~domain_error
+32    (int (*)(...))std::logic_error::what
+
+Class std::domain_error
+   size=16 align=8
+   base size=16 base align=8
+std::domain_error (0x0x7f3bfdf25138) 0
+    vptr=((& std::domain_error::_ZTVSt12domain_error) + 16)
+  std::logic_error (0x0x7f3bfdf251a0) 0
+      primary-for std::domain_error (0x0x7f3bfdf25138)
+    std::exception (0x0x7f3bfdf14720) 0 nearly-empty
+        primary-for std::logic_error (0x0x7f3bfdf251a0)
+
+Vtable for std::invalid_argument
+std::invalid_argument::_ZTVSt16invalid_argument: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt16invalid_argument)
+16    (int (*)(...))std::invalid_argument::~invalid_argument
+24    (int (*)(...))std::invalid_argument::~invalid_argument
+32    (int (*)(...))std::logic_error::what
+
+Class std::invalid_argument
+   size=16 align=8
+   base size=16 base align=8
+std::invalid_argument (0x0x7f3bfdf25208) 0
+    vptr=((& std::invalid_argument::_ZTVSt16invalid_argument) + 16)
+  std::logic_error (0x0x7f3bfdf25270) 0
+      primary-for std::invalid_argument (0x0x7f3bfdf25208)
+    std::exception (0x0x7f3bfdf14780) 0 nearly-empty
+        primary-for std::logic_error (0x0x7f3bfdf25270)
+
+Vtable for std::length_error
+std::length_error::_ZTVSt12length_error: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt12length_error)
+16    (int (*)(...))std::length_error::~length_error
+24    (int (*)(...))std::length_error::~length_error
+32    (int (*)(...))std::logic_error::what
+
+Class std::length_error
+   size=16 align=8
+   base size=16 base align=8
+std::length_error (0x0x7f3bfdf252d8) 0
+    vptr=((& std::length_error::_ZTVSt12length_error) + 16)
+  std::logic_error (0x0x7f3bfdf25340) 0
+      primary-for std::length_error (0x0x7f3bfdf252d8)
+    std::exception (0x0x7f3bfdf147e0) 0 nearly-empty
+        primary-for std::logic_error (0x0x7f3bfdf25340)
+
+Vtable for std::out_of_range
+std::out_of_range::_ZTVSt12out_of_range: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt12out_of_range)
+16    (int (*)(...))std::out_of_range::~out_of_range
+24    (int (*)(...))std::out_of_range::~out_of_range
+32    (int (*)(...))std::logic_error::what
+
+Class std::out_of_range
+   size=16 align=8
+   base size=16 base align=8
+std::out_of_range (0x0x7f3bfdf253a8) 0
+    vptr=((& std::out_of_range::_ZTVSt12out_of_range) + 16)
+  std::logic_error (0x0x7f3bfdf25410) 0
+      primary-for std::out_of_range (0x0x7f3bfdf253a8)
+    std::exception (0x0x7f3bfdf14840) 0 nearly-empty
+        primary-for std::logic_error (0x0x7f3bfdf25410)
+
+Vtable for std::runtime_error
+std::runtime_error::_ZTVSt13runtime_error: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt13runtime_error)
+16    (int (*)(...))std::runtime_error::~runtime_error
+24    (int (*)(...))std::runtime_error::~runtime_error
+32    (int (*)(...))std::runtime_error::what
+
+Class std::runtime_error
+   size=16 align=8
+   base size=16 base align=8
+std::runtime_error (0x0x7f3bfdf25478) 0
+    vptr=((& std::runtime_error::_ZTVSt13runtime_error) + 16)
+  std::exception (0x0x7f3bfdf148a0) 0 nearly-empty
+      primary-for std::runtime_error (0x0x7f3bfdf25478)
+
+Vtable for std::range_error
+std::range_error::_ZTVSt11range_error: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt11range_error)
+16    (int (*)(...))std::range_error::~range_error
+24    (int (*)(...))std::range_error::~range_error
+32    (int (*)(...))std::runtime_error::what
+
+Class std::range_error
+   size=16 align=8
+   base size=16 base align=8
+std::range_error (0x0x7f3bfdf254e0) 0
+    vptr=((& std::range_error::_ZTVSt11range_error) + 16)
+  std::runtime_error (0x0x7f3bfdf25548) 0
+      primary-for std::range_error (0x0x7f3bfdf254e0)
+    std::exception (0x0x7f3bfdf14900) 0 nearly-empty
+        primary-for std::runtime_error (0x0x7f3bfdf25548)
+
+Vtable for std::overflow_error
+std::overflow_error::_ZTVSt14overflow_error: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt14overflow_error)
+16    (int (*)(...))std::overflow_error::~overflow_error
+24    (int (*)(...))std::overflow_error::~overflow_error
+32    (int (*)(...))std::runtime_error::what
+
+Class std::overflow_error
+   size=16 align=8
+   base size=16 base align=8
+std::overflow_error (0x0x7f3bfdf255b0) 0
+    vptr=((& std::overflow_error::_ZTVSt14overflow_error) + 16)
+  std::runtime_error (0x0x7f3bfdf25618) 0
+      primary-for std::overflow_error (0x0x7f3bfdf255b0)
+    std::exception (0x0x7f3bfdf14960) 0 nearly-empty
+        primary-for std::runtime_error (0x0x7f3bfdf25618)
+
+Vtable for std::underflow_error
+std::underflow_error::_ZTVSt15underflow_error: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt15underflow_error)
+16    (int (*)(...))std::underflow_error::~underflow_error
+24    (int (*)(...))std::underflow_error::~underflow_error
+32    (int (*)(...))std::runtime_error::what
+
+Class std::underflow_error
+   size=16 align=8
+   base size=16 base align=8
+std::underflow_error (0x0x7f3bfdf25680) 0
+    vptr=((& std::underflow_error::_ZTVSt15underflow_error) + 16)
+  std::runtime_error (0x0x7f3bfdf256e8) 0
+      primary-for std::underflow_error (0x0x7f3bfdf25680)
+    std::exception (0x0x7f3bfdf149c0) 0 nearly-empty
+        primary-for std::runtime_error (0x0x7f3bfdf256e8)
+
+Vtable for std::_V2::error_category
+std::_V2::error_category::_ZTVNSt3_V214error_categoryE: 10 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTINSt3_V214error_categoryE)
+16    0
+24    0
+32    (int (*)(...))__cxa_pure_virtual
+40    (int (*)(...))std::_V2::error_category::_M_message
+48    (int (*)(...))__cxa_pure_virtual
+56    (int (*)(...))std::_V2::error_category::default_error_condition
+64    (int (*)(...))std::_V2::error_category::equivalent
+72    (int (*)(...))std::_V2::error_category::equivalent
+
+Class std::_V2::error_category
+   size=8 align=8
+   base size=8 base align=8
+std::_V2::error_category (0x0x7f3bfdf14b40) 0 nearly-empty
+    vptr=((& std::_V2::error_category::_ZTVNSt3_V214error_categoryE) + 16)
+
+Class std::error_code
+   size=16 align=8
+   base size=16 base align=8
+std::error_code (0x0x7f3bfdf14ea0) 0
+
+Class std::error_condition
+   size=16 align=8
+   base size=16 base align=8
+std::error_condition (0x0x7f3bfdf72720) 0
+
+Vtable for std::system_error
+std::system_error::_ZTVSt12system_error: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt12system_error)
+16    (int (*)(...))std::system_error::~system_error
+24    (int (*)(...))std::system_error::~system_error
+32    (int (*)(...))std::runtime_error::what
+
+Class std::system_error
+   size=32 align=8
+   base size=32 base align=8
+std::system_error (0x0x7f3bfdf25af8) 0
+    vptr=((& std::system_error::_ZTVSt12system_error) + 16)
+  std::runtime_error (0x0x7f3bfdf25b60) 0
+      primary-for std::system_error (0x0x7f3bfdf25af8)
+    std::exception (0x0x7f3bfdf99300) 0 nearly-empty
+        primary-for std::runtime_error (0x0x7f3bfdf25b60)
+
+Vtable for std::ios_base::failure
+std::ios_base::failure::_ZTVNSt8ios_base7failureB5cxx11E: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTINSt8ios_base7failureB5cxx11E)
+16    (int (*)(...))std::ios_base::failure::~failure
+24    (int (*)(...))std::ios_base::failure::~failure
+32    (int (*)(...))std::ios_base::failure::what
+
+Class std::ios_base::failure
+   size=32 align=8
+   base size=32 base align=8
+std::ios_base::failure (0x0x7f3bfdf25dd0) 0
+    vptr=((& std::ios_base::failure::_ZTVNSt8ios_base7failureB5cxx11E) + 16)
+  std::system_error (0x0x7f3bfdf25e38) 0
+      primary-for std::ios_base::failure (0x0x7f3bfdf25dd0)
+    std::runtime_error (0x0x7f3bfdf25ea0) 0
+        primary-for std::system_error (0x0x7f3bfdf25e38)
+      std::exception (0x0x7f3bfdfca8a0) 0 nearly-empty
+          primary-for std::runtime_error (0x0x7f3bfdf25ea0)
+
+Class std::ios_base::_Callback_list
+   size=24 align=8
+   base size=24 base align=8
+std::ios_base::_Callback_list (0x0x7f3bfdfca900) 0
+
+Class std::ios_base::_Words
+   size=16 align=8
+   base size=16 base align=8
+std::ios_base::_Words (0x0x7f3bfdfca960) 0
+
+Class std::ios_base::Init
+   size=1 align=1
+   base size=0 base align=1
+std::ios_base::Init (0x0x7f3bfdfca9c0) 0 empty
+
+Vtable for std::ios_base
+std::ios_base::_ZTVSt8ios_base: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt8ios_base)
+16    (int (*)(...))std::ios_base::~ios_base
+24    (int (*)(...))std::ios_base::~ios_base
+
+Class std::ios_base
+   size=216 align=8
+   base size=216 base align=8
+std::ios_base (0x0x7f3bfdfca840) 0
+    vptr=((& std::ios_base::_ZTVSt8ios_base) + 16)
+
+Class std::ctype_base
+   size=1 align=1
+   base size=0 base align=1
+std::ctype_base (0x0x7f3bfdcbe300) 0 empty
+
+Class std::__num_base
+   size=1 align=1
+   base size=0 base align=1
+std::__num_base (0x0x7f3bfdd8a4e0) 0 empty
+
+VTT for std::basic_ostream<char>
+std::basic_ostream<char>::_ZTTSo: 2 entries
+0     ((& std::basic_ostream<char>::_ZTVSo) + 24)
+8     ((& std::basic_ostream<char>::_ZTVSo) + 64)
+
+VTT for std::basic_ostream<wchar_t>
+std::basic_ostream<wchar_t>::_ZTTSt13basic_ostreamIwSt11char_traitsIwEE: 2 entries
+0     ((& std::basic_ostream<wchar_t>::_ZTVSt13basic_ostreamIwSt11char_traitsIwEE) + 24)
+8     ((& std::basic_ostream<wchar_t>::_ZTVSt13basic_ostreamIwSt11char_traitsIwEE) + 64)
+
+VTT for std::basic_istream<char>
+std::basic_istream<char>::_ZTTSi: 2 entries
+0     ((& std::basic_istream<char>::_ZTVSi) + 24)
+8     ((& std::basic_istream<char>::_ZTVSi) + 64)
+
+VTT for std::basic_istream<wchar_t>
+std::basic_istream<wchar_t>::_ZTTSt13basic_istreamIwSt11char_traitsIwEE: 2 entries
+0     ((& std::basic_istream<wchar_t>::_ZTVSt13basic_istreamIwSt11char_traitsIwEE) + 24)
+8     ((& std::basic_istream<wchar_t>::_ZTVSt13basic_istreamIwSt11char_traitsIwEE) + 64)
+
+Construction vtable for std::basic_istream<char> (0x0x7f3bfd9265b0 instance) in std::basic_iostream<char>
+std::basic_iostream<char>::_ZTCSd0_Si: 10 entries
+0     24
+8     (int (*)(...))0
+16    (int (*)(...))(& _ZTISi)
+24    0
+32    0
+40    18446744073709551592
+48    (int (*)(...))-24
+56    (int (*)(...))(& _ZTISi)
+64    0
+72    0
+
+Construction vtable for std::basic_ostream<char> (0x0x7f3bfd926680 instance) in std::basic_iostream<char>
+std::basic_iostream<char>::_ZTCSd16_So: 10 entries
+0     8
+8     (int (*)(...))0
+16    (int (*)(...))(& _ZTISo)
+24    0
+32    0
+40    18446744073709551608
+48    (int (*)(...))-8
+56    (int (*)(...))(& _ZTISo)
+64    0
+72    0
+
+VTT for std::basic_iostream<char>
+std::basic_iostream<char>::_ZTTSd: 7 entries
+0     ((& std::basic_iostream<char>::_ZTVSd) + 24)
+8     ((& std::basic_iostream<char>::_ZTCSd0_Si) + 24)
+16    ((& std::basic_iostream<char>::_ZTCSd0_Si) + 64)
+24    ((& std::basic_iostream<char>::_ZTCSd16_So) + 24)
+32    ((& std::basic_iostream<char>::_ZTCSd16_So) + 64)
+40    ((& std::basic_iostream<char>::_ZTVSd) + 104)
+48    ((& std::basic_iostream<char>::_ZTVSd) + 64)
+
+Construction vtable for std::basic_istream<wchar_t> (0x0x7f3bfd967340 instance) in std::basic_iostream<wchar_t>
+std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE0_St13basic_istreamIwS1_E: 10 entries
+0     24
+8     (int (*)(...))0
+16    (int (*)(...))(& _ZTISt13basic_istreamIwSt11char_traitsIwEE)
+24    0
+32    0
+40    18446744073709551592
+48    (int (*)(...))-24
+56    (int (*)(...))(& _ZTISt13basic_istreamIwSt11char_traitsIwEE)
+64    0
+72    0
+
+Construction vtable for std::basic_ostream<wchar_t> (0x0x7f3bfd967410 instance) in std::basic_iostream<wchar_t>
+std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE16_St13basic_ostreamIwS1_E: 10 entries
+0     8
+8     (int (*)(...))0
+16    (int (*)(...))(& _ZTISt13basic_ostreamIwSt11char_traitsIwEE)
+24    0
+32    0
+40    18446744073709551608
+48    (int (*)(...))-8
+56    (int (*)(...))(& _ZTISt13basic_ostreamIwSt11char_traitsIwEE)
+64    0
+72    0
+
+VTT for std::basic_iostream<wchar_t>
+std::basic_iostream<wchar_t>::_ZTTSt14basic_iostreamIwSt11char_traitsIwEE: 7 entries
+0     ((& std::basic_iostream<wchar_t>::_ZTVSt14basic_iostreamIwSt11char_traitsIwEE) + 24)
+8     ((& std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE0_St13basic_istreamIwS1_E) + 24)
+16    ((& std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE0_St13basic_istreamIwS1_E) + 64)
+24    ((& std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE16_St13basic_ostreamIwS1_E) + 24)
+32    ((& std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE16_St13basic_ostreamIwS1_E) + 64)
+40    ((& std::basic_iostream<wchar_t>::_ZTVSt14basic_iostreamIwSt11char_traitsIwEE) + 104)
+48    ((& std::basic_iostream<wchar_t>::_ZTVSt14basic_iostreamIwSt11char_traitsIwEE) + 64)
+
+Class QByteArrayDataPtr
+   size=8 align=8
+   base size=8 base align=8
+QByteArrayDataPtr (0x0x7f3bfd963e40) 0
+
+Class QByteArray
+   size=8 align=8
+   base size=8 base align=8
+QByteArray (0x0x7f3bfd963ea0) 0
+
+Class QByteRef
+   size=16 align=8
+   base size=12 base align=8
+QByteRef (0x0x7f3bfd6d02a0) 0
+
+Class QStringDataPtr
+   size=8 align=8
+   base size=8 base align=8
+QStringDataPtr (0x0x7f3bfd76c120) 0
+
+Class QStringView
+   size=16 align=8
+   base size=16 base align=8
+QStringView (0x0x7f3bfd76c5a0) 0
+
+Class QLatin1String
+   size=16 align=8
+   base size=16 base align=8
+QLatin1String (0x0x7f3bfd455660) 0
+
+Class QString::Null
+   size=1 align=1
+   base size=0 base align=1
+QString::Null (0x0x7f3bfd505600) 0 empty
+
+Class QString
+   size=8 align=8
+   base size=8 base align=8
+QString (0x0x7f3bfd5054e0) 0
+
+Class QCharRef
+   size=16 align=8
+   base size=12 base align=8
+QCharRef (0x0x7f3bfd3df480) 0
+
+Class QStringRef
+   size=16 align=8
+   base size=16 base align=8
+QStringRef (0x0x7f3bfd162060) 0
+
+Class QtPrivate::ArgBase
+   size=1 align=1
+   base size=1 base align=1
+QtPrivate::ArgBase (0x0x7f3bfcec0e40) 0
+
+Class QtPrivate::QStringViewArg
+   size=24 align=8
+   base size=24 base align=8
+QtPrivate::QStringViewArg (0x0x7f3bfd1f5270) 0
+  QtPrivate::ArgBase (0x0x7f3bfcec0ea0) 0
+
+Class QtPrivate::QLatin1StringArg
+   size=24 align=8
+   base size=24 base align=8
+QtPrivate::QLatin1StringArg (0x0x7f3bfd1f52d8) 0
+  QtPrivate::ArgBase (0x0x7f3bfcefd0c0) 0
+
+Class std::__erased_type
+   size=1 align=1
+   base size=0 base align=1
+std::__erased_type (0x0x7f3bfcfbc000) 0 empty
+
+Class std::allocator_arg_t
+   size=1 align=1
+   base size=0 base align=1
+std::allocator_arg_t (0x0x7f3bfcfbc060) 0 empty
+
+Class std::__uses_alloc_base
+   size=1 align=1
+   base size=0 base align=1
+std::__uses_alloc_base (0x0x7f3bfcfbc1e0) 0 empty
+
+Class std::__uses_alloc0::_Sink
+   size=1 align=1
+   base size=0 base align=1
+std::__uses_alloc0::_Sink (0x0x7f3bfcfbc2a0) 0 empty
+
+Class std::__uses_alloc0
+   size=1 align=1
+   base size=1 base align=1
+std::__uses_alloc0 (0x0x7f3bfd1f5680) 0
+  std::__uses_alloc_base (0x0x7f3bfcfbc240) 0 empty
+
+Class std::_Swallow_assign
+   size=1 align=1
+   base size=0 base align=1
+std::_Swallow_assign (0x0x7f3bfcd27600) 0 empty
+
+Vtable for std::bad_function_call
+std::bad_function_call::_ZTVSt17bad_function_call: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt17bad_function_call)
+16    (int (*)(...))std::bad_function_call::~bad_function_call
+24    (int (*)(...))std::bad_function_call::~bad_function_call
+32    (int (*)(...))std::bad_function_call::what
+
+Class std::bad_function_call
+   size=8 align=8
+   base size=8 base align=8
+std::bad_function_call (0x0x7f3bfcd6f8f0) 0 nearly-empty
+    vptr=((& std::bad_function_call::_ZTVSt17bad_function_call) + 16)
+  std::exception (0x0x7f3bfcd6cf00) 0 nearly-empty
+      primary-for std::bad_function_call (0x0x7f3bfcd6f8f0)
+
+Class std::_Nocopy_types
+   size=16 align=8
+   base size=16 base align=8
+std::_Nocopy_types (0x0x7f3bfcda0000) 0
+
+Class std::_Any_data
+   size=16 align=8
+   base size=16 base align=8
+std::_Any_data (0x0x7f3bfcda0060) 0
+
+Class std::_Function_base
+   size=24 align=8
+   base size=24 base align=8
+std::_Function_base (0x0x7f3bfcda0360) 0
+
+Class QtPrivate::QHashCombine
+   size=1 align=1
+   base size=0 base align=1
+QtPrivate::QHashCombine (0x0x7f3bfcb927e0) 0 empty
+
+Class QtPrivate::QHashCombineCommutative
+   size=1 align=1
+   base size=0 base align=1
+QtPrivate::QHashCombineCommutative (0x0x7f3bfcb928a0) 0 empty
+
+Class std::_Bit_reference
+   size=16 align=8
+   base size=16 base align=8
+std::_Bit_reference (0x0x7f3bfc8c5000) 0
+
+Class std::_Bit_iterator_base
+   size=16 align=8
+   base size=12 base align=8
+std::_Bit_iterator_base (0x0x7f3bfcbf2478) 0
+  std::iterator<std::random_access_iterator_tag, bool> (0x0x7f3bfc8c5720) 0 empty
+
+Class std::_Bit_iterator
+   size=16 align=8
+   base size=12 base align=8
+std::_Bit_iterator (0x0x7f3bfcbf25b0) 0
+  std::_Bit_iterator_base (0x0x7f3bfcbf2618) 0
+    std::iterator<std::random_access_iterator_tag, bool> (0x0x7f3bfc8c5d80) 0 empty
+
+Class std::_Bit_const_iterator
+   size=16 align=8
+   base size=12 base align=8
+std::_Bit_const_iterator (0x0x7f3bfcbf2680) 0
+  std::_Bit_iterator_base (0x0x7f3bfcbf26e8) 0
+    std::iterator<std::random_access_iterator_tag, bool> (0x0x7f3bfc8fd5a0) 0 empty
+
+Class std::__detail::_List_node_base
+   size=16 align=8
+   base size=16 base align=8
+std::__detail::_List_node_base (0x0x7f3bfc748120) 0
+
+Class QListData::NotArrayCompatibleLayout
+   size=1 align=1
+   base size=0 base align=1
+QListData::NotArrayCompatibleLayout (0x0x7f3bfc7f5ea0) 0 empty
+
+Class QListData::NotIndirectLayout
+   size=1 align=1
+   base size=0 base align=1
+QListData::NotIndirectLayout (0x0x7f3bfc7f5f00) 0 empty
+
+Class QListData::ArrayCompatibleLayout
+   size=1 align=1
+   base size=1 base align=1
+QListData::ArrayCompatibleLayout (0x0x7f3bfc744208) 0 empty
+  QListData::NotIndirectLayout (0x0x7f3bfc7f5f60) 0 empty
+
+Class QListData::InlineWithPaddingLayout
+   size=1 align=1
+   base size=1 base align=1
+QListData::InlineWithPaddingLayout (0x0x7f3bfc738af0) 0 empty
+  QListData::NotArrayCompatibleLayout (0x0x7f3bfc80d000) 0 empty
+  QListData::NotIndirectLayout (0x0x7f3bfc80d060) 0 empty
+
+Class QListData::IndirectLayout
+   size=1 align=1
+   base size=1 base align=1
+QListData::IndirectLayout (0x0x7f3bfc744270) 0 empty
+  QListData::NotArrayCompatibleLayout (0x0x7f3bfc80d0c0) 0 empty
+
+Class QListData::Data
+   size=24 align=8
+   base size=24 base align=8
+QListData::Data (0x0x7f3bfc80d120) 0
+
+Class QListData
+   size=8 align=8
+   base size=8 base align=8
+QListData (0x0x7f3bfc7f5e40) 0
+
+Class QRegExp
+   size=8 align=8
+   base size=8 base align=8
+QRegExp (0x0x7f3bfc5072a0) 0
+
+Class QStringMatcher::Data
+   size=272 align=8
+   base size=272 base align=8
+QStringMatcher::Data (0x0x7f3bfc5e57e0) 0
+
+Class QStringMatcher
+   size=1048 align=8
+   base size=1048 base align=8
+QStringMatcher (0x0x7f3bfc5e5780) 0
+
+Class QStringList
+   size=8 align=8
+   base size=8 base align=8
+QStringList (0x0x7f3bfc5d5f08) 0
+  QList<QString> (0x0x7f3bfc5d5f70) 0
+    QListSpecialMethods<QString> (0x0x7f3bfc5e5a20) 0 empty
+
+Class QScopedPointerPodDeleter
+   size=1 align=1
+   base size=0 base align=1
+QScopedPointerPodDeleter (0x0x7f3bfc2b4960) 0 empty
+
+Class std::_Rb_tree_node_base
+   size=32 align=8
+   base size=32 base align=8
+std::_Rb_tree_node_base (0x0x7f3bfc34aba0) 0
+
+Class std::_Rb_tree_header
+   size=40 align=8
+   base size=40 base align=8
+std::_Rb_tree_header (0x0x7f3bfc34af00) 0
+
+Class QtPrivate::AbstractDebugStreamFunction
+   size=16 align=8
+   base size=16 base align=8
+QtPrivate::AbstractDebugStreamFunction (0x0x7f3bfc0a6540) 0
+
+Class QtPrivate::AbstractComparatorFunction
+   size=24 align=8
+   base size=24 base align=8
+QtPrivate::AbstractComparatorFunction (0x0x7f3bfc0a68a0) 0
+
+Class QtPrivate::AbstractConverterFunction
+   size=8 align=8
+   base size=8 base align=8
+QtPrivate::AbstractConverterFunction (0x0x7f3bfc0a6de0) 0
+
+Class QMetaType
+   size=80 align=8
+   base size=80 base align=8
+QMetaType (0x0x7f3bfc0cb360) 0
+
+Class QtMetaTypePrivate::VariantData
+   size=24 align=8
+   base size=20 base align=8
+QtMetaTypePrivate::VariantData (0x0x7f3bfc136540) 0
+
+Class QtMetaTypePrivate::VectorBoolElements
+   size=1 align=1
+   base size=0 base align=1
+QtMetaTypePrivate::VectorBoolElements (0x0x7f3bfc136c00) 0 empty
+
+Class QtMetaTypePrivate::QSequentialIterableImpl
+   size=104 align=8
+   base size=104 base align=8
+QtMetaTypePrivate::QSequentialIterableImpl (0x0x7f3bfbd8da80) 0
+
+Class QtMetaTypePrivate::QAssociativeIterableImpl
+   size=112 align=8
+   base size=112 base align=8
+QtMetaTypePrivate::QAssociativeIterableImpl (0x0x7f3bfbe46180) 0
+
+Class QtMetaTypePrivate::QPairVariantInterfaceImpl
+   size=40 align=8
+   base size=40 base align=8
+QtMetaTypePrivate::QPairVariantInterfaceImpl (0x0x7f3bfbe9d6c0) 0
+
+Class std::chrono::_V2::system_clock
+   size=1 align=1
+   base size=0 base align=1
+std::chrono::_V2::system_clock (0x0x7f3bfbd30c60) 0 empty
+
+Class std::chrono::_V2::steady_clock
+   size=1 align=1
+   base size=0 base align=1
+std::chrono::_V2::steady_clock (0x0x7f3bfba65720) 0 empty
+
+Vtable for QObjectData
+QObjectData::_ZTV11QObjectData: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI11QObjectData)
+16    (int (*)(...))__cxa_pure_virtual
+24    (int (*)(...))__cxa_pure_virtual
+
+Class QObjectData
+   size=48 align=8
+   base size=48 base align=8
+QObjectData (0x0x7f3bfba65780) 0
+    vptr=((& QObjectData::_ZTV11QObjectData) + 16)
+
+Class QObject::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QObject::QPrivateSignal (0x0x7f3bfba65960) 0 empty
+
+Vtable for QObject
+QObject::_ZTV7QObject: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI7QObject)
+16    (int (*)(...))QObject::metaObject
+24    (int (*)(...))QObject::qt_metacast
+32    (int (*)(...))QObject::qt_metacall
+40    (int (*)(...))QObject::~QObject
+48    (int (*)(...))QObject::~QObject
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QObject
+   size=16 align=8
+   base size=16 base align=8
+QObject (0x0x7f3bfba65900) 0
+    vptr=((& QObject::_ZTV7QObject) + 16)
+
+Vtable for QObjectUserData
+QObjectUserData::_ZTV15QObjectUserData: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI15QObjectUserData)
+16    (int (*)(...))QObjectUserData::~QObjectUserData
+24    (int (*)(...))QObjectUserData::~QObjectUserData
+
+Class QObjectUserData
+   size=8 align=8
+   base size=8 base align=8
+QObjectUserData (0x0x7f3bfb749780) 0 nearly-empty
+    vptr=((& QObjectUserData::_ZTV15QObjectUserData) + 16)
+
+Class QSignalBlocker
+   size=16 align=8
+   base size=10 base align=8
+QSignalBlocker (0x0x7f3bfb749900) 0
+
+Class QAbstractAnimation::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QAbstractAnimation::QPrivateSignal (0x0x7f3bfb76c1e0) 0 empty
+
+Vtable for QAbstractAnimation
+QAbstractAnimation::_ZTV18QAbstractAnimation: 18 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI18QAbstractAnimation)
+16    (int (*)(...))QAbstractAnimation::metaObject
+24    (int (*)(...))QAbstractAnimation::qt_metacast
+32    (int (*)(...))QAbstractAnimation::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QAbstractAnimation::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))__cxa_pure_virtual
+120   (int (*)(...))__cxa_pure_virtual
+128   (int (*)(...))QAbstractAnimation::updateState
+136   (int (*)(...))QAbstractAnimation::updateDirection
+
+Class QAbstractAnimation
+   size=16 align=8
+   base size=16 base align=8
+QAbstractAnimation (0x0x7f3bfb74d0d0) 0
+    vptr=((& QAbstractAnimation::_ZTV18QAbstractAnimation) + 16)
+  QObject (0x0x7f3bfb76c180) 0
+      primary-for QAbstractAnimation (0x0x7f3bfb74d0d0)
+
+Class QAnimationDriver::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QAnimationDriver::QPrivateSignal (0x0x7f3bfb76c5a0) 0 empty
+
+Vtable for QAnimationDriver
+QAnimationDriver::_ZTV16QAnimationDriver: 18 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI16QAnimationDriver)
+16    (int (*)(...))QAnimationDriver::metaObject
+24    (int (*)(...))QAnimationDriver::qt_metacast
+32    (int (*)(...))QAnimationDriver::qt_metacall
+40    (int (*)(...))QAnimationDriver::~QAnimationDriver
+48    (int (*)(...))QAnimationDriver::~QAnimationDriver
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QAnimationDriver::advance
+120   (int (*)(...))QAnimationDriver::elapsed
+128   (int (*)(...))QAnimationDriver::start
+136   (int (*)(...))QAnimationDriver::stop
+
+Class QAnimationDriver
+   size=16 align=8
+   base size=16 base align=8
+QAnimationDriver (0x0x7f3bfb74d138) 0
+    vptr=((& QAnimationDriver::_ZTV16QAnimationDriver) + 16)
+  QObject (0x0x7f3bfb76c540) 0
+      primary-for QAnimationDriver (0x0x7f3bfb74d138)
+
+Class QEventLoop::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QEventLoop::QPrivateSignal (0x0x7f3bfb76c7e0) 0 empty
+
+Vtable for QEventLoop
+QEventLoop::_ZTV10QEventLoop: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI10QEventLoop)
+16    (int (*)(...))QEventLoop::metaObject
+24    (int (*)(...))QEventLoop::qt_metacast
+32    (int (*)(...))QEventLoop::qt_metacall
+40    (int (*)(...))QEventLoop::~QEventLoop
+48    (int (*)(...))QEventLoop::~QEventLoop
+56    (int (*)(...))QEventLoop::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QEventLoop
+   size=16 align=8
+   base size=16 base align=8
+QEventLoop (0x0x7f3bfb74d1a0) 0
+    vptr=((& QEventLoop::_ZTV10QEventLoop) + 16)
+  QObject (0x0x7f3bfb76c780) 0
+      primary-for QEventLoop (0x0x7f3bfb74d1a0)
+
+Class QEventLoopLocker
+   size=8 align=8
+   base size=8 base align=8
+QEventLoopLocker (0x0x7f3bfb7ca0c0) 0
+
+Class QAbstractEventDispatcher::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QAbstractEventDispatcher::QPrivateSignal (0x0x7f3bfb7ca180) 0 empty
+
+Class QAbstractEventDispatcher::TimerInfo
+   size=12 align=4
+   base size=12 base align=4
+QAbstractEventDispatcher::TimerInfo (0x0x7f3bfb7ca1e0) 0
+
+Vtable for QAbstractEventDispatcher
+QAbstractEventDispatcher::_ZTV24QAbstractEventDispatcher: 28 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI24QAbstractEventDispatcher)
+16    (int (*)(...))QAbstractEventDispatcher::metaObject
+24    (int (*)(...))QAbstractEventDispatcher::qt_metacast
+32    (int (*)(...))QAbstractEventDispatcher::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))__cxa_pure_virtual
+120   (int (*)(...))__cxa_pure_virtual
+128   (int (*)(...))__cxa_pure_virtual
+136   (int (*)(...))__cxa_pure_virtual
+144   (int (*)(...))__cxa_pure_virtual
+152   (int (*)(...))__cxa_pure_virtual
+160   (int (*)(...))__cxa_pure_virtual
+168   (int (*)(...))__cxa_pure_virtual
+176   (int (*)(...))__cxa_pure_virtual
+184   (int (*)(...))__cxa_pure_virtual
+192   (int (*)(...))__cxa_pure_virtual
+200   (int (*)(...))__cxa_pure_virtual
+208   (int (*)(...))QAbstractEventDispatcher::startingUp
+216   (int (*)(...))QAbstractEventDispatcher::closingDown
+
+Class QAbstractEventDispatcher
+   size=16 align=8
+   base size=16 base align=8
+QAbstractEventDispatcher (0x0x7f3bfb74d2d8) 0
+    vptr=((& QAbstractEventDispatcher::_ZTV24QAbstractEventDispatcher) + 16)
+  QObject (0x0x7f3bfb7ca120) 0
+      primary-for QAbstractEventDispatcher (0x0x7f3bfb74d2d8)
+
+Class QMapNodeBase
+   size=24 align=8
+   base size=24 base align=8
+QMapNodeBase (0x0x7f3bfb8201e0) 0
+
+Class QMapDataBase
+   size=40 align=8
+   base size=40 base align=8
+QMapDataBase (0x0x7f3bfb820e40) 0
+
+Class QHashData::Node
+   size=16 align=8
+   base size=16 base align=8
+QHashData::Node (0x0x7f3bfb9117e0) 0
+
+Class QHashData
+   size=48 align=8
+   base size=44 base align=8
+QHashData (0x0x7f3bfb911780) 0
+
+Class QHashDummyValue
+   size=1 align=1
+   base size=0 base align=1
+QHashDummyValue (0x0x7f3bfb911a80) 0 empty
+
+Class QVariant::PrivateShared
+   size=16 align=8
+   base size=12 base align=8
+QVariant::PrivateShared (0x0x7f3bfb6451e0) 0
+
+Class QVariant::Private::Data
+   size=8 align=8
+   base size=8 base align=8
+QVariant::Private::Data (0x0x7f3bfb6452a0) 0
+
+Class QVariant::Private
+   size=16 align=8
+   base size=12 base align=8
+QVariant::Private (0x0x7f3bfb645240) 0
+
+Class QVariant::Handler
+   size=72 align=8
+   base size=72 base align=8
+QVariant::Handler (0x0x7f3bfb645300) 0
+
+Class QVariant
+   size=16 align=8
+   base size=16 base align=8
+QVariant (0x0x7f3bfb645180) 0
+
+Class QVariantComparisonHelper
+   size=8 align=8
+   base size=8 base align=8
+QVariantComparisonHelper (0x0x7f3bfb3a55a0) 0
+
+Class QSequentialIterable::const_iterator
+   size=112 align=8
+   base size=112 base align=8
+QSequentialIterable::const_iterator (0x0x7f3bfb3e7c00) 0
+
+Class QSequentialIterable
+   size=104 align=8
+   base size=104 base align=8
+QSequentialIterable (0x0x7f3bfb3e7ba0) 0
+
+Class QAssociativeIterable::const_iterator
+   size=120 align=8
+   base size=120 base align=8
+QAssociativeIterable::const_iterator (0x0x7f3bfb3e7d20) 0
+
+Class QAssociativeIterable
+   size=112 align=8
+   base size=112 base align=8
+QAssociativeIterable (0x0x7f3bfb3e7cc0) 0
+
+Class QModelIndex
+   size=24 align=8
+   base size=24 base align=8
+QModelIndex (0x0x7f3bfb4b3ea0) 0
+
+Class QPersistentModelIndex
+   size=8 align=8
+   base size=8 base align=8
+QPersistentModelIndex (0x0x7f3bfb526ae0) 0
+
+Class QAbstractItemModel::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QAbstractItemModel::QPrivateSignal (0x0x7f3bfb1f5900) 0 empty
+
+Vtable for QAbstractItemModel
+QAbstractItemModel::_ZTV18QAbstractItemModel: 48 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI18QAbstractItemModel)
+16    (int (*)(...))QAbstractItemModel::metaObject
+24    (int (*)(...))QAbstractItemModel::qt_metacast
+32    (int (*)(...))QAbstractItemModel::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))__cxa_pure_virtual
+120   (int (*)(...))__cxa_pure_virtual
+128   (int (*)(...))QAbstractItemModel::sibling
+136   (int (*)(...))__cxa_pure_virtual
+144   (int (*)(...))__cxa_pure_virtual
+152   (int (*)(...))QAbstractItemModel::hasChildren
+160   (int (*)(...))__cxa_pure_virtual
+168   (int (*)(...))QAbstractItemModel::setData
+176   (int (*)(...))QAbstractItemModel::headerData
+184   (int (*)(...))QAbstractItemModel::setHeaderData
+192   (int (*)(...))QAbstractItemModel::itemData
+200   (int (*)(...))QAbstractItemModel::setItemData
+208   (int (*)(...))QAbstractItemModel::mimeTypes
+216   (int (*)(...))QAbstractItemModel::mimeData
+224   (int (*)(...))QAbstractItemModel::canDropMimeData
+232   (int (*)(...))QAbstractItemModel::dropMimeData
+240   (int (*)(...))QAbstractItemModel::supportedDropActions
+248   (int (*)(...))QAbstractItemModel::supportedDragActions
+256   (int (*)(...))QAbstractItemModel::insertRows
+264   (int (*)(...))QAbstractItemModel::insertColumns
+272   (int (*)(...))QAbstractItemModel::removeRows
+280   (int (*)(...))QAbstractItemModel::removeColumns
+288   (int (*)(...))QAbstractItemModel::moveRows
+296   (int (*)(...))QAbstractItemModel::moveColumns
+304   (int (*)(...))QAbstractItemModel::fetchMore
+312   (int (*)(...))QAbstractItemModel::canFetchMore
+320   (int (*)(...))QAbstractItemModel::flags
+328   (int (*)(...))QAbstractItemModel::sort
+336   (int (*)(...))QAbstractItemModel::buddy
+344   (int (*)(...))QAbstractItemModel::match
+352   (int (*)(...))QAbstractItemModel::span
+360   (int (*)(...))QAbstractItemModel::roleNames
+368   (int (*)(...))QAbstractItemModel::submit
+376   (int (*)(...))QAbstractItemModel::revert
+
+Class QAbstractItemModel
+   size=16 align=8
+   base size=16 base align=8
+QAbstractItemModel (0x0x7f3bfb203478) 0
+    vptr=((& QAbstractItemModel::_ZTV18QAbstractItemModel) + 16)
+  QObject (0x0x7f3bfb1f58a0) 0
+      primary-for QAbstractItemModel (0x0x7f3bfb203478)
+
+Class QAbstractTableModel::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QAbstractTableModel::QPrivateSignal (0x0x7f3bfb26ecc0) 0 empty
+
+Vtable for QAbstractTableModel
+QAbstractTableModel::_ZTV19QAbstractTableModel: 48 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI19QAbstractTableModel)
+16    (int (*)(...))QAbstractTableModel::metaObject
+24    (int (*)(...))QAbstractTableModel::qt_metacast
+32    (int (*)(...))QAbstractTableModel::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QAbstractTableModel::index
+120   (int (*)(...))QAbstractTableModel::parent
+128   (int (*)(...))QAbstractTableModel::sibling
+136   (int (*)(...))__cxa_pure_virtual
+144   (int (*)(...))__cxa_pure_virtual
+152   (int (*)(...))QAbstractTableModel::hasChildren
+160   (int (*)(...))__cxa_pure_virtual
+168   (int (*)(...))QAbstractItemModel::setData
+176   (int (*)(...))QAbstractItemModel::headerData
+184   (int (*)(...))QAbstractItemModel::setHeaderData
+192   (int (*)(...))QAbstractItemModel::itemData
+200   (int (*)(...))QAbstractItemModel::setItemData
+208   (int (*)(...))QAbstractItemModel::mimeTypes
+216   (int (*)(...))QAbstractItemModel::mimeData
+224   (int (*)(...))QAbstractItemModel::canDropMimeData
+232   (int (*)(...))QAbstractTableModel::dropMimeData
+240   (int (*)(...))QAbstractItemModel::supportedDropActions
+248   (int (*)(...))QAbstractItemModel::supportedDragActions
+256   (int (*)(...))QAbstractItemModel::insertRows
+264   (int (*)(...))QAbstractItemModel::insertColumns
+272   (int (*)(...))QAbstractItemModel::removeRows
+280   (int (*)(...))QAbstractItemModel::removeColumns
+288   (int (*)(...))QAbstractItemModel::moveRows
+296   (int (*)(...))QAbstractItemModel::moveColumns
+304   (int (*)(...))QAbstractItemModel::fetchMore
+312   (int (*)(...))QAbstractItemModel::canFetchMore
+320   (int (*)(...))QAbstractTableModel::flags
+328   (int (*)(...))QAbstractItemModel::sort
+336   (int (*)(...))QAbstractItemModel::buddy
+344   (int (*)(...))QAbstractItemModel::match
+352   (int (*)(...))QAbstractItemModel::span
+360   (int (*)(...))QAbstractItemModel::roleNames
+368   (int (*)(...))QAbstractItemModel::submit
+376   (int (*)(...))QAbstractItemModel::revert
+
+Class QAbstractTableModel
+   size=16 align=8
+   base size=16 base align=8
+QAbstractTableModel (0x0x7f3bfb203a90) 0
+    vptr=((& QAbstractTableModel::_ZTV19QAbstractTableModel) + 16)
+  QAbstractItemModel (0x0x7f3bfb203af8) 0
+      primary-for QAbstractTableModel (0x0x7f3bfb203a90)
+    QObject (0x0x7f3bfb26ec60) 0
+        primary-for QAbstractItemModel (0x0x7f3bfb203af8)
+
+Class QAbstractListModel::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QAbstractListModel::QPrivateSignal (0x0x7f3bfb26ee40) 0 empty
+
+Vtable for QAbstractListModel
+QAbstractListModel::_ZTV18QAbstractListModel: 48 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI18QAbstractListModel)
+16    (int (*)(...))QAbstractListModel::metaObject
+24    (int (*)(...))QAbstractListModel::qt_metacast
+32    (int (*)(...))QAbstractListModel::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QAbstractListModel::index
+120   (int (*)(...))QAbstractListModel::parent
+128   (int (*)(...))QAbstractListModel::sibling
+136   (int (*)(...))__cxa_pure_virtual
+144   (int (*)(...))QAbstractListModel::columnCount
+152   (int (*)(...))QAbstractListModel::hasChildren
+160   (int (*)(...))__cxa_pure_virtual
+168   (int (*)(...))QAbstractItemModel::setData
+176   (int (*)(...))QAbstractItemModel::headerData
+184   (int (*)(...))QAbstractItemModel::setHeaderData
+192   (int (*)(...))QAbstractItemModel::itemData
+200   (int (*)(...))QAbstractItemModel::setItemData
+208   (int (*)(...))QAbstractItemModel::mimeTypes
+216   (int (*)(...))QAbstractItemModel::mimeData
+224   (int (*)(...))QAbstractItemModel::canDropMimeData
+232   (int (*)(...))QAbstractListModel::dropMimeData
+240   (int (*)(...))QAbstractItemModel::supportedDropActions
+248   (int (*)(...))QAbstractItemModel::supportedDragActions
+256   (int (*)(...))QAbstractItemModel::insertRows
+264   (int (*)(...))QAbstractItemModel::insertColumns
+272   (int (*)(...))QAbstractItemModel::removeRows
+280   (int (*)(...))QAbstractItemModel::removeColumns
+288   (int (*)(...))QAbstractItemModel::moveRows
+296   (int (*)(...))QAbstractItemModel::moveColumns
+304   (int (*)(...))QAbstractItemModel::fetchMore
+312   (int (*)(...))QAbstractItemModel::canFetchMore
+320   (int (*)(...))QAbstractListModel::flags
+328   (int (*)(...))QAbstractItemModel::sort
+336   (int (*)(...))QAbstractItemModel::buddy
+344   (int (*)(...))QAbstractItemModel::match
+352   (int (*)(...))QAbstractItemModel::span
+360   (int (*)(...))QAbstractItemModel::roleNames
+368   (int (*)(...))QAbstractItemModel::submit
+376   (int (*)(...))QAbstractItemModel::revert
+
+Class QAbstractListModel
+   size=16 align=8
+   base size=16 base align=8
+QAbstractListModel (0x0x7f3bfb203b60) 0
+    vptr=((& QAbstractListModel::_ZTV18QAbstractListModel) + 16)
+  QAbstractItemModel (0x0x7f3bfb203bc8) 0
+      primary-for QAbstractListModel (0x0x7f3bfb203b60)
+    QObject (0x0x7f3bfb26ede0) 0
+        primary-for QAbstractItemModel (0x0x7f3bfb203bc8)
+
+Vtable for QAbstractNativeEventFilter
+QAbstractNativeEventFilter::_ZTV26QAbstractNativeEventFilter: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI26QAbstractNativeEventFilter)
+16    0
+24    0
+32    (int (*)(...))__cxa_pure_virtual
+
+Class QAbstractNativeEventFilter
+   size=16 align=8
+   base size=16 base align=8
+QAbstractNativeEventFilter (0x0x7f3bfb2f65a0) 0
+    vptr=((& QAbstractNativeEventFilter::_ZTV26QAbstractNativeEventFilter) + 16)
+
+Class QAbstractProxyModel::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QAbstractProxyModel::QPrivateSignal (0x0x7f3bfb2f6660) 0 empty
+
+Vtable for QAbstractProxyModel
+QAbstractProxyModel::_ZTV19QAbstractProxyModel: 53 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI19QAbstractProxyModel)
+16    (int (*)(...))QAbstractProxyModel::metaObject
+24    (int (*)(...))QAbstractProxyModel::qt_metacast
+32    (int (*)(...))QAbstractProxyModel::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))__cxa_pure_virtual
+120   (int (*)(...))__cxa_pure_virtual
+128   (int (*)(...))QAbstractProxyModel::sibling
+136   (int (*)(...))__cxa_pure_virtual
+144   (int (*)(...))__cxa_pure_virtual
+152   (int (*)(...))QAbstractProxyModel::hasChildren
+160   (int (*)(...))QAbstractProxyModel::data
+168   (int (*)(...))QAbstractProxyModel::setData
+176   (int (*)(...))QAbstractProxyModel::headerData
+184   (int (*)(...))QAbstractProxyModel::setHeaderData
+192   (int (*)(...))QAbstractProxyModel::itemData
+200   (int (*)(...))QAbstractProxyModel::setItemData
+208   (int (*)(...))QAbstractProxyModel::mimeTypes
+216   (int (*)(...))QAbstractProxyModel::mimeData
+224   (int (*)(...))QAbstractProxyModel::canDropMimeData
+232   (int (*)(...))QAbstractProxyModel::dropMimeData
+240   (int (*)(...))QAbstractProxyModel::supportedDropActions
+248   (int (*)(...))QAbstractProxyModel::supportedDragActions
+256   (int (*)(...))QAbstractItemModel::insertRows
+264   (int (*)(...))QAbstractItemModel::insertColumns
+272   (int (*)(...))QAbstractItemModel::removeRows
+280   (int (*)(...))QAbstractItemModel::removeColumns
+288   (int (*)(...))QAbstractItemModel::moveRows
+296   (int (*)(...))QAbstractItemModel::moveColumns
+304   (int (*)(...))QAbstractProxyModel::fetchMore
+312   (int (*)(...))QAbstractProxyModel::canFetchMore
+320   (int (*)(...))QAbstractProxyModel::flags
+328   (int (*)(...))QAbstractProxyModel::sort
+336   (int (*)(...))QAbstractProxyModel::buddy
+344   (int (*)(...))QAbstractItemModel::match
+352   (int (*)(...))QAbstractProxyModel::span
+360   (int (*)(...))QAbstractItemModel::roleNames
+368   (int (*)(...))QAbstractProxyModel::submit
+376   (int (*)(...))QAbstractProxyModel::revert
+384   (int (*)(...))QAbstractProxyModel::setSourceModel
+392   (int (*)(...))__cxa_pure_virtual
+400   (int (*)(...))__cxa_pure_virtual
+408   (int (*)(...))QAbstractProxyModel::mapSelectionToSource
+416   (int (*)(...))QAbstractProxyModel::mapSelectionFromSource
+
+Class QAbstractProxyModel
+   size=16 align=8
+   base size=16 base align=8
+QAbstractProxyModel (0x0x7f3bfb203c98) 0
+    vptr=((& QAbstractProxyModel::_ZTV19QAbstractProxyModel) + 16)
+  QAbstractItemModel (0x0x7f3bfb203d00) 0
+      primary-for QAbstractProxyModel (0x0x7f3bfb203c98)
+    QObject (0x0x7f3bfb2f6600) 0
+        primary-for QAbstractItemModel (0x0x7f3bfb203d00)
+
+Class QAbstractState::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QAbstractState::QPrivateSignal (0x0x7f3bfb2f68a0) 0 empty
+
+Vtable for QAbstractState
+QAbstractState::_ZTV14QAbstractState: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI14QAbstractState)
+16    (int (*)(...))QAbstractState::metaObject
+24    (int (*)(...))QAbstractState::qt_metacast
+32    (int (*)(...))QAbstractState::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QAbstractState::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))__cxa_pure_virtual
+120   (int (*)(...))__cxa_pure_virtual
+
+Class QAbstractState
+   size=16 align=8
+   base size=16 base align=8
+QAbstractState (0x0x7f3bfb203d68) 0
+    vptr=((& QAbstractState::_ZTV14QAbstractState) + 16)
+  QObject (0x0x7f3bfb2f6840) 0
+      primary-for QAbstractState (0x0x7f3bfb203d68)
+
+Class QAbstractTransition::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QAbstractTransition::QPrivateSignal (0x0x7f3bfb2f6ae0) 0 empty
+
+Vtable for QAbstractTransition
+QAbstractTransition::_ZTV19QAbstractTransition: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI19QAbstractTransition)
+16    (int (*)(...))QAbstractTransition::metaObject
+24    (int (*)(...))QAbstractTransition::qt_metacast
+32    (int (*)(...))QAbstractTransition::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QAbstractTransition::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))__cxa_pure_virtual
+120   (int (*)(...))__cxa_pure_virtual
+
+Class QAbstractTransition
+   size=16 align=8
+   base size=16 base align=8
+QAbstractTransition (0x0x7f3bfb203dd0) 0
+    vptr=((& QAbstractTransition::_ZTV19QAbstractTransition) + 16)
+  QObject (0x0x7f3bfb2f6a80) 0
+      primary-for QAbstractTransition (0x0x7f3bfb203dd0)
+
+Class QAnimationGroup::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QAnimationGroup::QPrivateSignal (0x0x7f3bfb2f6de0) 0 empty
+
+Vtable for QAnimationGroup
+QAnimationGroup::_ZTV15QAnimationGroup: 18 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI15QAnimationGroup)
+16    (int (*)(...))QAnimationGroup::metaObject
+24    (int (*)(...))QAnimationGroup::qt_metacast
+32    (int (*)(...))QAnimationGroup::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QAnimationGroup::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))__cxa_pure_virtual
+120   (int (*)(...))__cxa_pure_virtual
+128   (int (*)(...))QAbstractAnimation::updateState
+136   (int (*)(...))QAbstractAnimation::updateDirection
+
+Class QAnimationGroup
+   size=16 align=8
+   base size=16 base align=8
+QAnimationGroup (0x0x7f3bfb203e38) 0
+    vptr=((& QAnimationGroup::_ZTV15QAnimationGroup) + 16)
+  QAbstractAnimation (0x0x7f3bfb203ea0) 0
+      primary-for QAnimationGroup (0x0x7f3bfb203e38)
+    QObject (0x0x7f3bfb2f6d80) 0
+        primary-for QAbstractAnimation (0x0x7f3bfb203ea0)
+
+Class QBasicTimer
+   size=4 align=4
+   base size=4 base align=4
+QBasicTimer (0x0x7f3bfafc9120) 0
+
+Class QBitArray
+   size=8 align=8
+   base size=8 base align=8
+QBitArray (0x0x7f3bfb04aa80) 0
+
+Class QBitRef
+   size=16 align=8
+   base size=12 base align=8
+QBitRef (0x0x7f3bfb099f00) 0
+
+Class QIODevice::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QIODevice::QPrivateSignal (0x0x7f3bfb10f1e0) 0 empty
+
+Vtable for QIODevice
+QIODevice::_ZTV9QIODevice: 30 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI9QIODevice)
+16    (int (*)(...))QIODevice::metaObject
+24    (int (*)(...))QIODevice::qt_metacast
+32    (int (*)(...))QIODevice::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QIODevice::isSequential
+120   (int (*)(...))QIODevice::open
+128   (int (*)(...))QIODevice::close
+136   (int (*)(...))QIODevice::pos
+144   (int (*)(...))QIODevice::size
+152   (int (*)(...))QIODevice::seek
+160   (int (*)(...))QIODevice::atEnd
+168   (int (*)(...))QIODevice::reset
+176   (int (*)(...))QIODevice::bytesAvailable
+184   (int (*)(...))QIODevice::bytesToWrite
+192   (int (*)(...))QIODevice::canReadLine
+200   (int (*)(...))QIODevice::waitForReadyRead
+208   (int (*)(...))QIODevice::waitForBytesWritten
+216   (int (*)(...))__cxa_pure_virtual
+224   (int (*)(...))QIODevice::readLineData
+232   (int (*)(...))__cxa_pure_virtual
+
+Class QIODevice
+   size=16 align=8
+   base size=16 base align=8
+QIODevice (0x0x7f3bfb108478) 0
+    vptr=((& QIODevice::_ZTV9QIODevice) + 16)
+  QObject (0x0x7f3bfb10f180) 0
+      primary-for QIODevice (0x0x7f3bfb108478)
+
+Class QBuffer::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QBuffer::QPrivateSignal (0x0x7f3bfb10fb40) 0 empty
+
+Vtable for QBuffer
+QBuffer::_ZTV7QBuffer: 30 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI7QBuffer)
+16    (int (*)(...))QBuffer::metaObject
+24    (int (*)(...))QBuffer::qt_metacast
+32    (int (*)(...))QBuffer::qt_metacall
+40    (int (*)(...))QBuffer::~QBuffer
+48    (int (*)(...))QBuffer::~QBuffer
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QBuffer::connectNotify
+104   (int (*)(...))QBuffer::disconnectNotify
+112   (int (*)(...))QIODevice::isSequential
+120   (int (*)(...))QBuffer::open
+128   (int (*)(...))QBuffer::close
+136   (int (*)(...))QBuffer::pos
+144   (int (*)(...))QBuffer::size
+152   (int (*)(...))QBuffer::seek
+160   (int (*)(...))QBuffer::atEnd
+168   (int (*)(...))QIODevice::reset
+176   (int (*)(...))QIODevice::bytesAvailable
+184   (int (*)(...))QIODevice::bytesToWrite
+192   (int (*)(...))QBuffer::canReadLine
+200   (int (*)(...))QIODevice::waitForReadyRead
+208   (int (*)(...))QIODevice::waitForBytesWritten
+216   (int (*)(...))QBuffer::readData
+224   (int (*)(...))QIODevice::readLineData
+232   (int (*)(...))QBuffer::writeData
+
+Class QBuffer
+   size=16 align=8
+   base size=16 base align=8
+QBuffer (0x0x7f3bfb1085b0) 0
+    vptr=((& QBuffer::_ZTV7QBuffer) + 16)
+  QIODevice (0x0x7f3bfb108618) 0
+      primary-for QBuffer (0x0x7f3bfb1085b0)
+    QObject (0x0x7f3bfb10fae0) 0
+        primary-for QIODevice (0x0x7f3bfb108618)
+
+Class QByteArrayMatcher::Data
+   size=272 align=8
+   base size=272 base align=8
+QByteArrayMatcher::Data (0x0x7f3bfb10fde0) 0
+
+Class QByteArrayMatcher
+   size=1040 align=8
+   base size=1040 base align=8
+QByteArrayMatcher (0x0x7f3bfb10fd80) 0
+
+Class QStaticByteArrayMatcherBase::Skiptable
+   size=256 align=1
+   base size=256 base align=1
+QStaticByteArrayMatcherBase::Skiptable (0x0x7f3bfb10ff60) 0
+
+Class QStaticByteArrayMatcherBase
+   size=256 align=16
+   base size=256 base align=16
+QStaticByteArrayMatcherBase (0x0x7f3bfb10ff00) 0
+
+Class QSharedData
+   size=4 align=4
+   base size=4 base align=4
+QSharedData (0x0x7f3bfad77e40) 0
+
+Class QLocale
+   size=8 align=8
+   base size=8 base align=8
+QLocale (0x0x7f3bfadd4d20) 0
+
+Class QCalendar::YearMonthDay
+   size=12 align=4
+   base size=12 base align=4
+QCalendar::YearMonthDay (0x0x7f3bfab61240) 0
+
+Class QCalendar
+   size=8 align=8
+   base size=8 base align=8
+QCalendar (0x0x7f3bfab611e0) 0
+
+Class QDate
+   size=8 align=8
+   base size=8 base align=8
+QDate (0x0x7f3bfab61a20) 0
+
+Class QTime
+   size=4 align=4
+   base size=4 base align=4
+QTime (0x0x7f3bfabe8300) 0
+
+Class QDateTime::ShortData
+   size=8 align=8
+   base size=8 base align=8
+QDateTime::ShortData (0x0x7f3bfac37f60) 0
+
+Class QDateTime::Data
+   size=8 align=8
+   base size=8 base align=8
+QDateTime::Data (0x0x7f3bfac51000) 0
+
+Class QDateTime
+   size=8 align=8
+   base size=8 base align=8
+QDateTime (0x0x7f3bfac37f00) 0
+
+Vtable for QTextStream
+QTextStream::_ZTV11QTextStream: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI11QTextStream)
+16    (int (*)(...))QTextStream::~QTextStream
+24    (int (*)(...))QTextStream::~QTextStream
+
+Class QTextStream
+   size=16 align=8
+   base size=16 base align=8
+QTextStream (0x0x7f3bfad296c0) 0
+    vptr=((& QTextStream::_ZTV11QTextStream) + 16)
+
+Class QTextStreamManipulator
+   size=40 align=8
+   base size=38 base align=8
+QTextStreamManipulator (0x0x7f3bfad29f60) 0
+
+Class QContiguousCacheData
+   size=24 align=4
+   base size=24 base align=4
+QContiguousCacheData (0x0x7f3bfa9fac00) 0
+
+Vtable for __gnu_cxx::__concurrence_lock_error
+__gnu_cxx::__concurrence_lock_error::_ZTVN9__gnu_cxx24__concurrence_lock_errorE: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTIN9__gnu_cxx24__concurrence_lock_errorE)
+16    (int (*)(...))__gnu_cxx::__concurrence_lock_error::~__concurrence_lock_error
+24    (int (*)(...))__gnu_cxx::__concurrence_lock_error::~__concurrence_lock_error
+32    (int (*)(...))__gnu_cxx::__concurrence_lock_error::what
+
+Class __gnu_cxx::__concurrence_lock_error
+   size=8 align=8
+   base size=8 base align=8
+__gnu_cxx::__concurrence_lock_error (0x0x7f3bfad2a618) 0 nearly-empty
+    vptr=((& __gnu_cxx::__concurrence_lock_error::_ZTVN9__gnu_cxx24__concurrence_lock_errorE) + 16)
+  std::exception (0x0x7f3bfaa43a80) 0 nearly-empty
+      primary-for __gnu_cxx::__concurrence_lock_error (0x0x7f3bfad2a618)
+
+Vtable for __gnu_cxx::__concurrence_unlock_error
+__gnu_cxx::__concurrence_unlock_error::_ZTVN9__gnu_cxx26__concurrence_unlock_errorE: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTIN9__gnu_cxx26__concurrence_unlock_errorE)
+16    (int (*)(...))__gnu_cxx::__concurrence_unlock_error::~__concurrence_unlock_error
+24    (int (*)(...))__gnu_cxx::__concurrence_unlock_error::~__concurrence_unlock_error
+32    (int (*)(...))__gnu_cxx::__concurrence_unlock_error::what
+
+Class __gnu_cxx::__concurrence_unlock_error
+   size=8 align=8
+   base size=8 base align=8
+__gnu_cxx::__concurrence_unlock_error (0x0x7f3bfad2a680) 0 nearly-empty
+    vptr=((& __gnu_cxx::__concurrence_unlock_error::_ZTVN9__gnu_cxx26__concurrence_unlock_errorE) + 16)
+  std::exception (0x0x7f3bfaa43ba0) 0 nearly-empty
+      primary-for __gnu_cxx::__concurrence_unlock_error (0x0x7f3bfad2a680)
+
+Vtable for __gnu_cxx::__concurrence_broadcast_error
+__gnu_cxx::__concurrence_broadcast_error::_ZTVN9__gnu_cxx29__concurrence_broadcast_errorE: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTIN9__gnu_cxx29__concurrence_broadcast_errorE)
+16    (int (*)(...))__gnu_cxx::__concurrence_broadcast_error::~__concurrence_broadcast_error
+24    (int (*)(...))__gnu_cxx::__concurrence_broadcast_error::~__concurrence_broadcast_error
+32    (int (*)(...))__gnu_cxx::__concurrence_broadcast_error::what
+
+Class __gnu_cxx::__concurrence_broadcast_error
+   size=8 align=8
+   base size=8 base align=8
+__gnu_cxx::__concurrence_broadcast_error (0x0x7f3bfad2a6e8) 0 nearly-empty
+    vptr=((& __gnu_cxx::__concurrence_broadcast_error::_ZTVN9__gnu_cxx29__concurrence_broadcast_errorE) + 16)
+  std::exception (0x0x7f3bfaa43cc0) 0 nearly-empty
+      primary-for __gnu_cxx::__concurrence_broadcast_error (0x0x7f3bfad2a6e8)
+
+Vtable for __gnu_cxx::__concurrence_wait_error
+__gnu_cxx::__concurrence_wait_error::_ZTVN9__gnu_cxx24__concurrence_wait_errorE: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTIN9__gnu_cxx24__concurrence_wait_errorE)
+16    (int (*)(...))__gnu_cxx::__concurrence_wait_error::~__concurrence_wait_error
+24    (int (*)(...))__gnu_cxx::__concurrence_wait_error::~__concurrence_wait_error
+32    (int (*)(...))__gnu_cxx::__concurrence_wait_error::what
+
+Class __gnu_cxx::__concurrence_wait_error
+   size=8 align=8
+   base size=8 base align=8
+__gnu_cxx::__concurrence_wait_error (0x0x7f3bfad2a7b8) 0 nearly-empty
+    vptr=((& __gnu_cxx::__concurrence_wait_error::_ZTVN9__gnu_cxx24__concurrence_wait_errorE) + 16)
+  std::exception (0x0x7f3bfaa43de0) 0 nearly-empty
+      primary-for __gnu_cxx::__concurrence_wait_error (0x0x7f3bfad2a7b8)
+
+Class __gnu_cxx::__mutex
+   size=40 align=8
+   base size=40 base align=8
+__gnu_cxx::__mutex (0x0x7f3bfaa6fe40) 0
+
+Class __gnu_cxx::__recursive_mutex
+   size=40 align=8
+   base size=40 base align=8
+__gnu_cxx::__recursive_mutex (0x0x7f3bfaa96180) 0
+
+Class __gnu_cxx::__scoped_lock
+   size=8 align=8
+   base size=8 base align=8
+__gnu_cxx::__scoped_lock (0x0x7f3bfaa96480) 0
+
+Class __gnu_cxx::__cond
+   size=48 align=8
+   base size=48 base align=8
+__gnu_cxx::__cond (0x0x7f3bfaa967e0) 0
+
+Vtable for std::bad_weak_ptr
+std::bad_weak_ptr::_ZTVSt12bad_weak_ptr: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt12bad_weak_ptr)
+16    (int (*)(...))std::bad_weak_ptr::~bad_weak_ptr
+24    (int (*)(...))std::bad_weak_ptr::~bad_weak_ptr
+32    (int (*)(...))std::bad_weak_ptr::what
+
+Class std::bad_weak_ptr
+   size=8 align=8
+   base size=8 base align=8
+std::bad_weak_ptr (0x0x7f3bfad2a820) 0 nearly-empty
+    vptr=((& std::bad_weak_ptr::_ZTVSt12bad_weak_ptr) + 16)
+  std::exception (0x0x7f3bfab0a9c0) 0 nearly-empty
+      primary-for std::bad_weak_ptr (0x0x7f3bfad2a820)
+
+Class std::_Sp_make_shared_tag
+   size=1 align=1
+   base size=0 base align=1
+std::_Sp_make_shared_tag (0x0x7f3bfa776960) 0 empty
+
+Class std::__sp_array_delete
+   size=1 align=1
+   base size=0 base align=1
+std::__sp_array_delete (0x0x7f3bfa776d80) 0 empty
+
+Class std::_Sp_locker
+   size=2 align=1
+   base size=2 base align=1
+std::_Sp_locker (0x0x7f3bfa8acc00) 0
+
+Class QtSharedPointer::NormalDeleter
+   size=1 align=1
+   base size=0 base align=1
+QtSharedPointer::NormalDeleter (0x0x7f3bfa90d120) 0 empty
+
+Class QtSharedPointer::ExternalRefCountData
+   size=16 align=8
+   base size=16 base align=8
+QtSharedPointer::ExternalRefCountData (0x0x7f3bfa90d2a0) 0
+
+Class QtPrivate::EnableInternalData
+   size=1 align=1
+   base size=0 base align=1
+QtPrivate::EnableInternalData (0x0x7f3bfa56eba0) 0 empty
+
+Class QDebug::Stream
+   size=80 align=8
+   base size=76 base align=8
+QDebug::Stream (0x0x7f3bfa5c82a0) 0
+
+Class QDebug
+   size=8 align=8
+   base size=8 base align=8
+QDebug (0x0x7f3bfa5c8240) 0
+
+Class QDebugStateSaver
+   size=8 align=8
+   base size=8 base align=8
+QDebugStateSaver (0x0x7f3bfa738ba0) 0
+
+Class QNoDebug
+   size=1 align=1
+   base size=0 base align=1
+QNoDebug (0x0x7f3bfa738c60) 0 empty
+
+Class QCborError
+   size=4 align=4
+   base size=4 base align=4
+QCborError (0x0x7f3bfa3b7ea0) 0
+
+Class QRegularExpression
+   size=8 align=8
+   base size=8 base align=8
+QRegularExpression (0x0x7f3bfa3ea660) 0
+
+Class QRegularExpressionMatch
+   size=8 align=8
+   base size=8 base align=8
+QRegularExpressionMatch (0x0x7f3bfa499540) 0
+
+Class QRegularExpressionMatchIterator
+   size=8 align=8
+   base size=8 base align=8
+QRegularExpressionMatchIterator (0x0x7f3bfa500300) 0
+
+Class QUrl
+   size=8 align=8
+   base size=8 base align=8
+QUrl (0x0x7f3bfa153d20) 0
+
+Class QUuid
+   size=16 align=4
+   base size=16 base align=4
+QUuid (0x0x7f3bfa29acc0) 0
+
+Class QCborParserError
+   size=16 align=8
+   base size=12 base align=8
+QCborParserError (0x0x7f3bfa32f840) 0
+
+Class QCborValue
+   size=24 align=8
+   base size=20 base align=8
+QCborValue (0x0x7f3bfa32f900) 0
+
+Class QCborValueRef
+   size=16 align=8
+   base size=16 base align=8
+QCborValueRef (0x0x7f3bf9daf4e0) 0
+
+Class QCborArray::Iterator
+   size=16 align=8
+   base size=16 base align=8
+QCborArray::Iterator (0x0x7f3bf9e1ff00) 0
+
+Class QCborArray::ConstIterator
+   size=16 align=8
+   base size=16 base align=8
+QCborArray::ConstIterator (0x0x7f3bf9e1ff60) 0
+
+Class QCborArray
+   size=8 align=8
+   base size=8 base align=8
+QCborArray (0x0x7f3bf9e1fea0) 0
+
+Class QCborMap::Iterator
+   size=16 align=8
+   base size=16 base align=8
+QCborMap::Iterator (0x0x7f3bf9ba2b40) 0
+
+Class QCborMap::ConstIterator
+   size=16 align=8
+   base size=16 base align=8
+QCborMap::ConstIterator (0x0x7f3bf9ba2ba0) 0
+
+Class QCborMap
+   size=8 align=8
+   base size=8 base align=8
+QCborMap (0x0x7f3bf9ba2ae0) 0
+
+Class qfloat16::Wrap
+   size=2 align=2
+   base size=2 base align=2
+qfloat16::Wrap (0x0x7f3bf99bf360) 0
+
+Class qfloat16
+   size=2 align=2
+   base size=2 base align=2
+qfloat16 (0x0x7f3bf99bf300) 0
+
+Class QCborStreamWriter
+   size=8 align=8
+   base size=8 base align=8
+QCborStreamWriter (0x0x7f3bf9aaf000) 0
+
+Class QCborStreamReader
+   size=24 align=8
+   base size=20 base align=8
+QCborStreamReader (0x0x7f3bf9aafd20) 0
+
+Class QCollatorSortKey
+   size=8 align=8
+   base size=8 base align=8
+QCollatorSortKey (0x0x7f3bf9740e40) 0
+
+Class QCollator
+   size=8 align=8
+   base size=8 base align=8
+QCollator (0x0x7f3bf976d060) 0
+
+Class QCommandLineOption
+   size=8 align=8
+   base size=8 base align=8
+QCommandLineOption (0x0x7f3bf985d660) 0
+
+Vtable for QEvent
+QEvent::_ZTV6QEvent: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI6QEvent)
+16    (int (*)(...))QEvent::~QEvent
+24    (int (*)(...))QEvent::~QEvent
+
+Class QEvent
+   size=24 align=8
+   base size=20 base align=8
+QEvent (0x0x7f3bf991fba0) 0
+    vptr=((& QEvent::_ZTV6QEvent) + 16)
+
+Vtable for QTimerEvent
+QTimerEvent::_ZTV11QTimerEvent: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI11QTimerEvent)
+16    (int (*)(...))QTimerEvent::~QTimerEvent
+24    (int (*)(...))QTimerEvent::~QTimerEvent
+
+Class QTimerEvent
+   size=24 align=8
+   base size=24 base align=8
+QTimerEvent (0x0x7f3bf9926270) 0
+    vptr=((& QTimerEvent::_ZTV11QTimerEvent) + 16)
+  QEvent (0x0x7f3bf991ff60) 0
+      primary-for QTimerEvent (0x0x7f3bf9926270)
+
+Vtable for QChildEvent
+QChildEvent::_ZTV11QChildEvent: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI11QChildEvent)
+16    (int (*)(...))QChildEvent::~QChildEvent
+24    (int (*)(...))QChildEvent::~QChildEvent
+
+Class QChildEvent
+   size=32 align=8
+   base size=32 base align=8
+QChildEvent (0x0x7f3bf99262d8) 0
+    vptr=((& QChildEvent::_ZTV11QChildEvent) + 16)
+  QEvent (0x0x7f3bf9566060) 0
+      primary-for QChildEvent (0x0x7f3bf99262d8)
+
+Vtable for QDynamicPropertyChangeEvent
+QDynamicPropertyChangeEvent::_ZTV27QDynamicPropertyChangeEvent: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI27QDynamicPropertyChangeEvent)
+16    (int (*)(...))QDynamicPropertyChangeEvent::~QDynamicPropertyChangeEvent
+24    (int (*)(...))QDynamicPropertyChangeEvent::~QDynamicPropertyChangeEvent
+
+Class QDynamicPropertyChangeEvent
+   size=32 align=8
+   base size=32 base align=8
+QDynamicPropertyChangeEvent (0x0x7f3bf9926820) 0
+    vptr=((& QDynamicPropertyChangeEvent::_ZTV27QDynamicPropertyChangeEvent) + 16)
+  QEvent (0x0x7f3bf95666c0) 0
+      primary-for QDynamicPropertyChangeEvent (0x0x7f3bf9926820)
+
+Vtable for QDeferredDeleteEvent
+QDeferredDeleteEvent::_ZTV20QDeferredDeleteEvent: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI20QDeferredDeleteEvent)
+16    (int (*)(...))QDeferredDeleteEvent::~QDeferredDeleteEvent
+24    (int (*)(...))QDeferredDeleteEvent::~QDeferredDeleteEvent
+
+Class QDeferredDeleteEvent
+   size=24 align=8
+   base size=24 base align=8
+QDeferredDeleteEvent (0x0x7f3bf9926888) 0
+    vptr=((& QDeferredDeleteEvent::_ZTV20QDeferredDeleteEvent) + 16)
+  QEvent (0x0x7f3bf9566780) 0
+      primary-for QDeferredDeleteEvent (0x0x7f3bf9926888)
+
+Class QCoreApplication::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QCoreApplication::QPrivateSignal (0x0x7f3bf95668a0) 0 empty
+
+Vtable for QCoreApplication
+QCoreApplication::_ZTV16QCoreApplication: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI16QCoreApplication)
+16    (int (*)(...))QCoreApplication::metaObject
+24    (int (*)(...))QCoreApplication::qt_metacast
+32    (int (*)(...))QCoreApplication::qt_metacall
+40    (int (*)(...))QCoreApplication::~QCoreApplication
+48    (int (*)(...))QCoreApplication::~QCoreApplication
+56    (int (*)(...))QCoreApplication::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QCoreApplication::notify
+120   (int (*)(...))QCoreApplication::compressEvent
+
+Class QCoreApplication
+   size=16 align=8
+   base size=16 base align=8
+QCoreApplication (0x0x7f3bf99268f0) 0
+    vptr=((& QCoreApplication::_ZTV16QCoreApplication) + 16)
+  QObject (0x0x7f3bf9566840) 0
+      primary-for QCoreApplication (0x0x7f3bf99268f0)
+
+Class QCommandLineParser
+   size=8 align=8
+   base size=8 base align=8
+QCommandLineParser (0x0x7f3bf9566ae0) 0
+
+Class QConcatenateTablesProxyModel::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QConcatenateTablesProxyModel::QPrivateSignal (0x0x7f3bf9566c60) 0 empty
+
+Vtable for QConcatenateTablesProxyModel
+QConcatenateTablesProxyModel::_ZTV28QConcatenateTablesProxyModel: 48 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI28QConcatenateTablesProxyModel)
+16    (int (*)(...))QConcatenateTablesProxyModel::metaObject
+24    (int (*)(...))QConcatenateTablesProxyModel::qt_metacast
+32    (int (*)(...))QConcatenateTablesProxyModel::qt_metacall
+40    (int (*)(...))QConcatenateTablesProxyModel::~QConcatenateTablesProxyModel
+48    (int (*)(...))QConcatenateTablesProxyModel::~QConcatenateTablesProxyModel
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QConcatenateTablesProxyModel::index
+120   (int (*)(...))QConcatenateTablesProxyModel::parent
+128   (int (*)(...))QAbstractItemModel::sibling
+136   (int (*)(...))QConcatenateTablesProxyModel::rowCount
+144   (int (*)(...))QConcatenateTablesProxyModel::columnCount
+152   (int (*)(...))QAbstractItemModel::hasChildren
+160   (int (*)(...))QConcatenateTablesProxyModel::data
+168   (int (*)(...))QConcatenateTablesProxyModel::setData
+176   (int (*)(...))QConcatenateTablesProxyModel::headerData
+184   (int (*)(...))QAbstractItemModel::setHeaderData
+192   (int (*)(...))QConcatenateTablesProxyModel::itemData
+200   (int (*)(...))QConcatenateTablesProxyModel::setItemData
+208   (int (*)(...))QConcatenateTablesProxyModel::mimeTypes
+216   (int (*)(...))QConcatenateTablesProxyModel::mimeData
+224   (int (*)(...))QConcatenateTablesProxyModel::canDropMimeData
+232   (int (*)(...))QConcatenateTablesProxyModel::dropMimeData
+240   (int (*)(...))QAbstractItemModel::supportedDropActions
+248   (int (*)(...))QAbstractItemModel::supportedDragActions
+256   (int (*)(...))QAbstractItemModel::insertRows
+264   (int (*)(...))QAbstractItemModel::insertColumns
+272   (int (*)(...))QAbstractItemModel::removeRows
+280   (int (*)(...))QAbstractItemModel::removeColumns
+288   (int (*)(...))QAbstractItemModel::moveRows
+296   (int (*)(...))QAbstractItemModel::moveColumns
+304   (int (*)(...))QAbstractItemModel::fetchMore
+312   (int (*)(...))QAbstractItemModel::canFetchMore
+320   (int (*)(...))QConcatenateTablesProxyModel::flags
+328   (int (*)(...))QAbstractItemModel::sort
+336   (int (*)(...))QAbstractItemModel::buddy
+344   (int (*)(...))QAbstractItemModel::match
+352   (int (*)(...))QConcatenateTablesProxyModel::span
+360   (int (*)(...))QAbstractItemModel::roleNames
+368   (int (*)(...))QAbstractItemModel::submit
+376   (int (*)(...))QAbstractItemModel::revert
+
+Class QConcatenateTablesProxyModel
+   size=16 align=8
+   base size=16 base align=8
+QConcatenateTablesProxyModel (0x0x7f3bf9926958) 0
+    vptr=((& QConcatenateTablesProxyModel::_ZTV28QConcatenateTablesProxyModel) + 16)
+  QAbstractItemModel (0x0x7f3bf99269c0) 0
+      primary-for QConcatenateTablesProxyModel (0x0x7f3bf9926958)
+    QObject (0x0x7f3bf9566c00) 0
+        primary-for QAbstractItemModel (0x0x7f3bf99269c0)
+
+Class QCryptographicHash
+   size=8 align=8
+   base size=8 base align=8
+QCryptographicHash (0x0x7f3bf9566e40) 0
+
+Class QDataStream
+   size=32 align=8
+   base size=32 base align=8
+QDataStream (0x0x7f3bf9566f60) 0
+
+Class QtPrivate::StreamStateSaver
+   size=16 align=8
+   base size=12 base align=8
+QtPrivate::StreamStateSaver (0x0x7f3bf95ed120) 0
+
+Class QElapsedTimer
+   size=16 align=8
+   base size=16 base align=8
+QElapsedTimer (0x0x7f3bf962a840) 0
+
+Class QDeadlineTimer
+   size=16 align=8
+   base size=16 base align=8
+QDeadlineTimer (0x0x7f3bf962af60) 0
+
+Class QFileDevice::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QFileDevice::QPrivateSignal (0x0x7f3bf937ec60) 0 empty
+
+Vtable for QFileDevice
+QFileDevice::_ZTV11QFileDevice: 34 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI11QFileDevice)
+16    (int (*)(...))QFileDevice::metaObject
+24    (int (*)(...))QFileDevice::qt_metacast
+32    (int (*)(...))QFileDevice::qt_metacall
+40    (int (*)(...))QFileDevice::~QFileDevice
+48    (int (*)(...))QFileDevice::~QFileDevice
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QFileDevice::isSequential
+120   (int (*)(...))QIODevice::open
+128   (int (*)(...))QFileDevice::close
+136   (int (*)(...))QFileDevice::pos
+144   (int (*)(...))QFileDevice::size
+152   (int (*)(...))QFileDevice::seek
+160   (int (*)(...))QFileDevice::atEnd
+168   (int (*)(...))QIODevice::reset
+176   (int (*)(...))QIODevice::bytesAvailable
+184   (int (*)(...))QIODevice::bytesToWrite
+192   (int (*)(...))QIODevice::canReadLine
+200   (int (*)(...))QIODevice::waitForReadyRead
+208   (int (*)(...))QIODevice::waitForBytesWritten
+216   (int (*)(...))QFileDevice::readData
+224   (int (*)(...))QFileDevice::readLineData
+232   (int (*)(...))QFileDevice::writeData
+240   (int (*)(...))QFileDevice::fileName
+248   (int (*)(...))QFileDevice::resize
+256   (int (*)(...))QFileDevice::permissions
+264   (int (*)(...))QFileDevice::setPermissions
+
+Class QFileDevice
+   size=16 align=8
+   base size=16 base align=8
+QFileDevice (0x0x7f3bf9375bc8) 0
+    vptr=((& QFileDevice::_ZTV11QFileDevice) + 16)
+  QIODevice (0x0x7f3bf9375c30) 0
+      primary-for QFileDevice (0x0x7f3bf9375bc8)
+    QObject (0x0x7f3bf937ec00) 0
+        primary-for QIODevice (0x0x7f3bf9375c30)
+
+Class QFile::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QFile::QPrivateSignal (0x0x7f3bf93c55a0) 0 empty
+
+Vtable for QFile
+QFile::_ZTV5QFile: 34 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI5QFile)
+16    (int (*)(...))QFile::metaObject
+24    (int (*)(...))QFile::qt_metacast
+32    (int (*)(...))QFile::qt_metacall
+40    (int (*)(...))QFile::~QFile
+48    (int (*)(...))QFile::~QFile
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QFileDevice::isSequential
+120   (int (*)(...))QFile::open
+128   (int (*)(...))QFileDevice::close
+136   (int (*)(...))QFileDevice::pos
+144   (int (*)(...))QFile::size
+152   (int (*)(...))QFileDevice::seek
+160   (int (*)(...))QFileDevice::atEnd
+168   (int (*)(...))QIODevice::reset
+176   (int (*)(...))QIODevice::bytesAvailable
+184   (int (*)(...))QIODevice::bytesToWrite
+192   (int (*)(...))QIODevice::canReadLine
+200   (int (*)(...))QIODevice::waitForReadyRead
+208   (int (*)(...))QIODevice::waitForBytesWritten
+216   (int (*)(...))QFileDevice::readData
+224   (int (*)(...))QFileDevice::readLineData
+232   (int (*)(...))QFileDevice::writeData
+240   (int (*)(...))QFile::fileName
+248   (int (*)(...))QFile::resize
+256   (int (*)(...))QFile::permissions
+264   (int (*)(...))QFile::setPermissions
+
+Class QFile
+   size=16 align=8
+   base size=16 base align=8
+QFile (0x0x7f3bf9375d68) 0
+    vptr=((& QFile::_ZTV5QFile) + 16)
+  QFileDevice (0x0x7f3bf9375dd0) 0
+      primary-for QFile (0x0x7f3bf9375d68)
+    QIODevice (0x0x7f3bf9375e38) 0
+        primary-for QFileDevice (0x0x7f3bf9375dd0)
+      QObject (0x0x7f3bf93c5540) 0
+          primary-for QIODevice (0x0x7f3bf9375e38)
+
+Class QFileInfo
+   size=8 align=8
+   base size=8 base align=8
+QFileInfo (0x0x7f3bf93c5c00) 0
+
+Class QDir
+   size=8 align=8
+   base size=8 base align=8
+QDir (0x0x7f3bf94bdae0) 0
+
+Class QDirIterator
+   size=8 align=8
+   base size=8 base align=8
+QDirIterator (0x0x7f3bf9156ae0) 0
+
+Class QEasingCurve
+   size=8 align=8
+   base size=8 base align=8
+QEasingCurve (0x0x7f3bf91b02a0) 0
+
+Class QEventTransition::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QEventTransition::QPrivateSignal (0x0x7f3bf92af3c0) 0 empty
+
+Vtable for QEventTransition
+QEventTransition::_ZTV16QEventTransition: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI16QEventTransition)
+16    (int (*)(...))QEventTransition::metaObject
+24    (int (*)(...))QEventTransition::qt_metacast
+32    (int (*)(...))QEventTransition::qt_metacall
+40    (int (*)(...))QEventTransition::~QEventTransition
+48    (int (*)(...))QEventTransition::~QEventTransition
+56    (int (*)(...))QEventTransition::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QEventTransition::eventTest
+120   (int (*)(...))QEventTransition::onTransition
+
+Class QEventTransition
+   size=16 align=8
+   base size=16 base align=8
+QEventTransition (0x0x7f3bf9269af8) 0
+    vptr=((& QEventTransition::_ZTV16QEventTransition) + 16)
+  QAbstractTransition (0x0x7f3bf9269b60) 0
+      primary-for QEventTransition (0x0x7f3bf9269af8)
+    QObject (0x0x7f3bf92af360) 0
+        primary-for QAbstractTransition (0x0x7f3bf9269b60)
+
+Vtable for QException
+QException::_ZTV10QException: 7 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI10QException)
+16    (int (*)(...))QException::~QException
+24    (int (*)(...))QException::~QException
+32    (int (*)(...))std::exception::what
+40    (int (*)(...))QException::raise
+48    (int (*)(...))QException::clone
+
+Class QException
+   size=8 align=8
+   base size=8 base align=8
+QException (0x0x7f3bf9269bc8) 0 nearly-empty
+    vptr=((& QException::_ZTV10QException) + 16)
+  std::exception (0x0x7f3bf92af5a0) 0 nearly-empty
+      primary-for QException (0x0x7f3bf9269bc8)
+
+Vtable for QUnhandledException
+QUnhandledException::_ZTV19QUnhandledException: 7 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI19QUnhandledException)
+16    (int (*)(...))QUnhandledException::~QUnhandledException
+24    (int (*)(...))QUnhandledException::~QUnhandledException
+32    (int (*)(...))std::exception::what
+40    (int (*)(...))QUnhandledException::raise
+48    (int (*)(...))QUnhandledException::clone
+
+Class QUnhandledException
+   size=8 align=8
+   base size=8 base align=8
+QUnhandledException (0x0x7f3bf9269c30) 0 nearly-empty
+    vptr=((& QUnhandledException::_ZTV19QUnhandledException) + 16)
+  QException (0x0x7f3bf9269c98) 0 nearly-empty
+      primary-for QUnhandledException (0x0x7f3bf9269c30)
+    std::exception (0x0x7f3bf92af600) 0 nearly-empty
+        primary-for QException (0x0x7f3bf9269c98)
+
+Class QtPrivate::ExceptionHolder
+   size=8 align=8
+   base size=8 base align=8
+QtPrivate::ExceptionHolder (0x0x7f3bf92af660) 0
+
+Class QtPrivate::ExceptionStore
+   size=8 align=8
+   base size=8 base align=8
+QtPrivate::ExceptionStore (0x0x7f3bf92af720) 0
+
+Vtable for QFactoryInterface
+QFactoryInterface::_ZTV17QFactoryInterface: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI17QFactoryInterface)
+16    0
+24    0
+32    (int (*)(...))__cxa_pure_virtual
+
+Class QFactoryInterface
+   size=8 align=8
+   base size=8 base align=8
+QFactoryInterface (0x0x7f3bf92af780) 0 nearly-empty
+    vptr=((& QFactoryInterface::_ZTV17QFactoryInterface) + 16)
+
+Class QFileSelector::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QFileSelector::QPrivateSignal (0x0x7f3bf92af9c0) 0 empty
+
+Vtable for QFileSelector
+QFileSelector::_ZTV13QFileSelector: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI13QFileSelector)
+16    (int (*)(...))QFileSelector::metaObject
+24    (int (*)(...))QFileSelector::qt_metacast
+32    (int (*)(...))QFileSelector::qt_metacall
+40    (int (*)(...))QFileSelector::~QFileSelector
+48    (int (*)(...))QFileSelector::~QFileSelector
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QFileSelector
+   size=16 align=8
+   base size=16 base align=8
+QFileSelector (0x0x7f3bf9269d00) 0
+    vptr=((& QFileSelector::_ZTV13QFileSelector) + 16)
+  QObject (0x0x7f3bf92af960) 0
+      primary-for QFileSelector (0x0x7f3bf9269d00)
+
+Class QFileSystemWatcher::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QFileSystemWatcher::QPrivateSignal (0x0x7f3bf92afc00) 0 empty
+
+Vtable for QFileSystemWatcher
+QFileSystemWatcher::_ZTV18QFileSystemWatcher: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI18QFileSystemWatcher)
+16    (int (*)(...))QFileSystemWatcher::metaObject
+24    (int (*)(...))QFileSystemWatcher::qt_metacast
+32    (int (*)(...))QFileSystemWatcher::qt_metacall
+40    (int (*)(...))QFileSystemWatcher::~QFileSystemWatcher
+48    (int (*)(...))QFileSystemWatcher::~QFileSystemWatcher
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QFileSystemWatcher
+   size=16 align=8
+   base size=16 base align=8
+QFileSystemWatcher (0x0x7f3bf9269d68) 0
+    vptr=((& QFileSystemWatcher::_ZTV18QFileSystemWatcher) + 16)
+  QObject (0x0x7f3bf92afba0) 0
+      primary-for QFileSystemWatcher (0x0x7f3bf9269d68)
+
+Class QFinalState::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QFinalState::QPrivateSignal (0x0x7f3bf92afe40) 0 empty
+
+Vtable for QFinalState
+QFinalState::_ZTV11QFinalState: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI11QFinalState)
+16    (int (*)(...))QFinalState::metaObject
+24    (int (*)(...))QFinalState::qt_metacast
+32    (int (*)(...))QFinalState::qt_metacall
+40    (int (*)(...))QFinalState::~QFinalState
+48    (int (*)(...))QFinalState::~QFinalState
+56    (int (*)(...))QFinalState::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QFinalState::onEntry
+120   (int (*)(...))QFinalState::onExit
+
+Class QFinalState
+   size=16 align=8
+   base size=16 base align=8
+QFinalState (0x0x7f3bf9269dd0) 0
+    vptr=((& QFinalState::_ZTV11QFinalState) + 16)
+  QAbstractState (0x0x7f3bf9269e38) 0
+      primary-for QFinalState (0x0x7f3bf9269dd0)
+    QObject (0x0x7f3bf92afde0) 0
+        primary-for QAbstractState (0x0x7f3bf9269e38)
+
+Vtable for QRunnable
+QRunnable::_ZTV9QRunnable: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI9QRunnable)
+16    (int (*)(...))__cxa_pure_virtual
+24    0
+32    0
+
+Class QRunnable
+   size=16 align=8
+   base size=12 base align=8
+QRunnable (0x0x7f3bf8ecd060) 0
+    vptr=((& QRunnable::_ZTV9QRunnable) + 16)
+
+Class QBasicMutex
+   size=8 align=8
+   base size=8 base align=8
+QBasicMutex (0x0x7f3bf8ecd300) 0
+
+Class QMutex
+   size=8 align=8
+   base size=8 base align=8
+QMutex (0x0x7f3bf9269f08) 0
+  QBasicMutex (0x0x7f3bf8ecdf60) 0
+
+Class QRecursiveMutex
+   size=8 align=8
+   base size=8 base align=8
+QRecursiveMutex (0x0x7f3bf9269f70) 0
+  QMutex (0x0x7f3bf8f5c000) 0
+    QBasicMutex (0x0x7f3bf8f571e0) 0
+
+Class QMutexLocker
+   size=8 align=8
+   base size=8 base align=8
+QMutexLocker (0x0x7f3bf8f57240) 0
+
+Class QtPrivate::ResultItem
+   size=16 align=8
+   base size=16 base align=8
+QtPrivate::ResultItem (0x0x7f3bf8f57840) 0
+
+Class QtPrivate::ResultIteratorBase
+   size=16 align=8
+   base size=12 base align=8
+QtPrivate::ResultIteratorBase (0x0x7f3bf8f57e40) 0
+
+Vtable for QtPrivate::ResultStoreBase
+QtPrivate::ResultStoreBase::_ZTVN9QtPrivate15ResultStoreBaseE: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTIN9QtPrivate15ResultStoreBaseE)
+16    (int (*)(...))QtPrivate::ResultStoreBase::~ResultStoreBase
+24    (int (*)(...))QtPrivate::ResultStoreBase::~ResultStoreBase
+
+Class QtPrivate::ResultStoreBase
+   size=48 align=8
+   base size=44 base align=8
+QtPrivate::ResultStoreBase (0x0x7f3bf8fa7060) 0
+    vptr=((& QtPrivate::ResultStoreBase::_ZTVN9QtPrivate15ResultStoreBaseE) + 16)
+
+Class std::__mutex_base
+   size=40 align=8
+   base size=40 base align=8
+std::__mutex_base (0x0x7f3bf8ff3840) 0
+
+Class std::mutex
+   size=40 align=8
+   base size=40 base align=8
+std::mutex (0x0x7f3bf8ff18f0) 0
+  std::__mutex_base (0x0x7f3bf8ff38a0) 0
+
+Class std::defer_lock_t
+   size=1 align=1
+   base size=0 base align=1
+std::defer_lock_t (0x0x7f3bf8ff3a80) 0 empty
+
+Class std::try_to_lock_t
+   size=1 align=1
+   base size=0 base align=1
+std::try_to_lock_t (0x0x7f3bf8ff3ae0) 0 empty
+
+Class std::adopt_lock_t
+   size=1 align=1
+   base size=0 base align=1
+std::adopt_lock_t (0x0x7f3bf8ff3b40) 0 empty
+
+Class std::__recursive_mutex_base
+   size=40 align=8
+   base size=40 base align=8
+std::__recursive_mutex_base (0x0x7f3bf90265a0) 0
+
+Class std::recursive_mutex
+   size=40 align=8
+   base size=40 base align=8
+std::recursive_mutex (0x0x7f3bf8ff1958) 0
+  std::__recursive_mutex_base (0x0x7f3bf9026600) 0
+
+Class std::timed_mutex
+   size=40 align=8
+   base size=40 base align=8
+std::timed_mutex (0x0x7f3bf8ffdd20) 0
+  std::__mutex_base (0x0x7f3bf90269c0) 0
+  std::__timed_mutex_impl<std::timed_mutex> (0x0x7f3bf9026a20) 0 empty
+
+Class std::recursive_timed_mutex
+   size=40 align=8
+   base size=40 base align=8
+std::recursive_timed_mutex (0x0x7f3bf9051070) 0
+  std::__recursive_mutex_base (0x0x7f3bf9026d80) 0
+  std::__timed_mutex_impl<std::recursive_timed_mutex> (0x0x7f3bf9026de0) 0 empty
+
+Class std::once_flag
+   size=4 align=4
+   base size=4 base align=4
+std::once_flag (0x0x7f3bf9067540) 0
+
+Vtable for QFutureInterfaceBase
+QFutureInterfaceBase::_ZTV20QFutureInterfaceBase: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI20QFutureInterfaceBase)
+16    (int (*)(...))QFutureInterfaceBase::~QFutureInterfaceBase
+24    (int (*)(...))QFutureInterfaceBase::~QFutureInterfaceBase
+
+Class QFutureInterfaceBase
+   size=16 align=8
+   base size=16 base align=8
+QFutureInterfaceBase (0x0x7f3bf9067780) 0
+    vptr=((& QFutureInterfaceBase::_ZTV20QFutureInterfaceBase) + 16)
+
+Class QFutureWatcherBase::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QFutureWatcherBase::QPrivateSignal (0x0x7f3bf8d15ae0) 0 empty
+
+Vtable for QFutureWatcherBase
+QFutureWatcherBase::_ZTV18QFutureWatcherBase: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI18QFutureWatcherBase)
+16    (int (*)(...))QFutureWatcherBase::metaObject
+24    (int (*)(...))QFutureWatcherBase::qt_metacast
+32    (int (*)(...))QFutureWatcherBase::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QFutureWatcherBase::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QFutureWatcherBase::connectNotify
+104   (int (*)(...))QFutureWatcherBase::disconnectNotify
+112   (int (*)(...))__cxa_pure_virtual
+120   (int (*)(...))__cxa_pure_virtual
+
+Class QFutureWatcherBase
+   size=16 align=8
+   base size=16 base align=8
+QFutureWatcherBase (0x0x7f3bf8cb3750) 0
+    vptr=((& QFutureWatcherBase::_ZTV18QFutureWatcherBase) + 16)
+  QObject (0x0x7f3bf8d15a80) 0
+      primary-for QFutureWatcherBase (0x0x7f3bf8cb3750)
+
+Class QHistoryState::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QHistoryState::QPrivateSignal (0x0x7f3bf8d40e40) 0 empty
+
+Vtable for QHistoryState
+QHistoryState::_ZTV13QHistoryState: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI13QHistoryState)
+16    (int (*)(...))QHistoryState::metaObject
+24    (int (*)(...))QHistoryState::qt_metacast
+32    (int (*)(...))QHistoryState::qt_metacall
+40    (int (*)(...))QHistoryState::~QHistoryState
+48    (int (*)(...))QHistoryState::~QHistoryState
+56    (int (*)(...))QHistoryState::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QHistoryState::onEntry
+120   (int (*)(...))QHistoryState::onExit
+
+Class QHistoryState
+   size=16 align=8
+   base size=16 base align=8
+QHistoryState (0x0x7f3bf8cb3f70) 0
+    vptr=((& QHistoryState::_ZTV13QHistoryState) + 16)
+  QAbstractState (0x0x7f3bf8d60000) 0
+      primary-for QHistoryState (0x0x7f3bf8cb3f70)
+    QObject (0x0x7f3bf8d40de0) 0
+        primary-for QAbstractState (0x0x7f3bf8d60000)
+
+Class QIdentityProxyModel::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QIdentityProxyModel::QPrivateSignal (0x0x7f3bf8d6e180) 0 empty
+
+Vtable for QIdentityProxyModel
+QIdentityProxyModel::_ZTV19QIdentityProxyModel: 53 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI19QIdentityProxyModel)
+16    (int (*)(...))QIdentityProxyModel::metaObject
+24    (int (*)(...))QIdentityProxyModel::qt_metacast
+32    (int (*)(...))QIdentityProxyModel::qt_metacall
+40    (int (*)(...))QIdentityProxyModel::~QIdentityProxyModel
+48    (int (*)(...))QIdentityProxyModel::~QIdentityProxyModel
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QIdentityProxyModel::index
+120   (int (*)(...))QIdentityProxyModel::parent
+128   (int (*)(...))QIdentityProxyModel::sibling
+136   (int (*)(...))QIdentityProxyModel::rowCount
+144   (int (*)(...))QIdentityProxyModel::columnCount
+152   (int (*)(...))QAbstractProxyModel::hasChildren
+160   (int (*)(...))QAbstractProxyModel::data
+168   (int (*)(...))QAbstractProxyModel::setData
+176   (int (*)(...))QIdentityProxyModel::headerData
+184   (int (*)(...))QAbstractProxyModel::setHeaderData
+192   (int (*)(...))QAbstractProxyModel::itemData
+200   (int (*)(...))QAbstractProxyModel::setItemData
+208   (int (*)(...))QAbstractProxyModel::mimeTypes
+216   (int (*)(...))QAbstractProxyModel::mimeData
+224   (int (*)(...))QAbstractProxyModel::canDropMimeData
+232   (int (*)(...))QIdentityProxyModel::dropMimeData
+240   (int (*)(...))QAbstractProxyModel::supportedDropActions
+248   (int (*)(...))QAbstractProxyModel::supportedDragActions
+256   (int (*)(...))QIdentityProxyModel::insertRows
+264   (int (*)(...))QIdentityProxyModel::insertColumns
+272   (int (*)(...))QIdentityProxyModel::removeRows
+280   (int (*)(...))QIdentityProxyModel::removeColumns
+288   (int (*)(...))QAbstractItemModel::moveRows
+296   (int (*)(...))QAbstractItemModel::moveColumns
+304   (int (*)(...))QAbstractProxyModel::fetchMore
+312   (int (*)(...))QAbstractProxyModel::canFetchMore
+320   (int (*)(...))QAbstractProxyModel::flags
+328   (int (*)(...))QAbstractProxyModel::sort
+336   (int (*)(...))QAbstractProxyModel::buddy
+344   (int (*)(...))QIdentityProxyModel::match
+352   (int (*)(...))QAbstractProxyModel::span
+360   (int (*)(...))QAbstractItemModel::roleNames
+368   (int (*)(...))QAbstractProxyModel::submit
+376   (int (*)(...))QAbstractProxyModel::revert
+384   (int (*)(...))QIdentityProxyModel::setSourceModel
+392   (int (*)(...))QIdentityProxyModel::mapToSource
+400   (int (*)(...))QIdentityProxyModel::mapFromSource
+408   (int (*)(...))QIdentityProxyModel::mapSelectionToSource
+416   (int (*)(...))QIdentityProxyModel::mapSelectionFromSource
+
+Class QIdentityProxyModel
+   size=16 align=8
+   base size=16 base align=8
+QIdentityProxyModel (0x0x7f3bf8d60068) 0
+    vptr=((& QIdentityProxyModel::_ZTV19QIdentityProxyModel) + 16)
+  QAbstractProxyModel (0x0x7f3bf8d600d0) 0
+      primary-for QIdentityProxyModel (0x0x7f3bf8d60068)
+    QAbstractItemModel (0x0x7f3bf8d60138) 0
+        primary-for QAbstractProxyModel (0x0x7f3bf8d600d0)
+      QObject (0x0x7f3bf8d6e120) 0
+          primary-for QAbstractItemModel (0x0x7f3bf8d60138)
+
+Class QItemSelectionRange
+   size=16 align=8
+   base size=16 base align=8
+QItemSelectionRange (0x0x7f3bf8d6e360) 0
+
+Class QItemSelectionModel::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QItemSelectionModel::QPrivateSignal (0x0x7f3bf8e29c60) 0 empty
+
+Vtable for QItemSelectionModel
+QItemSelectionModel::_ZTV19QItemSelectionModel: 20 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI19QItemSelectionModel)
+16    (int (*)(...))QItemSelectionModel::metaObject
+24    (int (*)(...))QItemSelectionModel::qt_metacast
+32    (int (*)(...))QItemSelectionModel::qt_metacall
+40    (int (*)(...))QItemSelectionModel::~QItemSelectionModel
+48    (int (*)(...))QItemSelectionModel::~QItemSelectionModel
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QItemSelectionModel::setCurrentIndex
+120   (int (*)(...))QItemSelectionModel::select
+128   (int (*)(...))QItemSelectionModel::select
+136   (int (*)(...))QItemSelectionModel::clear
+144   (int (*)(...))QItemSelectionModel::reset
+152   (int (*)(...))QItemSelectionModel::clearCurrentIndex
+
+Class QItemSelectionModel
+   size=16 align=8
+   base size=16 base align=8
+QItemSelectionModel (0x0x7f3bf8e33a90) 0
+    vptr=((& QItemSelectionModel::_ZTV19QItemSelectionModel) + 16)
+  QObject (0x0x7f3bf8e29c00) 0
+      primary-for QItemSelectionModel (0x0x7f3bf8e33a90)
+
+Class QItemSelection
+   size=8 align=8
+   base size=8 base align=8
+QItemSelection (0x0x7f3bf8e33c30) 0
+  QList<QItemSelectionRange> (0x0x7f3bf8e33c98) 0
+    QListSpecialMethods<QItemSelectionRange> (0x0x7f3bf8e6b780) 0 empty
+
+Class QJsonValue
+   size=24 align=8
+   base size=20 base align=8
+QJsonValue (0x0x7f3bf8aff0c0) 0
+
+Class QJsonValueRef
+   size=16 align=8
+   base size=12 base align=8
+QJsonValueRef (0x0x7f3bf8c2bd20) 0
+
+Class QJsonValuePtr
+   size=24 align=8
+   base size=24 base align=8
+QJsonValuePtr (0x0x7f3bf8c68cc0) 0
+
+Class QJsonValueRefPtr
+   size=16 align=8
+   base size=16 base align=8
+QJsonValueRefPtr (0x0x7f3bf8c68f60) 0
+
+Class QJsonArray::iterator
+   size=16 align=8
+   base size=12 base align=8
+QJsonArray::iterator (0x0x7f3bf88e4300) 0
+
+Class QJsonArray::const_iterator
+   size=16 align=8
+   base size=12 base align=8
+QJsonArray::const_iterator (0x0x7f3bf88e4360) 0
+
+Class QJsonArray
+   size=16 align=8
+   base size=16 base align=8
+QJsonArray (0x0x7f3bf88e42a0) 0
+
+Class QJsonParseError
+   size=8 align=4
+   base size=8 base align=4
+QJsonParseError (0x0x7f3bf8a14240) 0
+
+Class QJsonDocument
+   size=8 align=8
+   base size=8 base align=8
+QJsonDocument (0x0x7f3bf8a142a0) 0
+
+Class QJsonObject::iterator
+   size=16 align=8
+   base size=12 base align=8
+QJsonObject::iterator (0x0x7f3bf8a65a80) 0
+
+Class QJsonObject::const_iterator
+   size=16 align=8
+   base size=12 base align=8
+QJsonObject::const_iterator (0x0x7f3bf8a65ae0) 0
+
+Class QJsonObject
+   size=16 align=8
+   base size=16 base align=8
+QJsonObject (0x0x7f3bf8a65a20) 0
+
+Class QLibrary::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QLibrary::QPrivateSignal (0x0x7f3bf8781f00) 0 empty
+
+Vtable for QLibrary
+QLibrary::_ZTV8QLibrary: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI8QLibrary)
+16    (int (*)(...))QLibrary::metaObject
+24    (int (*)(...))QLibrary::qt_metacast
+32    (int (*)(...))QLibrary::qt_metacall
+40    (int (*)(...))QLibrary::~QLibrary
+48    (int (*)(...))QLibrary::~QLibrary
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QLibrary
+   size=32 align=8
+   base size=25 base align=8
+QLibrary (0x0x7f3bf878e8f0) 0
+    vptr=((& QLibrary::_ZTV8QLibrary) + 16)
+  QObject (0x0x7f3bf8781ea0) 0
+      primary-for QLibrary (0x0x7f3bf878e8f0)
+
+Class QVersionNumber::SegmentStorage
+   size=8 align=8
+   base size=8 base align=8
+QVersionNumber::SegmentStorage (0x0x7f3bf87b1d80) 0
+
+Class QVersionNumber
+   size=8 align=8
+   base size=8 base align=8
+QVersionNumber (0x0x7f3bf87b18a0) 0
+
+Class QLibraryInfo
+   size=1 align=1
+   base size=0 base align=1
+QLibraryInfo (0x0x7f3bf8481540) 0 empty
+
+Class QPoint
+   size=8 align=4
+   base size=8 base align=4
+QPoint (0x0x7f3bf84815a0) 0
+
+Class QPointF
+   size=16 align=8
+   base size=16 base align=8
+QPointF (0x0x7f3bf84f9420) 0
+
+Class QLine
+   size=16 align=4
+   base size=16 base align=4
+QLine (0x0x7f3bf856a600) 0
+
+Class QLineF
+   size=32 align=8
+   base size=32 base align=8
+QLineF (0x0x7f3bf85d79c0) 0
+
+Class QLinkedListData
+   size=32 align=8
+   base size=25 base align=8
+QLinkedListData (0x0x7f3bf8654c60) 0
+
+Class QLockFile
+   size=8 align=8
+   base size=8 base align=8
+QLockFile (0x0x7f3bf831a1e0) 0
+
+Class QLoggingCategory::AtomicBools
+   size=4 align=1
+   base size=4 base align=1
+QLoggingCategory::AtomicBools (0x0x7f3bf831a420) 0
+
+Class QLoggingCategory
+   size=24 align=8
+   base size=24 base align=8
+QLoggingCategory (0x0x7f3bf831a3c0) 0
+
+Class QMargins
+   size=16 align=4
+   base size=16 base align=4
+QMargins (0x0x7f3bf831a840) 0
+
+Class QMarginsF
+   size=32 align=8
+   base size=32 base align=8
+QMarginsF (0x0x7f3bf83d8780) 0
+
+Class QMessageAuthenticationCode
+   size=8 align=8
+   base size=8 base align=8
+QMessageAuthenticationCode (0x0x7f3bf8221f60) 0
+
+Class QMetaMethod
+   size=16 align=8
+   base size=12 base align=8
+QMetaMethod (0x0x7f3bf8248000) 0
+
+Class QMetaEnum
+   size=16 align=8
+   base size=12 base align=8
+QMetaEnum (0x0x7f3bf7e2a840) 0
+
+Class QMetaProperty
+   size=32 align=8
+   base size=32 base align=8
+QMetaProperty (0x0x7f3bf7e6ea20) 0
+
+Class QMetaClassInfo
+   size=16 align=8
+   base size=12 base align=8
+QMetaClassInfo (0x0x7f3bf7e6eb40) 0
+
+Class QMimeData::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QMimeData::QPrivateSignal (0x0x7f3bf7ec9120) 0 empty
+
+Vtable for QMimeData
+QMimeData::_ZTV9QMimeData: 17 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI9QMimeData)
+16    (int (*)(...))QMimeData::metaObject
+24    (int (*)(...))QMimeData::qt_metacast
+32    (int (*)(...))QMimeData::qt_metacall
+40    (int (*)(...))QMimeData::~QMimeData
+48    (int (*)(...))QMimeData::~QMimeData
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QMimeData::hasFormat
+120   (int (*)(...))QMimeData::formats
+128   (int (*)(...))QMimeData::retrieveData
+
+Class QMimeData
+   size=16 align=8
+   base size=16 base align=8
+QMimeData (0x0x7f3bf7ec1548) 0
+    vptr=((& QMimeData::_ZTV9QMimeData) + 16)
+  QObject (0x0x7f3bf7ec90c0) 0
+      primary-for QMimeData (0x0x7f3bf7ec1548)
+
+Class QMimeType
+   size=8 align=8
+   base size=8 base align=8
+QMimeType (0x0x7f3bf7ec9300) 0
+
+Class QMimeDatabase
+   size=8 align=8
+   base size=8 base align=8
+QMimeDatabase (0x0x7f3bf7f97240) 0
+
+Class QObjectCleanupHandler::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QObjectCleanupHandler::QPrivateSignal (0x0x7f3bf7f97300) 0 empty
+
+Vtable for QObjectCleanupHandler
+QObjectCleanupHandler::_ZTV21QObjectCleanupHandler: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI21QObjectCleanupHandler)
+16    (int (*)(...))QObjectCleanupHandler::metaObject
+24    (int (*)(...))QObjectCleanupHandler::qt_metacast
+32    (int (*)(...))QObjectCleanupHandler::qt_metacall
+40    (int (*)(...))QObjectCleanupHandler::~QObjectCleanupHandler
+48    (int (*)(...))QObjectCleanupHandler::~QObjectCleanupHandler
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QObjectCleanupHandler
+   size=24 align=8
+   base size=24 base align=8
+QObjectCleanupHandler (0x0x7f3bf7f990d0) 0
+    vptr=((& QObjectCleanupHandler::_ZTV21QObjectCleanupHandler) + 16)
+  QObject (0x0x7f3bf7f972a0) 0
+      primary-for QObjectCleanupHandler (0x0x7f3bf7f990d0)
+
+Class QOperatingSystemVersion
+   size=16 align=4
+   base size=16 base align=4
+QOperatingSystemVersion (0x0x7f3bf7f97420) 0
+
+Class QParallelAnimationGroup::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QParallelAnimationGroup::QPrivateSignal (0x0x7f3bf7c08ba0) 0 empty
+
+Vtable for QParallelAnimationGroup
+QParallelAnimationGroup::_ZTV23QParallelAnimationGroup: 18 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI23QParallelAnimationGroup)
+16    (int (*)(...))QParallelAnimationGroup::metaObject
+24    (int (*)(...))QParallelAnimationGroup::qt_metacast
+32    (int (*)(...))QParallelAnimationGroup::qt_metacall
+40    (int (*)(...))QParallelAnimationGroup::~QParallelAnimationGroup
+48    (int (*)(...))QParallelAnimationGroup::~QParallelAnimationGroup
+56    (int (*)(...))QParallelAnimationGroup::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QParallelAnimationGroup::duration
+120   (int (*)(...))QParallelAnimationGroup::updateCurrentTime
+128   (int (*)(...))QParallelAnimationGroup::updateState
+136   (int (*)(...))QParallelAnimationGroup::updateDirection
+
+Class QParallelAnimationGroup
+   size=16 align=8
+   base size=16 base align=8
+QParallelAnimationGroup (0x0x7f3bf7c12958) 0
+    vptr=((& QParallelAnimationGroup::_ZTV23QParallelAnimationGroup) + 16)
+  QAnimationGroup (0x0x7f3bf7c129c0) 0
+      primary-for QParallelAnimationGroup (0x0x7f3bf7c12958)
+    QAbstractAnimation (0x0x7f3bf7c12a28) 0
+        primary-for QAnimationGroup (0x0x7f3bf7c129c0)
+      QObject (0x0x7f3bf7c08b40) 0
+          primary-for QAbstractAnimation (0x0x7f3bf7c12a28)
+
+Class QPauseAnimation::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QPauseAnimation::QPrivateSignal (0x0x7f3bf7c08de0) 0 empty
+
+Vtable for QPauseAnimation
+QPauseAnimation::_ZTV15QPauseAnimation: 18 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI15QPauseAnimation)
+16    (int (*)(...))QPauseAnimation::metaObject
+24    (int (*)(...))QPauseAnimation::qt_metacast
+32    (int (*)(...))QPauseAnimation::qt_metacall
+40    (int (*)(...))QPauseAnimation::~QPauseAnimation
+48    (int (*)(...))QPauseAnimation::~QPauseAnimation
+56    (int (*)(...))QPauseAnimation::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QPauseAnimation::duration
+120   (int (*)(...))QPauseAnimation::updateCurrentTime
+128   (int (*)(...))QAbstractAnimation::updateState
+136   (int (*)(...))QAbstractAnimation::updateDirection
+
+Class QPauseAnimation
+   size=16 align=8
+   base size=16 base align=8
+QPauseAnimation (0x0x7f3bf7c12a90) 0
+    vptr=((& QPauseAnimation::_ZTV15QPauseAnimation) + 16)
+  QAbstractAnimation (0x0x7f3bf7c12af8) 0
+      primary-for QPauseAnimation (0x0x7f3bf7c12a90)
+    QObject (0x0x7f3bf7c08d80) 0
+        primary-for QAbstractAnimation (0x0x7f3bf7c12af8)
+
+Class QStaticPlugin
+   size=16 align=8
+   base size=16 base align=8
+QStaticPlugin (0x0x7f3bf7c39960) 0
+
+Class QPluginLoader::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QPluginLoader::QPrivateSignal (0x0x7f3bf7c84ae0) 0 empty
+
+Vtable for QPluginLoader
+QPluginLoader::_ZTV13QPluginLoader: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI13QPluginLoader)
+16    (int (*)(...))QPluginLoader::metaObject
+24    (int (*)(...))QPluginLoader::qt_metacast
+32    (int (*)(...))QPluginLoader::qt_metacall
+40    (int (*)(...))QPluginLoader::~QPluginLoader
+48    (int (*)(...))QPluginLoader::~QPluginLoader
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QPluginLoader
+   size=32 align=8
+   base size=25 base align=8
+QPluginLoader (0x0x7f3bf7c79e38) 0
+    vptr=((& QPluginLoader::_ZTV13QPluginLoader) + 16)
+  QObject (0x0x7f3bf7c84a80) 0
+      primary-for QPluginLoader (0x0x7f3bf7c79e38)
+
+Class QProcessEnvironment
+   size=8 align=8
+   base size=8 base align=8
+QProcessEnvironment (0x0x7f3bf7c84c00) 0
+
+Class QProcess::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QProcess::QPrivateSignal (0x0x7f3bf7d670c0) 0 empty
+
+Vtable for QProcess
+QProcess::_ZTV8QProcess: 31 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI8QProcess)
+16    (int (*)(...))QProcess::metaObject
+24    (int (*)(...))QProcess::qt_metacast
+32    (int (*)(...))QProcess::qt_metacall
+40    (int (*)(...))QProcess::~QProcess
+48    (int (*)(...))QProcess::~QProcess
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QProcess::isSequential
+120   (int (*)(...))QProcess::open
+128   (int (*)(...))QProcess::close
+136   (int (*)(...))QIODevice::pos
+144   (int (*)(...))QIODevice::size
+152   (int (*)(...))QIODevice::seek
+160   (int (*)(...))QProcess::atEnd
+168   (int (*)(...))QIODevice::reset
+176   (int (*)(...))QProcess::bytesAvailable
+184   (int (*)(...))QProcess::bytesToWrite
+192   (int (*)(...))QProcess::canReadLine
+200   (int (*)(...))QProcess::waitForReadyRead
+208   (int (*)(...))QProcess::waitForBytesWritten
+216   (int (*)(...))QProcess::readData
+224   (int (*)(...))QIODevice::readLineData
+232   (int (*)(...))QProcess::writeData
+240   (int (*)(...))QProcess::setupChildProcess
+
+Class QProcess
+   size=16 align=8
+   base size=16 base align=8
+QProcess (0x0x7f3bf7d632d8) 0
+    vptr=((& QProcess::_ZTV8QProcess) + 16)
+  QIODevice (0x0x7f3bf7d63340) 0
+      primary-for QProcess (0x0x7f3bf7d632d8)
+    QObject (0x0x7f3bf7d67060) 0
+        primary-for QIODevice (0x0x7f3bf7d63340)
+
+Class QVariantAnimation::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QVariantAnimation::QPrivateSignal (0x0x7f3bf7d67780) 0 empty
+
+Vtable for QVariantAnimation
+QVariantAnimation::_ZTV17QVariantAnimation: 20 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI17QVariantAnimation)
+16    (int (*)(...))QVariantAnimation::metaObject
+24    (int (*)(...))QVariantAnimation::qt_metacast
+32    (int (*)(...))QVariantAnimation::qt_metacall
+40    (int (*)(...))QVariantAnimation::~QVariantAnimation
+48    (int (*)(...))QVariantAnimation::~QVariantAnimation
+56    (int (*)(...))QVariantAnimation::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QVariantAnimation::duration
+120   (int (*)(...))QVariantAnimation::updateCurrentTime
+128   (int (*)(...))QVariantAnimation::updateState
+136   (int (*)(...))QAbstractAnimation::updateDirection
+144   (int (*)(...))QVariantAnimation::updateCurrentValue
+152   (int (*)(...))QVariantAnimation::interpolated
+
+Class QVariantAnimation
+   size=16 align=8
+   base size=16 base align=8
+QVariantAnimation (0x0x7f3bf7d633a8) 0
+    vptr=((& QVariantAnimation::_ZTV17QVariantAnimation) + 16)
+  QAbstractAnimation (0x0x7f3bf7d63410) 0
+      primary-for QVariantAnimation (0x0x7f3bf7d633a8)
+    QObject (0x0x7f3bf7d67720) 0
+        primary-for QAbstractAnimation (0x0x7f3bf7d63410)
+
+Class QPropertyAnimation::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QPropertyAnimation::QPrivateSignal (0x0x7f3bf7d67a20) 0 empty
+
+Vtable for QPropertyAnimation
+QPropertyAnimation::_ZTV18QPropertyAnimation: 20 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI18QPropertyAnimation)
+16    (int (*)(...))QPropertyAnimation::metaObject
+24    (int (*)(...))QPropertyAnimation::qt_metacast
+32    (int (*)(...))QPropertyAnimation::qt_metacall
+40    (int (*)(...))QPropertyAnimation::~QPropertyAnimation
+48    (int (*)(...))QPropertyAnimation::~QPropertyAnimation
+56    (int (*)(...))QPropertyAnimation::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QVariantAnimation::duration
+120   (int (*)(...))QVariantAnimation::updateCurrentTime
+128   (int (*)(...))QPropertyAnimation::updateState
+136   (int (*)(...))QAbstractAnimation::updateDirection
+144   (int (*)(...))QPropertyAnimation::updateCurrentValue
+152   (int (*)(...))QVariantAnimation::interpolated
+
+Class QPropertyAnimation
+   size=16 align=8
+   base size=16 base align=8
+QPropertyAnimation (0x0x7f3bf7d634e0) 0
+    vptr=((& QPropertyAnimation::_ZTV18QPropertyAnimation) + 16)
+  QVariantAnimation (0x0x7f3bf7d63548) 0
+      primary-for QPropertyAnimation (0x0x7f3bf7d634e0)
+    QAbstractAnimation (0x0x7f3bf7d635b0) 0
+        primary-for QVariantAnimation (0x0x7f3bf7d63548)
+      QObject (0x0x7f3bf7d679c0) 0
+          primary-for QAbstractAnimation (0x0x7f3bf7d635b0)
+
+Class std::random_device
+   size=5000 align=8
+   base size=5000 base align=8
+std::random_device (0x0x7f3bf7a39180) 0
+
+Class std::bernoulli_distribution::param_type
+   size=8 align=8
+   base size=8 base align=8
+std::bernoulli_distribution::param_type (0x0x7f3bf7b13ea0) 0
+
+Class std::bernoulli_distribution
+   size=8 align=8
+   base size=8 base align=8
+std::bernoulli_distribution (0x0x7f3bf7b13e40) 0
+
+Class std::seed_seq
+   size=24 align=8
+   base size=24 base align=8
+std::seed_seq (0x0x7f3bf7901c00) 0
+
+Class QRandomGenerator::Storage
+   size=2504 align=8
+   base size=2504 base align=8
+QRandomGenerator::Storage (0x0x7f3bf773f8a0) 0
+
+Class QRandomGenerator
+   size=2512 align=8
+   base size=2512 base align=8
+QRandomGenerator (0x0x7f3bf773f840) 0
+
+Class QRandomGenerator64
+   size=2512 align=8
+   base size=2512 base align=8
+QRandomGenerator64 (0x0x7f3bf77d6270) 0
+  QRandomGenerator (0x0x7f3bf77e93c0) 0
+
+Class QReadWriteLock
+   size=8 align=8
+   base size=8 base align=8
+QReadWriteLock (0x0x7f3bf77e9f60) 0
+
+Class QReadLocker
+   size=8 align=8
+   base size=8 base align=8
+QReadLocker (0x0x7f3bf7408240) 0
+
+Class QWriteLocker
+   size=8 align=8
+   base size=8 base align=8
+QWriteLocker (0x0x7f3bf7408720) 0
+
+Class QSize
+   size=8 align=4
+   base size=8 base align=4
+QSize (0x0x7f3bf7408c00) 0
+
+Class QSizeF
+   size=16 align=8
+   base size=16 base align=8
+QSizeF (0x0x7f3bf74ddae0) 0
+
+Class QRect
+   size=16 align=4
+   base size=16 base align=4
+QRect (0x0x7f3bf7558b40) 0
+
+Class QRectF
+   size=32 align=8
+   base size=32 base align=8
+QRectF (0x0x7f3bf7208ba0) 0
+
+Class QResource
+   size=8 align=8
+   base size=8 base align=8
+QResource (0x0x7f3bf72c9cc0) 0
+
+Class QSaveFile::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QSaveFile::QPrivateSignal (0x0x7f3bf72c9f60) 0 empty
+
+Vtable for QSaveFile
+QSaveFile::_ZTV9QSaveFile: 34 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI9QSaveFile)
+16    (int (*)(...))QSaveFile::metaObject
+24    (int (*)(...))QSaveFile::qt_metacast
+32    (int (*)(...))QSaveFile::qt_metacall
+40    (int (*)(...))QSaveFile::~QSaveFile
+48    (int (*)(...))QSaveFile::~QSaveFile
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QFileDevice::isSequential
+120   (int (*)(...))QSaveFile::open
+128   (int (*)(...))QSaveFile::close
+136   (int (*)(...))QFileDevice::pos
+144   (int (*)(...))QFileDevice::size
+152   (int (*)(...))QFileDevice::seek
+160   (int (*)(...))QFileDevice::atEnd
+168   (int (*)(...))QIODevice::reset
+176   (int (*)(...))QIODevice::bytesAvailable
+184   (int (*)(...))QIODevice::bytesToWrite
+192   (int (*)(...))QIODevice::canReadLine
+200   (int (*)(...))QIODevice::waitForReadyRead
+208   (int (*)(...))QIODevice::waitForBytesWritten
+216   (int (*)(...))QFileDevice::readData
+224   (int (*)(...))QFileDevice::readLineData
+232   (int (*)(...))QSaveFile::writeData
+240   (int (*)(...))QSaveFile::fileName
+248   (int (*)(...))QFileDevice::resize
+256   (int (*)(...))QFileDevice::permissions
+264   (int (*)(...))QFileDevice::setPermissions
+
+Class QSaveFile
+   size=16 align=8
+   base size=16 base align=8
+QSaveFile (0x0x7f3bf7289c30) 0
+    vptr=((& QSaveFile::_ZTV9QSaveFile) + 16)
+  QFileDevice (0x0x7f3bf7289c98) 0
+      primary-for QSaveFile (0x0x7f3bf7289c30)
+    QIODevice (0x0x7f3bf7289d00) 0
+        primary-for QFileDevice (0x0x7f3bf7289c98)
+      QObject (0x0x7f3bf72c9f00) 0
+          primary-for QIODevice (0x0x7f3bf7289d00)
+
+Class QSemaphore
+   size=8 align=8
+   base size=8 base align=8
+QSemaphore (0x0x7f3bf73205a0) 0
+
+Class QSemaphoreReleaser
+   size=16 align=8
+   base size=12 base align=8
+QSemaphoreReleaser (0x0x7f3bf7320720) 0
+
+Class QSequentialAnimationGroup::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QSequentialAnimationGroup::QPrivateSignal (0x0x7f3bf73f3360) 0 empty
+
+Vtable for QSequentialAnimationGroup
+QSequentialAnimationGroup::_ZTV25QSequentialAnimationGroup: 18 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI25QSequentialAnimationGroup)
+16    (int (*)(...))QSequentialAnimationGroup::metaObject
+24    (int (*)(...))QSequentialAnimationGroup::qt_metacast
+32    (int (*)(...))QSequentialAnimationGroup::qt_metacall
+40    (int (*)(...))QSequentialAnimationGroup::~QSequentialAnimationGroup
+48    (int (*)(...))QSequentialAnimationGroup::~QSequentialAnimationGroup
+56    (int (*)(...))QSequentialAnimationGroup::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QSequentialAnimationGroup::duration
+120   (int (*)(...))QSequentialAnimationGroup::updateCurrentTime
+128   (int (*)(...))QSequentialAnimationGroup::updateState
+136   (int (*)(...))QSequentialAnimationGroup::updateDirection
+
+Class QSequentialAnimationGroup
+   size=16 align=8
+   base size=16 base align=8
+QSequentialAnimationGroup (0x0x7f3bf73f54e0) 0
+    vptr=((& QSequentialAnimationGroup::_ZTV25QSequentialAnimationGroup) + 16)
+  QAnimationGroup (0x0x7f3bf73f5548) 0
+      primary-for QSequentialAnimationGroup (0x0x7f3bf73f54e0)
+    QAbstractAnimation (0x0x7f3bf73f55b0) 0
+        primary-for QAnimationGroup (0x0x7f3bf73f5548)
+      QObject (0x0x7f3bf73f3300) 0
+          primary-for QAbstractAnimation (0x0x7f3bf73f55b0)
+
+Class QSettings::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QSettings::QPrivateSignal (0x0x7f3bf73f35a0) 0 empty
+
+Vtable for QSettings
+QSettings::_ZTV9QSettings: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI9QSettings)
+16    (int (*)(...))QSettings::metaObject
+24    (int (*)(...))QSettings::qt_metacast
+32    (int (*)(...))QSettings::qt_metacall
+40    (int (*)(...))QSettings::~QSettings
+48    (int (*)(...))QSettings::~QSettings
+56    (int (*)(...))QSettings::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QSettings
+   size=16 align=8
+   base size=16 base align=8
+QSettings (0x0x7f3bf73f5618) 0
+    vptr=((& QSettings::_ZTV9QSettings) + 16)
+  QObject (0x0x7f3bf73f3540) 0
+      primary-for QSettings (0x0x7f3bf73f5618)
+
+Class QSharedMemory::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QSharedMemory::QPrivateSignal (0x0x7f3bf73f3a20) 0 empty
+
+Vtable for QSharedMemory
+QSharedMemory::_ZTV13QSharedMemory: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI13QSharedMemory)
+16    (int (*)(...))QSharedMemory::metaObject
+24    (int (*)(...))QSharedMemory::qt_metacast
+32    (int (*)(...))QSharedMemory::qt_metacall
+40    (int (*)(...))QSharedMemory::~QSharedMemory
+48    (int (*)(...))QSharedMemory::~QSharedMemory
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QSharedMemory
+   size=16 align=8
+   base size=16 base align=8
+QSharedMemory (0x0x7f3bf73f5680) 0
+    vptr=((& QSharedMemory::_ZTV13QSharedMemory) + 16)
+  QObject (0x0x7f3bf73f39c0) 0
+      primary-for QSharedMemory (0x0x7f3bf73f5680)
+
+Class QSignalMapper::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QSignalMapper::QPrivateSignal (0x0x7f3bf73f3c60) 0 empty
+
+Vtable for QSignalMapper
+QSignalMapper::_ZTV13QSignalMapper: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI13QSignalMapper)
+16    (int (*)(...))QSignalMapper::metaObject
+24    (int (*)(...))QSignalMapper::qt_metacast
+32    (int (*)(...))QSignalMapper::qt_metacall
+40    (int (*)(...))QSignalMapper::~QSignalMapper
+48    (int (*)(...))QSignalMapper::~QSignalMapper
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QSignalMapper
+   size=16 align=8
+   base size=16 base align=8
+QSignalMapper (0x0x7f3bf73f56e8) 0
+    vptr=((& QSignalMapper::_ZTV13QSignalMapper) + 16)
+  QObject (0x0x7f3bf73f3c00) 0
+      primary-for QSignalMapper (0x0x7f3bf73f56e8)
+
+Class QSignalTransition::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QSignalTransition::QPrivateSignal (0x0x7f3bf73f3ea0) 0 empty
+
+Vtable for QSignalTransition
+QSignalTransition::_ZTV17QSignalTransition: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI17QSignalTransition)
+16    (int (*)(...))QSignalTransition::metaObject
+24    (int (*)(...))QSignalTransition::qt_metacast
+32    (int (*)(...))QSignalTransition::qt_metacall
+40    (int (*)(...))QSignalTransition::~QSignalTransition
+48    (int (*)(...))QSignalTransition::~QSignalTransition
+56    (int (*)(...))QSignalTransition::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QSignalTransition::eventTest
+120   (int (*)(...))QSignalTransition::onTransition
+
+Class QSignalTransition
+   size=16 align=8
+   base size=16 base align=8
+QSignalTransition (0x0x7f3bf73f5750) 0
+    vptr=((& QSignalTransition::_ZTV17QSignalTransition) + 16)
+  QAbstractTransition (0x0x7f3bf73f57b8) 0
+      primary-for QSignalTransition (0x0x7f3bf73f5750)
+    QObject (0x0x7f3bf73f3e40) 0
+        primary-for QAbstractTransition (0x0x7f3bf73f57b8)
+
+Class QSocketNotifier::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QSocketNotifier::QPrivateSignal (0x0x7f3bf705c180) 0 empty
+
+Vtable for QSocketNotifier
+QSocketNotifier::_ZTV15QSocketNotifier: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI15QSocketNotifier)
+16    (int (*)(...))QSocketNotifier::metaObject
+24    (int (*)(...))QSocketNotifier::qt_metacast
+32    (int (*)(...))QSocketNotifier::qt_metacall
+40    (int (*)(...))QSocketNotifier::~QSocketNotifier
+48    (int (*)(...))QSocketNotifier::~QSocketNotifier
+56    (int (*)(...))QSocketNotifier::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QSocketNotifier
+   size=16 align=8
+   base size=16 base align=8
+QSocketNotifier (0x0x7f3bf73f5820) 0
+    vptr=((& QSocketNotifier::_ZTV15QSocketNotifier) + 16)
+  QObject (0x0x7f3bf705c120) 0
+      primary-for QSocketNotifier (0x0x7f3bf73f5820)
+
+Class QSortFilterProxyModel::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QSortFilterProxyModel::QPrivateSignal (0x0x7f3bf705c3c0) 0 empty
+
+Vtable for QSortFilterProxyModel
+QSortFilterProxyModel::_ZTV21QSortFilterProxyModel: 56 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI21QSortFilterProxyModel)
+16    (int (*)(...))QSortFilterProxyModel::metaObject
+24    (int (*)(...))QSortFilterProxyModel::qt_metacast
+32    (int (*)(...))QSortFilterProxyModel::qt_metacall
+40    (int (*)(...))QSortFilterProxyModel::~QSortFilterProxyModel
+48    (int (*)(...))QSortFilterProxyModel::~QSortFilterProxyModel
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QSortFilterProxyModel::index
+120   (int (*)(...))QSortFilterProxyModel::parent
+128   (int (*)(...))QSortFilterProxyModel::sibling
+136   (int (*)(...))QSortFilterProxyModel::rowCount
+144   (int (*)(...))QSortFilterProxyModel::columnCount
+152   (int (*)(...))QSortFilterProxyModel::hasChildren
+160   (int (*)(...))QSortFilterProxyModel::data
+168   (int (*)(...))QSortFilterProxyModel::setData
+176   (int (*)(...))QSortFilterProxyModel::headerData
+184   (int (*)(...))QSortFilterProxyModel::setHeaderData
+192   (int (*)(...))QAbstractProxyModel::itemData
+200   (int (*)(...))QAbstractProxyModel::setItemData
+208   (int (*)(...))QSortFilterProxyModel::mimeTypes
+216   (int (*)(...))QSortFilterProxyModel::mimeData
+224   (int (*)(...))QAbstractProxyModel::canDropMimeData
+232   (int (*)(...))QSortFilterProxyModel::dropMimeData
+240   (int (*)(...))QSortFilterProxyModel::supportedDropActions
+248   (int (*)(...))QAbstractProxyModel::supportedDragActions
+256   (int (*)(...))QSortFilterProxyModel::insertRows
+264   (int (*)(...))QSortFilterProxyModel::insertColumns
+272   (int (*)(...))QSortFilterProxyModel::removeRows
+280   (int (*)(...))QSortFilterProxyModel::removeColumns
+288   (int (*)(...))QAbstractItemModel::moveRows
+296   (int (*)(...))QAbstractItemModel::moveColumns
+304   (int (*)(...))QSortFilterProxyModel::fetchMore
+312   (int (*)(...))QSortFilterProxyModel::canFetchMore
+320   (int (*)(...))QSortFilterProxyModel::flags
+328   (int (*)(...))QSortFilterProxyModel::sort
+336   (int (*)(...))QSortFilterProxyModel::buddy
+344   (int (*)(...))QSortFilterProxyModel::match
+352   (int (*)(...))QSortFilterProxyModel::span
+360   (int (*)(...))QAbstractItemModel::roleNames
+368   (int (*)(...))QAbstractProxyModel::submit
+376   (int (*)(...))QAbstractProxyModel::revert
+384   (int (*)(...))QSortFilterProxyModel::setSourceModel
+392   (int (*)(...))QSortFilterProxyModel::mapToSource
+400   (int (*)(...))QSortFilterProxyModel::mapFromSource
+408   (int (*)(...))QSortFilterProxyModel::mapSelectionToSource
+416   (int (*)(...))QSortFilterProxyModel::mapSelectionFromSource
+424   (int (*)(...))QSortFilterProxyModel::filterAcceptsRow
+432   (int (*)(...))QSortFilterProxyModel::filterAcceptsColumn
+440   (int (*)(...))QSortFilterProxyModel::lessThan
+
+Class QSortFilterProxyModel
+   size=16 align=8
+   base size=16 base align=8
+QSortFilterProxyModel (0x0x7f3bf73f5888) 0
+    vptr=((& QSortFilterProxyModel::_ZTV21QSortFilterProxyModel) + 16)
+  QAbstractProxyModel (0x0x7f3bf73f58f0) 0
+      primary-for QSortFilterProxyModel (0x0x7f3bf73f5888)
+    QAbstractItemModel (0x0x7f3bf73f5958) 0
+        primary-for QAbstractProxyModel (0x0x7f3bf73f58f0)
+      QObject (0x0x7f3bf705c360) 0
+          primary-for QAbstractItemModel (0x0x7f3bf73f5958)
+
+Class QStandardPaths
+   size=1 align=1
+   base size=0 base align=1
+QStandardPaths (0x0x7f3bf705c7e0) 0 empty
+
+Class QState::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QState::QPrivateSignal (0x0x7f3bf70c7120) 0 empty
+
+Vtable for QState
+QState::_ZTV6QState: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI6QState)
+16    (int (*)(...))QState::metaObject
+24    (int (*)(...))QState::qt_metacast
+32    (int (*)(...))QState::qt_metacall
+40    (int (*)(...))QState::~QState
+48    (int (*)(...))QState::~QState
+56    (int (*)(...))QState::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QState::onEntry
+120   (int (*)(...))QState::onExit
+
+Class QState
+   size=16 align=8
+   base size=16 base align=8
+QState (0x0x7f3bf73f5af8) 0
+    vptr=((& QState::_ZTV6QState) + 16)
+  QAbstractState (0x0x7f3bf73f5b60) 0
+      primary-for QState (0x0x7f3bf73f5af8)
+    QObject (0x0x7f3bf70c70c0) 0
+        primary-for QAbstractState (0x0x7f3bf73f5b60)
+
+Class QStateMachine::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QStateMachine::QPrivateSignal (0x0x7f3bf70c75a0) 0 empty
+
+Vtable for QStateMachine::SignalEvent
+QStateMachine::SignalEvent::_ZTVN13QStateMachine11SignalEventE: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTIN13QStateMachine11SignalEventE)
+16    (int (*)(...))QStateMachine::SignalEvent::~SignalEvent
+24    (int (*)(...))QStateMachine::SignalEvent::~SignalEvent
+
+Class QStateMachine::SignalEvent
+   size=48 align=8
+   base size=48 base align=8
+QStateMachine::SignalEvent (0x0x7f3bf73f5d00) 0
+    vptr=((& QStateMachine::SignalEvent::_ZTVN13QStateMachine11SignalEventE) + 16)
+  QEvent (0x0x7f3bf70c7600) 0
+      primary-for QStateMachine::SignalEvent (0x0x7f3bf73f5d00)
+
+Vtable for QStateMachine::WrappedEvent
+QStateMachine::WrappedEvent::_ZTVN13QStateMachine12WrappedEventE: 4 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTIN13QStateMachine12WrappedEventE)
+16    (int (*)(...))QStateMachine::WrappedEvent::~WrappedEvent
+24    (int (*)(...))QStateMachine::WrappedEvent::~WrappedEvent
+
+Class QStateMachine::WrappedEvent
+   size=40 align=8
+   base size=40 base align=8
+QStateMachine::WrappedEvent (0x0x7f3bf73f5d68) 0
+    vptr=((& QStateMachine::WrappedEvent::_ZTVN13QStateMachine12WrappedEventE) + 16)
+  QEvent (0x0x7f3bf70c7660) 0
+      primary-for QStateMachine::WrappedEvent (0x0x7f3bf73f5d68)
+
+Vtable for QStateMachine
+QStateMachine::_ZTV13QStateMachine: 20 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI13QStateMachine)
+16    (int (*)(...))QStateMachine::metaObject
+24    (int (*)(...))QStateMachine::qt_metacast
+32    (int (*)(...))QStateMachine::qt_metacall
+40    (int (*)(...))QStateMachine::~QStateMachine
+48    (int (*)(...))QStateMachine::~QStateMachine
+56    (int (*)(...))QStateMachine::event
+64    (int (*)(...))QStateMachine::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QStateMachine::onEntry
+120   (int (*)(...))QStateMachine::onExit
+128   (int (*)(...))QStateMachine::beginSelectTransitions
+136   (int (*)(...))QStateMachine::endSelectTransitions
+144   (int (*)(...))QStateMachine::beginMicrostep
+152   (int (*)(...))QStateMachine::endMicrostep
+
+Class QStateMachine
+   size=16 align=8
+   base size=16 base align=8
+QStateMachine (0x0x7f3bf73f5bc8) 0
+    vptr=((& QStateMachine::_ZTV13QStateMachine) + 16)
+  QState (0x0x7f3bf73f5c30) 0
+      primary-for QStateMachine (0x0x7f3bf73f5bc8)
+    QAbstractState (0x0x7f3bf73f5c98) 0
+        primary-for QState (0x0x7f3bf73f5c30)
+      QObject (0x0x7f3bf70c7540) 0
+          primary-for QAbstractState (0x0x7f3bf73f5c98)
+
+Class QStorageInfo
+   size=8 align=8
+   base size=8 base align=8
+QStorageInfo (0x0x7f3bf70c7a20) 0
+
+Class QAbstractConcatenable
+   size=1 align=1
+   base size=0 base align=1
+QAbstractConcatenable (0x0x7f3bf71ea7e0) 0 empty
+
+Class QStringListModel::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QStringListModel::QPrivateSignal (0x0x7f3bf6e72b40) 0 empty
+
+Vtable for QStringListModel
+QStringListModel::_ZTV16QStringListModel: 48 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI16QStringListModel)
+16    (int (*)(...))QStringListModel::metaObject
+24    (int (*)(...))QStringListModel::qt_metacast
+32    (int (*)(...))QStringListModel::qt_metacall
+40    (int (*)(...))QStringListModel::~QStringListModel
+48    (int (*)(...))QStringListModel::~QStringListModel
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QAbstractListModel::index
+120   (int (*)(...))QAbstractListModel::parent
+128   (int (*)(...))QStringListModel::sibling
+136   (int (*)(...))QStringListModel::rowCount
+144   (int (*)(...))QAbstractListModel::columnCount
+152   (int (*)(...))QAbstractListModel::hasChildren
+160   (int (*)(...))QStringListModel::data
+168   (int (*)(...))QStringListModel::setData
+176   (int (*)(...))QAbstractItemModel::headerData
+184   (int (*)(...))QAbstractItemModel::setHeaderData
+192   (int (*)(...))QStringListModel::itemData
+200   (int (*)(...))QStringListModel::setItemData
+208   (int (*)(...))QAbstractItemModel::mimeTypes
+216   (int (*)(...))QAbstractItemModel::mimeData
+224   (int (*)(...))QAbstractItemModel::canDropMimeData
+232   (int (*)(...))QAbstractListModel::dropMimeData
+240   (int (*)(...))QStringListModel::supportedDropActions
+248   (int (*)(...))QAbstractItemModel::supportedDragActions
+256   (int (*)(...))QStringListModel::insertRows
+264   (int (*)(...))QAbstractItemModel::insertColumns
+272   (int (*)(...))QStringListModel::removeRows
+280   (int (*)(...))QAbstractItemModel::removeColumns
+288   (int (*)(...))QStringListModel::moveRows
+296   (int (*)(...))QAbstractItemModel::moveColumns
+304   (int (*)(...))QAbstractItemModel::fetchMore
+312   (int (*)(...))QAbstractItemModel::canFetchMore
+320   (int (*)(...))QStringListModel::flags
+328   (int (*)(...))QStringListModel::sort
+336   (int (*)(...))QAbstractItemModel::buddy
+344   (int (*)(...))QAbstractItemModel::match
+352   (int (*)(...))QAbstractItemModel::span
+360   (int (*)(...))QAbstractItemModel::roleNames
+368   (int (*)(...))QAbstractItemModel::submit
+376   (int (*)(...))QAbstractItemModel::revert
+
+Class QStringListModel
+   size=24 align=8
+   base size=24 base align=8
+QStringListModel (0x0x7f3bf6e6f680) 0
+    vptr=((& QStringListModel::_ZTV16QStringListModel) + 16)
+  QAbstractListModel (0x0x7f3bf6e6f6e8) 0
+      primary-for QStringListModel (0x0x7f3bf6e6f680)
+    QAbstractItemModel (0x0x7f3bf6e6f750) 0
+        primary-for QAbstractListModel (0x0x7f3bf6e6f6e8)
+      QObject (0x0x7f3bf6e72ae0) 0
+          primary-for QAbstractItemModel (0x0x7f3bf6e6f750)
+
+Class QSystemSemaphore
+   size=8 align=8
+   base size=8 base align=8
+QSystemSemaphore (0x0x7f3bf6e72c60) 0
+
+Class QTemporaryDir
+   size=8 align=8
+   base size=8 base align=8
+QTemporaryDir (0x0x7f3bf6e72d20) 0
+
+Class QTemporaryFile::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QTemporaryFile::QPrivateSignal (0x0x7f3bf6e72e40) 0 empty
+
+Vtable for QTemporaryFile
+QTemporaryFile::_ZTV14QTemporaryFile: 34 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI14QTemporaryFile)
+16    (int (*)(...))QTemporaryFile::metaObject
+24    (int (*)(...))QTemporaryFile::qt_metacast
+32    (int (*)(...))QTemporaryFile::qt_metacall
+40    (int (*)(...))QTemporaryFile::~QTemporaryFile
+48    (int (*)(...))QTemporaryFile::~QTemporaryFile
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QFileDevice::isSequential
+120   (int (*)(...))QTemporaryFile::open
+128   (int (*)(...))QFileDevice::close
+136   (int (*)(...))QFileDevice::pos
+144   (int (*)(...))QFile::size
+152   (int (*)(...))QFileDevice::seek
+160   (int (*)(...))QFileDevice::atEnd
+168   (int (*)(...))QIODevice::reset
+176   (int (*)(...))QIODevice::bytesAvailable
+184   (int (*)(...))QIODevice::bytesToWrite
+192   (int (*)(...))QIODevice::canReadLine
+200   (int (*)(...))QIODevice::waitForReadyRead
+208   (int (*)(...))QIODevice::waitForBytesWritten
+216   (int (*)(...))QFileDevice::readData
+224   (int (*)(...))QFileDevice::readLineData
+232   (int (*)(...))QFileDevice::writeData
+240   (int (*)(...))QTemporaryFile::fileName
+248   (int (*)(...))QFile::resize
+256   (int (*)(...))QFile::permissions
+264   (int (*)(...))QFile::setPermissions
+
+Class QTemporaryFile
+   size=16 align=8
+   base size=16 base align=8
+QTemporaryFile (0x0x7f3bf6e6f7b8) 0
+    vptr=((& QTemporaryFile::_ZTV14QTemporaryFile) + 16)
+  QFile (0x0x7f3bf6e6f820) 0
+      primary-for QTemporaryFile (0x0x7f3bf6e6f7b8)
+    QFileDevice (0x0x7f3bf6e6f888) 0
+        primary-for QFile (0x0x7f3bf6e6f820)
+      QIODevice (0x0x7f3bf6e6f8f0) 0
+          primary-for QFileDevice (0x0x7f3bf6e6f888)
+        QObject (0x0x7f3bf6e72de0) 0
+            primary-for QIODevice (0x0x7f3bf6e6f8f0)
+
+Class QTextBoundaryFinder
+   size=48 align=8
+   base size=48 base align=8
+QTextBoundaryFinder (0x0x7f3bf6ed01e0) 0
+
+Class QTextCodec::ConverterState
+   size=32 align=8
+   base size=32 base align=8
+QTextCodec::ConverterState (0x0x7f3bf6ed0a20) 0
+
+Vtable for QTextCodec
+QTextCodec::_ZTV10QTextCodec: 9 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI10QTextCodec)
+16    (int (*)(...))__cxa_pure_virtual
+24    (int (*)(...))QTextCodec::aliases
+32    (int (*)(...))__cxa_pure_virtual
+40    (int (*)(...))__cxa_pure_virtual
+48    (int (*)(...))__cxa_pure_virtual
+56    0
+64    0
+
+Class QTextCodec
+   size=8 align=8
+   base size=8 base align=8
+QTextCodec (0x0x7f3bf6ed09c0) 0 nearly-empty
+    vptr=((& QTextCodec::_ZTV10QTextCodec) + 16)
+
+Class QTextEncoder
+   size=40 align=8
+   base size=40 base align=8
+QTextEncoder (0x0x7f3bf6f35420) 0
+
+Class QTextDecoder
+   size=40 align=8
+   base size=40 base align=8
+QTextDecoder (0x0x7f3bf6f35600) 0
+
+Vtable for std::thread::_State
+std::thread::_State::_ZTVNSt6thread6_StateE: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTINSt6thread6_StateE)
+16    0
+24    0
+32    (int (*)(...))__cxa_pure_virtual
+
+Class std::thread::_State
+   size=8 align=8
+   base size=8 base align=8
+std::thread::_State (0x0x7f3bf6f35840) 0 nearly-empty
+    vptr=((& std::thread::_State::_ZTVNSt6thread6_StateE) + 16)
+
+Class std::thread::id
+   size=8 align=8
+   base size=8 base align=8
+std::thread::id (0x0x7f3bf6f358a0) 0
+
+Class std::thread
+   size=8 align=8
+   base size=8 base align=8
+std::thread (0x0x7f3bf6f357e0) 0
+
+Class std::condition_variable
+   size=48 align=8
+   base size=48 base align=8
+std::condition_variable (0x0x7f3bf6dd9c60) 0
+
+Class std::__at_thread_exit_elt
+   size=16 align=8
+   base size=16 base align=8
+std::__at_thread_exit_elt (0x0x7f3bf6a26060) 0
+
+Class std::_V2::condition_variable_any
+   size=64 align=8
+   base size=64 base align=8
+std::_V2::condition_variable_any (0x0x7f3bf6a260c0) 0
+
+Class std::__atomic_futex_unsigned_base
+   size=1 align=1
+   base size=0 base align=1
+std::__atomic_futex_unsigned_base (0x0x7f3bf6b8a3c0) 0 empty
+
+Vtable for std::future_error
+std::future_error::_ZTVSt12future_error: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTISt12future_error)
+16    (int (*)(...))std::future_error::~future_error
+24    (int (*)(...))std::future_error::~future_error
+32    (int (*)(...))std::future_error::what
+
+Class std::future_error
+   size=32 align=8
+   base size=32 base align=8
+std::future_error (0x0x7f3bf6b7bc98) 0
+    vptr=((& std::future_error::_ZTVSt12future_error) + 16)
+  std::logic_error (0x0x7f3bf6b7bd00) 0
+      primary-for std::future_error (0x0x7f3bf6b7bc98)
+    std::exception (0x0x7f3bf6b8aae0) 0 nearly-empty
+        primary-for std::logic_error (0x0x7f3bf6b7bd00)
+
+Class std::__future_base::_Result_base::_Deleter
+   size=1 align=1
+   base size=0 base align=1
+std::__future_base::_Result_base::_Deleter (0x0x7f3bf6bbd240) 0 empty
+
+Vtable for std::__future_base::_Result_base
+std::__future_base::_Result_base::_ZTVNSt13__future_base12_Result_baseE: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTINSt13__future_base12_Result_baseE)
+16    (int (*)(...))__cxa_pure_virtual
+24    0
+32    0
+
+Class std::__future_base::_Result_base
+   size=16 align=8
+   base size=16 base align=8
+std::__future_base::_Result_base (0x0x7f3bf6bbd1e0) 0
+    vptr=((& std::__future_base::_Result_base::_ZTVNSt13__future_base12_Result_baseE) + 16)
+
+Class std::__future_base::_State_baseV2::__exception_ptr_tag
+   size=1 align=1
+   base size=0 base align=1
+std::__future_base::_State_baseV2::__exception_ptr_tag (0x0x7f3bf699a960) 0 empty
+
+Class std::__future_base::_State_baseV2::_Make_ready
+   size=32 align=8
+   base size=32 base align=8
+std::__future_base::_State_baseV2::_Make_ready (0x0x7f3bf69a0548) 0
+  std::__at_thread_exit_elt (0x0x7f3bf699aa20) 0
+
+Vtable for std::__future_base::_State_baseV2
+std::__future_base::_State_baseV2::_ZTVNSt13__future_base13_State_baseV2E: 6 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTINSt13__future_base13_State_baseV2E)
+16    (int (*)(...))std::__future_base::_State_baseV2::~_State_baseV2
+24    (int (*)(...))std::__future_base::_State_baseV2::~_State_baseV2
+32    (int (*)(...))std::__future_base::_State_baseV2::_M_complete_async
+40    (int (*)(...))std::__future_base::_State_baseV2::_M_is_deferred_future
+
+Class std::__future_base::_State_baseV2
+   size=32 align=8
+   base size=28 base align=8
+std::__future_base::_State_baseV2 (0x0x7f3bf6bbd3c0) 0
+    vptr=((& std::__future_base::_State_baseV2::_ZTVNSt13__future_base13_State_baseV2E) + 16)
+
+Class std::__future_base
+   size=1 align=1
+   base size=0 base align=1
+std::__future_base (0x0x7f3bf6bbd180) 0 empty
+
+Vtable for std::__future_base::_Async_state_commonV2
+std::__future_base::_Async_state_commonV2::_ZTVNSt13__future_base21_Async_state_commonV2E: 6 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTINSt13__future_base21_Async_state_commonV2E)
+16    (int (*)(...))std::__future_base::_Async_state_commonV2::~_Async_state_commonV2
+24    (int (*)(...))std::__future_base::_Async_state_commonV2::~_Async_state_commonV2
+32    (int (*)(...))std::__future_base::_Async_state_commonV2::_M_complete_async
+40    (int (*)(...))std::__future_base::_State_baseV2::_M_is_deferred_future
+
+Class std::__future_base::_Async_state_commonV2
+   size=48 align=8
+   base size=44 base align=8
+std::__future_base::_Async_state_commonV2 (0x0x7f3bf6136270) 0
+    vptr=((& std::__future_base::_Async_state_commonV2::_ZTVNSt13__future_base21_Async_state_commonV2E) + 16)
+  std::__future_base::_State_baseV2 (0x0x7f3bf6143a20) 0
+      primary-for std::__future_base::_Async_state_commonV2 (0x0x7f3bf6136270)
+
+Class QThread::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QThread::QPrivateSignal (0x0x7f3bf6177300) 0 empty
+
+Vtable for QThread
+QThread::_ZTV7QThread: 15 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI7QThread)
+16    (int (*)(...))QThread::metaObject
+24    (int (*)(...))QThread::qt_metacast
+32    (int (*)(...))QThread::qt_metacall
+40    (int (*)(...))QThread::~QThread
+48    (int (*)(...))QThread::~QThread
+56    (int (*)(...))QThread::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QThread::run
+
+Class QThread
+   size=16 align=8
+   base size=16 base align=8
+QThread (0x0x7f3bf61365b0) 0
+    vptr=((& QThread::_ZTV7QThread) + 16)
+  QObject (0x0x7f3bf61772a0) 0
+      primary-for QThread (0x0x7f3bf61365b0)
+
+Class QThreadPool::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QThreadPool::QPrivateSignal (0x0x7f3bf61776c0) 0 empty
+
+Vtable for QThreadPool
+QThreadPool::_ZTV11QThreadPool: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI11QThreadPool)
+16    (int (*)(...))QThreadPool::metaObject
+24    (int (*)(...))QThreadPool::qt_metacast
+32    (int (*)(...))QThreadPool::qt_metacall
+40    (int (*)(...))QThreadPool::~QThreadPool
+48    (int (*)(...))QThreadPool::~QThreadPool
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QThreadPool
+   size=16 align=8
+   base size=16 base align=8
+QThreadPool (0x0x7f3bf6136618) 0
+    vptr=((& QThreadPool::_ZTV11QThreadPool) + 16)
+  QObject (0x0x7f3bf6177660) 0
+      primary-for QThreadPool (0x0x7f3bf6136618)
+
+Class QThreadStorageData
+   size=4 align=4
+   base size=4 base align=4
+QThreadStorageData (0x0x7f3bf61778a0) 0
+
+Class QTimeLine::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QTimeLine::QPrivateSignal (0x0x7f3bf6177f60) 0 empty
+
+Vtable for QTimeLine
+QTimeLine::_ZTV9QTimeLine: 15 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI9QTimeLine)
+16    (int (*)(...))QTimeLine::metaObject
+24    (int (*)(...))QTimeLine::qt_metacast
+32    (int (*)(...))QTimeLine::qt_metacall
+40    (int (*)(...))QTimeLine::~QTimeLine
+48    (int (*)(...))QTimeLine::~QTimeLine
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QTimeLine::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QTimeLine::valueForTime
+
+Class QTimeLine
+   size=16 align=8
+   base size=16 base align=8
+QTimeLine (0x0x7f3bf6136680) 0
+    vptr=((& QTimeLine::_ZTV9QTimeLine) + 16)
+  QObject (0x0x7f3bf6177f00) 0
+      primary-for QTimeLine (0x0x7f3bf6136680)
+
+Class QTimer::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QTimer::QPrivateSignal (0x0x7f3bf61ca1e0) 0 empty
+
+Vtable for QTimer
+QTimer::_ZTV6QTimer: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI6QTimer)
+16    (int (*)(...))QTimer::metaObject
+24    (int (*)(...))QTimer::qt_metacast
+32    (int (*)(...))QTimer::qt_metacall
+40    (int (*)(...))QTimer::~QTimer
+48    (int (*)(...))QTimer::~QTimer
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QTimer::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QTimer
+   size=32 align=8
+   base size=29 base align=8
+QTimer (0x0x7f3bf61366e8) 0
+    vptr=((& QTimer::_ZTV6QTimer) + 16)
+  QObject (0x0x7f3bf61ca180) 0
+      primary-for QTimer (0x0x7f3bf61366e8)
+
+Class QTimeZone::OffsetData
+   size=32 align=8
+   base size=28 base align=8
+QTimeZone::OffsetData (0x0x7f3bf5e02b40) 0
+
+Class QTimeZone
+   size=8 align=8
+   base size=8 base align=8
+QTimeZone (0x0x7f3bf5e02ae0) 0
+
+Class QTranslator::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QTranslator::QPrivateSignal (0x0x7f3bf5ea0c00) 0 empty
+
+Vtable for QTranslator
+QTranslator::_ZTV11QTranslator: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI11QTranslator)
+16    (int (*)(...))QTranslator::metaObject
+24    (int (*)(...))QTranslator::qt_metacast
+32    (int (*)(...))QTranslator::qt_metacall
+40    (int (*)(...))QTranslator::~QTranslator
+48    (int (*)(...))QTranslator::~QTranslator
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QTranslator::translate
+120   (int (*)(...))QTranslator::isEmpty
+
+Class QTranslator
+   size=16 align=8
+   base size=16 base align=8
+QTranslator (0x0x7f3bf5e9fdd0) 0
+    vptr=((& QTranslator::_ZTV11QTranslator) + 16)
+  QObject (0x0x7f3bf5ea0ba0) 0
+      primary-for QTranslator (0x0x7f3bf5e9fdd0)
+
+Class QTransposeProxyModel::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QTransposeProxyModel::QPrivateSignal (0x0x7f3bf5ea0e40) 0 empty
+
+Vtable for QTransposeProxyModel
+QTransposeProxyModel::_ZTV20QTransposeProxyModel: 53 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI20QTransposeProxyModel)
+16    (int (*)(...))QTransposeProxyModel::metaObject
+24    (int (*)(...))QTransposeProxyModel::qt_metacast
+32    (int (*)(...))QTransposeProxyModel::qt_metacall
+40    (int (*)(...))QTransposeProxyModel::~QTransposeProxyModel
+48    (int (*)(...))QTransposeProxyModel::~QTransposeProxyModel
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QTransposeProxyModel::index
+120   (int (*)(...))QTransposeProxyModel::parent
+128   (int (*)(...))QAbstractProxyModel::sibling
+136   (int (*)(...))QTransposeProxyModel::rowCount
+144   (int (*)(...))QTransposeProxyModel::columnCount
+152   (int (*)(...))QAbstractProxyModel::hasChildren
+160   (int (*)(...))QAbstractProxyModel::data
+168   (int (*)(...))QAbstractProxyModel::setData
+176   (int (*)(...))QTransposeProxyModel::headerData
+184   (int (*)(...))QTransposeProxyModel::setHeaderData
+192   (int (*)(...))QTransposeProxyModel::itemData
+200   (int (*)(...))QTransposeProxyModel::setItemData
+208   (int (*)(...))QAbstractProxyModel::mimeTypes
+216   (int (*)(...))QAbstractProxyModel::mimeData
+224   (int (*)(...))QAbstractProxyModel::canDropMimeData
+232   (int (*)(...))QAbstractProxyModel::dropMimeData
+240   (int (*)(...))QAbstractProxyModel::supportedDropActions
+248   (int (*)(...))QAbstractProxyModel::supportedDragActions
+256   (int (*)(...))QTransposeProxyModel::insertRows
+264   (int (*)(...))QTransposeProxyModel::insertColumns
+272   (int (*)(...))QTransposeProxyModel::removeRows
+280   (int (*)(...))QTransposeProxyModel::removeColumns
+288   (int (*)(...))QTransposeProxyModel::moveRows
+296   (int (*)(...))QTransposeProxyModel::moveColumns
+304   (int (*)(...))QAbstractProxyModel::fetchMore
+312   (int (*)(...))QAbstractProxyModel::canFetchMore
+320   (int (*)(...))QAbstractProxyModel::flags
+328   (int (*)(...))QTransposeProxyModel::sort
+336   (int (*)(...))QAbstractProxyModel::buddy
+344   (int (*)(...))QAbstractItemModel::match
+352   (int (*)(...))QTransposeProxyModel::span
+360   (int (*)(...))QAbstractItemModel::roleNames
+368   (int (*)(...))QAbstractProxyModel::submit
+376   (int (*)(...))QAbstractProxyModel::revert
+384   (int (*)(...))QTransposeProxyModel::setSourceModel
+392   (int (*)(...))QTransposeProxyModel::mapToSource
+400   (int (*)(...))QTransposeProxyModel::mapFromSource
+408   (int (*)(...))QAbstractProxyModel::mapSelectionToSource
+416   (int (*)(...))QAbstractProxyModel::mapSelectionFromSource
+
+Class QTransposeProxyModel
+   size=16 align=8
+   base size=16 base align=8
+QTransposeProxyModel (0x0x7f3bf5e9fe38) 0
+    vptr=((& QTransposeProxyModel::_ZTV20QTransposeProxyModel) + 16)
+  QAbstractProxyModel (0x0x7f3bf5e9fea0) 0
+      primary-for QTransposeProxyModel (0x0x7f3bf5e9fe38)
+    QAbstractItemModel (0x0x7f3bf5e9ff08) 0
+        primary-for QAbstractProxyModel (0x0x7f3bf5e9fea0)
+      QObject (0x0x7f3bf5ea0de0) 0
+          primary-for QAbstractItemModel (0x0x7f3bf5e9ff08)
+
+Class QUrlQuery
+   size=8 align=8
+   base size=8 base align=8
+QUrlQuery (0x0x7f3bf5ee2060) 0
+
+Class QWaitCondition
+   size=8 align=8
+   base size=8 base align=8
+QWaitCondition (0x0x7f3bf5fbd540) 0
+
+Class QXmlStreamStringRef
+   size=16 align=8
+   base size=16 base align=8
+QXmlStreamStringRef (0x0x7f3bf5fbd660) 0
+
+Class QXmlStreamAttribute
+   size=80 align=8
+   base size=73 base align=8
+QXmlStreamAttribute (0x0x7f3bf5b50a20) 0
+
+Class QXmlStreamAttributes
+   size=8 align=8
+   base size=8 base align=8
+QXmlStreamAttributes (0x0x7f3bf5bc6208) 0
+  QVector<QXmlStreamAttribute> (0x0x7f3bf5bc7180) 0
+
+Class QXmlStreamNamespaceDeclaration
+   size=40 align=8
+   base size=40 base align=8
+QXmlStreamNamespaceDeclaration (0x0x7f3bf5bc7480) 0
+
+Class QXmlStreamNotationDeclaration
+   size=56 align=8
+   base size=56 base align=8
+QXmlStreamNotationDeclaration (0x0x7f3bf5c51420) 0
+
+Class QXmlStreamEntityDeclaration
+   size=88 align=8
+   base size=88 base align=8
+QXmlStreamEntityDeclaration (0x0x7f3bf5cb0420) 0
+
+Vtable for QXmlStreamEntityResolver
+QXmlStreamEntityResolver::_ZTV24QXmlStreamEntityResolver: 6 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI24QXmlStreamEntityResolver)
+16    (int (*)(...))QXmlStreamEntityResolver::~QXmlStreamEntityResolver
+24    (int (*)(...))QXmlStreamEntityResolver::~QXmlStreamEntityResolver
+32    (int (*)(...))QXmlStreamEntityResolver::resolveEntity
+40    (int (*)(...))QXmlStreamEntityResolver::resolveUndeclaredEntity
+
+Class QXmlStreamEntityResolver
+   size=8 align=8
+   base size=8 base align=8
+QXmlStreamEntityResolver (0x0x7f3bf591a4e0) 0 nearly-empty
+    vptr=((& QXmlStreamEntityResolver::_ZTV24QXmlStreamEntityResolver) + 16)
+
+Class QXmlStreamReader
+   size=8 align=8
+   base size=8 base align=8
+QXmlStreamReader (0x0x7f3bf591a540) 0
+
+Class QXmlStreamWriter
+   size=8 align=8
+   base size=8 base align=8
+QXmlStreamWriter (0x0x7f3bf5977420) 0
+
+Class QNetworkRequest
+   size=8 align=8
+   base size=8 base align=8
+QNetworkRequest (0x0x7f3bf5977600) 0
+
+Class QNetworkCacheMetaData
+   size=8 align=8
+   base size=8 base align=8
+QNetworkCacheMetaData (0x0x7f3bf5a56a80) 0
+
+Class QAbstractNetworkCache::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QAbstractNetworkCache::QPrivateSignal (0x0x7f3bf5725f60) 0 empty
+
+Vtable for QAbstractNetworkCache
+QAbstractNetworkCache::_ZTV21QAbstractNetworkCache: 22 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI21QAbstractNetworkCache)
+16    (int (*)(...))QAbstractNetworkCache::metaObject
+24    (int (*)(...))QAbstractNetworkCache::qt_metacast
+32    (int (*)(...))QAbstractNetworkCache::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))__cxa_pure_virtual
+120   (int (*)(...))__cxa_pure_virtual
+128   (int (*)(...))__cxa_pure_virtual
+136   (int (*)(...))__cxa_pure_virtual
+144   (int (*)(...))__cxa_pure_virtual
+152   (int (*)(...))__cxa_pure_virtual
+160   (int (*)(...))__cxa_pure_virtual
+168   (int (*)(...))__cxa_pure_virtual
+
+Class QAbstractNetworkCache
+   size=16 align=8
+   base size=16 base align=8
+QAbstractNetworkCache (0x0x7f3bf5728af8) 0
+    vptr=((& QAbstractNetworkCache::_ZTV21QAbstractNetworkCache) + 16)
+  QObject (0x0x7f3bf5725f00) 0
+      primary-for QAbstractNetworkCache (0x0x7f3bf5728af8)
+
+Class QAbstractSocket::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QAbstractSocket::QPrivateSignal (0x0x7f3bf57491e0) 0 empty
+
+Vtable for QAbstractSocket
+QAbstractSocket::_ZTV15QAbstractSocket: 41 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI15QAbstractSocket)
+16    (int (*)(...))QAbstractSocket::metaObject
+24    (int (*)(...))QAbstractSocket::qt_metacast
+32    (int (*)(...))QAbstractSocket::qt_metacall
+40    (int (*)(...))QAbstractSocket::~QAbstractSocket
+48    (int (*)(...))QAbstractSocket::~QAbstractSocket
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QAbstractSocket::isSequential
+120   (int (*)(...))QIODevice::open
+128   (int (*)(...))QAbstractSocket::close
+136   (int (*)(...))QIODevice::pos
+144   (int (*)(...))QIODevice::size
+152   (int (*)(...))QIODevice::seek
+160   (int (*)(...))QAbstractSocket::atEnd
+168   (int (*)(...))QIODevice::reset
+176   (int (*)(...))QAbstractSocket::bytesAvailable
+184   (int (*)(...))QAbstractSocket::bytesToWrite
+192   (int (*)(...))QAbstractSocket::canReadLine
+200   (int (*)(...))QAbstractSocket::waitForReadyRead
+208   (int (*)(...))QAbstractSocket::waitForBytesWritten
+216   (int (*)(...))QAbstractSocket::readData
+224   (int (*)(...))QAbstractSocket::readLineData
+232   (int (*)(...))QAbstractSocket::writeData
+240   (int (*)(...))QAbstractSocket::resume
+248   (int (*)(...))QAbstractSocket::connectToHost
+256   (int (*)(...))QAbstractSocket::connectToHost
+264   (int (*)(...))QAbstractSocket::disconnectFromHost
+272   (int (*)(...))QAbstractSocket::setReadBufferSize
+280   (int (*)(...))QAbstractSocket::socketDescriptor
+288   (int (*)(...))QAbstractSocket::setSocketDescriptor
+296   (int (*)(...))QAbstractSocket::setSocketOption
+304   (int (*)(...))QAbstractSocket::socketOption
+312   (int (*)(...))QAbstractSocket::waitForConnected
+320   (int (*)(...))QAbstractSocket::waitForDisconnected
+
+Class QAbstractSocket
+   size=16 align=8
+   base size=16 base align=8
+QAbstractSocket (0x0x7f3bf5728b60) 0
+    vptr=((& QAbstractSocket::_ZTV15QAbstractSocket) + 16)
+  QIODevice (0x0x7f3bf5728bc8) 0
+      primary-for QAbstractSocket (0x0x7f3bf5728b60)
+    QObject (0x0x7f3bf5749180) 0
+        primary-for QIODevice (0x0x7f3bf5728bc8)
+
+Class QAuthenticator
+   size=8 align=8
+   base size=8 base align=8
+QAuthenticator (0x0x7f3bf57c5900) 0
+
+Class QDnsDomainNameRecord
+   size=8 align=8
+   base size=8 base align=8
+QDnsDomainNameRecord (0x0x7f3bf57c59c0) 0
+
+Class QDnsHostAddressRecord
+   size=8 align=8
+   base size=8 base align=8
+QDnsHostAddressRecord (0x0x7f3bf589aa80) 0
+
+Class QDnsMailExchangeRecord
+   size=8 align=8
+   base size=8 base align=8
+QDnsMailExchangeRecord (0x0x7f3bf5555b40) 0
+
+Class QDnsServiceRecord
+   size=8 align=8
+   base size=8 base align=8
+QDnsServiceRecord (0x0x7f3bf5611b40) 0
+
+Class QDnsTextRecord
+   size=8 align=8
+   base size=8 base align=8
+QDnsTextRecord (0x0x7f3bf56cca20) 0
+
+Class QDnsLookup::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QDnsLookup::QPrivateSignal (0x0x7f3bf5389a80) 0 empty
+
+Vtable for QDnsLookup
+QDnsLookup::_ZTV10QDnsLookup: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI10QDnsLookup)
+16    (int (*)(...))QDnsLookup::metaObject
+24    (int (*)(...))QDnsLookup::qt_metacast
+32    (int (*)(...))QDnsLookup::qt_metacall
+40    (int (*)(...))QDnsLookup::~QDnsLookup
+48    (int (*)(...))QDnsLookup::~QDnsLookup
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QDnsLookup
+   size=16 align=8
+   base size=16 base align=8
+QDnsLookup (0x0x7f3bf538aa90) 0
+    vptr=((& QDnsLookup::_ZTV10QDnsLookup) + 16)
+  QObject (0x0x7f3bf5389a20) 0
+      primary-for QDnsLookup (0x0x7f3bf538aa90)
+
+Class QTcpSocket::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QTcpSocket::QPrivateSignal (0x0x7f3bf5389e40) 0 empty
+
+Vtable for QTcpSocket
+QTcpSocket::_ZTV10QTcpSocket: 41 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI10QTcpSocket)
+16    (int (*)(...))QTcpSocket::metaObject
+24    (int (*)(...))QTcpSocket::qt_metacast
+32    (int (*)(...))QTcpSocket::qt_metacall
+40    (int (*)(...))QTcpSocket::~QTcpSocket
+48    (int (*)(...))QTcpSocket::~QTcpSocket
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QAbstractSocket::isSequential
+120   (int (*)(...))QIODevice::open
+128   (int (*)(...))QAbstractSocket::close
+136   (int (*)(...))QIODevice::pos
+144   (int (*)(...))QIODevice::size
+152   (int (*)(...))QIODevice::seek
+160   (int (*)(...))QAbstractSocket::atEnd
+168   (int (*)(...))QIODevice::reset
+176   (int (*)(...))QAbstractSocket::bytesAvailable
+184   (int (*)(...))QAbstractSocket::bytesToWrite
+192   (int (*)(...))QAbstractSocket::canReadLine
+200   (int (*)(...))QAbstractSocket::waitForReadyRead
+208   (int (*)(...))QAbstractSocket::waitForBytesWritten
+216   (int (*)(...))QAbstractSocket::readData
+224   (int (*)(...))QAbstractSocket::readLineData
+232   (int (*)(...))QAbstractSocket::writeData
+240   (int (*)(...))QAbstractSocket::resume
+248   (int (*)(...))QAbstractSocket::connectToHost
+256   (int (*)(...))QAbstractSocket::connectToHost
+264   (int (*)(...))QAbstractSocket::disconnectFromHost
+272   (int (*)(...))QAbstractSocket::setReadBufferSize
+280   (int (*)(...))QAbstractSocket::socketDescriptor
+288   (int (*)(...))QAbstractSocket::setSocketDescriptor
+296   (int (*)(...))QAbstractSocket::setSocketOption
+304   (int (*)(...))QAbstractSocket::socketOption
+312   (int (*)(...))QAbstractSocket::waitForConnected
+320   (int (*)(...))QAbstractSocket::waitForDisconnected
+
+Class QTcpSocket
+   size=16 align=8
+   base size=16 base align=8
+QTcpSocket (0x0x7f3bf538aaf8) 0
+    vptr=((& QTcpSocket::_ZTV10QTcpSocket) + 16)
+  QAbstractSocket (0x0x7f3bf538ab60) 0
+      primary-for QTcpSocket (0x0x7f3bf538aaf8)
+    QIODevice (0x0x7f3bf538abc8) 0
+        primary-for QAbstractSocket (0x0x7f3bf538ab60)
+      QObject (0x0x7f3bf5389de0) 0
+          primary-for QIODevice (0x0x7f3bf538abc8)
+
+Class QSslCertificate
+   size=8 align=8
+   base size=8 base align=8
+QSslCertificate (0x0x7f3bf53bf720) 0
+
+Class QSslError
+   size=8 align=8
+   base size=8 base align=8
+QSslError (0x0x7f3bf54a7f60) 0
+
+Class QSslSocket::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QSslSocket::QPrivateSignal (0x0x7f3bf5191240) 0 empty
+
+Vtable for QSslSocket
+QSslSocket::_ZTV10QSslSocket: 41 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI10QSslSocket)
+16    (int (*)(...))QSslSocket::metaObject
+24    (int (*)(...))QSslSocket::qt_metacast
+32    (int (*)(...))QSslSocket::qt_metacall
+40    (int (*)(...))QSslSocket::~QSslSocket
+48    (int (*)(...))QSslSocket::~QSslSocket
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QAbstractSocket::isSequential
+120   (int (*)(...))QIODevice::open
+128   (int (*)(...))QSslSocket::close
+136   (int (*)(...))QIODevice::pos
+144   (int (*)(...))QIODevice::size
+152   (int (*)(...))QIODevice::seek
+160   (int (*)(...))QSslSocket::atEnd
+168   (int (*)(...))QIODevice::reset
+176   (int (*)(...))QSslSocket::bytesAvailable
+184   (int (*)(...))QSslSocket::bytesToWrite
+192   (int (*)(...))QSslSocket::canReadLine
+200   (int (*)(...))QSslSocket::waitForReadyRead
+208   (int (*)(...))QSslSocket::waitForBytesWritten
+216   (int (*)(...))QSslSocket::readData
+224   (int (*)(...))QAbstractSocket::readLineData
+232   (int (*)(...))QSslSocket::writeData
+240   (int (*)(...))QSslSocket::resume
+248   (int (*)(...))QSslSocket::connectToHost
+256   (int (*)(...))QAbstractSocket::connectToHost
+264   (int (*)(...))QSslSocket::disconnectFromHost
+272   (int (*)(...))QSslSocket::setReadBufferSize
+280   (int (*)(...))QAbstractSocket::socketDescriptor
+288   (int (*)(...))QSslSocket::setSocketDescriptor
+296   (int (*)(...))QSslSocket::setSocketOption
+304   (int (*)(...))QSslSocket::socketOption
+312   (int (*)(...))QSslSocket::waitForConnected
+320   (int (*)(...))QSslSocket::waitForDisconnected
+
+Class QSslSocket
+   size=16 align=8
+   base size=16 base align=8
+QSslSocket (0x0x7f3bf5180888) 0
+    vptr=((& QSslSocket::_ZTV10QSslSocket) + 16)
+  QTcpSocket (0x0x7f3bf51808f0) 0
+      primary-for QSslSocket (0x0x7f3bf5180888)
+    QAbstractSocket (0x0x7f3bf5180958) 0
+        primary-for QTcpSocket (0x0x7f3bf51808f0)
+      QIODevice (0x0x7f3bf51809c0) 0
+          primary-for QAbstractSocket (0x0x7f3bf5180958)
+        QObject (0x0x7f3bf51911e0) 0
+            primary-for QIODevice (0x0x7f3bf51809c0)
+
+Class QDtlsClientVerifier::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QDtlsClientVerifier::QPrivateSignal (0x0x7f3bf5191480) 0 empty
+
+Class QDtlsClientVerifier::GeneratorParameters
+   size=16 align=8
+   base size=16 base align=8
+QDtlsClientVerifier::GeneratorParameters (0x0x7f3bf51914e0) 0
+
+Vtable for QDtlsClientVerifier
+QDtlsClientVerifier::_ZTV19QDtlsClientVerifier: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI19QDtlsClientVerifier)
+16    (int (*)(...))QDtlsClientVerifier::metaObject
+24    (int (*)(...))QDtlsClientVerifier::qt_metacast
+32    (int (*)(...))QDtlsClientVerifier::qt_metacall
+40    (int (*)(...))QDtlsClientVerifier::~QDtlsClientVerifier
+48    (int (*)(...))QDtlsClientVerifier::~QDtlsClientVerifier
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QDtlsClientVerifier
+   size=16 align=8
+   base size=16 base align=8
+QDtlsClientVerifier (0x0x7f3bf5180a28) 0
+    vptr=((& QDtlsClientVerifier::_ZTV19QDtlsClientVerifier) + 16)
+  QObject (0x0x7f3bf5191420) 0
+      primary-for QDtlsClientVerifier (0x0x7f3bf5180a28)
+
+Class QDtls::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QDtls::QPrivateSignal (0x0x7f3bf5191720) 0 empty
+
+Vtable for QDtls
+QDtls::_ZTV5QDtls: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI5QDtls)
+16    (int (*)(...))QDtls::metaObject
+24    (int (*)(...))QDtls::qt_metacast
+32    (int (*)(...))QDtls::qt_metacall
+40    (int (*)(...))QDtls::~QDtls
+48    (int (*)(...))QDtls::~QDtls
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QDtls
+   size=16 align=8
+   base size=16 base align=8
+QDtls (0x0x7f3bf5180a90) 0
+    vptr=((& QDtls::_ZTV5QDtls) + 16)
+  QObject (0x0x7f3bf51916c0) 0
+      primary-for QDtls (0x0x7f3bf5180a90)
+
+Class QIPv6Address
+   size=16 align=1
+   base size=16 base align=1
+QIPv6Address (0x0x7f3bf5191960) 0
+
+Class QHostAddress
+   size=8 align=8
+   base size=8 base align=8
+QHostAddress (0x0x7f3bf5191a80) 0
+
+Class QHostInfo
+   size=8 align=8
+   base size=8 base align=8
+QHostInfo (0x0x7f3bf5293840) 0
+
+Class QHstsPolicy
+   size=8 align=8
+   base size=8 base align=8
+QHstsPolicy (0x0x7f3bf4f55f00) 0
+
+Class QHttp2Configuration
+   size=8 align=8
+   base size=8 base align=8
+QHttp2Configuration (0x0x7f3bf5058660) 0
+
+Class QHttpPart
+   size=8 align=8
+   base size=8 base align=8
+QHttpPart (0x0x7f3bf50b0ba0) 0
+
+Class QHttpMultiPart::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QHttpMultiPart::QPrivateSignal (0x0x7f3bf4d79840) 0 empty
+
+Vtable for QHttpMultiPart
+QHttpMultiPart::_ZTV14QHttpMultiPart: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI14QHttpMultiPart)
+16    (int (*)(...))QHttpMultiPart::metaObject
+24    (int (*)(...))QHttpMultiPart::qt_metacast
+32    (int (*)(...))QHttpMultiPart::qt_metacall
+40    (int (*)(...))QHttpMultiPart::~QHttpMultiPart
+48    (int (*)(...))QHttpMultiPart::~QHttpMultiPart
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QHttpMultiPart
+   size=16 align=8
+   base size=16 base align=8
+QHttpMultiPart (0x0x7f3bf4d82208) 0
+    vptr=((& QHttpMultiPart::_ZTV14QHttpMultiPart) + 16)
+  QObject (0x0x7f3bf4d797e0) 0
+      primary-for QHttpMultiPart (0x0x7f3bf4d82208)
+
+Class QLocalServer::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QLocalServer::QPrivateSignal (0x0x7f3bf4d79a80) 0 empty
+
+Vtable for QLocalServer
+QLocalServer::_ZTV12QLocalServer: 17 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI12QLocalServer)
+16    (int (*)(...))QLocalServer::metaObject
+24    (int (*)(...))QLocalServer::qt_metacast
+32    (int (*)(...))QLocalServer::qt_metacall
+40    (int (*)(...))QLocalServer::~QLocalServer
+48    (int (*)(...))QLocalServer::~QLocalServer
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QLocalServer::hasPendingConnections
+120   (int (*)(...))QLocalServer::nextPendingConnection
+128   (int (*)(...))QLocalServer::incomingConnection
+
+Class QLocalServer
+   size=16 align=8
+   base size=16 base align=8
+QLocalServer (0x0x7f3bf4d82270) 0
+    vptr=((& QLocalServer::_ZTV12QLocalServer) + 16)
+  QObject (0x0x7f3bf4d79a20) 0
+      primary-for QLocalServer (0x0x7f3bf4d82270)
+
+Class QLocalSocket::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QLocalSocket::QPrivateSignal (0x0x7f3bf4dc7540) 0 empty
+
+Vtable for QLocalSocket
+QLocalSocket::_ZTV12QLocalSocket: 30 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI12QLocalSocket)
+16    (int (*)(...))QLocalSocket::metaObject
+24    (int (*)(...))QLocalSocket::qt_metacast
+32    (int (*)(...))QLocalSocket::qt_metacall
+40    (int (*)(...))QLocalSocket::~QLocalSocket
+48    (int (*)(...))QLocalSocket::~QLocalSocket
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QLocalSocket::isSequential
+120   (int (*)(...))QLocalSocket::open
+128   (int (*)(...))QLocalSocket::close
+136   (int (*)(...))QIODevice::pos
+144   (int (*)(...))QIODevice::size
+152   (int (*)(...))QIODevice::seek
+160   (int (*)(...))QIODevice::atEnd
+168   (int (*)(...))QIODevice::reset
+176   (int (*)(...))QLocalSocket::bytesAvailable
+184   (int (*)(...))QLocalSocket::bytesToWrite
+192   (int (*)(...))QLocalSocket::canReadLine
+200   (int (*)(...))QLocalSocket::waitForReadyRead
+208   (int (*)(...))QLocalSocket::waitForBytesWritten
+216   (int (*)(...))QLocalSocket::readData
+224   (int (*)(...))QIODevice::readLineData
+232   (int (*)(...))QLocalSocket::writeData
+
+Class QLocalSocket
+   size=16 align=8
+   base size=16 base align=8
+QLocalSocket (0x0x7f3bf4d82410) 0
+    vptr=((& QLocalSocket::_ZTV12QLocalSocket) + 16)
+  QIODevice (0x0x7f3bf4d82478) 0
+      primary-for QLocalSocket (0x0x7f3bf4d82410)
+    QObject (0x0x7f3bf4dc74e0) 0
+        primary-for QIODevice (0x0x7f3bf4d82478)
+
+Class QSslConfiguration
+   size=8 align=8
+   base size=8 base align=8
+QSslConfiguration (0x0x7f3bf4dc7720) 0
+
+Class QSslPreSharedKeyAuthenticator
+   size=8 align=8
+   base size=8 base align=8
+QSslPreSharedKeyAuthenticator (0x0x7f3bf4ed2c00) 0
+
+Class QNetworkAccessManager::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QNetworkAccessManager::QPrivateSignal (0x0x7f3bf4bbf2a0) 0 empty
+
+Vtable for QNetworkAccessManager
+QNetworkAccessManager::_ZTV21QNetworkAccessManager: 15 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI21QNetworkAccessManager)
+16    (int (*)(...))QNetworkAccessManager::metaObject
+24    (int (*)(...))QNetworkAccessManager::qt_metacast
+32    (int (*)(...))QNetworkAccessManager::qt_metacall
+40    (int (*)(...))QNetworkAccessManager::~QNetworkAccessManager
+48    (int (*)(...))QNetworkAccessManager::~QNetworkAccessManager
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QNetworkAccessManager::createRequest
+
+Class QNetworkAccessManager
+   size=16 align=8
+   base size=16 base align=8
+QNetworkAccessManager (0x0x7f3bf4bab958) 0
+    vptr=((& QNetworkAccessManager::_ZTV21QNetworkAccessManager) + 16)
+  QObject (0x0x7f3bf4bbf240) 0
+      primary-for QNetworkAccessManager (0x0x7f3bf4bab958)
+
+Class QNetworkConfiguration
+   size=8 align=8
+   base size=8 base align=8
+QNetworkConfiguration (0x0x7f3bf4bbf540) 0
+
+Class QNetworkConfigurationManager::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QNetworkConfigurationManager::QPrivateSignal (0x0x7f3bf4ca6900) 0 empty
+
+Vtable for QNetworkConfigurationManager
+QNetworkConfigurationManager::_ZTV28QNetworkConfigurationManager: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI28QNetworkConfigurationManager)
+16    (int (*)(...))QNetworkConfigurationManager::metaObject
+24    (int (*)(...))QNetworkConfigurationManager::qt_metacast
+32    (int (*)(...))QNetworkConfigurationManager::qt_metacall
+40    (int (*)(...))QNetworkConfigurationManager::~QNetworkConfigurationManager
+48    (int (*)(...))QNetworkConfigurationManager::~QNetworkConfigurationManager
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QNetworkConfigurationManager
+   size=16 align=8
+   base size=16 base align=8
+QNetworkConfigurationManager (0x0x7f3bf4c96c30) 0
+    vptr=((& QNetworkConfigurationManager::_ZTV28QNetworkConfigurationManager) + 16)
+  QObject (0x0x7f3bf4ca68a0) 0
+      primary-for QNetworkConfigurationManager (0x0x7f3bf4c96c30)
+
+Class QNetworkCookie
+   size=8 align=8
+   base size=8 base align=8
+QNetworkCookie (0x0x7f3bf4cf9480) 0
+
+Class QNetworkCookieJar::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QNetworkCookieJar::QPrivateSignal (0x0x7f3bf49c8a80) 0 empty
+
+Vtable for QNetworkCookieJar
+QNetworkCookieJar::_ZTV17QNetworkCookieJar: 20 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI17QNetworkCookieJar)
+16    (int (*)(...))QNetworkCookieJar::metaObject
+24    (int (*)(...))QNetworkCookieJar::qt_metacast
+32    (int (*)(...))QNetworkCookieJar::qt_metacall
+40    (int (*)(...))QNetworkCookieJar::~QNetworkCookieJar
+48    (int (*)(...))QNetworkCookieJar::~QNetworkCookieJar
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QNetworkCookieJar::cookiesForUrl
+120   (int (*)(...))QNetworkCookieJar::setCookiesFromUrl
+128   (int (*)(...))QNetworkCookieJar::insertCookie
+136   (int (*)(...))QNetworkCookieJar::updateCookie
+144   (int (*)(...))QNetworkCookieJar::deleteCookie
+152   (int (*)(...))QNetworkCookieJar::validateCookie
+
+Class QNetworkCookieJar
+   size=16 align=8
+   base size=16 base align=8
+QNetworkCookieJar (0x0x7f3bf49bbea0) 0
+    vptr=((& QNetworkCookieJar::_ZTV17QNetworkCookieJar) + 16)
+  QObject (0x0x7f3bf49c8a20) 0
+      primary-for QNetworkCookieJar (0x0x7f3bf49bbea0)
+
+Class QNetworkDatagram
+   size=8 align=8
+   base size=8 base align=8
+QNetworkDatagram (0x0x7f3bf49c8c60) 0
+
+Class QNetworkDiskCache::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QNetworkDiskCache::QPrivateSignal (0x0x7f3bf4aa27e0) 0 empty
+
+Vtable for QNetworkDiskCache
+QNetworkDiskCache::_ZTV17QNetworkDiskCache: 23 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI17QNetworkDiskCache)
+16    (int (*)(...))QNetworkDiskCache::metaObject
+24    (int (*)(...))QNetworkDiskCache::qt_metacast
+32    (int (*)(...))QNetworkDiskCache::qt_metacall
+40    (int (*)(...))QNetworkDiskCache::~QNetworkDiskCache
+48    (int (*)(...))QNetworkDiskCache::~QNetworkDiskCache
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QNetworkDiskCache::metaData
+120   (int (*)(...))QNetworkDiskCache::updateMetaData
+128   (int (*)(...))QNetworkDiskCache::data
+136   (int (*)(...))QNetworkDiskCache::remove
+144   (int (*)(...))QNetworkDiskCache::cacheSize
+152   (int (*)(...))QNetworkDiskCache::prepare
+160   (int (*)(...))QNetworkDiskCache::insert
+168   (int (*)(...))QNetworkDiskCache::clear
+176   (int (*)(...))QNetworkDiskCache::expire
+
+Class QNetworkDiskCache
+   size=16 align=8
+   base size=16 base align=8
+QNetworkDiskCache (0x0x7f3bf4a95d68) 0
+    vptr=((& QNetworkDiskCache::_ZTV17QNetworkDiskCache) + 16)
+  QAbstractNetworkCache (0x0x7f3bf4a95dd0) 0
+      primary-for QNetworkDiskCache (0x0x7f3bf4a95d68)
+    QObject (0x0x7f3bf4aa2780) 0
+        primary-for QAbstractNetworkCache (0x0x7f3bf4a95dd0)
+
+Class QNetworkAddressEntry
+   size=8 align=8
+   base size=8 base align=8
+QNetworkAddressEntry (0x0x7f3bf4aa29c0) 0
+
+Class QNetworkInterface
+   size=8 align=8
+   base size=8 base align=8
+QNetworkInterface (0x0x7f3bf477b960) 0
+
+Class QNetworkProxyQuery
+   size=8 align=8
+   base size=8 base align=8
+QNetworkProxyQuery (0x0x7f3bf4878480) 0
+
+Class QNetworkProxy
+   size=8 align=8
+   base size=8 base align=8
+QNetworkProxy (0x0x7f3bf4555780) 0
+
+Vtable for QNetworkProxyFactory
+QNetworkProxyFactory::_ZTV20QNetworkProxyFactory: 5 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI20QNetworkProxyFactory)
+16    0
+24    0
+32    (int (*)(...))__cxa_pure_virtual
+
+Class QNetworkProxyFactory
+   size=8 align=8
+   base size=8 base align=8
+QNetworkProxyFactory (0x0x7f3bf4660000) 0 nearly-empty
+    vptr=((& QNetworkProxyFactory::_ZTV20QNetworkProxyFactory) + 16)
+
+Class QNetworkReply::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QNetworkReply::QPrivateSignal (0x0x7f3bf46602a0) 0 empty
+
+Vtable for QNetworkReply
+QNetworkReply::_ZTV13QNetworkReply: 36 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI13QNetworkReply)
+16    (int (*)(...))QNetworkReply::metaObject
+24    (int (*)(...))QNetworkReply::qt_metacast
+32    (int (*)(...))QNetworkReply::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QNetworkReply::isSequential
+120   (int (*)(...))QIODevice::open
+128   (int (*)(...))QNetworkReply::close
+136   (int (*)(...))QIODevice::pos
+144   (int (*)(...))QIODevice::size
+152   (int (*)(...))QIODevice::seek
+160   (int (*)(...))QIODevice::atEnd
+168   (int (*)(...))QIODevice::reset
+176   (int (*)(...))QIODevice::bytesAvailable
+184   (int (*)(...))QIODevice::bytesToWrite
+192   (int (*)(...))QIODevice::canReadLine
+200   (int (*)(...))QIODevice::waitForReadyRead
+208   (int (*)(...))QIODevice::waitForBytesWritten
+216   (int (*)(...))__cxa_pure_virtual
+224   (int (*)(...))QIODevice::readLineData
+232   (int (*)(...))QNetworkReply::writeData
+240   (int (*)(...))QNetworkReply::setReadBufferSize
+248   (int (*)(...))__cxa_pure_virtual
+256   (int (*)(...))QNetworkReply::ignoreSslErrors
+264   (int (*)(...))QNetworkReply::sslConfigurationImplementation
+272   (int (*)(...))QNetworkReply::setSslConfigurationImplementation
+280   (int (*)(...))QNetworkReply::ignoreSslErrorsImplementation
+
+Class QNetworkReply
+   size=16 align=8
+   base size=16 base align=8
+QNetworkReply (0x0x7f3bf4630208) 0
+    vptr=((& QNetworkReply::_ZTV13QNetworkReply) + 16)
+  QIODevice (0x0x7f3bf4630270) 0
+      primary-for QNetworkReply (0x0x7f3bf4630208)
+    QObject (0x0x7f3bf4660240) 0
+        primary-for QIODevice (0x0x7f3bf4630270)
+
+Class QNetworkSession::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QNetworkSession::QPrivateSignal (0x0x7f3bf4660780) 0 empty
+
+Vtable for QNetworkSession
+QNetworkSession::_ZTV15QNetworkSession: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI15QNetworkSession)
+16    (int (*)(...))QNetworkSession::metaObject
+24    (int (*)(...))QNetworkSession::qt_metacast
+32    (int (*)(...))QNetworkSession::qt_metacall
+40    (int (*)(...))QNetworkSession::~QNetworkSession
+48    (int (*)(...))QNetworkSession::~QNetworkSession
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QNetworkSession::connectNotify
+104   (int (*)(...))QNetworkSession::disconnectNotify
+
+Class QNetworkSession
+   size=24 align=8
+   base size=24 base align=8
+QNetworkSession (0x0x7f3bf46302d8) 0
+    vptr=((& QNetworkSession::_ZTV15QNetworkSession) + 16)
+  QObject (0x0x7f3bf4660720) 0
+      primary-for QNetworkSession (0x0x7f3bf46302d8)
+
+Class QOcspResponse
+   size=8 align=8
+   base size=8 base align=8
+QOcspResponse (0x0x7f3bf46c9000) 0
+
+Class QTcpServer::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QTcpServer::QPrivateSignal (0x0x7f3bf4319840) 0 empty
+
+Vtable for QTcpServer
+QTcpServer::_ZTV10QTcpServer: 17 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI10QTcpServer)
+16    (int (*)(...))QTcpServer::metaObject
+24    (int (*)(...))QTcpServer::qt_metacast
+32    (int (*)(...))QTcpServer::qt_metacall
+40    (int (*)(...))QTcpServer::~QTcpServer
+48    (int (*)(...))QTcpServer::~QTcpServer
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QTcpServer::hasPendingConnections
+120   (int (*)(...))QTcpServer::nextPendingConnection
+128   (int (*)(...))QTcpServer::incomingConnection
+
+Class QTcpServer
+   size=16 align=8
+   base size=16 base align=8
+QTcpServer (0x0x7f3bf430cb60) 0
+    vptr=((& QTcpServer::_ZTV10QTcpServer) + 16)
+  QObject (0x0x7f3bf43197e0) 0
+      primary-for QTcpServer (0x0x7f3bf430cb60)
+
+Class QSslCertificateExtension
+   size=8 align=8
+   base size=8 base align=8
+QSslCertificateExtension (0x0x7f3bf4319a20) 0
+
+Class QSslCipher
+   size=8 align=8
+   base size=8 base align=8
+QSslCipher (0x0x7f3bf43ea9c0) 0
+
+Class QSslDiffieHellmanParameters
+   size=8 align=8
+   base size=8 base align=8
+QSslDiffieHellmanParameters (0x0x7f3bf44afa80) 0
+
+Class QSslEllipticCurve
+   size=4 align=4
+   base size=4 base align=4
+QSslEllipticCurve (0x0x7f3bf41737e0) 0
+
+Class QSslKey
+   size=8 align=8
+   base size=8 base align=8
+QSslKey (0x0x7f3bf41da180) 0
+
+Class QUdpSocket::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QUdpSocket::QPrivateSignal (0x0x7f3bf42a9060) 0 empty
+
+Vtable for QUdpSocket
+QUdpSocket::_ZTV10QUdpSocket: 41 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI10QUdpSocket)
+16    (int (*)(...))QUdpSocket::metaObject
+24    (int (*)(...))QUdpSocket::qt_metacast
+32    (int (*)(...))QUdpSocket::qt_metacall
+40    (int (*)(...))QUdpSocket::~QUdpSocket
+48    (int (*)(...))QUdpSocket::~QUdpSocket
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QAbstractSocket::isSequential
+120   (int (*)(...))QIODevice::open
+128   (int (*)(...))QAbstractSocket::close
+136   (int (*)(...))QIODevice::pos
+144   (int (*)(...))QIODevice::size
+152   (int (*)(...))QIODevice::seek
+160   (int (*)(...))QAbstractSocket::atEnd
+168   (int (*)(...))QIODevice::reset
+176   (int (*)(...))QAbstractSocket::bytesAvailable
+184   (int (*)(...))QAbstractSocket::bytesToWrite
+192   (int (*)(...))QAbstractSocket::canReadLine
+200   (int (*)(...))QAbstractSocket::waitForReadyRead
+208   (int (*)(...))QAbstractSocket::waitForBytesWritten
+216   (int (*)(...))QAbstractSocket::readData
+224   (int (*)(...))QAbstractSocket::readLineData
+232   (int (*)(...))QAbstractSocket::writeData
+240   (int (*)(...))QAbstractSocket::resume
+248   (int (*)(...))QAbstractSocket::connectToHost
+256   (int (*)(...))QAbstractSocket::connectToHost
+264   (int (*)(...))QAbstractSocket::disconnectFromHost
+272   (int (*)(...))QAbstractSocket::setReadBufferSize
+280   (int (*)(...))QAbstractSocket::socketDescriptor
+288   (int (*)(...))QAbstractSocket::setSocketDescriptor
+296   (int (*)(...))QAbstractSocket::setSocketOption
+304   (int (*)(...))QAbstractSocket::socketOption
+312   (int (*)(...))QAbstractSocket::waitForConnected
+320   (int (*)(...))QAbstractSocket::waitForDisconnected
+
+Class QUdpSocket
+   size=16 align=8
+   base size=16 base align=8
+QUdpSocket (0x0x7f3bf42a4138) 0
+    vptr=((& QUdpSocket::_ZTV10QUdpSocket) + 16)
+  QAbstractSocket (0x0x7f3bf42a41a0) 0
+      primary-for QUdpSocket (0x0x7f3bf42a4138)
+    QIODevice (0x0x7f3bf42a4208) 0
+        primary-for QAbstractSocket (0x0x7f3bf42a41a0)
+      QObject (0x0x7f3bf42a9000) 0
+          primary-for QIODevice (0x0x7f3bf42a4208)
+
+Class QRemoteObjectSourceLocationInfo
+   size=16 align=8
+   base size=16 base align=8
+QRemoteObjectSourceLocationInfo (0x0x7f3bf42a92a0) 0
+
+Class QAbstractItemModelReplica::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QAbstractItemModelReplica::QPrivateSignal (0x0x7f3bf3fa9180) 0 empty
+
+Vtable for QAbstractItemModelReplica
+QAbstractItemModelReplica::_ZTV25QAbstractItemModelReplica: 48 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI25QAbstractItemModelReplica)
+16    (int (*)(...))QAbstractItemModelReplica::metaObject
+24    (int (*)(...))QAbstractItemModelReplica::qt_metacast
+32    (int (*)(...))QAbstractItemModelReplica::qt_metacall
+40    (int (*)(...))QAbstractItemModelReplica::~QAbstractItemModelReplica
+48    (int (*)(...))QAbstractItemModelReplica::~QAbstractItemModelReplica
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QAbstractItemModelReplica::index
+120   (int (*)(...))QAbstractItemModelReplica::parent
+128   (int (*)(...))QAbstractItemModel::sibling
+136   (int (*)(...))QAbstractItemModelReplica::rowCount
+144   (int (*)(...))QAbstractItemModelReplica::columnCount
+152   (int (*)(...))QAbstractItemModelReplica::hasChildren
+160   (int (*)(...))QAbstractItemModelReplica::data
+168   (int (*)(...))QAbstractItemModelReplica::setData
+176   (int (*)(...))QAbstractItemModelReplica::headerData
+184   (int (*)(...))QAbstractItemModel::setHeaderData
+192   (int (*)(...))QAbstractItemModel::itemData
+200   (int (*)(...))QAbstractItemModel::setItemData
+208   (int (*)(...))QAbstractItemModel::mimeTypes
+216   (int (*)(...))QAbstractItemModel::mimeData
+224   (int (*)(...))QAbstractItemModel::canDropMimeData
+232   (int (*)(...))QAbstractItemModel::dropMimeData
+240   (int (*)(...))QAbstractItemModel::supportedDropActions
+248   (int (*)(...))QAbstractItemModel::supportedDragActions
+256   (int (*)(...))QAbstractItemModel::insertRows
+264   (int (*)(...))QAbstractItemModel::insertColumns
+272   (int (*)(...))QAbstractItemModel::removeRows
+280   (int (*)(...))QAbstractItemModel::removeColumns
+288   (int (*)(...))QAbstractItemModel::moveRows
+296   (int (*)(...))QAbstractItemModel::moveColumns
+304   (int (*)(...))QAbstractItemModel::fetchMore
+312   (int (*)(...))QAbstractItemModel::canFetchMore
+320   (int (*)(...))QAbstractItemModelReplica::flags
+328   (int (*)(...))QAbstractItemModel::sort
+336   (int (*)(...))QAbstractItemModel::buddy
+344   (int (*)(...))QAbstractItemModel::match
+352   (int (*)(...))QAbstractItemModel::span
+360   (int (*)(...))QAbstractItemModelReplica::roleNames
+368   (int (*)(...))QAbstractItemModel::submit
+376   (int (*)(...))QAbstractItemModel::revert
+
+Class QAbstractItemModelReplica
+   size=24 align=8
+   base size=24 base align=8
+QAbstractItemModelReplica (0x0x7f3bf42e5958) 0
+    vptr=((& QAbstractItemModelReplica::_ZTV25QAbstractItemModelReplica) + 16)
+  QAbstractItemModel (0x0x7f3bf42e59c0) 0
+      primary-for QAbstractItemModelReplica (0x0x7f3bf42e5958)
+    QObject (0x0x7f3bf3fa9120) 0
+        primary-for QAbstractItemModel (0x0x7f3bf42e59c0)
+
+Class ModelIndex
+   size=8 align=4
+   base size=8 base align=4
+ModelIndex (0x0x7f3bf3fa9300) 0
+
+Class IndexValuePair
+   size=40 align=8
+   base size=40 base align=8
+IndexValuePair (0x0x7f3bf3fa9ba0) 0
+
+Class DataEntries
+   size=8 align=8
+   base size=8 base align=8
+DataEntries (0x0x7f3bf4070420) 0
+
+Class MetaAndDataEntries
+   size=24 align=8
+   base size=24 base align=8
+MetaAndDataEntries (0x0x7f3bf4073dd0) 0
+  DataEntries (0x0x7f3bf4070e40) 0
+
+Class QRemoteObjectReplica::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QRemoteObjectReplica::QPrivateSignal (0x0x7f3bf3da21e0) 0 empty
+
+Vtable for QRemoteObjectReplica
+QRemoteObjectReplica::_ZTV20QRemoteObjectReplica: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI20QRemoteObjectReplica)
+16    (int (*)(...))QRemoteObjectReplica::metaObject
+24    (int (*)(...))QRemoteObjectReplica::qt_metacast
+32    (int (*)(...))QRemoteObjectReplica::qt_metacall
+40    (int (*)(...))QRemoteObjectReplica::~QRemoteObjectReplica
+48    (int (*)(...))QRemoteObjectReplica::~QRemoteObjectReplica
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QRemoteObjectReplica::setNode
+120   (int (*)(...))QRemoteObjectReplica::initialize
+
+Class QRemoteObjectReplica
+   size=32 align=8
+   base size=32 base align=8
+QRemoteObjectReplica (0x0x7f3bf3d5f068) 0
+    vptr=((& QRemoteObjectReplica::_ZTV20QRemoteObjectReplica) + 16)
+  QObject (0x0x7f3bf3da2180) 0
+      primary-for QRemoteObjectReplica (0x0x7f3bf3d5f068)
+
+Vtable for QRemoteObjectDynamicReplica
+QRemoteObjectDynamicReplica::_ZTV27QRemoteObjectDynamicReplica: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI27QRemoteObjectDynamicReplica)
+16    (int (*)(...))QRemoteObjectDynamicReplica::metaObject
+24    (int (*)(...))QRemoteObjectDynamicReplica::qt_metacast
+32    (int (*)(...))QRemoteObjectDynamicReplica::qt_metacall
+40    (int (*)(...))QRemoteObjectDynamicReplica::~QRemoteObjectDynamicReplica
+48    (int (*)(...))QRemoteObjectDynamicReplica::~QRemoteObjectDynamicReplica
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QRemoteObjectReplica::setNode
+120   (int (*)(...))QRemoteObjectReplica::initialize
+
+Class QRemoteObjectDynamicReplica
+   size=32 align=8
+   base size=32 base align=8
+QRemoteObjectDynamicReplica (0x0x7f3bf3d5f0d0) 0
+    vptr=((& QRemoteObjectDynamicReplica::_ZTV27QRemoteObjectDynamicReplica) + 16)
+  QRemoteObjectReplica (0x0x7f3bf3d5f138) 0
+      primary-for QRemoteObjectDynamicReplica (0x0x7f3bf3d5f0d0)
+    QObject (0x0x7f3bf3da2420) 0
+        primary-for QRemoteObjectReplica (0x0x7f3bf3d5f138)
+
+Class QRemoteObjectRegistry::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QRemoteObjectRegistry::QPrivateSignal (0x0x7f3bf3da24e0) 0 empty
+
+Vtable for QRemoteObjectRegistry
+QRemoteObjectRegistry::_ZTV21QRemoteObjectRegistry: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI21QRemoteObjectRegistry)
+16    (int (*)(...))QRemoteObjectRegistry::metaObject
+24    (int (*)(...))QRemoteObjectRegistry::qt_metacast
+32    (int (*)(...))QRemoteObjectRegistry::qt_metacall
+40    (int (*)(...))QRemoteObjectRegistry::~QRemoteObjectRegistry
+48    (int (*)(...))QRemoteObjectRegistry::~QRemoteObjectRegistry
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QRemoteObjectReplica::setNode
+120   (int (*)(...))QRemoteObjectRegistry::initialize
+
+Class QRemoteObjectRegistry
+   size=32 align=8
+   base size=32 base align=8
+QRemoteObjectRegistry (0x0x7f3bf3d5f1a0) 0
+    vptr=((& QRemoteObjectRegistry::_ZTV21QRemoteObjectRegistry) + 16)
+  QRemoteObjectReplica (0x0x7f3bf3d5f208) 0
+      primary-for QRemoteObjectRegistry (0x0x7f3bf3d5f1a0)
+    QObject (0x0x7f3bf3da2480) 0
+        primary-for QRemoteObjectReplica (0x0x7f3bf3d5f208)
+
+Class QRemoteObjectAbstractPersistedStore::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QRemoteObjectAbstractPersistedStore::QPrivateSignal (0x0x7f3bf3da2720) 0 empty
+
+Vtable for QRemoteObjectAbstractPersistedStore
+QRemoteObjectAbstractPersistedStore::_ZTV35QRemoteObjectAbstractPersistedStore: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI35QRemoteObjectAbstractPersistedStore)
+16    (int (*)(...))QRemoteObjectAbstractPersistedStore::metaObject
+24    (int (*)(...))QRemoteObjectAbstractPersistedStore::qt_metacast
+32    (int (*)(...))QRemoteObjectAbstractPersistedStore::qt_metacall
+40    0
+48    0
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))__cxa_pure_virtual
+120   (int (*)(...))__cxa_pure_virtual
+
+Class QRemoteObjectAbstractPersistedStore
+   size=16 align=8
+   base size=16 base align=8
+QRemoteObjectAbstractPersistedStore (0x0x7f3bf3d5f270) 0
+    vptr=((& QRemoteObjectAbstractPersistedStore::_ZTV35QRemoteObjectAbstractPersistedStore) + 16)
+  QObject (0x0x7f3bf3da26c0) 0
+      primary-for QRemoteObjectAbstractPersistedStore (0x0x7f3bf3d5f270)
+
+Class QRemoteObjectNode::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QRemoteObjectNode::QPrivateSignal (0x0x7f3bf3da29c0) 0 empty
+
+Vtable for QRemoteObjectNode
+QRemoteObjectNode::_ZTV17QRemoteObjectNode: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI17QRemoteObjectNode)
+16    (int (*)(...))QRemoteObjectNode::metaObject
+24    (int (*)(...))QRemoteObjectNode::qt_metacast
+32    (int (*)(...))QRemoteObjectNode::qt_metacall
+40    (int (*)(...))QRemoteObjectNode::~QRemoteObjectNode
+48    (int (*)(...))QRemoteObjectNode::~QRemoteObjectNode
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QRemoteObjectNode::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QRemoteObjectNode::setName
+120   (int (*)(...))QRemoteObjectNode::setRegistryUrl
+
+Class QRemoteObjectNode
+   size=16 align=8
+   base size=16 base align=8
+QRemoteObjectNode (0x0x7f3bf3d5f2d8) 0
+    vptr=((& QRemoteObjectNode::_ZTV17QRemoteObjectNode) + 16)
+  QObject (0x0x7f3bf3da2960) 0
+      primary-for QRemoteObjectNode (0x0x7f3bf3d5f2d8)
+
+Class QRemoteObjectHostBase::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QRemoteObjectHostBase::QPrivateSignal (0x0x7f3bf3da2d80) 0 empty
+
+Vtable for QRemoteObjectHostBase
+QRemoteObjectHostBase::_ZTV21QRemoteObjectHostBase: 18 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI21QRemoteObjectHostBase)
+16    (int (*)(...))QRemoteObjectHostBase::metaObject
+24    (int (*)(...))QRemoteObjectHostBase::qt_metacast
+32    (int (*)(...))QRemoteObjectHostBase::qt_metacall
+40    (int (*)(...))QRemoteObjectHostBase::~QRemoteObjectHostBase
+48    (int (*)(...))QRemoteObjectHostBase::~QRemoteObjectHostBase
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QRemoteObjectNode::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QRemoteObjectHostBase::setName
+120   (int (*)(...))QRemoteObjectNode::setRegistryUrl
+128   (int (*)(...))QRemoteObjectHostBase::hostUrl
+136   (int (*)(...))QRemoteObjectHostBase::setHostUrl
+
+Class QRemoteObjectHostBase
+   size=16 align=8
+   base size=16 base align=8
+QRemoteObjectHostBase (0x0x7f3bf3d5f340) 0
+    vptr=((& QRemoteObjectHostBase::_ZTV21QRemoteObjectHostBase) + 16)
+  QRemoteObjectNode (0x0x7f3bf3d5f3a8) 0
+      primary-for QRemoteObjectHostBase (0x0x7f3bf3d5f340)
+    QObject (0x0x7f3bf3da2d20) 0
+        primary-for QRemoteObjectNode (0x0x7f3bf3d5f3a8)
+
+Class QRemoteObjectHost::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QRemoteObjectHost::QPrivateSignal (0x0x7f3bf3eba000) 0 empty
+
+Vtable for QRemoteObjectHost
+QRemoteObjectHost::_ZTV17QRemoteObjectHost: 18 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI17QRemoteObjectHost)
+16    (int (*)(...))QRemoteObjectHost::metaObject
+24    (int (*)(...))QRemoteObjectHost::qt_metacast
+32    (int (*)(...))QRemoteObjectHost::qt_metacall
+40    (int (*)(...))QRemoteObjectHost::~QRemoteObjectHost
+48    (int (*)(...))QRemoteObjectHost::~QRemoteObjectHost
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QRemoteObjectNode::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QRemoteObjectHostBase::setName
+120   (int (*)(...))QRemoteObjectNode::setRegistryUrl
+128   (int (*)(...))QRemoteObjectHost::hostUrl
+136   (int (*)(...))QRemoteObjectHost::setHostUrl
+
+Class QRemoteObjectHost
+   size=16 align=8
+   base size=16 base align=8
+QRemoteObjectHost (0x0x7f3bf3e95c30) 0
+    vptr=((& QRemoteObjectHost::_ZTV17QRemoteObjectHost) + 16)
+  QRemoteObjectHostBase (0x0x7f3bf3e95c98) 0
+      primary-for QRemoteObjectHost (0x0x7f3bf3e95c30)
+    QRemoteObjectNode (0x0x7f3bf3e95d00) 0
+        primary-for QRemoteObjectHostBase (0x0x7f3bf3e95c98)
+      QObject (0x0x7f3bf3e91f60) 0
+          primary-for QRemoteObjectNode (0x0x7f3bf3e95d00)
+
+Class QRemoteObjectRegistryHost::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QRemoteObjectRegistryHost::QPrivateSignal (0x0x7f3bf3eba240) 0 empty
+
+Vtable for QRemoteObjectRegistryHost
+QRemoteObjectRegistryHost::_ZTV25QRemoteObjectRegistryHost: 18 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI25QRemoteObjectRegistryHost)
+16    (int (*)(...))QRemoteObjectRegistryHost::metaObject
+24    (int (*)(...))QRemoteObjectRegistryHost::qt_metacast
+32    (int (*)(...))QRemoteObjectRegistryHost::qt_metacall
+40    (int (*)(...))QRemoteObjectRegistryHost::~QRemoteObjectRegistryHost
+48    (int (*)(...))QRemoteObjectRegistryHost::~QRemoteObjectRegistryHost
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QRemoteObjectNode::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QRemoteObjectHostBase::setName
+120   (int (*)(...))QRemoteObjectRegistryHost::setRegistryUrl
+128   (int (*)(...))QRemoteObjectHostBase::hostUrl
+136   (int (*)(...))QRemoteObjectHostBase::setHostUrl
+
+Class QRemoteObjectRegistryHost
+   size=16 align=8
+   base size=16 base align=8
+QRemoteObjectRegistryHost (0x0x7f3bf3e95d68) 0
+    vptr=((& QRemoteObjectRegistryHost::_ZTV25QRemoteObjectRegistryHost) + 16)
+  QRemoteObjectHostBase (0x0x7f3bf3e95dd0) 0
+      primary-for QRemoteObjectRegistryHost (0x0x7f3bf3e95d68)
+    QRemoteObjectNode (0x0x7f3bf3e95e38) 0
+        primary-for QRemoteObjectHostBase (0x0x7f3bf3e95dd0)
+      QObject (0x0x7f3bf3eba1e0) 0
+          primary-for QRemoteObjectNode (0x0x7f3bf3e95e38)
+
+Class QRemoteObjectPendingCall
+   size=8 align=8
+   base size=8 base align=8
+QRemoteObjectPendingCall (0x0x7f3bf3eba420) 0
+
+Class QRemoteObjectPendingCallWatcher::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QRemoteObjectPendingCallWatcher::QPrivateSignal (0x0x7f3bf3eba780) 0 empty
+
+Vtable for QRemoteObjectPendingCallWatcher
+QRemoteObjectPendingCallWatcher::_ZTV31QRemoteObjectPendingCallWatcher: 14 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI31QRemoteObjectPendingCallWatcher)
+16    (int (*)(...))QRemoteObjectPendingCallWatcher::metaObject
+24    (int (*)(...))QRemoteObjectPendingCallWatcher::qt_metacast
+32    (int (*)(...))QRemoteObjectPendingCallWatcher::qt_metacall
+40    (int (*)(...))QRemoteObjectPendingCallWatcher::~QRemoteObjectPendingCallWatcher
+48    (int (*)(...))QRemoteObjectPendingCallWatcher::~QRemoteObjectPendingCallWatcher
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+
+Class QRemoteObjectPendingCallWatcher
+   size=24 align=8
+   base size=24 base align=8
+QRemoteObjectPendingCallWatcher (0x0x7f3bf3ee53f0) 0
+    vptr=((& QRemoteObjectPendingCallWatcher::_ZTV31QRemoteObjectPendingCallWatcher) + 16)
+  QObject (0x0x7f3bf3eba6c0) 0
+      primary-for QRemoteObjectPendingCallWatcher (0x0x7f3bf3ee53f0)
+  QRemoteObjectPendingCall (0x0x7f3bf3eba720) 16
+
+Class QRemoteObjectSettingsStore::QPrivateSignal
+   size=1 align=1
+   base size=0 base align=1
+QRemoteObjectSettingsStore::QPrivateSignal (0x0x7f3bf3ebac60) 0 empty
+
+Vtable for QRemoteObjectSettingsStore
+QRemoteObjectSettingsStore::_ZTV26QRemoteObjectSettingsStore: 16 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI26QRemoteObjectSettingsStore)
+16    (int (*)(...))QRemoteObjectSettingsStore::metaObject
+24    (int (*)(...))QRemoteObjectSettingsStore::qt_metacast
+32    (int (*)(...))QRemoteObjectSettingsStore::qt_metacall
+40    (int (*)(...))QRemoteObjectSettingsStore::~QRemoteObjectSettingsStore
+48    (int (*)(...))QRemoteObjectSettingsStore::~QRemoteObjectSettingsStore
+56    (int (*)(...))QObject::event
+64    (int (*)(...))QObject::eventFilter
+72    (int (*)(...))QObject::timerEvent
+80    (int (*)(...))QObject::childEvent
+88    (int (*)(...))QObject::customEvent
+96    (int (*)(...))QObject::connectNotify
+104   (int (*)(...))QObject::disconnectNotify
+112   (int (*)(...))QRemoteObjectSettingsStore::saveProperties
+120   (int (*)(...))QRemoteObjectSettingsStore::restoreProperties
+
+Class QRemoteObjectSettingsStore
+   size=16 align=8
+   base size=16 base align=8
+QRemoteObjectSettingsStore (0x0x7f3bf3ef70d0) 0
+    vptr=((& QRemoteObjectSettingsStore::_ZTV26QRemoteObjectSettingsStore) + 16)
+  QRemoteObjectAbstractPersistedStore (0x0x7f3bf3ef7138) 0
+      primary-for QRemoteObjectSettingsStore (0x0x7f3bf3ef70d0)
+    QObject (0x0x7f3bf3ebac00) 0
+        primary-for QRemoteObjectAbstractPersistedStore (0x0x7f3bf3ef7138)
+
+Class QtPrivate::QMetaObjectPrivate
+   size=56 align=4
+   base size=56 base align=4
+QtPrivate::QMetaObjectPrivate (0x0x7f3bf3b311e0) 0
+
+Class ModelInfo
+   size=24 align=8
+   base size=24 base align=8
+ModelInfo (0x0x7f3bf3b31ea0) 0
+
+Vtable for SourceApiMap
+SourceApiMap::_ZTV12SourceApiMap: 32 entries
+0     (int (*)(...))0
+8     (int (*)(...))(& _ZTI12SourceApiMap)
+16    0
+24    0
+32    (int (*)(...))__cxa_pure_virtual
+40    (int (*)(...))__cxa_pure_virtual
+48    (int (*)(...))SourceApiMap::className
+56    (int (*)(...))__cxa_pure_virtual
+64    (int (*)(...))__cxa_pure_virtual
+72    (int (*)(...))__cxa_pure_virtual
+80    (int (*)(...))__cxa_pure_virtual
+88    (int (*)(...))__cxa_pure_virtual
+96    (int (*)(...))__cxa_pure_virtual
+104   (int (*)(...))__cxa_pure_virtual
+112   (int (*)(...))__cxa_pure_virtual
+120   (int (*)(...))__cxa_pure_virtual
+128   (int (*)(...))__cxa_pure_virtual
+136   (int (*)(...))__cxa_pure_virtual
+144   (int (*)(...))__cxa_pure_virtual
+152   (int (*)(...))__cxa_pure_virtual
+160   (int (*)(...))__cxa_pure_virtual
+168   (int (*)(...))__cxa_pure_virtual
+176   (int (*)(...))__cxa_pure_virtual
+184   (int (*)(...))__cxa_pure_virtual
+192   (int (*)(...))__cxa_pure_virtual
+200   (int (*)(...))__cxa_pure_virtual
+208   (int (*)(...))__cxa_pure_virtual
+216   (int (*)(...))__cxa_pure_virtual
+224   (int (*)(...))SourceApiMap::isDynamic
+232   (int (*)(...))SourceApiMap::isAdapterSignal
+240   (int (*)(...))SourceApiMap::isAdapterMethod
+248   (int (*)(...))SourceApiMap::isAdapterProperty
+
+Class SourceApiMap
+   size=24 align=8
+   base size=24 base align=8
+SourceApiMap (0x0x7f3bf3b31f00) 0
+    vptr=((& SourceApiMap::_ZTV12SourceApiMap) + 16)
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3bf3900) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf3bf3c60) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3bf3e40) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf3c241e0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3c243c0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf3c24720) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3c24900) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf3c24c60) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3c24e40) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf3c591e0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3c593c0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf3c59720) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3c59900) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf3c59c60) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3c59e40) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf3c911e0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3cbb6c0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf3cbba20) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3cbbba0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf3cbbf00) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3ceb0c0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf3ceb420) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3ceb5a0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf3ceb900) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3ceba80) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf3cebde0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3cebf60) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf389f300) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf389f480) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf389f7e0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+   size=4 align=4
+   base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf389f960) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+   size=1 align=1
+   base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf389fcc0) 0 empty
+
diff --git a/tests/auto/cmake/CMakeLists.txt b/tests/auto/cmake/CMakeLists.txt
new file mode 100644 (file)
index 0000000..52910eb
--- /dev/null
@@ -0,0 +1,46 @@
+# This is an automatic test for the CMake configuration files.
+# To run it manually,
+# 1) mkdir build   # Create a build directory
+# 2) cd build
+# 3) # Run cmake on this directory
+#    `$qt_prefix/bin/qt-cmake ..` or `cmake -DCMAKE_PREFIX_PATH=/path/to/qt ..`
+# 4) ctest         # Run ctest
+
+cmake_minimum_required(VERSION 3.16)
+project(remoteobjects_cmake_tests)
+enable_testing()
+
+set(required_packages Core Network RemoteObjects)
+
+# Setup the test when called as a completely standalone project.
+if(TARGET Qt6::Core)
+    # Tests are built as part of the repository's build tree.
+    # Setup paths so that the Qt packages are found.
+    qt_internal_set_up_build_dir_package_paths()
+endif()
+
+find_package(Qt6 REQUIRED COMPONENTS ${required_packages})
+
+# Setup common test variables which were previously set by ctest_testcase_common.prf.
+set(CMAKE_MODULES_UNDER_TEST "${required_packages}")
+
+foreach(qt_package ${CMAKE_MODULES_UNDER_TEST})
+    set(package_name "${QT_CMAKE_EXPORT_NAMESPACE}${qt_package}")
+    if(${package_name}_FOUND)
+        set(CMAKE_${qt_package}_MODULE_MAJOR_VERSION "${${package_name}_VERSION_MAJOR}")
+        set(CMAKE_${qt_package}_MODULE_MINOR_VERSION "${${package_name}_VERSION_MINOR}")
+        set(CMAKE_${qt_package}_MODULE_PATCH_VERSION "${${package_name}_VERSION_PATCH}")
+    endif()
+endforeach()
+
+include("${_Qt6CTestMacros}")
+
+set(module_includes
+    RemoteObjects QRemoteObjectNode
+)
+
+_qt_internal_test_module_includes(
+    ${module_includes}
+)
+
+_qt_internal_test_expect_pass(test_cmake_macros)
diff --git a/tests/auto/cmake/test_cmake_macros/CMakeLists.txt b/tests/auto/cmake/test_cmake_macros/CMakeLists.txt
new file mode 100644 (file)
index 0000000..62c1801
--- /dev/null
@@ -0,0 +1,13 @@
+cmake_minimum_required(VERSION 3.16)
+
+project(test_qremoteobjects_module)
+
+find_package(Qt6RemoteObjects REQUIRED)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(MAIN_SRCS main.cpp)
+add_executable(mainapp ${MAIN_SRCS})
+qt6_add_repc_replicas(mainapp ../../integration/pod.rep)
+
+target_link_libraries(mainapp Qt::RemoteObjects)
diff --git a/tests/auto/cmake/test_cmake_macros/main.cpp b/tests/auto/cmake/test_cmake_macros/main.cpp
new file mode 100644 (file)
index 0000000..c8af883
--- /dev/null
@@ -0,0 +1,40 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include <QRemoteObjectNode>
+
+#include "rep_pod_replica.h"
+
+int main(int argc, char **argv)
+{
+  QRemoteObjectNode node;
+
+  MyClassReplica replica;
+
+  return 0;
+}
diff --git a/tests/auto/external_IODevice/CMakeLists.txt b/tests/auto/external_IODevice/CMakeLists.txt
new file mode 100644 (file)
index 0000000..a192d1e
--- /dev/null
@@ -0,0 +1,3 @@
+
+add_subdirectory(sslTestServer)
+add_subdirectory(tst_client)
diff --git a/tests/auto/external_IODevice/cert/cert.qrc b/tests/auto/external_IODevice/cert/cert.qrc
new file mode 100644 (file)
index 0000000..65f92e2
--- /dev/null
@@ -0,0 +1,11 @@
+<RCC>
+    <qresource prefix="/sslcert">
+        <file>client.crt</file>
+        <file>client.key</file>
+        <file>rootCA.key</file>
+        <file>rootCA.pem</file>
+        <file>rootCA.srl</file>
+        <file>server.crt</file>
+        <file>server.key</file>
+    </qresource>
+</RCC>
diff --git a/tests/auto/external_IODevice/cert/client.crt b/tests/auto/external_IODevice/cert/client.crt
new file mode 100644 (file)
index 0000000..3aa0ff8
--- /dev/null
@@ -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/tests/auto/external_IODevice/cert/client.key b/tests/auto/external_IODevice/cert/client.key
new file mode 100644 (file)
index 0000000..b3f4f1a
--- /dev/null
@@ -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/tests/auto/external_IODevice/cert/generate.sh b/tests/auto/external_IODevice/cert/generate.sh
new file mode 100644 (file)
index 0000000..b79c862
--- /dev/null
@@ -0,0 +1,70 @@
+#!/bin/sh
+#############################################################################
+##
+## Copyright (C) 2021 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is the build configuration utility 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$
+##
+#############################################################################
+
+# Generate the CA key
+openssl genrsa -out rootCA.key 2048
+# Generate the CA cert
+openssl req -x509 -key rootCA.key -out rootCA.pem -sha256 -nodes -subj "/CN=QtRO CA" -days 836
+
+# genFiles stem [extra args to signing]
+genFiles () {
+    stem=$1
+    shift
+    # Generate key
+    openssl genrsa -out $stem.key 2048
+    # Generate certificate-signing request
+    openssl req -new -key $stem.key -out $stem.csr -subj "/CN=127.0.0.1"
+    # Generate and sign the certificate
+    openssl x509 -req -in $stem.csr -out $stem.crt \
+                 -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -days 825 -sha256 "$@"
+    # Delete the signing request, no longer needed
+    rm $stem.csr
+}
+genFiles server -extfile server-req.ext
+genFiles client
+
+dest1="../../../../examples/remoteobjects/ssl/sslserver/cert/"
+dest2="../../../../examples/remoteobjects/websockets/common/cert/"
+
+cp -f "client.crt" $dest1
+cp -f "client.crt" $dest2
+cp -f "client.key" $dest1
+cp -f "client.key" $dest2
+
+cp -f "server.crt" $dest1
+cp -f "server.crt" $dest2
+cp -f "server.key" $dest1
+cp -f "server.key" $dest2
+
+cp -f "rootCA.pem" $dest1
+cp -f "rootCA.key" $dest1
+cp -f "rootCA.srl" $dest1
+cp -f "rootCA.pem" $dest2
+cp -f "rootCA.key" $dest2
+cp -f "rootCA.srl" $dest2
diff --git a/tests/auto/external_IODevice/cert/rootCA.key b/tests/auto/external_IODevice/cert/rootCA.key
new file mode 100644 (file)
index 0000000..1647817
--- /dev/null
@@ -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/tests/auto/external_IODevice/cert/rootCA.pem b/tests/auto/external_IODevice/cert/rootCA.pem
new file mode 100644 (file)
index 0000000..7f6cce5
--- /dev/null
@@ -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/tests/auto/external_IODevice/cert/rootCA.srl b/tests/auto/external_IODevice/cert/rootCA.srl
new file mode 100644 (file)
index 0000000..d292c9f
--- /dev/null
@@ -0,0 +1 @@
+7390820BD47F5A3C7398B7C8DCA218B35C2C2E29
diff --git a/tests/auto/external_IODevice/cert/server-req.ext b/tests/auto/external_IODevice/cert/server-req.ext
new file mode 100644 (file)
index 0000000..dc4377e
--- /dev/null
@@ -0,0 +1,8 @@
+authorityKeyIdentifier=keyid,issuer
+basicConstraints=CA:FALSE
+keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
+extendedKeyUsage = serverAuth
+subjectAltName = @alt_names
+
+[alt_names]
+IP.1 = 127.0.0.1
diff --git a/tests/auto/external_IODevice/cert/server.crt b/tests/auto/external_IODevice/cert/server.crt
new file mode 100644 (file)
index 0000000..df9d55c
--- /dev/null
@@ -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/tests/auto/external_IODevice/cert/server.key b/tests/auto/external_IODevice/cert/server.key
new file mode 100644 (file)
index 0000000..05144f4
--- /dev/null
@@ -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/tests/auto/external_IODevice/pingpong.rep b/tests/auto/external_IODevice/pingpong.rep
new file mode 100644 (file)
index 0000000..f981e55
--- /dev/null
@@ -0,0 +1,8 @@
+#include <QtCore>
+
+class PingPong
+{
+    SLOT(void ping(const QString &message));
+    SLOT(void quit());
+    SIGNAL(pong(const QString &message));
+};
diff --git a/tests/auto/external_IODevice/sslTestServer/CMakeLists.txt b/tests/auto/external_IODevice/sslTestServer/CMakeLists.txt
new file mode 100644 (file)
index 0000000..4f11f48
--- /dev/null
@@ -0,0 +1,44 @@
+
+#####################################################################
+## sslTestServer Binary:
+#####################################################################
+
+qt_internal_add_executable(sslTestServer
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        main.cpp
+        pingpong.cpp pingpong.h
+        sslserver.cpp sslserver.h
+    INCLUDE_DIRECTORIES
+        ${CMAKE_CURRENT_SOURCE_DIR}
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+
+# 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"
+)
+
+qt_internal_add_resource(sslTestServer "cert"
+    PREFIX
+        "/sslcert"
+    BASE
+        "../cert"
+    FILES
+        ${cert_resource_files}
+)
+
+qt6_add_repc_sources(sslTestServer
+    ../pingpong.rep
+)
+
+#### Keys ignored in scope 1:.:.:sslTestServer.pro:<TRUE>:
+# TEMPLATE = "app"
diff --git a/tests/auto/external_IODevice/sslTestServer/main.cpp b/tests/auto/external_IODevice/sslTestServer/main.cpp
new file mode 100644 (file)
index 0000000..b20eef6
--- /dev/null
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include "pingpong.h"
+#include "sslserver.h"
+
+#include <QCoreApplication>
+#include <QDebug>
+#include <QSslConfiguration>
+
+#include <QRemoteObjectHost>
+
+int main(int argc, char *argv[])
+{
+    QCoreApplication app(argc, argv);
+    QRemoteObjectHost host;
+    auto config = QSslConfiguration::defaultConfiguration();
+    config.setCaCertificates(QSslCertificate::fromPath(QStringLiteral(":/sslcert/rootCA.pem")));
+    QSslConfiguration::setDefaultConfiguration(config);
+    SslServer server;
+    server.listen(QHostAddress::Any, 65111);
+    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;
+            exit(1);
+        });
+        host.addHostSideConnection(socket);
+    });
+
+    PingPong pp;
+    host.enableRemoting(&pp);
+    return app.exec();
+}
diff --git a/tests/auto/external_IODevice/sslTestServer/pingpong.cpp b/tests/auto/external_IODevice/sslTestServer/pingpong.cpp
new file mode 100644 (file)
index 0000000..a014103
--- /dev/null
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include <QDebug>
+#include <QTimer>
+#include "pingpong.h"
+
+PingPong::PingPong(QObject *parent)
+    : PingPongSimpleSource(parent)
+{}
+
+void PingPong::ping(const QString &message)
+{
+    emit pong("Pong " + message);
+}
+
+void PingPong::quit()
+{
+    // Kill me softly
+    QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection);
+}
diff --git a/tests/auto/external_IODevice/sslTestServer/pingpong.h b/tests/auto/external_IODevice/sslTestServer/pingpong.h
new file mode 100644 (file)
index 0000000..2a7a788
--- /dev/null
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#ifndef PINGPONG_H
+#define PINGPONG_H
+
+#include "rep_pingpong_source.h"
+
+class PingPong : public PingPongSimpleSource
+{
+public:
+    PingPong(QObject *parent = nullptr);
+
+    // PingPongSource interface
+public slots:
+    void ping(const QString &message) override;
+    void quit() override;
+};
+
+#endif // PINGPONG_H
diff --git a/tests/auto/external_IODevice/sslTestServer/sslserver.cpp b/tests/auto/external_IODevice/sslTestServer/sslserver.cpp
new file mode 100644 (file)
index 0000000..725567c
--- /dev/null
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include "sslserver.h"
+#include <QSslSocket>
+
+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<void (QSslSocket::*)(const QList<QSslError>&)>(&QSslSocket::sslErrors),
+                this, [serverSocket](const QList<QSslError>& 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/tests/auto/external_IODevice/sslTestServer/sslserver.h b/tests/auto/external_IODevice/sslTestServer/sslserver.h
new file mode 100644 (file)
index 0000000..237823b
--- /dev/null
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#ifndef SSLSERVER_H
+#define SSLSERVER_H
+
+#include <QTcpServer>
+
+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/tests/auto/external_IODevice/tst_client/CMakeLists.txt b/tests/auto/external_IODevice/tst_client/CMakeLists.txt
new file mode 100644 (file)
index 0000000..75a9f7d
--- /dev/null
@@ -0,0 +1,36 @@
+
+#####################################################################
+## tst_external_IODevice Test:
+#####################################################################
+
+qt_internal_add_test(tst_external_IODevice
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        tst_client.cpp
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+)
+
+# 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"
+)
+
+qt_internal_add_resource(tst_external_IODevice "cert"
+    PREFIX
+        "/sslcert"
+    BASE
+        "../cert"
+    FILES
+        ${cert_resource_files}
+)
+
+qt6_add_repc_replicas(tst_external_IODevice
+    ../pingpong.rep
+)
diff --git a/tests/auto/external_IODevice/tst_client/tst_client.cpp b/tests/auto/external_IODevice/tst_client/tst_client.cpp
new file mode 100644 (file)
index 0000000..56fd1d3
--- /dev/null
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QRemoteObjectNode>
+#include <QScopedPointer>
+#include "rep_pingpong_replica.h"
+
+#include "../../../shared/testutils.h"
+
+class tst_clientSSL: public QObject
+{
+    Q_OBJECT
+public:
+    tst_clientSSL() = default;
+
+private slots:
+    void initTestCase()
+    {
+        QVERIFY(TestUtils::init("tst_client"));
+    }
+    void testRun()
+    {
+        QProcess serverProc;
+        serverProc.setProcessChannelMode(QProcess::ForwardedChannels);
+        serverProc.start(TestUtils::findExecutable("sslTestServer", "/sslTestServer"),
+                         QStringList());
+        QVERIFY(serverProc.waitForStarted());
+
+        // wait for server start
+        QTest::qWait(200);
+        QRemoteObjectNode m_client;
+        auto config = QSslConfiguration::defaultConfiguration();
+        config.setCaCertificates(QSslCertificate::fromPath(QStringLiteral(":/sslcert/rootCA.pem")));
+        QSslConfiguration::setDefaultConfiguration(config);
+
+        QScopedPointer<QSslSocket> 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"), 65111);
+        QVERIFY(socketClient->waitForEncrypted(-1));
+
+        connect(socketClient.data(), &QSslSocket::errorOccurred,
+                socketClient.data(), [](QAbstractSocket::SocketError error){
+            QCOMPARE(error, QAbstractSocket::RemoteHostClosedError);
+        });
+        m_client.addClientSideConnection(socketClient.data());
+
+        QScopedPointer<PingPongReplica> pp{m_client.acquire<PingPongReplica>()};
+        QVERIFY(pp->waitForSource());
+
+        QString pongStr;
+        connect(pp.data(), &PingPongReplica::pong, [&pongStr](const QString &str) {
+            pongStr = str;
+        });
+        pp->ping("yahoo");
+        QTRY_COMPARE(pongStr, "Pong yahoo");
+        pp->ping("one more");
+        QTRY_COMPARE(pongStr, "Pong one more");
+        pp->ping("last one");
+        QTRY_COMPARE(pongStr, "Pong last one");
+        pp->quit();
+        QTRY_VERIFY(serverProc.state() != QProcess::Running);
+        QCOMPARE(serverProc.exitCode(), 0);
+    }
+};
+
+QTEST_MAIN(tst_clientSSL)
+
+#include "tst_client.moc"
diff --git a/tests/auto/integration/CMakeLists.txt b/tests/auto/integration/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9b8c46e
--- /dev/null
@@ -0,0 +1,31 @@
+
+#####################################################################
+## tst_integration Test:
+#####################################################################
+
+qt_internal_add_test(tst_integration
+    SOURCES
+        engine.cpp engine.h
+        speedometer.cpp speedometer.h
+        temperature.h
+        tst_integration.cpp
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+)
+qt6_add_repc_sources(tst_integration
+    engine.rep
+    ../repfiles/localdatacenter.rep
+    ../repfiles/tcpdatacenter.rep
+)
+qt6_add_repc_replicas(tst_integration
+        engine.rep
+        ../repfiles/localdatacenter.rep
+        ../repfiles/tcpdatacenter.rep
+)
+qt6_add_repc_merged(tst_integration
+            speedometer.rep
+            enum.rep
+            pod.rep
+)
+
+add_dependencies(tst_integration localsockettestserver)
diff --git a/tests/auto/integration/engine.cpp b/tests/auto/integration/engine.cpp
new file mode 100644 (file)
index 0000000..9f1c103
--- /dev/null
@@ -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: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$
+**
+****************************************************************************/
+
+#include "engine.h"
+
+Engine::Engine(int cylinders, QObject *parent) :
+  EngineSimpleSource(cylinders, parent)
+{
+    setRpm(0);
+    setpurchasedPart(false);
+}
+
+Engine::~Engine()
+{
+}
+
+bool Engine::start()
+{
+    if (started())
+        return false; // already started
+
+    setStarted(true);
+    return true;
+}
+
+void Engine::increaseRpm(int deltaRpm)
+{
+    setRpm(rpm() + deltaRpm);
+}
+
+Temperature Engine::temperature()
+{
+    return _temperature;
+}
+
+void Engine::setTemperature(const Temperature &value)
+{
+    _temperature = value;
+}
+
+void Engine::setpurchasedPart(bool value)
+{
+    _purchasedPart = value;
+}
diff --git a/tests/auto/integration/engine.h b/tests/auto/integration/engine.h
new file mode 100644 (file)
index 0000000..12ef36a
--- /dev/null
@@ -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: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$
+**
+****************************************************************************/
+
+#ifndef TESTS_ENGINE_H
+#define TESTS_ENGINE_H
+
+#include "rep_engine_source.h"
+
+class Engine : public EngineSimpleSource
+{
+    Q_OBJECT
+    Q_PROPERTY(bool purchasedPart READ purchasedPart WRITE setpurchasedPart)
+
+public:
+    Engine(int cylinders = 4, QObject *parent = nullptr);
+    ~Engine() override;
+
+    bool start() override;
+    void increaseRpm(int deltaRpm) override;
+
+    void unnormalizedSignature(int, int) override {}
+
+    Temperature temperature() override;
+    void setTemperature(const Temperature &value);
+
+    void setSharedTemperature(const Temperature::Ptr &) override {}
+
+    bool purchasedPart() {return _purchasedPart;}
+
+public Q_SLOTS:
+    void setpurchasedPart(bool value);
+
+    QString myTestString() override { return _myTestString; }
+    void setMyTestString(QString value) override { _myTestString = value; }
+
+private:
+    bool _purchasedPart;
+    QString _myTestString;
+    Temperature _temperature;
+};
+
+#endif
diff --git a/tests/auto/integration/engine.rep b/tests/auto/integration/engine.rep
new file mode 100644 (file)
index 0000000..d486aa8
--- /dev/null
@@ -0,0 +1,21 @@
+#include "temperature.h"
+
+class Engine
+{
+    ENUM EngineType { GAS=0, ELECTRIC=1, HYBRID=2 }
+    PROP(int cylinders = 4 CONSTANT);
+    PROP(bool started);
+    PROP(int rpm READWRITE);
+    PROP(EngineType engineType=GAS PERSISTED)
+
+    SLOT(bool start());
+    SLOT(void increaseRpm(int deltaRpm));
+
+    SLOT(void unnormalizedSignature(int a, int b));
+
+    SLOT(Temperature temperature())
+    SLOT(void setSharedTemperature(const Temperature::Ptr &sharedTemperature))
+
+    SLOT(QString myTestString())
+    SLOT(setMyTestString(QString value))
+};
diff --git a/tests/auto/integration/enum.rep b/tests/auto/integration/enum.rep
new file mode 100644 (file)
index 0000000..8831926
--- /dev/null
@@ -0,0 +1,9 @@
+ENUM Test {TRUE, FALSE}
+
+class TestClass
+{
+    ENUM ClassEnum {Null, One, Two}
+    PROP(TestEnum::Test testEnum)
+    PROP(ClassEnum classEnum)
+    PROP(ClassEnum classEnumRW READWRITE)
+}
diff --git a/tests/auto/integration/pod.rep b/tests/auto/integration/pod.rep
new file mode 100644 (file)
index 0000000..8a006d8
--- /dev/null
@@ -0,0 +1,6 @@
+POD MyPOD(int i, float f, QString s)
+
+class MyClass
+{
+    PROP(MyPOD myPOD)
+}
diff --git a/tests/auto/integration/speedometer.cpp b/tests/auto/integration/speedometer.cpp
new file mode 100644 (file)
index 0000000..91ca5e0
--- /dev/null
@@ -0,0 +1,38 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include "speedometer.h"
+
+Speedometer::Speedometer(QObject *parent) :
+  SpeedometerSimpleSource(parent)
+{
+}
+
+Speedometer::~Speedometer()
+{
+}
diff --git a/tests/auto/integration/speedometer.h b/tests/auto/integration/speedometer.h
new file mode 100644 (file)
index 0000000..7514e12
--- /dev/null
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#ifndef TESTS_SPEEDOMETER_H
+#define TESTS_SPEEDOMETER_H
+
+#include "rep_speedometer_merged.h"
+
+class Speedometer : public SpeedometerSimpleSource
+{
+    Q_OBJECT
+public:
+    Speedometer(QObject *parent = nullptr);
+    ~Speedometer() override;
+
+private:
+    int speed;
+};
+
+#endif
diff --git a/tests/auto/integration/speedometer.rep b/tests/auto/integration/speedometer.rep
new file mode 100644 (file)
index 0000000..a8d36b4
--- /dev/null
@@ -0,0 +1,4 @@
+class Speedometer
+{
+    PROP(int mph);
+};
diff --git a/tests/auto/integration/temperature.h b/tests/auto/integration/temperature.h
new file mode 100644 (file)
index 0000000..d989258
--- /dev/null
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#ifndef TEMPERATURE_H
+#define TEMPERATURE_H
+
+#include <QSharedPointer>
+#include <QString>
+
+class Temperature
+{
+public:
+    typedef QSharedPointer<Temperature> Ptr;
+
+    Temperature() : _value(0) {}
+    Temperature(double value, const QString &unit) : _value(value), _unit(unit) {}
+
+    void setValue(double arg) { _value = arg; }
+    double value() const { return _value; }
+
+    void setUnit(const QString &arg) { _unit = arg; }
+    QString unit() const { return _unit; }
+
+private:
+    double _value;
+    QString _unit;
+};
+
+inline bool operator==(const Temperature &lhs, const Temperature &rhs)
+{
+    return lhs.unit() == rhs.unit() &&
+            lhs.value() == rhs.value();
+}
+
+inline bool operator!=(const Temperature &lhs, const Temperature &rhs)
+{
+    return !(lhs == rhs);
+}
+
+inline QDataStream &operator<<(QDataStream &out, const Temperature &temperature)
+{
+    out << temperature.value();
+    out << temperature.unit();
+    return out;
+}
+
+inline QDataStream &operator>>(QDataStream &in, Temperature &temperature)
+{
+    double value;
+    in >> value;
+    temperature.setValue(value);
+
+    QString unit;
+    in >> unit;
+    temperature.setUnit(unit);
+    return in;
+}
+
+inline QDataStream &operator>>(QDataStream &out, const Temperature::Ptr& temperaturePtr)
+{
+    out << *temperaturePtr;
+    return out;
+}
+
+inline QDataStream &operator>>(QDataStream &in, Temperature::Ptr& temperaturePtr)
+{
+    Temperature *temperature = new Temperature;
+    in >> *temperature;
+    temperaturePtr.reset(temperature);
+    return in;
+}
+
+Q_DECLARE_METATYPE(Temperature);
+Q_DECLARE_METATYPE(Temperature::Ptr);
+
+#endif
diff --git a/tests/auto/integration/tst_integration.cpp b/tests/auto/integration/tst_integration.cpp
new file mode 100644 (file)
index 0000000..c4a1369
--- /dev/null
@@ -0,0 +1,1535 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include "../../shared/testutils.h"
+
+#include <QtTest/QtTest>
+#include <QMetaType>
+#if QT_CONFIG(process)
+#include <QProcess>
+#endif
+#include <QFileInfo>
+#include <QTcpServer>
+#include <QTcpSocket>
+
+#include <QRemoteObjectReplica>
+#include <QRemoteObjectNode>
+#include <QRemoteObjectSettingsStore>
+#include "engine.h"
+#include "speedometer.h"
+#include "rep_engine_replica.h"
+#include "rep_speedometer_merged.h"
+#include "rep_enum_merged.h"
+#include "rep_pod_merged.h"
+#include "rep_localdatacenter_source.h"
+#include "rep_tcpdatacenter_source.h"
+#include "rep_localdatacenter_replica.h"
+#include "rep_tcpdatacenter_replica.h"
+
+#define SET_NODE_NAME(obj) (obj).setName(QLatin1String(#obj))
+
+//DUMMY impl for variant comparison
+bool operator<(const QList<int> &lhs, const QList<int> &rhs)
+{
+    return lhs.size() < rhs.size();
+}
+
+class TestLargeData: public QObject
+{
+    Q_OBJECT
+
+Q_SIGNALS:
+    void send(const QByteArray &data);
+};
+
+class TestDynamicBase : public QObject
+{
+    Q_OBJECT
+public:
+    TestDynamicBase(QObject *parent=nullptr) : QObject(parent) {}
+
+signals:
+    void otherValueChanged();
+};
+
+
+class TestDynamic : public TestDynamicBase
+{
+    Q_OBJECT
+    Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)
+    Q_PROPERTY(int otherValue READ otherValue WRITE setOtherValue NOTIFY otherValueChanged)
+public:
+    TestDynamic(QObject *parent=nullptr) :
+        TestDynamicBase(parent),
+        m_value(0),
+        m_otherValue(0) {}
+
+    int value() const { return m_value; }
+    void setValue(int value)
+    {
+        if (m_value == value)
+            return;
+
+        m_value = value;
+        emit valueChanged();
+    }
+
+    int otherValue() const { return m_otherValue; }
+    void setOtherValue(int otherValue)
+    {
+        if (m_otherValue == otherValue)
+            return;
+
+        m_otherValue = otherValue;
+        emit otherValueChanged();
+    }
+
+signals:
+    void valueChanged();
+
+private:
+    int m_value;
+    int m_otherValue;
+};
+
+class TestPersistedStore : public QRemoteObjectAbstractPersistedStore
+{
+    Q_OBJECT
+
+public:
+    TestPersistedStore() : type(EngineReplica::HYBRID) {}
+    void saveProperties(const QString &, const QByteArray &, const QVariantList &values) override
+    {
+        type = values.at(0).value<EngineReplica::EngineType>();
+    }
+    QVariantList restoreProperties(const QString &, const QByteArray &) override
+    {
+        return QVariantList() << QVariant::fromValue(type);
+    }
+private:
+    EngineReplica::EngineType type;
+};
+
+class tst_Integration: public QObject
+{
+    Q_OBJECT
+
+    void setupTcp()
+    {
+        if (!tcpServer) {
+            tcpServer = new QTcpServer;
+            tcpServer->listen(QHostAddress::Any, 65511);
+            socketClient = new QTcpSocket;
+            socketClient->connectToHost(QHostAddress::LocalHost, tcpServer->serverPort());
+            QVERIFY(socketClient->waitForConnected(5000));
+
+            QVERIFY(tcpServer->waitForNewConnection(5000));
+            QVERIFY(tcpServer->hasPendingConnections());
+            socketServer = tcpServer->nextPendingConnection();
+        }
+    }
+
+    void setupHost(bool useRegistry=false)
+    {
+        QFETCH_GLOBAL(QUrl, hostUrl);
+        QFETCH_GLOBAL(QUrl, registryUrl);
+        host = new QRemoteObjectHost;
+        SET_NODE_NAME(*host);
+        if (!hostUrl.isEmpty()) {
+            host->setHostUrl(hostUrl);
+            if (useRegistry)
+                host->setRegistryUrl(registryUrl);
+        } else {
+            setupTcp();
+            host->addHostSideConnection(socketServer);
+        }
+    }
+
+    void setupClient(bool useRegistry=false)
+    {
+        QFETCH_GLOBAL(QUrl, hostUrl);
+        QFETCH_GLOBAL(QUrl, registryUrl);
+        client = new QRemoteObjectNode;
+        Q_SET_OBJECT_NAME(*client);
+        if (!hostUrl.isEmpty())
+        {
+            if (useRegistry)
+                client->setRegistryUrl(registryUrl);
+            else {
+                client->connectToNode(hostUrl);
+            }
+        } else {
+            setupTcp();
+            client->addClientSideConnection(socketClient);
+        }
+    }
+
+    void setupRegistry()
+    {
+        QFETCH_GLOBAL(QUrl, registryUrl);
+        registry = new QRemoteObjectRegistryHost(registryUrl);
+        SET_NODE_NAME(*registry);
+    }
+
+signals:
+    void forwardResult(int);
+
+private:
+    QRemoteObjectHost *host;
+    QRemoteObjectNode *client;
+    QRemoteObjectRegistryHost *registry;
+    QTcpServer *tcpServer;
+    QPointer<QTcpSocket> socketClient, socketServer;
+
+private slots:
+    void initTestCase_data()
+    {
+        QTest::addColumn<QUrl>("hostUrl");
+        QTest::addColumn<QUrl>("registryUrl");
+
+        QTest::newRow("tcp") << QUrl(QLatin1String("tcp://127.0.0.1:65511")) << QUrl(QLatin1String("tcp://127.0.0.1:65512"));
+#ifdef __QNXNTO__
+        QTest::newRow("qnx") << QUrl(QLatin1String("qnx:replica")) << QUrl(QLatin1String("qnx:registry"));
+#endif
+        QTest::newRow("local") << QUrl(QLatin1String("local:replicaLocalIntegration")) << QUrl(QLatin1String("local:registryLocalIntegration"));
+#ifdef Q_OS_LINUX
+        QTest::newRow("localabstract") << QUrl(QLatin1String("localabstract:replicaAbstractIntegration")) << QUrl(QLatin1String("localabstract:registryAbstractIntegration"));
+#endif
+        QTest::newRow("external") << QUrl() << QUrl();
+    }
+
+    void initTestCase()
+    {
+        QVERIFY(TestUtils::init("integration"));
+        QLoggingCategory::setFilterRules("qt.remoteobjects.warning=false");
+
+        // use different paths in QRemoteObjectSettingsStore
+        QCoreApplication::setOrganizationName(QLatin1String("QtProject"));
+        QStandardPaths::setTestModeEnabled(true);
+    }
+
+    void init()
+    {
+        registry = nullptr;
+        host = nullptr;
+        client = nullptr;
+        tcpServer = nullptr;
+        socketClient = nullptr;
+        socketServer = nullptr;
+    }
+
+    void cleanup()
+    {
+        delete registry;
+        delete host;
+        delete client;
+        delete tcpServer;
+        if (socketClient) {
+            socketClient->deleteLater();
+        }
+        if (socketServer) {
+            socketServer->deleteLater();
+        }
+        // wait for delivery of RemoveObject events to the source
+        QTest::qWait(200);
+    }
+
+    void basicTest()
+    {
+        setupHost();
+        Engine e;
+        e.setRpm(1234);
+        host->enableRemoting(&e);
+
+        setupClient();
+        const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+        engine_r->waitForSource();
+        QCOMPARE(engine_r->rpm(), e.rpm());
+    }
+
+    void persistRestoreTest()
+    {
+        QRemoteObjectNode _client;
+        Q_SET_OBJECT_NAME(_client);
+        TestPersistedStore store;
+        _client.setPersistedStore(&store);
+
+        const QScopedPointer<EngineReplica> engine_r(_client.acquire<EngineReplica>());
+        QCOMPARE(engine_r->engineType(), EngineReplica::HYBRID);
+    }
+
+    void persistTest()
+    {
+        QRemoteObjectSettingsStore store;
+
+        setupHost();
+        Engine e;
+        e.setEngineType(EngineSimpleSource::ELECTRIC);
+        host->enableRemoting(&e);
+
+        setupClient();
+        client->setPersistedStore(&store);
+
+        QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+        engine_r->waitForSource();
+        QCOMPARE(engine_r->engineType(), EngineReplica::ELECTRIC);
+
+        // Delete to persist
+        engine_r.reset();
+        host->disableRemoting(&e);
+
+        engine_r.reset(client->acquire<EngineReplica>());
+        QCOMPARE(engine_r->waitForSource(1000), false);
+        QCOMPARE(engine_r->engineType(), EngineReplica::ELECTRIC);
+    }
+
+    // ensure we don't crash when ObjectList iterates over in process replicas
+    void inProcessObjectList()
+    {
+        setupRegistry();
+        setupHost(true);
+        setupClient(true);
+        Engine e;
+        host->enableRemoting(&e);
+        e.setStarted(false);
+
+        const QScopedPointer<EngineReplica> engine_r(host->acquire<EngineReplica>());
+        const QScopedPointer<EngineReplica> engine_r2(client->acquire<EngineReplica>());
+        engine_r->waitForSource(1000);
+        engine_r2->waitForSource(1000);
+        QCOMPARE(engine_r->started(), false);
+        QCOMPARE(engine_r2->started(), false);
+        engine_r->pushStarted(true);
+
+        QTRY_COMPARE(engine_r->started(), true);
+        QTRY_COMPARE(engine_r2->started(), true);
+    }
+
+    void enumTest()
+    {
+        setupHost();
+
+        setupClient();
+
+        TestClassSimpleSource tc;
+        tc.setTestEnum(TestEnum::FALSE);
+        tc.setClassEnum(TestClassSimpleSource::One);
+        tc.setClassEnumRW(TestClassSimpleSource::One);
+        host->enableRemoting(&tc);
+        const QScopedPointer<TestClassReplica> tc_rep(client->acquire<TestClassReplica>());
+        tc_rep->waitForSource();
+        QCOMPARE(tc.testEnum(), tc_rep->testEnum());
+        QCOMPARE(qint32(tc.classEnum()), qint32(TestClassSimpleSource::One));
+
+        // set property on the replica (test property change packet)
+        {
+            QSignalSpy spy(tc_rep.data(), &TestClassReplica::classEnumChanged);
+            QVERIFY(spy.isValid());
+            tc_rep->pushClassEnum(TestClassReplica::Two);
+            QVERIFY(spy.count() || spy.wait());
+
+            QCOMPARE(qint32(tc.classEnum()), qint32(tc_rep->classEnum()));
+        }
+
+        // set property on the source (test property change packet)
+        {
+            QSignalSpy spy(tc_rep.data(), &TestClassReplica::classEnumChanged);
+            tc.setClassEnum(TestClassSimpleSource::One);
+            QVERIFY(spy.wait());
+
+            QCOMPARE(qint32(tc.classEnum()), qint32(tc_rep->classEnum()));
+        }
+
+        QScopedPointer<QRemoteObjectDynamicReplica> tc_repDynamic(client->acquireDynamic(QStringLiteral("TestClass")));
+
+        tc_repDynamic->waitForSource(1000);
+        QVERIFY(tc_repDynamic->isInitialized());
+
+        const QMetaObject *metaObject = tc_repDynamic->metaObject();
+
+        int propertyIndex = metaObject->indexOfProperty("classEnumRW");
+        QVERIFY(propertyIndex >= 0);
+
+        QMetaProperty property = metaObject->property(propertyIndex);
+        QVERIFY(property.isValid());
+        QCOMPARE(property.typeName(), "TestClassReplica::ClassEnum");
+
+        // read enum on the dynamic replica
+        {
+            QCOMPARE(property.read(tc_repDynamic.data()).value<TestClassReplica::ClassEnum>(), TestClassReplica::One);
+        }
+
+        // write enum on the dynamic replica
+        {
+            QSignalSpy spy(tc_rep.data(), &TestClassReplica::classEnumRWChanged);
+            property.write(tc_repDynamic.data(), TestClassReplica::Two);
+            QVERIFY(spy.wait());
+
+            QCOMPARE(tc_rep->classEnumRW(), TestClassReplica::Two);
+        }
+
+        propertyIndex = metaObject->indexOfProperty("classEnum");
+        QVERIFY(propertyIndex >= 0);
+
+        property = metaObject->property(propertyIndex);
+        QVERIFY(property.isValid());
+        QCOMPARE(property.typeName(), "TestClassReplica::ClassEnum");
+
+        // read enum on the dynamic replica
+        {
+            QCOMPARE(property.read(tc_repDynamic.data()).value<TestClassReplica::ClassEnum>(), TestClassReplica::One);
+        }
+
+        // ensure write enum fails on ReadPush
+        {
+            QSignalSpy spy(tc_rep.data(), &TestClassReplica::classEnumChanged);
+            bool res = property.write(tc_repDynamic.data(), TestClassReplica::Two);
+            QVERIFY(!res);
+            int methodIndex = metaObject->indexOfMethod("pushClassEnum(TestClassReplica::ClassEnum)");
+            QVERIFY(methodIndex >= 0);
+            QMetaMethod method = metaObject->method(methodIndex);
+            QVERIFY(method.isValid());
+
+            QVERIFY(method.invoke(tc_repDynamic.data(), Q_ARG(TestClassReplica::ClassEnum, TestClassReplica::Two)));
+            QVERIFY(spy.wait());
+
+            QCOMPARE(tc_rep->classEnum(), TestClassReplica::Two);
+        }
+    }
+
+    void namedObjectTest()
+    {
+        setupHost();
+
+        setupClient();
+
+        Engine e;
+        e.setRpm(3333);
+        Engine *e2 = new Engine();
+        QScopedPointer<Engine> engineSave;
+        engineSave.reset(e2);
+        e2->setRpm(4444);
+        host->enableRemoting(&e);
+        host->enableRemoting(e2, QStringLiteral("MyTestEngine"));
+
+        const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+        const QScopedPointer<EngineReplica> namedEngine_r(client->acquire<EngineReplica>(QStringLiteral("MyTestEngine")));
+        engine_r->waitForSource();
+        QCOMPARE(engine_r->cylinders(), e.cylinders());
+        QCOMPARE(engine_r->rpm(), 3333);
+        namedEngine_r->waitForSource();
+        QCOMPARE(namedEngine_r->cylinders(), e2->cylinders());
+        QCOMPARE(namedEngine_r->rpm(), 4444);
+
+        engineSave.reset();
+        //Deleting the object before disable remoting will cause disable remoting to
+        //return false;
+        QVERIFY(!host->disableRemoting(e2));
+    }
+
+    void multipleInstancesTest()
+    {
+        setupHost();
+        Engine e;
+        host->enableRemoting(&e);
+
+        setupClient();
+
+        auto instances = client->instances<EngineReplica>();
+        QCOMPARE(instances, QStringList());
+
+        Engine e2;
+        host->enableRemoting(&e2, QStringLiteral("Engine2"));
+
+        const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+        const QScopedPointer<EngineReplica> engine2_r(client->acquire<EngineReplica>(QStringLiteral("Engine2")));
+        const QScopedPointer<EngineReplica> engine3_r(client->acquire<EngineReplica>(QStringLiteral("Engine_doesnotexist")));
+        QVERIFY(engine_r->waitForSource());
+        QVERIFY(engine2_r->waitForSource());
+        QVERIFY(!engine3_r->waitForSource(500));
+
+        instances = client->instances<EngineReplica>();
+        QCOMPARE(instances, QStringList({"Engine", "Engine2"}));
+
+        QSignalSpy spy(engine_r.data(), &QRemoteObjectReplica::stateChanged);
+        host->disableRemoting(&e);
+        spy.wait();
+        QCOMPARE(spy.count(), 1);
+
+        instances = client->instances<EngineReplica>();
+        QCOMPARE(instances, QStringList({"Engine2"}));
+    }
+
+    void registrySourceLocationBindings()
+    {
+        QFETCH_GLOBAL(QUrl, registryUrl);
+        QFETCH_GLOBAL(QUrl, hostUrl);
+        if (registryUrl.isEmpty())
+            QSKIP("Skipping registry tests for external QIODevice types.");
+
+        setupRegistry();
+        setupHost(true);
+        setupClient(true);
+
+        QVERIFY(host->registry()->sourceLocations().empty());
+        QVERIFY(client->registry()->sourceLocations().empty());
+
+        QVERIFY(host->registry()->bindableSourceLocations().isReadOnly());
+        QVERIFY(client->registry()->bindableSourceLocations().isReadOnly());
+
+        Engine e1;
+        const auto engine1 = QStringLiteral("Engine1");
+        Engine e2;
+        const auto engine2 = QStringLiteral("Engine2");
+
+        QRemoteObjectSourceLocations expectedSourceLocations;
+        expectedSourceLocations[engine1] = { QStringLiteral("Engine"), hostUrl };
+
+        int hostSrcLocationsChanged = 0;
+        auto hostHandler = host->registry()->bindableSourceLocations().onValueChanged([&] {
+            QCOMPARE(host->registry()->sourceLocations(), expectedSourceLocations);
+            ++hostSrcLocationsChanged;
+        });
+
+        int clientSrcLocationsChanged = 0;
+        auto clientHandler = client->registry()->bindableSourceLocations().onValueChanged([&] {
+            QCOMPARE(client->registry()->sourceLocations(), expectedSourceLocations);
+            ++clientSrcLocationsChanged;
+        });
+
+        QProperty<QRemoteObjectSourceLocations> hostObserver;
+        hostObserver.setBinding([&] { return host->registry()->sourceLocations(); });
+
+        QProperty<QRemoteObjectSourceLocations> clientObserver;
+        clientObserver.setBinding([&] { return client->registry()->sourceLocations(); });
+
+        QSignalSpy hostSpy(host->registry(), &QRemoteObjectRegistry::remoteObjectAdded);
+        QSignalSpy clientSpy(client->registry(), &QRemoteObjectRegistry::remoteObjectAdded);
+
+        host->enableRemoting(&e1, engine1);
+        QTRY_COMPARE(hostSpy.count(), 1);
+        QTRY_COMPARE(clientSpy.count(), 1);
+        QCOMPARE(hostObserver.value(), host->registry()->sourceLocations());
+        QCOMPARE(clientObserver.value(), client->registry()->sourceLocations());
+        QCOMPARE(hostObserver.value(), clientObserver.value());
+        QCOMPARE(hostObserver.value(), expectedSourceLocations);
+        QCOMPARE(hostSrcLocationsChanged, 1);
+        QCOMPARE(clientSrcLocationsChanged, 1);
+
+        expectedSourceLocations[engine2] = { QStringLiteral("Engine"), hostUrl };
+        host->enableRemoting(&e2, engine2);
+        QTRY_COMPARE(hostSpy.count(), 2);
+        QTRY_COMPARE(clientSpy.count(), 2);
+        QCOMPARE(hostObserver.value(), host->registry()->sourceLocations());
+        QCOMPARE(clientObserver.value(), client->registry()->sourceLocations());
+        QCOMPARE(hostObserver.value(), clientObserver.value());
+        QCOMPARE(hostObserver.value(), expectedSourceLocations);
+        QCOMPARE(hostSrcLocationsChanged, 2);
+        QCOMPARE(clientSrcLocationsChanged, 2);
+
+        // Test source removal
+        host->disableRemoting(&e1);
+        expectedSourceLocations.remove(engine1);
+        QSignalSpy srcRemovedHostSpy(host->registry(), &QRemoteObjectRegistry::remoteObjectRemoved);
+        QSignalSpy srcRemovedClientSpy(client->registry(),
+                                       &QRemoteObjectRegistry::remoteObjectRemoved);
+
+        QTRY_COMPARE(srcRemovedHostSpy.count(), 1);
+        QTRY_COMPARE(srcRemovedClientSpy.count(), 1);
+        QCOMPARE(hostObserver.value(), host->registry()->sourceLocations());
+        QCOMPARE(clientObserver.value(), client->registry()->sourceLocations());
+        QCOMPARE(hostObserver.value(), clientObserver.value());
+        QCOMPARE(hostObserver.value(), expectedSourceLocations);
+        QCOMPARE(hostSrcLocationsChanged, 3);
+        QCOMPARE(clientSrcLocationsChanged, 3);
+    }
+
+    void registryAddedTest()
+    {
+        QFETCH_GLOBAL(QUrl, registryUrl);
+        if (registryUrl.isEmpty())
+            QSKIP("Skipping registry tests for external QIODevice types.");
+        setupRegistry();
+
+        setupHost(true);
+
+        setupClient(true);
+
+        QScopedPointer<EngineReplica> regBase, regNamed;
+        QScopedPointer<QRemoteObjectDynamicReplica> regDynamic, regDynamicNamed;
+
+        int regAdded = 0;
+        connect(client->registry(), &QRemoteObjectRegistry::remoteObjectAdded, [&](QRemoteObjectSourceLocation entry)
+            {
+                if (entry.first == QLatin1String("Engine")) {
+                    ++regAdded;
+                    //Add regular replica first, then dynamic one
+                    regBase.reset(client->acquire<EngineReplica>());
+                    regDynamic.reset(client->acquireDynamic(QStringLiteral("Engine")));
+                }
+                if (entry.first == QLatin1String("MyTestEngine")) {
+                    regAdded += 2;
+                    //Now add dynamic replica first, then regular one
+                    regDynamicNamed.reset(client->acquireDynamic(QStringLiteral("MyTestEngine")));
+                    regNamed.reset(client->acquire<EngineReplica>(QStringLiteral("MyTestEngine")));
+                }
+            });
+
+        QSignalSpy addedSpy(client->registry(), &QRemoteObjectRegistry::remoteObjectAdded);
+
+        Engine e;
+        e.setRpm(1111);
+        host->enableRemoting(&e);
+        Engine e2;
+        e2.setRpm(2222);
+        host->enableRemoting(&e2, QStringLiteral("MyTestEngine"));
+        while (regAdded < 3) {
+            addedSpy.wait(100);
+        }
+        regBase->waitForSource(100);
+        regNamed->waitForSource(100);
+        regDynamic->waitForSource(100);
+        regDynamicNamed->waitForSource(100);
+        QVERIFY(regBase->isInitialized());
+        QCOMPARE(regBase->rpm(),e.rpm());
+        QVERIFY(regNamed->isInitialized());
+        QCOMPARE(regNamed->rpm(),e2.rpm());
+
+        QVERIFY(regDynamic->isInitialized());
+        const QMetaObject *metaObject = regDynamic->metaObject();
+
+        const int propertyIndex = metaObject->indexOfProperty("rpm");
+        QVERIFY(propertyIndex >= 0);
+        const QMetaProperty property = metaObject->property(propertyIndex);
+        QVERIFY(property.isValid());
+
+        QCOMPARE(property.read(regDynamic.data()).toInt(),e.rpm());
+
+        QVERIFY(regDynamicNamed->isInitialized());
+        QCOMPARE(property.read(regDynamicNamed.data()).toInt(),e2.rpm());
+
+        QVERIFY(host->disableRemoting(&e));
+        QVERIFY(host->disableRemoting(&e2));
+    }
+
+    void registryTest()
+    {
+        QFETCH_GLOBAL(QUrl, registryUrl);
+        if (registryUrl.isEmpty())
+            QSKIP("Skipping registry tests for external QIODevice types.");
+        setupRegistry();
+        TcpDataCenterSimpleSource source1;
+        source1.setData1(5);
+        source1.setData2(5.0);
+        source1.setData3(QStringLiteral("tcp"));
+        source1.setData4(QList<int> { 1, 2, 3, 4, 5 });
+        registry->enableRemoting(&source1);
+
+        setupHost(true);
+        LocalDataCenterSimpleSource source2;
+        source2.setData1(5);
+        source2.setData2(5.0);
+        source2.setData3(QStringLiteral("local"));
+        source2.setData4(QList<int> { 1, 2, 3, 4, 5 });
+        host->enableRemoting(&source2);
+        QVERIFY(host->waitForRegistry(1000));
+
+        setupClient(true);
+
+        const QScopedPointer<TcpDataCenterReplica> tcpCentre(client->acquire<TcpDataCenterReplica>());
+        const QScopedPointer<LocalDataCenterReplica> localCentre(client->acquire<LocalDataCenterReplica>());
+        QTRY_VERIFY(localCentre->waitForSource(100));
+        QTRY_VERIFY(tcpCentre->waitForSource(100));
+
+        QCOMPARE(client->registry()->sourceLocations(), host->registry()->sourceLocations());
+        QCOMPARE(client->registry()->sourceLocations(), registry->registry()->sourceLocations());
+        QTRY_VERIFY(localCentre->isInitialized());
+        QTRY_VERIFY(tcpCentre->isInitialized());
+
+        const QList<int> expected = { 1, 2, 3, 4, 5 };
+        QCOMPARE(tcpCentre->data1(), 5 );
+        QCOMPARE(tcpCentre->data2(), 5.0);
+        QCOMPARE(tcpCentre->data3(), QStringLiteral("tcp"));
+        QCOMPARE(tcpCentre->data4(), expected);
+
+        QCOMPARE(localCentre->data1(), 5);
+        QCOMPARE(localCentre->data2(), 5.0);
+        QCOMPARE(localCentre->data3(), QStringLiteral("local"));
+        QCOMPARE(localCentre->data4(), expected);
+    }
+
+    void invalidUrlsTest()
+    {
+        QFETCH_GLOBAL(QUrl, hostUrl);
+        QFETCH_GLOBAL(QUrl, registryUrl);
+        const QUrl invalidUrl;
+        {
+            QRemoteObjectHost _host(invalidUrl, registryUrl);
+            SET_NODE_NAME(_host);
+            const bool res = _host.waitForRegistry(3000);
+            QVERIFY(!res);
+        }
+
+        {
+            QRemoteObjectHost _host(hostUrl, invalidUrl);
+            SET_NODE_NAME(_host);
+            const bool res = _host.waitForRegistry(3000);
+            QVERIFY(!res);
+        }
+
+        {
+            QRemoteObjectHost _host(invalidUrl, invalidUrl);
+            SET_NODE_NAME(_host);
+            const bool res = _host.waitForRegistry(3000);
+            QVERIFY(!res);
+        }
+    }
+
+    void noRegistryTest()
+    {
+        QFETCH_GLOBAL(QUrl, registryUrl);
+        if (registryUrl.isEmpty())
+            QSKIP("Skipping registry tests for external QIODevice types.");
+        setupHost(true);
+        const bool res = host->waitForRegistry(3000);
+        QVERIFY(!res);
+        QCOMPARE(host->registry()->isInitialized(), false);
+        const QScopedPointer<Engine> localEngine(new Engine);
+        host->enableRemoting(localEngine.data());
+        QCOMPARE(host->registry()->sourceLocations().keys().isEmpty(), true);
+    }
+
+    void delayedRegistryTest()
+    {
+        QFETCH_GLOBAL(QUrl, hostUrl);
+        QFETCH_GLOBAL(QUrl, registryUrl);
+        if (registryUrl.isEmpty())
+            QSKIP("Skipping registry tests for external QIODevice types.");
+        setupClient(true);
+
+        // create a replica before the registry host started
+        // to check whether it gets valid later on
+        const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+        Q_SET_OBJECT_NAME(engine_r.data());
+        QTRY_VERIFY(!engine_r->waitForSource(100));
+
+        setupHost(true);
+        const bool res = host->waitForRegistry(3000);
+        QVERIFY(!res);
+        QCOMPARE(host->registry()->isInitialized(), false);
+
+        const QScopedPointer<Engine> localEngine(new Engine);
+        host->enableRemoting(localEngine.data());
+        QCOMPARE(host->registry()->sourceLocations().keys().isEmpty(), true);
+
+        QSignalSpy spy(host->registry(), &QRemoteObjectRegistry::initialized);
+        QSignalSpy addedSpy(host->registry(), &QRemoteObjectRegistry::remoteObjectAdded);
+        setupRegistry();
+        bool added = addedSpy.wait();
+        QVERIFY(spy.count() > 0);
+        QCOMPARE(added, true);
+        QCOMPARE(host->registry()->sourceLocations().keys().isEmpty(), false);
+        QCOMPARE(host->registry()->sourceLocations().keys().at(0), QStringLiteral("Engine"));
+        QCOMPARE(host->registry()->sourceLocations().value(QStringLiteral("Engine")).hostUrl, hostUrl);
+
+        // the replicate should be valid now
+        QTRY_VERIFY(engine_r->isInitialized());
+        QTRY_VERIFY(engine_r->isReplicaValid());
+
+        //This should produce a warning...
+        registry->enableRemoting(localEngine.data());
+        QVERIFY(host->registry()->sourceLocations().value(QStringLiteral("Engine")).hostUrl != registryUrl);
+    }
+
+    void defaultValueTest()
+    {
+        setupHost();
+        Engine e;
+        host->enableRemoting(&e);
+
+        setupClient();
+
+        const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+        engine_r->waitForSource();
+        QCOMPARE(engine_r->cylinders(), 4);
+    }
+
+    void notifyTest()
+    {
+        setupHost();
+        Engine e;
+        host->enableRemoting(&e);
+
+        setupClient();
+
+        const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+        QSignalSpy spy(engine_r.data(), &EngineReplica::rpmChanged);
+        e.setRpm(2345);
+
+        spy.wait();
+        QCOMPARE(spy.count(), 1);
+        const QList<QVariant> &arguments = spy.first();
+        bool ok;
+        int res = arguments.at(0).toInt(&ok);
+        QVERIFY(ok);
+        QCOMPARE(res, e.rpm());
+        QCOMPARE(engine_r->rpm(), e.rpm());
+    }
+
+    void dynamicNotifyTest()
+    {
+        setupHost();
+        Engine e;
+        host->enableRemoting(&e);
+
+        setupClient();
+
+        QSignalSpy spy(this, &tst_Integration::forwardResult);
+        QScopedPointer<QRemoteObjectDynamicReplica> engine_dr(client->acquireDynamic(QStringLiteral("Engine")));
+        connect(engine_dr.data(), &QRemoteObjectDynamicReplica::initialized, [&]()
+            {
+                const QMetaObject *metaObject = engine_dr->metaObject();
+                const int propIndex = metaObject->indexOfProperty("rpm");
+                QVERIFY(propIndex >= 0);
+                const QMetaProperty mp =  metaObject->property(propIndex);
+                QVERIFY(connect(engine_dr.data(), QByteArray(QByteArrayLiteral("2")+mp.notifySignal().methodSignature().constData()), this, SIGNAL(forwardResult(int))));
+             });
+        e.setRpm(3456);
+        spy.wait();
+        QCOMPARE(spy.count(), 1);
+        const QList<QVariant> &arguments = spy.first();
+        bool ok;
+        int res = arguments.at(0).toInt(&ok);
+        QVERIFY(ok);
+        QCOMPARE(res, e.rpm());
+    }
+
+    void slotTest()
+    {
+        setupHost();
+        Engine e;
+        host->enableRemoting(&e);
+
+        setupClient();
+        e.setStarted(false);
+
+        const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+        QEventLoop loop;
+        QTimer::singleShot(100, &loop, &QEventLoop::quit);
+        connect(engine_r.data(), &EngineReplica::initialized, &loop, &QEventLoop::quit);
+        if (!engine_r->isInitialized())
+            loop.exec();
+        QCOMPARE(engine_r->started(), false);
+
+        QRemoteObjectPendingReply<bool> reply = engine_r->start();
+        QCOMPARE(reply.error(), QRemoteObjectPendingCall::InvalidMessage);
+        QVERIFY(reply.waitForFinished());
+        QVERIFY(reply.isFinished());
+        QCOMPARE(reply.returnValue(), true);
+        QCOMPARE(reply.error(), QRemoteObjectPendingCall::NoError);
+
+        QCOMPARE(engine_r->started(), true);
+    }
+
+    void slotTestWithWatcher()
+    {
+        setupHost();
+        Engine e;
+        host->enableRemoting(&e);
+
+        setupClient();
+        e.setStarted(false);
+
+        const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+        QEventLoop loop;
+        QTimer::singleShot(100, &loop, &QEventLoop::quit);
+        connect(engine_r.data(), &EngineReplica::initialized, &loop, &QEventLoop::quit);
+        if (!engine_r->isInitialized())
+            loop.exec();
+        QCOMPARE(engine_r->started(), false);
+
+        QRemoteObjectPendingReply<bool> reply = engine_r->start();
+        QCOMPARE(reply.error(), QRemoteObjectPendingCall::InvalidMessage);
+
+        QRemoteObjectPendingCallWatcher watcher(reply);
+        QSignalSpy spy(&watcher, &QRemoteObjectPendingCallWatcher::finished);
+        spy.wait();
+        QCOMPARE(spy.count(), 1);
+
+        QVERIFY(reply.isFinished());
+        QCOMPARE(reply.returnValue(), true);
+        QCOMPARE(engine_r->started(), true);
+    }
+
+    void slotTestDynamicReplica()
+    {
+        setupHost();
+        Engine e;
+        host->enableRemoting(&e);
+
+        setupClient();
+        e.setStarted(false);
+
+        const QScopedPointer<QRemoteObjectDynamicReplica> engine_r(client->acquireDynamic(QStringLiteral("Engine")));
+        Q_ASSERT(engine_r);
+        QEventLoop loop;
+        QTimer::singleShot(100, &loop, &QEventLoop::quit);
+        connect(engine_r.data(), &EngineReplica::initialized, &loop, &QEventLoop::quit);
+        if (!engine_r->isInitialized())
+            loop.exec();
+
+        const QMetaObject *metaObject = engine_r->metaObject();
+        const int propIndex = metaObject->indexOfProperty("started");
+        QVERIFY(propIndex >= 0);
+        const QMetaProperty property = metaObject->property(propIndex);
+        bool started = property.read(engine_r.data()).value<bool>();
+        QCOMPARE(started, false);
+
+        const int methodIndex = metaObject->indexOfMethod("start()");
+        QVERIFY(methodIndex >= 0);
+        const QMetaMethod method = metaObject->method(methodIndex);
+        QRemoteObjectPendingCall call;
+        QVERIFY(method.invoke(engine_r.data(), Q_RETURN_ARG(QRemoteObjectPendingCall, call)));
+        QCOMPARE(call.error(), QRemoteObjectPendingCall::InvalidMessage);
+        QVERIFY(call.waitForFinished());
+        QVERIFY(call.isFinished());
+        QCOMPARE(call.returnValue().metaType(), QMetaType::fromType<bool>());
+        QCOMPARE(call.returnValue().toBool(), true);
+        started = property.read(engine_r.data()).value<bool>();
+        QCOMPARE(started, true);
+    }
+
+    void slotTestDynamicReplicaWithArguments()
+    {
+        setupHost();
+        Engine e;
+        host->enableRemoting(&e);
+
+        setupClient();
+
+        const QScopedPointer<QRemoteObjectDynamicReplica> engine_r(client->acquireDynamic(QStringLiteral("Engine")));
+        Q_ASSERT(engine_r);
+        bool ok = engine_r->waitForSource();
+        QVERIFY(ok);
+        const QMetaObject *metaObject = engine_r->metaObject();
+
+        int methodIndex = metaObject->indexOfMethod("setMyTestString(QString)");
+        QVERIFY(methodIndex >= 0);
+        QMetaMethod method = metaObject->method(methodIndex);
+        QVERIFY(method.isValid());
+
+        // The slot has no return-value, calling it with a Q_RETURN_ARG should fail.
+        QRemoteObjectPendingCall setCall;
+        QString s = QLatin1String("Hello World 1");
+        QVERIFY(!method.invoke(engine_r.data(), Q_RETURN_ARG(QRemoteObjectPendingCall, setCall), Q_ARG(QString, s)));
+        QVERIFY(!setCall.waitForFinished());
+        QVERIFY(!setCall.isFinished());
+        QCOMPARE(setCall.error(), QRemoteObjectPendingCall::InvalidMessage);
+
+        // Now call the method without return-value, that should succeed.
+        s = QLatin1String("Hello World 2");
+        QVERIFY(method.invoke(engine_r.data(), Q_ARG(QString, s)));
+
+        // Verify that the passed argument was proper set.
+        methodIndex = metaObject->indexOfMethod("myTestString()");
+        QVERIFY(methodIndex >= 0);
+        method = metaObject->method(methodIndex);
+        QRemoteObjectPendingCall getCall;
+        QVERIFY(method.invoke(engine_r.data(), Q_RETURN_ARG(QRemoteObjectPendingCall, getCall)));
+        QVERIFY(getCall.waitForFinished());
+        QVERIFY(getCall.isFinished());
+        QCOMPARE(getCall.error(), QRemoteObjectPendingCall::NoError);
+        QCOMPARE(getCall.returnValue().metaType(), QMetaType::fromType<QString>());
+        QCOMPARE(getCall.returnValue().toString(), s);
+    }
+
+    void expapiTestDynamicReplica()
+    {
+        setupHost();
+        Engine e;
+        host->enableRemoting(&e);
+
+        setupClient();
+
+        const QScopedPointer<QRemoteObjectDynamicReplica> engine_r(client->acquireDynamic(QStringLiteral("Engine")));
+        const QMetaObject *metaObject = engine_r->metaObject();
+        const int propIndex = metaObject->indexOfProperty("purchasedPart");
+        QVERIFY(propIndex < 0);
+        const int methodIndex = metaObject->indexOfMethod("setpurchasedPart(bool)");
+        QVERIFY(methodIndex < 0);
+    }
+
+    void slotTestInProcess()
+    {
+        setupHost();
+        Engine e;
+        host->enableRemoting(&e);
+        e.setStarted(false);
+
+        const QScopedPointer<EngineReplica> engine_r(host->acquire<EngineReplica>());
+        engine_r->waitForSource();
+        QCOMPARE(engine_r->started(), false);
+
+        QRemoteObjectPendingReply<bool> reply = engine_r->start();
+        QVERIFY(reply.waitForFinished());
+        QVERIFY(reply.isFinished());
+        QCOMPARE(reply.returnValue(), true);
+        QCOMPARE(reply.error(), QRemoteObjectPendingCall::NoError);
+
+        QCOMPARE(engine_r->started(), true);
+    }
+
+    void slotTestWithUnnormalizedSignature()
+    {
+        setupHost();
+        Engine e;
+        host->enableRemoting(&e);
+
+        setupClient();
+
+        const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+        engine_r->waitForSource();
+
+        engine_r->unnormalizedSignature(0, 0);
+    }
+
+    void setterTest()
+    {
+        setupHost();
+        Engine e(6);
+        QCOMPARE(e.cylinders(), 6);
+        host->enableRemoting(&e);
+
+        setupClient();
+
+        const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+        QCOMPARE(engine_r->cylinders(), 4); // Default value
+        engine_r->waitForSource();
+        QCOMPARE(engine_r->cylinders(), 6);
+        QSignalSpy spy(engine_r.data(), &EngineReplica::rpmChanged);
+        engine_r->setRpm(42);
+        spy.wait();
+        QCOMPARE(spy.count(), 1);
+        QCOMPARE(engine_r->rpm(), 42);
+    }
+
+    void pushTest()
+    {
+        setupHost();
+        Engine e;
+        host->enableRemoting(&e);
+
+        setupClient();
+
+        const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+        engine_r->waitForSource();
+        QCOMPARE(engine_r->started(), false);
+        QSignalSpy spy(engine_r.data(), &EngineReplica::startedChanged);
+        engine_r->pushStarted(true);
+        spy.wait();
+        QCOMPARE(spy.count(), 1);
+        QCOMPARE(engine_r->started(), true);
+    }
+
+    void dynamicSetterTest()
+    {
+        setupHost();
+        Engine e(6);
+        QCOMPARE(e.cylinders(), 6);
+        host->enableRemoting(&e);
+
+        setupClient();
+
+        const QScopedPointer<QRemoteObjectDynamicReplica> engine_dr(client->acquireDynamic(QStringLiteral("Engine")));
+        engine_dr->waitForSource();
+        const QMetaObject *metaObject = engine_dr->metaObject();
+        const QMetaProperty const_mp = metaObject->property(metaObject->indexOfProperty("cylinders"));
+        QCOMPARE(const_mp.read(engine_dr.data()).toInt(), 6);
+        const int propIndex = metaObject->indexOfProperty("rpm");
+        const QMetaProperty mp =  metaObject->property(propIndex);
+        QSignalSpy spy(engine_dr.data(), QByteArray(QByteArrayLiteral("2")+mp.notifySignal().methodSignature().constData()));
+        mp.write(engine_dr.data(), 44);
+        spy.wait();
+        QCOMPARE(spy.count(), 1);
+        QCOMPARE(mp.read(engine_dr.data()).toInt(), 44);
+    }
+
+    void slotWithParameterTest()
+    {
+        setupHost();
+        Engine e;
+        host->enableRemoting(&e);
+        e.setRpm(0);
+
+        setupClient();
+
+        const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+        engine_r->waitForSource();
+        QCOMPARE(engine_r->rpm(), 0);
+
+        QSignalSpy spy(engine_r.data(), &EngineReplica::rpmChanged);
+        engine_r->increaseRpm(1000);
+        spy.wait();
+        QCOMPARE(spy.count(), 1);
+        QCOMPARE(engine_r->rpm(), 1000);
+    }
+
+    void slotWithUserReturnTypeTest() {
+        setupHost();
+        Engine e;
+        host->enableRemoting(&e);
+
+        setupClient();
+
+        e.setTemperature(Temperature(400, QStringLiteral("Kelvin")));
+
+        const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+        engine_r->waitForSource();
+        QRemoteObjectPendingReply<Temperature> pendingReply = engine_r->temperature();
+        pendingReply.waitForFinished();
+        Temperature temperature = pendingReply.returnValue();
+        QCOMPARE(temperature, Temperature(400, QStringLiteral("Kelvin")));
+    }
+
+    void sequentialReplicaTest()
+    {
+        setupHost();
+        Engine e;
+        host->enableRemoting(&e);
+
+        setupClient();
+
+        e.setRpm(3456);
+
+        QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+        engine_r->waitForSource();
+        QCOMPARE(engine_r->rpm(), e.rpm());
+
+        engine_r.reset(client->acquire<EngineReplica>());
+        engine_r->waitForSource();
+        QCOMPARE(engine_r->rpm(), e.rpm());
+    }
+
+    void doubleReplicaTest()
+    {
+        setupHost();
+        Engine e;
+        host->enableRemoting(&e);
+        e.setRpm(3412);
+
+        setupClient();
+
+        const QScopedPointer<EngineReplica> engine_r1(client->acquire< EngineReplica >());
+        const QScopedPointer<EngineReplica> engine_r2(client->acquire< EngineReplica >());
+
+        engine_r1->waitForSource();
+        engine_r2->waitForSource();
+
+        QCOMPARE(engine_r1->rpm(), e.rpm());
+        QCOMPARE(engine_r2->rpm(), e.rpm());
+    }
+
+    // verify that our second replica emits "Changed" signals when initialized
+    void doubleReplicaTest2()
+    {
+        setupHost();
+        Engine e;
+        host->enableRemoting(&e);
+        e.setRpm(3412);
+
+        setupClient();
+
+        const QScopedPointer<EngineReplica> engine_r1(client->acquire< EngineReplica >());
+        QSignalSpy spy_r1(engine_r1.data(), &EngineReplica::rpmChanged);
+        engine_r1->waitForSource();
+        QCOMPARE(engine_r1->rpm(), e.rpm());
+        QCOMPARE(spy_r1.count(), 1);
+
+        // NOTE: A second replica will have initialized and notify signals emitted as part of acquire,
+        // which leads to different semantics for first and second replicas. Specifically, there is no
+        // way to hook in to initialized and the initial notify signals. We should consider changing this.
+        const QScopedPointer<EngineReplica> engine_r2(client->acquire< EngineReplica >());
+//        QSignalSpy spy_r2(engine_r2.data(), &EngineReplica::rpmChanged);
+//        engine_r2->waitForSource();
+        QCOMPARE(engine_r2->rpm(), e.rpm());
+//        QCOMPARE(spy_r2.count(), 1);
+    }
+
+    void twoReplicaTest() {
+        setupHost();
+        Engine e;
+        Speedometer s;
+        host->enableRemoting(&e);
+        host->enableRemoting(&s);
+
+        setupClient();
+
+        e.setRpm(1234);
+        s.setMph(70);
+
+        const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+        engine_r->waitForSource();
+        const QScopedPointer<SpeedometerReplica> speedometer_r(client->acquire<SpeedometerReplica>());
+        speedometer_r->waitForSource();
+
+        QCOMPARE(engine_r->rpm(), e.rpm());
+        QCOMPARE(speedometer_r->mph(), s.mph());
+    }
+
+    void rawDynamicReplicaTest()
+    {
+        setupHost();
+        TestDynamic source;
+        host->enableRemoting(&source, "TestDynamic");
+
+        setupClient();
+
+        const QScopedPointer<QRemoteObjectDynamicReplica> replica(client->acquireDynamic(QStringLiteral("TestDynamic")));
+        replica->waitForSource();
+        QVERIFY(replica->isInitialized());
+
+        QSignalSpy spy(replica.data(), SIGNAL(valueChanged()));
+
+        const QMetaObject *metaObject = replica->metaObject();
+        const int propIndex = metaObject->indexOfProperty("value");
+        QVERIFY(propIndex != -1);
+        const int signalIndex = metaObject->indexOfSignal("valueChanged()");
+        QVERIFY(signalIndex != -1);
+
+        // replica gets source change
+        source.setValue(1);
+        QTRY_COMPARE(spy.count(), 1);
+        QCOMPARE(replica->property("value"), QVariant(1));
+
+        // source gets replica change
+        replica->setProperty("value", 2);
+        QTRY_COMPARE(replica->property("value"), QVariant(2));
+        QCOMPARE(source.value(), 2);
+
+        // test parent NOTIFY
+        QSignalSpy otherSpy(replica.data(), SIGNAL(otherValueChanged()));
+
+        const int baseSignalIndex = metaObject->indexOfSignal("otherValueChanged()");
+        QVERIFY(baseSignalIndex != -1);
+
+        // replica gets source change
+        source.setOtherValue(1);
+        QTRY_COMPARE(otherSpy.count(), 1);
+        QCOMPARE(replica->property("otherValue"), QVariant(1));
+
+        // source gets replica change
+        replica->setProperty("otherValue", 2);
+        QTRY_COMPARE(replica->property("otherValue"), QVariant(2));
+        QCOMPARE(source.otherValue(), 2);
+    }
+
+    void dynamicReplicaTest()
+    {
+        setupHost();
+        TcpDataCenterSimpleSource t;
+        LocalDataCenterSimpleSource l;
+        host->enableRemoting(&t);
+        host->enableRemoting(&l);
+
+        setupClient();
+
+        const QScopedPointer<QRemoteObjectDynamicReplica> rep1(client->acquireDynamic(QStringLiteral("TcpDataCenter")));
+        const QScopedPointer<QRemoteObjectDynamicReplica> rep2(client->acquireDynamic(QStringLiteral("TcpDataCenter")));
+        const QScopedPointer<QRemoteObjectDynamicReplica> rep3(client->acquireDynamic(QStringLiteral("LocalDataCenter")));
+        rep1->waitForSource();
+        rep2->waitForSource();
+        rep3->waitForSource();
+        const QMetaObject *metaTcpRep1 = rep1->metaObject();
+        const QMetaObject *metaLocalRep1 = rep3->metaObject();
+        const QMetaObject *metaTcpSource = t.metaObject();
+        const QMetaObject *metaLocalSource = l.metaObject();
+        QVERIFY(rep1->isInitialized());
+        QVERIFY(rep2->isInitialized());
+        QVERIFY(rep3->isInitialized());
+
+        for (int i = 0; i < metaTcpRep1->propertyCount(); ++i)
+        {
+            const QMetaProperty propLhs =  metaTcpRep1->property(i);
+            if (qstrcmp(propLhs.name(), "isReplicaValid") == 0 || qstrcmp(propLhs.name(), "state") == 0 || qstrcmp(propLhs.name(), "node") == 0) //Ignore properties only on the Replica side
+                continue;
+            const QMetaProperty propRhs =  metaTcpSource->property(metaTcpSource->indexOfProperty(propLhs.name()));
+            if (propLhs.notifySignalIndex() == -1)
+                QCOMPARE(propRhs.hasNotifySignal(), false);
+            else {
+                QCOMPARE(propRhs.notifySignalIndex() != -1, true);
+                QCOMPARE(metaTcpRep1->method(propLhs.notifySignalIndex()).name(), metaTcpSource->method(propRhs.notifySignalIndex()).name());
+            }
+            QCOMPARE(propLhs.read(rep1.data()),  propRhs.read(&t));
+        }
+        for (int i = 0; i < metaLocalRep1->propertyCount(); ++i )
+        {
+            const QMetaProperty propLhs =  metaLocalRep1->property(i);
+            if (qstrcmp(propLhs.name(), "isReplicaValid") == 0 || qstrcmp(propLhs.name(), "state") == 0 || qstrcmp(propLhs.name(), "node") == 0) //Ignore properties only on the Replica side
+                continue;
+            const QMetaProperty propRhs =  metaLocalSource->property(metaTcpSource->indexOfProperty(propLhs.name()));
+            if (propLhs.notifySignalIndex() == -1)
+                QCOMPARE(propRhs.hasNotifySignal(), false);
+            else {
+                QCOMPARE(propRhs.notifySignalIndex() != -1, true);
+                QCOMPARE(metaTcpRep1->method(propLhs.notifySignalIndex()).name(), metaTcpSource->method(propRhs.notifySignalIndex()).name());
+            }
+            QCOMPARE(propLhs.read(rep3.data()),  propRhs.read(&l));
+        }
+
+    }
+
+    void apiTest()
+    {
+        setupHost();
+        Engine e;
+        host->enableRemoting<EngineSourceAPI>(&e);
+        e.setRpm(1234);
+
+        setupClient();
+
+        const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+        engine_r->waitForSource();
+
+        QCOMPARE(engine_r->rpm(), e.rpm());
+    }
+
+    void apiInProcTest()
+    {
+        setupHost();
+        Engine e;
+        host->enableRemoting<EngineSourceAPI>(&e);
+        e.setRpm(1234);
+
+        const QScopedPointer<EngineReplica> engine_r_inProc(host->acquire<EngineReplica>());
+        engine_r_inProc->waitForSource();
+
+        QCOMPARE(engine_r_inProc->rpm(), e.rpm());
+    }
+
+    void errorSignalTest()
+    {
+        QRemoteObjectNode _client;
+        Q_SET_OBJECT_NAME(_client);
+        QSignalSpy errorSpy(&_client, &QRemoteObjectNode::error);
+        QVERIFY(!_client.connectToNode(QUrl(QLatin1String("invalid:invalid"))));
+        QCOMPARE(errorSpy.count(), 1);
+        auto emittedErrorCode = errorSpy.first().at(0).value<QRemoteObjectNode::ErrorCode>();
+        QCOMPARE(emittedErrorCode, QRemoteObjectNode::RegistryNotAcquired);
+        QCOMPARE(_client.lastError(), QRemoteObjectNode::RegistryNotAcquired);
+    }
+
+    void clientBeforeServerTest() {
+        setupClient();
+        const QScopedPointer<EngineReplica> engine_d(client->acquire<EngineReplica>());
+
+        setupHost();
+        Engine e;
+        host->enableRemoting<EngineSourceAPI>(&e);
+        QSignalSpy spy(engine_d.data(), &EngineReplica::rpmChanged);
+        e.setRpm(50);
+
+        spy.wait();
+        QCOMPARE(spy.count(), 1);
+
+        QCOMPARE(engine_d->rpm(), e.rpm());
+    }
+
+    void largeDataTest()
+    {
+        TestLargeData t;
+        setupHost();
+        host->enableRemoting(&t, QStringLiteral("large"));
+
+        setupClient();
+        const QScopedPointer<QRemoteObjectDynamicReplica> rep(client->acquireDynamic(QStringLiteral("large")));
+        rep->waitForSource();
+        QVERIFY(rep->isInitialized());
+        const QMetaObject *metaObject = rep->metaObject();
+        const int sigIndex = metaObject->indexOfSignal("send(QByteArray)");
+        QVERIFY(sigIndex != -1);
+        const QMetaMethod mm =  metaObject->method(sigIndex);
+        QSignalSpy spy(rep.data(), QByteArray(QByteArrayLiteral("2")+mm.methodSignature().constData()));
+        const QByteArray data(16384,'y');
+        emit t.send(data);
+        spy.wait();
+        QCOMPARE(spy.count(), 1);
+        const QList<QVariant> &arguments = spy.first();
+        QVERIFY(arguments.at(0).toByteArray() == data);
+        QVERIFY(host->disableRemoting(&t));
+    }
+
+    void PODTest()
+    {
+        setupHost();
+
+        setupClient();
+
+        MyPOD shouldPass(1, 2.0, QStringLiteral("pass"));
+        MyPOD shouldFail(1, 2.0, QStringLiteral("fail"));
+        MyClassSimpleSource m;
+        m.setMyPOD(shouldPass);
+        host->enableRemoting(&m);
+        const QScopedPointer<MyClassReplica> myclass_r(client->acquire<MyClassReplica>());
+        myclass_r->waitForSource();
+
+        QVERIFY(myclass_r->myPOD() == m.myPOD());
+        QVERIFY(myclass_r->myPOD() != shouldFail);
+    }
+
+    void SchemeTest()
+    {
+        QFETCH_GLOBAL(QUrl, hostUrl);
+        QFETCH_GLOBAL(QUrl, registryUrl);
+        QRemoteObjectHost valid(hostUrl);
+        QVERIFY(valid.lastError() == QRemoteObjectNode::NoError);
+        QRemoteObjectHost invalid(QUrl(QLatin1String("invalid:invalid")));
+        QVERIFY(invalid.lastError() == QRemoteObjectNode::HostUrlInvalid);
+        QRemoteObjectHost validExternal(QUrl(QLatin1String("invalid:invalid")), registryUrl, QRemoteObjectHost::AllowExternalRegistration);
+        QVERIFY(validExternal.lastError() == QRemoteObjectNode::NoError);
+        QRemoteObjectNode invalidRegistry(QUrl(QLatin1String("invalid:invalid")));
+        QVERIFY(invalidRegistry.lastError() == QRemoteObjectNode::RegistryNotAcquired);
+    }
+
+#if QT_CONFIG(process) && (defined(Q_OS_LINUX) || defined(Q_OS_DARWIN))
+    void localServerConnectionTest()
+    {
+        QFETCH_GLOBAL(QUrl, hostUrl);
+        if (hostUrl.scheme() != QRemoteObjectStringLiterals::local())
+            QSKIP("Skipping 'local' specific backend for non-local test.");
+        const auto progName = TestUtils::findExecutable("localsockettestserver", "/localsockettestserver");
+
+        //create a fake socket as killing doesn't produce a necessarily unusable socket
+        QFile fake(QDir::temp().absoluteFilePath(QStringLiteral("crashMe")));
+        fake.remove();
+        QVERIFY(fake.open(QFile::Truncate | QFile::WriteOnly));
+        QFileInfo info(QDir::temp().absoluteFilePath(QStringLiteral("crashMe")));
+        QVERIFY(info.exists());
+
+        QRemoteObjectNode localSocketTestClient;
+        const QUrl connection = QUrl(QStringLiteral("local:crashMe"));
+        const QString objectname = QStringLiteral("connectme");
+        localSocketTestClient.connectToNode(connection);
+        QVERIFY(localSocketTestClient.lastError() == QRemoteObjectNode::NoError);
+        QScopedPointer<QRemoteObjectDynamicReplica> replica;
+        replica.reset(localSocketTestClient.acquireDynamic(objectname));
+
+        QProcess testServer;
+        testServer.start(progName, QStringList());
+        QVERIFY(testServer.waitForStarted());
+        QVERIFY(localSocketTestClient.lastError() == QRemoteObjectNode::NoError);
+        replica->waitForSource(1000);
+        QVERIFY(replica->isInitialized());
+        testServer.terminate();
+        QVERIFY(testServer.waitForFinished());
+    }
+    // Tests to take over an existing socket if its still valid
+    void localServerConnectionTest2()
+    {
+        QFETCH_GLOBAL(QUrl, hostUrl);
+        if (hostUrl.scheme() != QRemoteObjectStringLiterals::local())
+            QSKIP("Skipping 'local' specific backend for non-local test.");
+        const auto progName = TestUtils::findExecutable("localsockettestserver", "/localsockettestserver");
+
+        QProcess testServer;
+        testServer.start(progName, QStringList());
+        QVERIFY(testServer.waitForStarted());
+        QFileInfo info(QDir::temp().absoluteFilePath(QStringLiteral("crashMe")));
+        QVERIFY(info.exists());
+        testServer.kill();
+        testServer.waitForFinished();
+        QVERIFY(info.exists());
+
+        QRemoteObjectNode localSocketTestClient;
+        const QUrl connection = QUrl(QStringLiteral("local:crashMe"));
+        const QString objectname = QStringLiteral("connectme");
+        localSocketTestClient.connectToNode(connection);
+        QVERIFY(localSocketTestClient.lastError() == QRemoteObjectNode::NoError);
+        QScopedPointer<QRemoteObjectDynamicReplica> replica;
+        replica.reset(localSocketTestClient.acquireDynamic(objectname));
+
+        testServer.start(progName, QStringList());
+        QVERIFY(testServer.waitForStarted());
+        QVERIFY(localSocketTestClient.lastError() == QRemoteObjectNode::NoError);
+        replica->waitForSource(1000);
+        QVERIFY(replica->isInitialized());
+        testServer.terminate();
+        QVERIFY(testServer.waitForFinished());
+    }
+#endif
+
+    void tcpListenFailedTest()
+    {
+        QFETCH_GLOBAL(QUrl, registryUrl);
+
+        if (registryUrl.scheme() != QRemoteObjectStringLiterals::tcp())
+            QSKIP("Skipping test for local and external backends.");
+
+        // Need the Host or Registry running so that the port is in use.
+        setupRegistry();
+        QRemoteObjectHost badHost;
+        badHost.setHostUrl(registryUrl);
+        QCOMPARE(badHost.lastError(), QRemoteObjectNode::ListenFailed);
+
+    }
+
+    void invalidExternalTest()
+    {
+        QFETCH_GLOBAL(QUrl, hostUrl);
+        if (hostUrl.scheme() != QRemoteObjectStringLiterals::tcp())
+            QSKIP("Skipping test for tcp and external backends.");
+        QRemoteObjectHost srcNode;
+        QTest::ignoreMessage(QtWarningMsg, " Overriding a valid QtRO url ( QUrl(\"tcp://127.0.0.1:65511\") ) with AllowExternalRegistration is not allowed.");
+        srcNode.setHostUrl(hostUrl, QRemoteObjectHost::AllowExternalRegistration);
+        QCOMPARE(srcNode.lastError(), QRemoteObjectNode::HostUrlInvalid);
+        Engine e;
+        bool res = srcNode.enableRemoting(&e);
+        QVERIFY(res == false);
+    }
+
+    void startClientWithoutHost()
+    {
+        setupClient();
+        QScopedPointer<EngineReplica> replica(client->acquire<EngineReplica>());
+        client->setHeartbeatInterval(10);
+        // Wait, to make sure there's no crash (QTBUG-94513)
+        QTest::qWait(200);
+
+        // Make sure creating the host afterwards works
+        setupHost();
+        Engine e;
+        e.setRpm(42);
+        host->enableRemoting(&e);
+
+        QVERIFY(replica->waitForSource());
+        QCOMPARE(replica->rpm(), e.rpm());
+    }
+};
+
+QTEST_MAIN(tst_Integration)
+
+#include "tst_integration.moc"
diff --git a/tests/auto/integration_external/CMakeLists.txt b/tests/auto/integration_external/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7389323
--- /dev/null
@@ -0,0 +1,4 @@
+
+add_subdirectory(client)
+add_subdirectory(server)
+add_subdirectory(external)
diff --git a/tests/auto/integration_external/MyInterface.rep b/tests/auto/integration_external/MyInterface.rep
new file mode 100644 (file)
index 0000000..dfb8752
--- /dev/null
@@ -0,0 +1,18 @@
+#include <QtCore>
+
+class MyInterface
+{
+    ENUM Enum1 { First, Second, Third }
+    PROP(Enum1 enum1 = First READWRITE)
+
+    PROP(bool started = false)
+
+    SLOT(bool start())
+    SLOT(bool stop())
+    SLOT(bool quit())
+    SLOT(bool next())
+    SLOT(void testEnumParamsInSlots(Enum1 enumSlotParam, bool slotParam2, int))
+
+    SIGNAL(advance())
+    SIGNAL(testEnumParamsInSignals(Enum1 enumSignalParam, bool signalParam2, QString))
+};
diff --git a/tests/auto/integration_external/client/CMakeLists.txt b/tests/auto/integration_external/client/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9e5d767
--- /dev/null
@@ -0,0 +1,21 @@
+
+#####################################################################
+## integration_external_client Binary:
+#####################################################################
+
+qt_internal_add_executable(integration_external_client
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        main.cpp
+    INCLUDE_DIRECTORIES
+        ${CMAKE_CURRENT_SOURCE_DIR}
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+qt6_add_repc_replicas(integration_external_client
+    ../MyInterface.rep
+)
+
+#### Keys ignored in scope 1:.:.:client.pro:<TRUE>:
+# TEMPLATE = "app"
diff --git a/tests/auto/integration_external/client/main.cpp b/tests/auto/integration_external/client/main.cpp
new file mode 100644 (file)
index 0000000..86ce99b
--- /dev/null
@@ -0,0 +1,202 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include "rep_MyInterface_replica.h"
+
+#include <QCoreApplication>
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtTest/QtTest>
+#include <QTcpSocket>
+
+const QUrl registryUrl = QUrl(QStringLiteral("tcp://127.0.0.1:65212"));
+
+class tst_Client_Process : public QObject
+{
+    Q_OBJECT
+
+private Q_SLOTS:
+    void initTestCase()
+    {
+        m_repNode.setRegistryUrl(registryUrl);
+        QRemoteObjectNode::RemoteObjectSchemaHandler setupTcp = [this](QUrl url) {
+            QTcpSocket *socket = new QTcpSocket(&this->m_repNode);
+            connect(socket, &QTcpSocket::connected,
+                    [socket, this]() {
+                this->m_repNode.addClientSideConnection(socket);
+            });
+            connect(socket, &QTcpSocket::errorOccurred,
+                    [socket](QAbstractSocket::SocketError error) {
+                qDebug() << "SocketError" << error;
+                delete socket;
+            });
+            socket->connectToHost(url.host(), quint16(url.port()));
+        };
+        m_repNode.registerExternalSchema(QStringLiteral("exttcp"), setupTcp);
+        QVERIFY(m_repNode.waitForRegistry(3000));
+        m_rep.reset(m_repNode.acquire<MyInterfaceReplica>());
+    }
+
+    void testRun()
+    {
+
+        QVERIFY(m_rep->waitForSource());
+        auto reply = m_rep->start();
+        QVERIFY(reply.waitForFinished());
+
+        // BEGIN: Testing
+        QSignalSpy advanceSpy(m_rep.data(), &MyInterfaceReplica::advance);
+
+        QSignalSpy spy(m_rep.data(), &MyInterfaceReplica::enum1Changed);
+        QVERIFY(advanceSpy.wait());
+
+        QCOMPARE(spy.count(), 2);
+        // END: Testing
+
+        reply = m_rep->stop();
+        QVERIFY(reply.waitForFinished());
+    }
+
+    void testEnumDetails()
+    {
+        QHash<QByteArray, int> kvs = {{"First", 0}, {"Second", 1}, {"Third", 2}};
+        QScopedPointer<QRemoteObjectDynamicReplica> rep(m_repNode.acquireDynamic("MyInterface"));
+        QVERIFY(rep->waitForSource());
+
+        auto mo = rep->metaObject();
+        int enumIdx = mo->indexOfEnumerator("Enum1");
+        QVERIFY(enumIdx != -1);
+        auto enumerator = mo->enumerator(enumIdx);
+        QCOMPARE(enumerator.name(), "Enum1");
+        QCOMPARE(enumerator.keyCount(), 3);
+        for (int i = 0; i < 3; ++i) {
+            auto key = enumerator.key(i);
+            auto val = enumerator.value(i);
+            auto it = kvs.find(key);
+            QVERIFY(it != kvs.end());
+            QCOMPARE(*it, val);
+            kvs.erase(it);
+        }
+
+        int propIdx = mo->indexOfProperty("enum1");
+        QVERIFY(propIdx != -1);
+        auto property = mo->property(propIdx);
+        property.write(rep.data(), 1);
+        QTRY_COMPARE(property.read(rep.data()).toInt(), 1);
+    }
+
+    void testMethodSignalParamDetails()
+    {
+        QScopedPointer<QRemoteObjectDynamicReplica> rep(m_repNode.acquireDynamic("MyInterface"));
+        QVERIFY(rep->waitForSource());
+
+        auto mo = rep->metaObject();
+        int signalIdx = mo->indexOfSignal("testEnumParamsInSignals(MyInterfaceReplica::Enum1,bool,QString)");
+        QVERIFY(signalIdx != -1);
+        auto simm = mo->method(signalIdx);
+        {
+            QCOMPARE(simm.parameterCount(), 3);
+            auto paramNames = simm.parameterNames();
+            QCOMPARE(paramNames.size(), 3);
+            QCOMPARE(paramNames.at(0), QByteArrayLiteral("enumSignalParam"));
+            QCOMPARE(paramNames.at(1), QByteArrayLiteral("signalParam2"));
+            QCOMPARE(paramNames.at(2), QByteArrayLiteral("__repc_variable_1"));
+            QCOMPARE(simm.parameterMetaType(0), QMetaType::fromType<MyInterfaceReplica::Enum1>());
+            QCOMPARE(simm.parameterMetaType(1), QMetaType::fromType<bool>());
+            QCOMPARE(simm.parameterMetaType(2), QMetaType::fromType<QString>());
+        }
+
+        int slotIdx = mo->indexOfSlot("testEnumParamsInSlots(MyInterfaceReplica::Enum1,bool,int)");
+        QVERIFY(slotIdx != -1);
+        auto slmm = mo->method(slotIdx);
+        {
+            QCOMPARE(slmm .parameterCount(), 3);
+            auto paramNames = slmm .parameterNames();
+            QCOMPARE(paramNames.size(), 3);
+            QCOMPARE(paramNames.at(0), QByteArrayLiteral("enumSlotParam"));
+            QCOMPARE(paramNames.at(1), QByteArrayLiteral("slotParam2"));
+            QCOMPARE(paramNames.at(2), QByteArrayLiteral("__repc_variable_1"));
+        }
+
+        int enumVal = 0;
+        mo->invokeMethod(rep.data(), "testEnumParamsInSlots",
+                                    QGenericArgument("MyInterfaceReplica::Enum1", &enumVal),
+                                    Q_ARG(bool, true), Q_ARG(int, 1234));
+
+        int enumIdx = mo->indexOfProperty("enum1");
+        QVERIFY(enumIdx != -1);
+        QTRY_COMPARE(mo->property(enumIdx).read(rep.data()).toInt(), 0);
+
+        int startedIdx = mo->indexOfProperty("started");
+        QVERIFY(startedIdx != -1);
+        QTRY_COMPARE(mo->property(startedIdx).read(rep.data()).toBool(), true);
+    }
+
+    void testMethodSignal()
+    {
+        QScopedPointer<MyInterfaceReplica> rep(new MyInterfaceReplica());
+        rep->setNode(&m_repNode);
+        QVERIFY(rep->waitForSource());
+
+        rep->testEnumParamsInSlots(MyInterfaceReplica::Second, false, 74);
+
+        connect(rep.data(), &MyInterfaceReplica::testEnumParamsInSignals,
+                [](MyInterfaceReplica::Enum1 enumSignalParam) { QCOMPARE(enumSignalParam, MyInterfaceReplica::Second); });
+
+        QTRY_COMPARE(rep->enum1(), MyInterfaceReplica::Second);
+        QTRY_COMPARE(rep->started(), false);
+    }
+
+    void testDisconnect()
+    {
+        auto reply = m_rep->next();
+        QSignalSpy stateSpy(m_rep.data(), &MyInterfaceReplica::stateChanged);
+        QVERIFY(reply.waitForFinished());
+
+        QTRY_COMPARE(stateSpy.count(), 1);
+        QCOMPARE(m_rep->state(), QRemoteObjectReplica::Suspect);
+
+        QTRY_COMPARE(stateSpy.count(), 2);
+        QCOMPARE(m_rep->state(), QRemoteObjectReplica::Valid);
+        // Make sure we updated to the correct enum1 value
+        QCOMPARE(m_rep->enum1(), MyInterfaceReplica::First);
+    }
+
+    void cleanupTestCase()
+    {
+        auto reply = m_rep->quit();
+        QVERIFY(reply.waitForFinished());
+    }
+
+private:
+    QRemoteObjectNode m_repNode;
+    QScopedPointer<MyInterfaceReplica> m_rep;
+};
+
+QTEST_MAIN(tst_Client_Process)
+
+#include "main.moc"
diff --git a/tests/auto/integration_external/external/CMakeLists.txt b/tests/auto/integration_external/external/CMakeLists.txt
new file mode 100644 (file)
index 0000000..a4c9ecb
--- /dev/null
@@ -0,0 +1,12 @@
+
+#####################################################################
+## tst_integration_external Test:
+#####################################################################
+
+qt_internal_add_test(tst_integration_external
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        tst_integration_external.cpp
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+)
diff --git a/tests/auto/integration_external/external/tst_integration_external.cpp b/tests/auto/integration_external/external/tst_integration_external.cpp
new file mode 100644 (file)
index 0000000..348da5e
--- /dev/null
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QMetaType>
+#include <QProcess>
+
+#include "../../../shared/testutils.h"
+
+class tst_Integration_External: public QObject
+{
+    Q_OBJECT
+
+private slots:
+    void initTestCase()
+    {
+        QVERIFY(TestUtils::init("external"));
+        QLoggingCategory::setFilterRules("qt.remoteobjects.warning=false");
+    }
+
+    void cleanup()
+    {
+        // wait for delivery of RemoveObject events to the source
+        QTest::qWait(200);
+    }
+
+    void testRun_data()
+    {
+        QTest::addColumn<bool>("templated");
+        QTest::newRow("non-templated enableRemoting") << false;
+        QTest::newRow("templated enableRemoting") << true;
+    }
+
+    void testRun()
+    {
+        QFETCH(bool, templated);
+
+        qDebug() << "Starting server process";
+        QProcess serverProc;
+        serverProc.setProcessChannelMode(QProcess::ForwardedChannels);
+        if (templated) {
+            QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+            env.insert("TEMPLATED_REMOTING", "true");
+            serverProc.setProcessEnvironment(env);
+        }
+        serverProc.start(TestUtils::findExecutable("integration_external_server", "/server"),
+                         QStringList());
+        QVERIFY(serverProc.waitForStarted());
+
+        // wait for server start
+        QTest::qWait(200);
+
+        qDebug() << "Starting client process";
+        QProcess clientProc;
+        clientProc.setProcessChannelMode(QProcess::ForwardedChannels);
+        clientProc.start(TestUtils::findExecutable("integration_external_client", "/client"),
+                         QStringList());
+        QVERIFY(clientProc.waitForStarted());
+
+        QVERIFY(clientProc.waitForFinished());
+        QVERIFY(serverProc.waitForFinished());
+
+        QCOMPARE(serverProc.exitCode(), 0);
+        QCOMPARE(clientProc.exitCode(), 0);
+    }
+};
+
+QTEST_MAIN(tst_Integration_External)
+
+#include "tst_integration_external.moc"
diff --git a/tests/auto/integration_external/server/CMakeLists.txt b/tests/auto/integration_external/server/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c6e2392
--- /dev/null
@@ -0,0 +1,22 @@
+
+#####################################################################
+## integration_external_server Binary:
+#####################################################################
+
+qt_internal_add_executable(integration_external_server
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        main.cpp
+        mytestserver.cpp mytestserver.h
+    INCLUDE_DIRECTORIES
+        ${CMAKE_CURRENT_SOURCE_DIR}
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+qt6_add_repc_sources(integration_external_server
+    ../MyInterface.rep
+)
+
+#### Keys ignored in scope 1:.:.:server.pro:<TRUE>:
+# TEMPLATE = "app"
diff --git a/tests/auto/integration_external/server/main.cpp b/tests/auto/integration_external/server/main.cpp
new file mode 100644 (file)
index 0000000..ab179a1
--- /dev/null
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include "mytestserver.h"
+
+#include <QCoreApplication>
+#include <QTcpServer>
+#include <QtTest/QtTest>
+#include <QTcpSocket>
+
+const QUrl registryUrl = QUrl(QStringLiteral("tcp://127.0.0.1:65212"));
+const QUrl extUrl = QUrl(QStringLiteral("exttcp://127.0.0.1:65213"));
+const QUrl extUrl2 = QUrl(QStringLiteral("exttcp://127.0.0.1:65214"));
+
+class tst_Server_Process : public QObject
+{
+    Q_OBJECT
+
+    struct Device
+    {
+        Device(QUrl url) : srcNode(url, registryUrl, QRemoteObjectHost::AllowExternalRegistration)
+        {
+            tcpServer.listen(QHostAddress(url.host()), quint16(url.port()));
+            QVERIFY(srcNode.waitForRegistry(3000));
+            QObject::connect(&tcpServer, &QTcpServer::newConnection, [this]() {
+                auto conn = this->tcpServer.nextPendingConnection();
+                this->srcNode.addHostSideConnection(conn);
+            });
+        }
+        QTcpServer tcpServer;
+        QRemoteObjectHost srcNode;
+    };
+
+private Q_SLOTS:
+    void testRun()
+    {
+        QRemoteObjectRegistryHost registry(registryUrl);
+
+        Device dev1(extUrl);
+        MyTestServer myTestServer;
+        bool templated = qEnvironmentVariableIsSet("TEMPLATED_REMOTING");
+        if (templated)
+            QVERIFY(dev1.srcNode.enableRemoting<MyInterfaceSourceAPI>(&myTestServer));
+        else
+            QVERIFY(dev1.srcNode.enableRemoting(&myTestServer));
+
+        qDebug() << "Waiting for incoming connections";
+
+        QSignalSpy waitForStartedSpy(&myTestServer, &MyTestServer::startedChanged);
+        QVERIFY(waitForStartedSpy.isValid());
+        QVERIFY(waitForStartedSpy.wait());
+        QCOMPARE(waitForStartedSpy.value(0).value(0).toBool(), true);
+
+        // wait for delivery of events
+        QTest::qWait(200);
+
+        qDebug() << "Client connected";
+
+        // BEGIN: Testing
+
+        // make sure continuous changes to enums don't mess up the protocol
+        myTestServer.setEnum1(MyTestServer::Second);
+        myTestServer.setEnum1(MyTestServer::Third);
+
+        emit myTestServer.advance();
+
+        waitForStartedSpy.clear();
+        QVERIFY(waitForStartedSpy.wait());
+        QCOMPARE(waitForStartedSpy.value(0).value(0).toBool(), false);
+
+        bool next = false;
+        connect(&myTestServer, &MyTestServer::nextStep, [&next]{ next = true; });
+        QTRY_VERIFY_WITH_TIMEOUT(next, 5000);
+
+        qDebug() << "Disable remoting";
+        QVERIFY(dev1.srcNode.disableRemoting(&myTestServer));
+
+        // Wait before changing the state
+        QTest::qWait(200);
+
+        // Change a value while replica is suspect
+        myTestServer.setEnum1(MyTestServer::First);
+
+        // Share the object on a different "device", make sure registry updates and connects
+        qDebug() << "Enable remoting";
+        Device dev2(extUrl2);
+        QVERIFY(dev2.srcNode.enableRemoting(&myTestServer));
+
+        // wait for quit
+        bool quit = false;
+        connect(&myTestServer, &MyTestServer::quitApp, [&quit]{quit = true;});
+        QTRY_VERIFY_WITH_TIMEOUT(quit, 5000);
+
+        // wait for delivery of events
+        QTest::qWait(200);
+
+        qDebug() << "Done. Shutting down.";
+    }
+};
+
+QTEST_MAIN(tst_Server_Process)
+
+#include "main.moc"
diff --git a/tests/auto/integration_external/server/mytestserver.cpp b/tests/auto/integration_external/server/mytestserver.cpp
new file mode 100644 (file)
index 0000000..44421f4
--- /dev/null
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include <qdebug.h>
+
+#include "mytestserver.h"
+#include "rep_MyInterface_source.h"
+
+MyTestServer::MyTestServer(QObject *parent)
+    : MyInterfaceSimpleSource(parent)
+{
+    qDebug() << "Server started";
+}
+
+MyTestServer::~MyTestServer()
+{
+    qDebug() << "Server stopped";
+}
+
+bool MyTestServer::start()
+{
+    setStarted(true);
+    return true;
+}
+
+bool MyTestServer::stop()
+{
+    setStarted(false);
+    return true;
+}
+
+bool MyTestServer::quit()
+{
+    emit quitApp();
+    return true;
+}
+
+bool MyTestServer::next()
+{
+    emit nextStep();
+    return true;
+}
+
+void MyTestServer::testEnumParamsInSlots(Enum1 enumSlotParam, bool slotParam2, int number)
+{
+    setEnum1(enumSlotParam);
+    setStarted(slotParam2);
+    emit testEnumParamsInSignals(enum1(), started(), QString::number(number));
+}
diff --git a/tests/auto/integration_external/server/mytestserver.h b/tests/auto/integration_external/server/mytestserver.h
new file mode 100644 (file)
index 0000000..c0edda0
--- /dev/null
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#ifndef MYTESTSERVER_H
+#define MYTESTSERVER_H
+
+#include <QTimer>
+
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtRemoteObjects/qremoteobjectsource.h>
+
+#include "rep_MyInterface_source.h"
+
+class MyTestServer : public MyInterfaceSimpleSource
+{
+    Q_OBJECT
+
+public:
+    MyTestServer(QObject *parent = nullptr);
+    ~MyTestServer() override;
+
+public Q_SLOTS:
+    bool start() override;
+    bool stop() override;
+    bool quit() override;
+    bool next() override;
+    void testEnumParamsInSlots(Enum1 enumSlotParam, bool slotParam2, int __repc_variable_1) override;
+
+Q_SIGNALS:
+    void quitApp();
+    void nextStep();
+};
+
+#endif // MYTESTSERVER_H
diff --git a/tests/auto/integration_multiprocess/CMakeLists.txt b/tests/auto/integration_multiprocess/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5a97510
--- /dev/null
@@ -0,0 +1,4 @@
+
+add_subdirectory(client)
+add_subdirectory(server)
+add_subdirectory(tst)
diff --git a/tests/auto/integration_multiprocess/ExtPodInterface.rep b/tests/auto/integration_multiprocess/ExtPodInterface.rep
new file mode 100644 (file)
index 0000000..0c9ad56
--- /dev/null
@@ -0,0 +1 @@
+POD ExtPOD(int i, float f, QString s)
diff --git a/tests/auto/integration_multiprocess/MyInterface.rep b/tests/auto/integration_multiprocess/MyInterface.rep
new file mode 100644 (file)
index 0000000..5101529
--- /dev/null
@@ -0,0 +1,22 @@
+#include <QtCore>
+#include "rep_ExtPodInterface_merged.h"
+
+class MyInterface
+{
+    ENUM Enum1 { First, Second, Third }
+    PROP(Enum1 enum1 = First READWRITE)
+
+    PROP(bool started = false)
+    PROP(int initialValue)
+
+    SLOT(bool start())
+    SLOT(bool stop())
+    SLOT(bool quit())
+    SLOT(void testEnumParamsInSlots(Enum1 enumSlotParam, bool slotParam2, int))
+
+    SIGNAL(advance())
+    SIGNAL(testEnumParamsInSignals(Enum1 enumSignalParam, bool signalParam2, QString))
+
+    SLOT(void testExtPODListSlot(const QList<ExtPOD> &))
+    SIGNAL(testExtPODListSignal(const QList<ExtPOD> &))
+};
diff --git a/tests/auto/integration_multiprocess/PodInterface.rep b/tests/auto/integration_multiprocess/PodInterface.rep
new file mode 100644 (file)
index 0000000..8cdcf48
--- /dev/null
@@ -0,0 +1,8 @@
+#include <QtCore>
+
+POD MyPOD(int i, float f, QString s)
+
+class PodInterface
+{
+    PROP(MyPOD myPod)
+};
diff --git a/tests/auto/integration_multiprocess/client/CMakeLists.txt b/tests/auto/integration_multiprocess/client/CMakeLists.txt
new file mode 100644 (file)
index 0000000..88fdb34
--- /dev/null
@@ -0,0 +1,26 @@
+
+#####################################################################
+## integration_multiprocess_client Binary:
+#####################################################################
+
+qt_internal_add_executable(integration_multiprocess_client
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        main.cpp
+    INCLUDE_DIRECTORIES
+        ${CMAKE_CURRENT_SOURCE_DIR}
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+
+qt6_add_repc_merged(integration_multiprocess_client
+    ../ExtPodInterface.rep
+)
+
+qt6_add_repc_replicas(integration_multiprocess_client
+    ../MyInterface.rep
+)
+
+#### Keys ignored in scope 1:.:.:client.pro:<TRUE>:
+# TEMPLATE = "app"
diff --git a/tests/auto/integration_multiprocess/client/main.cpp b/tests/auto/integration_multiprocess/client/main.cpp
new file mode 100644 (file)
index 0000000..e07cefc
--- /dev/null
@@ -0,0 +1,217 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include "rep_MyInterface_replica.h"
+#include "rep_ExtPodInterface_merged.h"
+
+#include <QCoreApplication>
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtTest/QtTest>
+
+class tst_Client_Process : public QObject
+{
+    Q_OBJECT
+
+private Q_SLOTS:
+    void initTestCase()
+    {
+        m_repNode.reset(new QRemoteObjectNode);
+        m_repNode->connectToNode(QUrl(QStringLiteral("tcp://127.0.0.1:65213")));
+        m_rep.reset(m_repNode->acquire<MyInterfaceReplica>());
+        connect(m_rep.data(), &MyInterfaceReplica::notified, [&]() { m_notified = true; });
+        connect(m_rep.data(), &MyInterfaceReplica::initialValueChanged, [&]() {
+            // this value is only set when the replica first connects to the source
+            QCOMPARE(m_notified, false);
+            QCOMPARE(m_rep->initialValue(), 18);
+        });
+        QVERIFY(m_rep->waitForSource());
+    }
+
+    void testRun()
+    {
+        auto reply = m_rep->start();
+        QVERIFY(reply.waitForFinished());
+
+        // BEGIN: Testing
+        QSignalSpy advanceSpy(m_rep.data(), &MyInterfaceReplica::advance);
+
+        QSignalSpy spy(m_rep.data(), &MyInterfaceReplica::enum1Changed);
+        QVERIFY(advanceSpy.wait());
+
+        QCOMPARE(spy.count(), 2);
+        // END: Testing
+
+        reply = m_rep->stop();
+        QVERIFY(reply.waitForFinished());
+    }
+
+    void testEnumDetails()
+    {
+        QHash<QByteArray, int> kvs = {{"First", 0}, {"Second", 1}, {"Third", 2}};
+        QScopedPointer<QRemoteObjectDynamicReplica> rep(m_repNode->acquireDynamic("MyInterface"));
+        QVERIFY(rep->waitForSource());
+
+        auto mo = rep->metaObject();
+        int enumIdx = mo->indexOfEnumerator("Enum1");
+        QVERIFY(enumIdx != -1);
+        auto enumerator = mo->enumerator(enumIdx);
+        QCOMPARE(enumerator.name(), "Enum1");
+        QCOMPARE(enumerator.keyCount(), 3);
+        for (int i = 0; i < 3; ++i) {
+            auto key = enumerator.key(i);
+            auto val = enumerator.value(i);
+            auto it = kvs.find(key);
+            QVERIFY(it != kvs.end());
+            QCOMPARE(*it, val);
+            kvs.erase(it);
+        }
+
+        int propIdx = mo->indexOfProperty("enum1");
+        QVERIFY(propIdx != -1);
+        auto property = mo->property(propIdx);
+        property.write(rep.data(), 1);
+        QTRY_COMPARE(property.read(rep.data()).toInt(), 1);
+    }
+
+    void testMethodSignalParamDetails()
+    {
+        QScopedPointer<QRemoteObjectDynamicReplica> rep(m_repNode->acquireDynamic("MyInterface"));
+        QVERIFY(rep->waitForSource());
+
+        auto mo = rep->metaObject();
+        int signalIdx = mo->indexOfSignal("testEnumParamsInSignals(MyInterfaceReplica::Enum1,bool,QString)");
+        QVERIFY(signalIdx != -1);
+        auto simm = mo->method(signalIdx);
+        {
+            QCOMPARE(simm.parameterCount(), 3);
+            auto paramNames = simm.parameterNames();
+            QCOMPARE(paramNames.size(), 3);
+            QCOMPARE(paramNames.at(0), QByteArrayLiteral("enumSignalParam"));
+            QCOMPARE(paramNames.at(1), QByteArrayLiteral("signalParam2"));
+            QCOMPARE(paramNames.at(2), QByteArrayLiteral("__repc_variable_1"));
+            QCOMPARE(simm.parameterMetaType(0), QMetaType::fromType<MyInterfaceReplica::Enum1>());
+            QCOMPARE(simm.parameterMetaType(1), QMetaType::fromType<bool>());
+            QCOMPARE(simm.parameterMetaType(2), QMetaType::fromType<QString>());
+        }
+
+        int slotIdx = mo->indexOfSlot("testEnumParamsInSlots(MyInterfaceReplica::Enum1,bool,int)");
+        QVERIFY(slotIdx != -1);
+        auto slmm = mo->method(slotIdx);
+        {
+            QCOMPARE(slmm .parameterCount(), 3);
+            auto paramNames = slmm .parameterNames();
+            QCOMPARE(paramNames.size(), 3);
+            QCOMPARE(paramNames.at(0), QByteArrayLiteral("enumSlotParam"));
+            QCOMPARE(paramNames.at(1), QByteArrayLiteral("slotParam2"));
+            QCOMPARE(paramNames.at(2), QByteArrayLiteral("__repc_variable_1"));
+        }
+
+        int enumVal = 0;
+        mo->invokeMethod(rep.data(), "testEnumParamsInSlots",
+                                    QGenericArgument("MyInterfaceReplica::Enum1", &enumVal),
+                                    Q_ARG(bool, true), Q_ARG(int, 1234));
+
+        int enumIdx = mo->indexOfProperty("enum1");
+        QVERIFY(enumIdx != -1);
+        QTRY_COMPARE(mo->property(enumIdx).read(rep.data()).toInt(), 0);
+
+        int startedIdx = mo->indexOfProperty("started");
+        QVERIFY(startedIdx != -1);
+        QTRY_COMPARE(mo->property(startedIdx).read(rep.data()).toBool(), true);
+    }
+
+    void testMethodSignal()
+    {
+        QScopedPointer<MyInterfaceReplica> rep(new MyInterfaceReplica());
+        rep->setNode(m_repNode.get());
+        QVERIFY(rep->waitForSource());
+
+        rep->testEnumParamsInSlots(MyInterfaceReplica::Second, false, 74);
+
+        connect(rep.data(), &MyInterfaceReplica::testEnumParamsInSignals,
+                [](MyInterfaceReplica::Enum1 enumSignalParam) { QCOMPARE(enumSignalParam, MyInterfaceReplica::Second); });
+
+        QTRY_COMPARE(rep->enum1(), MyInterfaceReplica::Second);
+        QTRY_COMPARE(rep->started(), false);
+    }
+
+    void testExtPodListSignals()
+    {
+        QScopedPointer<MyInterfaceReplica> rep(new MyInterfaceReplica());
+        rep->setNode(m_repNode.get());
+        QVERIFY(rep->waitForSource());
+
+        auto list = QList { ExtPOD(1, 1.1f, QStringLiteral("v1")),
+                            ExtPOD(2, 2.2f, QStringLiteral("v2")) };
+        rep->testExtPODListSlot(list);
+        QSignalSpy spy(rep.data(), &MyInterfaceReplica::testExtPODListSignal);
+        connect(rep.data(), &MyInterfaceReplica::testExtPODListSignal,
+                [list](const QList<ExtPOD> &l) { QCOMPARE(l, list); });
+        QTRY_COMPARE(spy.count(), 1);
+    }
+
+    void testPod()
+    {
+        QScopedPointer<QRemoteObjectDynamicReplica> podRep(m_repNode->acquireDynamic("PodInterface"));
+        QVERIFY(podRep->waitForSource());
+        QVariant value = podRep->property("myPod");
+        const QMetaObject *mo = value.metaType().metaObject();
+        const void *gadget = value.constData();
+
+        QMetaProperty iProp = mo->property(mo->indexOfProperty("i"));
+        QVariant iValue = iProp.readOnGadget(gadget);
+        QCOMPARE(iValue.toInt(), 1);
+
+        QMetaProperty fProp = mo->property(mo->indexOfProperty("f"));
+        QVariant fValue = fProp.readOnGadget(gadget);
+        QCOMPARE(fValue.toFloat(), 5.0f);
+
+        QMetaProperty sProp = mo->property(mo->indexOfProperty("s"));
+        QVariant sValue = sProp.readOnGadget(gadget);
+        QCOMPARE(sValue.toString(), QString(QLatin1String("test")));
+    }
+
+    void cleanupTestCase()
+    {
+        auto reply = m_rep->quit();
+        QVERIFY(reply.waitForFinished());
+        m_rep.reset();
+        QVERIFY(QMetaType::fromName("MyPOD").isValid());
+        m_repNode.reset();
+        QVERIFY(!QMetaType::fromName("MyPOD").isValid());
+    }
+
+private:
+    QScopedPointer<QRemoteObjectNode> m_repNode;
+    QScopedPointer<MyInterfaceReplica> m_rep;
+    bool m_notified = false;
+};
+
+QTEST_MAIN(tst_Client_Process)
+
+#include "main.moc"
diff --git a/tests/auto/integration_multiprocess/server/CMakeLists.txt b/tests/auto/integration_multiprocess/server/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3ed2421
--- /dev/null
@@ -0,0 +1,27 @@
+
+#####################################################################
+## integration_multiprocess_server Binary:
+#####################################################################
+
+qt_internal_add_executable(integration_multiprocess_server
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        main.cpp
+        mytestserver.cpp mytestserver.h
+    INCLUDE_DIRECTORIES
+        ${CMAKE_CURRENT_SOURCE_DIR}
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+qt6_add_repc_merged(integration_multiprocess_server
+    ../ExtPodInterface.rep
+)
+
+qt6_add_repc_sources(integration_multiprocess_server
+    ../MyInterface.rep
+    ../PodInterface.rep
+)
+
+#### Keys ignored in scope 1:.:.:server.pro:<TRUE>:
+# TEMPLATE = "app"
diff --git a/tests/auto/integration_multiprocess/server/main.cpp b/tests/auto/integration_multiprocess/server/main.cpp
new file mode 100644 (file)
index 0000000..c4e40e8
--- /dev/null
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include "mytestserver.h"
+#include "rep_PodInterface_source.h"
+
+#include <QCoreApplication>
+#include <QtTest/QtTest>
+
+class tst_Server_Process : public QObject
+{
+    Q_OBJECT
+
+private Q_SLOTS:
+    void testRun()
+    {
+        QRemoteObjectHost srcNode(QUrl(QStringLiteral("tcp://127.0.0.1:65213")));
+        MyTestServer myTestServer;
+        bool templated = qEnvironmentVariableIsSet("TEMPLATED_REMOTING");
+        if (templated)
+            srcNode.enableRemoting<MyInterfaceSourceAPI>(&myTestServer);
+        else
+            srcNode.enableRemoting(&myTestServer);
+
+        PodInterfaceSimpleSource myPodSource;
+        myPodSource.setMyPod(MyPOD(1, 5.0, "test"));
+        if (templated)
+            srcNode.enableRemoting<PodInterfaceSourceAPI>(&myPodSource);
+        else
+            srcNode.enableRemoting(&myPodSource);
+
+        qDebug() << "Waiting for incoming connections";
+
+        QSignalSpy waitForStartedSpy(&myTestServer, &MyTestServer::startedChanged);
+        QVERIFY(waitForStartedSpy.isValid());
+        QVERIFY(waitForStartedSpy.wait());
+        QCOMPARE(waitForStartedSpy.value(0).value(0).toBool(), true);
+
+        // wait for delivery of events
+        QTest::qWait(200);
+
+        qDebug() << "Client connected";
+
+        // BEGIN: Testing
+
+        // make sure continuous changes to enums don't mess up the protocol
+        myTestServer.setEnum1(MyTestServer::Second);
+        myTestServer.setEnum1(MyTestServer::Third);
+
+        emit myTestServer.advance();
+
+        // END: Testing
+
+        waitForStartedSpy.clear();
+        QVERIFY(waitForStartedSpy.wait());
+        QCOMPARE(waitForStartedSpy.value(0).value(0).toBool(), false);
+
+        // wait for quit
+        bool quit = false;
+        connect(&myTestServer, &MyTestServer::quitApp, [&quit]{quit = true;});
+        QTRY_VERIFY_WITH_TIMEOUT(quit, 5000);
+
+        // wait for delivery of events
+        QTest::qWait(200);
+
+        qDebug() << "Done. Shutting down.";
+    }
+};
+
+QTEST_MAIN(tst_Server_Process)
+
+#include "main.moc"
diff --git a/tests/auto/integration_multiprocess/server/mytestserver.cpp b/tests/auto/integration_multiprocess/server/mytestserver.cpp
new file mode 100644 (file)
index 0000000..500a6fe
--- /dev/null
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include <qdebug.h>
+
+#include "mytestserver.h"
+#include "rep_MyInterface_source.h"
+
+MyTestServer::MyTestServer(QObject *parent)
+    : MyInterfaceSimpleSource(parent)
+{
+    qDebug() << "Server started";
+    setInitialValue(18);
+}
+
+MyTestServer::~MyTestServer()
+{
+    qDebug() << "Server stopped";
+}
+
+bool MyTestServer::start()
+{
+    setStarted(true);
+    return true;
+}
+
+bool MyTestServer::stop()
+{
+    setStarted(false);
+    return true;
+}
+
+bool MyTestServer::quit()
+{
+    emit quitApp();
+    return true;
+}
+
+void MyTestServer::testEnumParamsInSlots(Enum1 enumSlotParam, bool slotParam2, int number)
+{
+    setEnum1(enumSlotParam);
+    setStarted(slotParam2);
+    emit testEnumParamsInSignals(enum1(), started(), QString::number(number));
+}
+
+void MyTestServer::testExtPODListSlot(const QList<ExtPOD> &l)
+{
+    emit testExtPODListSignal(l);
+}
diff --git a/tests/auto/integration_multiprocess/server/mytestserver.h b/tests/auto/integration_multiprocess/server/mytestserver.h
new file mode 100644 (file)
index 0000000..9bc47ae
--- /dev/null
@@ -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: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$
+**
+****************************************************************************/
+
+#ifndef MYTESTSERVER_H
+#define MYTESTSERVER_H
+
+#include <QTimer>
+
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtRemoteObjects/qremoteobjectsource.h>
+
+#include "rep_MyInterface_source.h"
+
+class MyTestServer : public MyInterfaceSimpleSource
+{
+    Q_OBJECT
+
+public:
+    MyTestServer(QObject *parent = nullptr);
+    ~MyTestServer() override;
+
+public Q_SLOTS:
+    bool start() override;
+    bool stop() override;
+    bool quit() override;
+    void testEnumParamsInSlots(Enum1 enumSlotParam, bool slotParam2, int __repc_variable_1) override;
+    void testExtPODListSlot(const QList<ExtPOD> &l) override;
+
+Q_SIGNALS:
+    void quitApp();
+};
+
+#endif // MYTESTSERVER_H
diff --git a/tests/auto/integration_multiprocess/tst/CMakeLists.txt b/tests/auto/integration_multiprocess/tst/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3730f20
--- /dev/null
@@ -0,0 +1,12 @@
+
+#####################################################################
+## tst_integration_multiprocess Test:
+#####################################################################
+
+qt_internal_add_test(tst_integration_multiprocess
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        tst_integration_multiprocess.cpp
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+)
diff --git a/tests/auto/integration_multiprocess/tst/tst_integration_multiprocess.cpp b/tests/auto/integration_multiprocess/tst/tst_integration_multiprocess.cpp
new file mode 100644 (file)
index 0000000..cee22b6
--- /dev/null
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QMetaType>
+#include <QProcess>
+
+#include "../../../shared/testutils.h"
+
+class tst_Integration_MultiProcess: public QObject
+{
+    Q_OBJECT
+
+private slots:
+    void initTestCase()
+    {
+        QVERIFY(TestUtils::init("tst"));
+        QLoggingCategory::setFilterRules("qt.remoteobjects.warning=false");
+    }
+
+    void cleanup()
+    {
+        // wait for delivery of RemoveObject events to the source
+        QTest::qWait(200);
+    }
+
+    void testRun_data()
+    {
+        QTest::addColumn<bool>("templated");
+        QTest::newRow("non-templated enableRemoting") << false;
+        QTest::newRow("templated enableRemoting") << true;
+    }
+
+    void testRun()
+    {
+        QFETCH(bool, templated);
+
+        qDebug() << "Starting server process";
+        QProcess serverProc;
+        serverProc.setProcessChannelMode(QProcess::ForwardedChannels);
+        if (templated) {
+            QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+            env.insert("TEMPLATED_REMOTING", "true");
+            serverProc.setProcessEnvironment(env);
+        }
+        serverProc.start(TestUtils::findExecutable("integration_multiprocess_server", "/server"),
+                         QStringList());
+        QVERIFY(serverProc.waitForStarted());
+
+        // wait for server start
+        QTest::qWait(200);
+
+        qDebug() << "Starting client process";
+        QProcess clientProc;
+        clientProc.setProcessChannelMode(QProcess::ForwardedChannels);
+        clientProc.start(TestUtils::findExecutable("integration_multiprocess_client", "/client"),
+                         QStringList());
+        QVERIFY(clientProc.waitForStarted());
+
+        QVERIFY(clientProc.waitForFinished());
+        QVERIFY(serverProc.waitForFinished());
+
+        QCOMPARE(serverProc.exitCode(), 0);
+        QCOMPARE(clientProc.exitCode(), 0);
+    }
+};
+
+QTEST_MAIN(tst_Integration_MultiProcess)
+
+#include "tst_integration_multiprocess.moc"
diff --git a/tests/auto/localsockettestserver/CMakeLists.txt b/tests/auto/localsockettestserver/CMakeLists.txt
new file mode 100644 (file)
index 0000000..2943c47
--- /dev/null
@@ -0,0 +1,16 @@
+
+#####################################################################
+## localsockettestserver Binary:
+#####################################################################
+
+qt_internal_add_executable(localsockettestserver
+    SOURCES
+        main.cpp
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+    OUTPUT_DIRECTORY
+        ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+#### Keys ignored in scope 1:.:.:localsockettestserver.pro:<TRUE>:
+# TEMPLATE = "app"
diff --git a/tests/auto/localsockettestserver/main.cpp b/tests/auto/localsockettestserver/main.cpp
new file mode 100644 (file)
index 0000000..045f6a4
--- /dev/null
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include <QRemoteObjectNode>
+
+int main(int argc, char *argv[])
+{
+    QCoreApplication a(argc, argv);
+    QObject remotedObject;
+    remotedObject.setObjectName(QStringLiteral("connectme"));
+    QRemoteObjectHost node(QUrl(QStringLiteral("local:crashMe")));
+    node.enableRemoting(&remotedObject);
+
+    return a.exec();
+}
diff --git a/tests/auto/modelreplica/CMakeLists.txt b/tests/auto/modelreplica/CMakeLists.txt
new file mode 100644 (file)
index 0000000..48c9b3b
--- /dev/null
@@ -0,0 +1,19 @@
+
+#####################################################################
+## tst_modelreplicatest Test:
+#####################################################################
+
+qt_internal_add_test(tst_modelreplicatest
+    SOURCES
+        tst_modelreplicatest.cpp
+    DEFINES
+        SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/\\\"
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+)
+qt6_add_repc_merged(tst_modelreplicatest
+    model.rep
+)
+
+#### Keys ignored in scope 1:.:.:modelreplica.pro:<TRUE>:
+# TEMPLATE = "app"
diff --git a/tests/auto/modelreplica/model.rep b/tests/auto/modelreplica/model.rep
new file mode 100644 (file)
index 0000000..95d0f45
--- /dev/null
@@ -0,0 +1,12 @@
+class Media
+{
+    ENUM state{Stopped, Paused, Playing}
+    PROP(QString currentTrack)
+    PROP(state playState)
+    MODEL tracks(display)
+}
+
+class OtherMedia
+{
+    MODEL tracks(display,decoration)
+}
diff --git a/tests/auto/modelreplica/tst_modelreplicatest.cpp b/tests/auto/modelreplica/tst_modelreplicatest.cpp
new file mode 100644 (file)
index 0000000..038b339
--- /dev/null
@@ -0,0 +1,221 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include <QString>
+#include <QtTest>
+#include "rep_model_merged.h"
+
+class ModelreplicaTest : public QObject
+{
+    Q_OBJECT
+
+public:
+    ModelreplicaTest() = default;
+
+private Q_SLOTS:
+    void basicFunctions();
+    void basicFunctions_data();
+    void nullModel();
+    void nestedSortFilterProxyModel_data() { basicFunctions_data(); }
+    void nestedSortFilterProxyModel();
+    void sortFilterProxyModel_data();
+    void sortFilterProxyModel();
+};
+
+void ModelreplicaTest::basicFunctions_data()
+{
+    QTest::addColumn<bool>("templated");
+    QTest::newRow("non-templated enableRemoting") << false;
+    QTest::newRow("templated enableRemoting") << true;
+}
+
+void ModelreplicaTest::basicFunctions()
+{
+    QFETCH(bool, templated);
+
+    QRemoteObjectRegistryHost host(QUrl("tcp://localhost:5555"));
+    auto model = new QStringListModel();
+    model->setStringList(QStringList() << "Track1" << "Track2" << "Track3");
+    MediaSimpleSource source;
+    source.setTracks(model);
+    if (templated)
+        host.enableRemoting<MediaSourceAPI>(&source);
+    else
+        host.enableRemoting(&source);
+
+    auto model2 = new QStringListModel();
+    model2->setStringList(QStringList() << "Track4" << "Track5");
+    OtherMediaSimpleSource source2;
+    source2.setTracks(model2);
+    host.enableRemoting(&source2);
+
+    QRemoteObjectNode client(QUrl("tcp://localhost:5555"));
+    const QScopedPointer<MediaReplica> replica(client.acquire<MediaReplica>());
+    QSignalSpy tracksSpy(replica->tracks(), &QAbstractItemModelReplica::initialized);
+    QVERIFY(replica->waitForSource(300));
+    QVERIFY(tracksSpy.wait());
+    // Rep file only uses display role
+    QCOMPARE(QList<int>{Qt::DisplayRole}, replica->tracks()->availableRoles());
+
+    QCOMPARE(model->rowCount(), replica->tracks()->rowCount());
+    for (int i = 0; i < replica->tracks()->rowCount(); i++)
+    {
+        // We haven't received any data yet
+        QCOMPARE(QVariant(), replica->tracks()->data(replica->tracks()->index(i, 0)));
+    }
+
+    // Wait for data to be fetch and confirm
+    QTest::qWait(100);
+    QCOMPARE(model->rowCount(), replica->tracks()->rowCount());
+    for (int i = 0; i < replica->tracks()->rowCount(); i++)
+    {
+        QTRY_COMPARE(model->data(model->index(i), Qt::DisplayRole), replica->tracks()->data(replica->tracks()->index(i, 0)));
+    }
+
+    // ensure the tracks objects are distinct
+    const QScopedPointer<OtherMediaReplica> otherReplica(client.acquire<OtherMediaReplica>());
+    QSignalSpy otherTracksSpy(otherReplica->tracks(), &QAbstractItemModelReplica::initialized);
+    QVERIFY(otherReplica->waitForSource(300));
+    QVERIFY(otherTracksSpy.wait());
+    QCOMPARE(otherReplica->tracks()->availableRoles().count(), 2);
+
+}
+
+void ModelreplicaTest::nullModel()
+{
+    QRemoteObjectRegistryHost host(QUrl("tcp://localhost:5555"));
+    MediaSimpleSource source;
+    host.enableRemoting(&source);
+
+    QRemoteObjectNode client(QUrl("tcp://localhost:5555"));
+    const QScopedPointer<MediaReplica> replica(client.acquire<MediaReplica>());
+    QVERIFY(replica->waitForSource(300));
+
+    auto model = new QStringListModel(this);
+    model->setStringList(QStringList() << "Track1" << "Track2" << "Track3");
+    source.setTracks(model);
+
+    QTRY_VERIFY(replica->tracks());
+    QTRY_COMPARE(replica->tracks()->rowCount(), 3);
+    QTRY_COMPARE(replica->tracks()->data(replica->tracks()->index(0, 0)), "Track1");
+
+    model = new QStringListModel(this);
+    model->setStringList(QStringList() << "New Track1" << "New Track2" << "New Track3"  << "New Track4");
+    source.setTracks(model);
+    QTRY_COMPARE(replica->tracks()->rowCount(), 4);
+    QTRY_COMPARE(replica->tracks()->data(replica->tracks()->index(3, 0)), "New Track4");
+}
+
+void ModelreplicaTest::nestedSortFilterProxyModel()
+{
+    QFETCH(bool, templated);
+
+    QRemoteObjectRegistryHost host(QUrl("tcp://localhost:5555"));
+    auto model = new QStringListModel(this);
+    model->setStringList(QStringList() << "CCC" << "AAA" << "BBB");
+    auto proxyModel = new QSortFilterProxyModel(this);
+    proxyModel->setSourceModel(model);
+
+    MediaSimpleSource source;
+    source.setTracks(proxyModel);
+    if (templated)
+        host.enableRemoting<MediaSourceAPI>(&source);
+    else
+        host.enableRemoting(&source);
+
+    QRemoteObjectNode client(QUrl("tcp://localhost:5555"));
+    const QScopedPointer<MediaReplica> replica(client.acquire<MediaReplica>());
+    QSignalSpy tracksSpy(replica->tracks(), &QAbstractItemModelReplica::initialized);
+    QVERIFY(replica->waitForSource(300));
+    QVERIFY(tracksSpy.wait());
+    // Rep file only uses display role
+    QCOMPARE(QVector<int>{Qt::DisplayRole}, replica->tracks()->availableRoles());
+
+    QCOMPARE(proxyModel->rowCount(), replica->tracks()->rowCount());
+    for (int i = 0; i < replica->tracks()->rowCount(); i++) {
+        // We haven't received any data yet
+        QCOMPARE(QVariant(), replica->tracks()->data(replica->tracks()->index(i, 0)));
+    }
+
+    // Wait for data to be fetch and confirm
+    QCOMPARE(proxyModel->rowCount(), replica->tracks()->rowCount());
+    for (int i = 0; i < replica->tracks()->rowCount(); i++)
+        QTRY_COMPARE(proxyModel->data(proxyModel->index(i, 0), Qt::DisplayRole), replica->tracks()->data(replica->tracks()->index(i, 0)));
+
+    proxyModel->sort(0, Qt::AscendingOrder);
+    QCOMPARE(proxyModel->rowCount(), replica->tracks()->rowCount());
+    for (int i = 0; i < replica->tracks()->rowCount(); i++)
+        QTRY_COMPARE(proxyModel->data(proxyModel->index(i, 0), Qt::DisplayRole), replica->tracks()->data(replica->tracks()->index(i, 0)));
+}
+
+void ModelreplicaTest::sortFilterProxyModel_data()
+{
+    QTest::addColumn<bool>("prefetch");
+
+    QTest::newRow("size only") << false;
+    QTest::newRow("prefetch") << true;
+}
+
+void ModelreplicaTest::sortFilterProxyModel()
+{
+    QFETCH(bool, prefetch);
+
+    QRemoteObjectRegistryHost host(QUrl("tcp://localhost:5555"));
+    auto model = new QStringListModel(this);
+    model->setStringList(QStringList() << "CCC" << "AAA" << "BBB");
+    auto proxyModel = new QSortFilterProxyModel(this);
+    proxyModel->setSourceModel(model);
+
+    QList<int> roles = { Qt::DisplayRole };
+    host.enableRemoting(proxyModel, "test", roles);
+
+    auto fetchMode = prefetch ? QtRemoteObjects::PrefetchData : QtRemoteObjects::FetchRootSize;
+    QRemoteObjectNode client(QUrl("tcp://localhost:5555"));
+    QScopedPointer<QAbstractItemModelReplica> replica(client.acquireModel("test", fetchMode));
+    QSignalSpy initSpy(replica.get(), &QAbstractItemModelReplica::initialized);
+    QVERIFY(initSpy.wait());
+
+    QCOMPARE(roles, replica->availableRoles());
+
+    // Wait for data to be fetch and confirm
+    QCOMPARE(proxyModel->rowCount(), replica->rowCount());
+    for (int i = 0; i < replica->rowCount(); i++)
+        QTRY_COMPARE(proxyModel->data(proxyModel->index(i, 0), Qt::DisplayRole),
+                     replica->data(replica->index(i, 0)));
+
+    proxyModel->sort(0, Qt::AscendingOrder);
+    QCOMPARE(proxyModel->rowCount(), replica->rowCount());
+
+    for (int i = 0; i < replica->rowCount(); i++)
+        QTRY_COMPARE(proxyModel->data(proxyModel->index(i, 0), Qt::DisplayRole),
+                     replica->data(replica->index(i, 0)));
+}
+
+QTEST_MAIN(ModelreplicaTest)
+
+#include "tst_modelreplicatest.moc"
diff --git a/tests/auto/modelview/CMakeLists.txt b/tests/auto/modelview/CMakeLists.txt
new file mode 100644 (file)
index 0000000..51fc670
--- /dev/null
@@ -0,0 +1,26 @@
+
+#####################################################################
+## tst_modelview Test:
+#####################################################################
+
+qt_internal_add_test(tst_modelview
+    SOURCES
+        tst_modelview.cpp
+        ../shared/model_utilities.h
+    PUBLIC_LIBRARIES
+        Qt::Gui
+        Qt::RemoteObjects
+)
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(tst_modelview CONDITION boot2qt
+    DEFINES
+        SLOW_MODELTEST
+)
+
+qt_internal_extend_target(tst_modelview CONDITION MINGW
+    DEFINES
+        SLOW_MODELTEST
+)
diff --git a/tests/auto/modelview/tst_modelview.cpp b/tests/auto/modelview/tst_modelview.cpp
new file mode 100644 (file)
index 0000000..2a8a34b
--- /dev/null
@@ -0,0 +1,1162 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include "../shared/model_utilities.h"
+
+#include <QtTest/QtTest>
+#include <QAbstractItemModelTester>
+#include <QMetaType>
+#include <QRemoteObjectReplica>
+#include <QRemoteObjectNode>
+#include <QAbstractItemModelReplica>
+#include <QStandardItemModel>
+#include <QSortFilterProxyModel>
+#include <QEventLoop>
+#include <QRandomGenerator>
+
+namespace {
+
+QList<QStandardItem*> createInsertionChildren(int num, const QString& name, const QColor &background)
+{
+    QList<QStandardItem*> children;
+    for (int i = 0; i < num; ++i) {
+        QStandardItem *item = new QStandardItem(QStringLiteral("%1 %2").arg(name).arg(i+1));
+        item->setBackground(background);
+        children.append(item);
+    }
+    return children;
+}
+
+class RowsWatcher : public WaitHelper
+{
+public:
+    RowsWatcher(const QAbstractItemModel *model, int expectedRowsCount)
+        : WaitHelper(), m_model(model), m_expectedRowsCount(expectedRowsCount)
+    {
+        connect(m_model, &QAbstractItemModel::rowsInserted, this,
+                [this](const QModelIndex &parent, int first, int last) {
+                    const auto columnCount = m_model->columnCount(parent);
+                    for (int row = first; row <= last; ++row) {
+                        for (int column = 0; column < columnCount; ++column)
+                            m_changedData.append(m_model->index(row, column, parent));
+                    }
+                    onNumRowsChanged(parent, first, last);
+                });
+
+        connect(m_model, &QAbstractItemModel::rowsRemoved, this, &RowsWatcher::onNumRowsChanged);
+    }
+
+    void onNumRowsChanged(const QModelIndex &parent, int first, int last)
+    {
+        const auto compare = [=](const RowData &row) {
+            return (row.m_start == first && row.m_end == last
+                    && compareIndices(row.m_index, parent));
+        };
+        QVERIFY(std::find_if(m_pendingRows.begin(), m_pendingRows.end(), compare)
+                != m_pendingRows.end());
+
+        m_currentRowsCount += last - first + 1;
+        if (m_currentRowsCount == m_expectedRowsCount)
+            finish();
+    }
+
+    void scheduleRowsToWatch(const QModelIndex &index, int start, int end)
+    {
+        m_pendingRows.push_back(RowData { index, start, end });
+    }
+
+    QList<QModelIndex> changedData() const { return m_changedData; }
+
+private:
+    struct RowData
+    {
+        QModelIndex m_index;
+        int m_start = -1;
+        int m_end = -1;
+    };
+
+    const QAbstractItemModel *m_model;
+    QList<RowData> m_pendingRows;
+    QList<QModelIndex> m_changedData;
+    int m_currentRowsCount = 0;
+    const int m_expectedRowsCount;
+};
+
+QTextStream cout(stdout, QIODevice::WriteOnly);
+
+//Keep in case we need detailed debugging in the future...
+#if 0
+inline QDebug operator <<(QDebug dbg, const InsertedRow &row)
+{
+    return dbg.nospace() << "Index(" << row.m_index << ", " << row.m_start << ", " << row.m_end << ")";
+}
+
+inline void dumpModel(const QAbstractItemModel *model, const QModelIndex &parent = QModelIndex())
+{
+    int level = 0;
+    for (QModelIndex idx = parent; idx.isValid(); idx = model->parent(idx), ++level);
+    const QHash<int,QByteArray> roles = model->roleNames();
+    for (int i = 0; i < model->rowCount(parent); ++i) {
+        for (int j = 0; j < model->columnCount(parent); ++j) {
+            const QModelIndex index = model->index(i, j);
+            Q_ASSERT(index.isValid());
+            QString s;
+            s.fill(QChar(' '), level*2);
+            cout << qPrintable(s);
+            cout << QString(QLatin1String("%1:%2")).arg(i).arg(j);
+            for (auto it = roles.cbegin(), end = roles.cend(); it != end; ++it) {
+                const QVariant v = model->data(index, it.key());
+                if (!v.isValid()) continue;
+                QString t;
+                QDebug(&t) << v;
+                cout << " " << QString::fromUtf8(it.value()) << "=" << t.trimmed();
+            }
+
+            {
+                QString t;
+                QDebug(&t) << model->flags(index);
+                cout << " flags=" << t;
+            }
+
+            cout << "\n";
+            cout.flush();
+            dumpModel(model, index); // recursive
+        }
+    }
+}
+#endif
+
+void compareData(const QAbstractItemModel *sourceModel, const QAbstractItemModelReplica *replica)
+{
+    QVERIFY(sourceModel);
+    QVERIFY(replica);
+
+    QCOMPARE(replica->rowCount(), sourceModel->rowCount());
+    QCOMPARE(replica->columnCount(), sourceModel->columnCount());
+    QCOMPARE(replica->roleNames(), sourceModel->roleNames());
+
+    for (int i = 0; i < sourceModel->rowCount(); ++i) {
+        for (int j = 0; j < sourceModel->columnCount(); ++j) {
+            const auto roles = replica->availableRoles();
+            for (int role : roles) {
+                QCOMPARE(replica->index(i, j).data(role), sourceModel->index(i, j).data(role));
+            }
+        }
+    }
+}
+
+void compareIndex(const QModelIndex &sourceIndex, const QModelIndex &replicaIndex,
+                  const QList<int> &roles)
+{
+    QVERIFY(sourceIndex.isValid());
+    QVERIFY(replicaIndex.isValid());
+    for (int role : roles) {
+        QCOMPARE(replicaIndex.data(role), sourceIndex.data(role));
+    }
+    const QAbstractItemModel *sourceModel = sourceIndex.model();
+    const QAbstractItemModel *replicaModel = replicaIndex.model();
+    const int sourceRowCount = sourceModel->rowCount(sourceIndex);
+    const int replicaRowCount = replicaModel->rowCount(replicaIndex);
+    QCOMPARE(replicaRowCount, sourceRowCount);
+    const int sourceColumnCount = sourceModel->columnCount(sourceIndex);
+    const int replicaColumnCount = replicaModel->columnCount(replicaIndex);
+    // only test the column count if the row count is larger than zero, because we
+    // assume the column count is constant over a tree model and it doesn't make a
+    // difference in the view.
+    if (sourceRowCount)
+        QCOMPARE(replicaColumnCount, sourceColumnCount);
+    for (int i = 0; i < sourceRowCount; ++i) {
+        for (int j = 0; j < sourceColumnCount; ++j) {
+            auto sourceChild = sourceModel->index(i, j, sourceIndex);
+            auto replicaChild = replicaModel->index(i, j, replicaIndex);
+            compareIndex(sourceChild, replicaChild, roles);
+
+        }
+    }
+}
+
+void compareTreeData(const QAbstractItemModel *sourceModel, const QAbstractItemModelReplica *replica)
+{
+    QVERIFY(sourceModel);
+    QVERIFY(replica);
+
+    QCOMPARE(replica->rowCount(), sourceModel->rowCount());
+    QCOMPARE(replica->columnCount(), sourceModel->columnCount());
+
+    for (int i = 0; i < sourceModel->rowCount(); ++i) {
+        for (int j = 0; j < sourceModel->columnCount(); ++j) {
+            const QModelIndex replicaIndex = replica->index(i, j);
+            const QModelIndex sourceIndex = sourceModel->index(i, j);
+            compareIndex(sourceIndex, replicaIndex, replica->availableRoles());
+        }
+    }
+}
+
+void compareTreeData(const QAbstractItemModel *sourceModel, const QAbstractItemModel *replica, const QList<int> &roles)
+{
+    QVERIFY(sourceModel);
+    QVERIFY(replica);
+
+    QCOMPARE(replica->rowCount(), sourceModel->rowCount());
+    QCOMPARE(replica->columnCount(), sourceModel->columnCount());
+
+    for (int i = 0; i < sourceModel->rowCount(); ++i) {
+        for (int j = 0; j < sourceModel->columnCount(); ++j) {
+            const QModelIndex replicaIndex = replica->index(i, j);
+            const QModelIndex sourceIndex = sourceModel->index(i, j);
+            compareIndex(sourceIndex, replicaIndex, roles);
+        }
+    }
+}
+
+void compareFlags(const QAbstractItemModel *sourceModel, const QAbstractItemModelReplica *replica)
+{
+    QVERIFY(sourceModel);
+    QVERIFY(replica);
+
+    QCOMPARE(replica->rowCount(), sourceModel->rowCount());
+    QCOMPARE(replica->columnCount(), sourceModel->columnCount());
+
+    for (int i = 0; i < sourceModel->rowCount(); ++i) {
+        for (int j = 0; j < sourceModel->columnCount(); ++j) {
+            if (replica->index(i, j).flags() != sourceModel->index(i, j).flags())
+                qWarning() << sourceModel->index(i, j).flags() << replica->index(i, j).flags() << i << j;
+            QCOMPARE(replica->index(i, j).flags(), sourceModel->index(i, j).flags());
+        }
+    }
+}
+
+// class to test cutom role names
+class RolenamesListModel : public QAbstractListModel
+{
+public:
+    explicit RolenamesListModel(QObject *parent = nullptr) : QAbstractListModel(parent) { }
+    int rowCount(const QModelIndex &) const override { return int(m_list.length()); }
+    QVariant data(const QModelIndex &index, int role) const override
+    {
+       if (role == Qt::UserRole)
+           return m_list.at(index.row()).second;
+       else if (role == Qt::UserRole+1)
+           return m_list.at(index.row()).first;
+       else
+           return QVariant();
+    }
+    QHash<int, QByteArray> roleNames() const override
+    {
+        QHash<int, QByteArray> roles;
+        roles[Qt::UserRole] = "name";
+        roles[Qt::UserRole+1] = "pid";
+        return roles;
+    }
+    void addPair(const QVariant pid,const QVariant name) {
+        m_list.append(qMakePair(pid, name));
+    }
+    void clearList() {
+        m_list.clear();
+    }
+private:
+    QList<QPair<QVariant, QVariant>> m_list;
+};
+
+QList<QStandardItem*> addChild(int numChilds, int nestingLevel)
+{
+    QList<QStandardItem*> result;
+    if (nestingLevel == 0)
+        return result;
+    for (int i = 0; i < numChilds; ++i) {
+        QStandardItem *child = new QStandardItem(QStringLiteral("Child num %1, nesting Level %2").arg(i+1).arg(nestingLevel));
+        if (i == 0) {
+            QList<QStandardItem*> res = addChild(numChilds, nestingLevel -1);
+            if (res.size() > 0)
+                child->appendRow(res);
+        }
+        result.push_back(child);
+    }
+    return result;
+}
+
+int getRandomNumber(int min, int max)
+{
+    int res = QRandomGenerator::global()->generate() & INT_MAX;
+    const int diff = (max - min);
+    res = res % diff;
+    res += min;
+    return res;
+}
+
+class FetchData : public WaitHelper
+{
+public:
+    FetchData(const QAbstractItemModelReplica *replica) : WaitHelper(), m_replica(replica)
+    {
+        if (!m_replica->isInitialized()) {
+            QEventLoop l;
+            connect(m_replica, &QAbstractItemModelReplica::initialized, &l, &QEventLoop::quit);
+            l.exec();
+        }
+
+        connect(m_replica, &QAbstractItemModelReplica::dataChanged, this, &FetchData::dataChanged);
+        connect(m_replica, &QAbstractItemModelReplica::rowsInserted, this, &FetchData::rowsInserted);
+    }
+
+    bool fetchAndWait(int timeout = 15000)
+    {
+        addAll();
+        fetch();
+        return wait(timeout);
+    }
+
+private:
+    const QAbstractItemModelReplica *m_replica;
+    QHash<QPersistentModelIndex, QList<int>> m_pending;
+    QSet<QPersistentModelIndex> m_waitForInsertion;
+
+    void addData(const QModelIndex &index, const QList<int> &roles)
+    {
+        for (int role : roles) {
+            const bool cached = m_replica->hasData(index, role);
+            if (cached)
+                continue;
+            if (!m_pending.contains(index))
+                m_pending[index] = QList<int>() << role;
+            else {
+                if (!m_pending[index].contains(role))
+                    m_pending[index].append(role);
+            }
+        }
+    }
+
+    void addIndex(const QModelIndex &parent, const QList<int> &roles)
+    {
+        if (parent.isValid())
+            addData(parent, roles);
+        for (int i = 0; i < m_replica->rowCount(parent); ++i) {
+            for (int j = 0; j < m_replica->columnCount(parent); ++j) {
+                const QModelIndex index = m_replica->index(i, j, parent);
+                Q_ASSERT(index.isValid());
+                addIndex(index, roles);
+            }
+        }
+    }
+
+    void addAll()
+    {
+        addIndex(QModelIndex(), m_replica->availableRoles());
+    }
+
+    void fetch()
+    {
+        if (m_pending.isEmpty() && m_waitForInsertion.isEmpty()) {
+            finish();
+            return;
+        }
+        QHash<QPersistentModelIndex, QList<int>> pending(m_pending);
+        pending.detach();
+        auto it(pending.constBegin()), end(pending.constEnd());
+        for (; it != end; ++it) {
+            for (int role : it.value()) {
+                QVariant v = m_replica->data(it.key(), role);
+                Q_UNUSED(v)
+            }
+        }
+    }
+
+    void rowsInserted(const QModelIndex &parent, int first, int last)
+    {
+        static QList<int> rolesV;
+        if (rolesV.isEmpty())
+            rolesV << Qt::DisplayRole << Qt::BackgroundRole;
+        m_waitForInsertion.remove(parent);
+        const int columnCount = m_replica->columnCount(parent);
+        if (!(m_replica->hasChildren(parent) && columnCount > 0 && m_replica->rowCount(parent) > 0))
+            qWarning() << m_replica->hasChildren(parent) << columnCount << m_replica->rowCount(parent) << parent.data();
+        QVERIFY(m_replica->hasChildren(parent) && columnCount > 0 && m_replica->rowCount(parent) > 0);
+        for (int i = first; i <= last; ++i) {
+            for (int j = 0; j < columnCount; ++j) {
+                const QModelIndex index = m_replica->index(i, j, parent);
+                const int childRowCount = m_replica->rowCount(index);
+
+                QVERIFY(index.isValid());
+                if (m_replica->hasChildren(index) && childRowCount == 0) {
+                    if (index.column() == 0)
+                        m_waitForInsertion.insert(index);
+                }
+                addIndex(index, rolesV);
+            }
+        }
+        if (m_replica->hasChildren(parent))
+            fetch();
+    }
+
+    void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList<int> &roles = {})
+    {
+        Q_ASSERT(topLeft.isValid());
+        Q_ASSERT(bottomRight.isValid());
+        Q_ASSERT(topLeft.parent() == bottomRight.parent());
+
+        const QModelIndex parent = topLeft.parent();
+        for (int i = topLeft.row(); i <= bottomRight.row(); ++i) {
+            for (int j = topLeft.column(); j <= bottomRight.column(); ++j) {
+                const QModelIndex index = m_replica->index(i, j, parent);
+                Q_ASSERT(index.isValid());
+                auto it = m_pending.find(index);
+                if (it == m_pending.end())
+                    continue;
+
+#if 0
+                QList<int> itroles = it.value();
+                itroles.detach();
+                if (roles.isEmpty()) {
+                    itroles.clear();
+                } else {
+                    for (int r : roles) {
+                        itroles.removeAll(r);
+                    }
+                }
+                if (itroles.isEmpty()) {
+                    m_pending.erase(it);
+                } else {
+                    m_pending[index] = itroles;
+                }
+#else
+                Q_UNUSED(roles)
+                m_pending.erase(it);
+                if (m_replica->hasChildren(index)) {
+                    // ask for the row count to get an update
+                    const int rowCount = m_replica->rowCount(index);
+                    for (int i = 0; i < rowCount; ++i) {
+                        const QModelIndex cIndex = m_replica->index(i, 0, index);
+                        Q_ASSERT(cIndex.isValid());
+                        addIndex(cIndex, m_replica->availableRoles());
+                    }
+                    if (rowCount)
+                        fetch();
+                    else if (index.column() == 0)
+                        m_waitForInsertion.insert(index);
+                }
+#endif
+            }
+        }
+
+        if (m_pending.isEmpty() && m_waitForInsertion.isEmpty())
+            finish();
+    }
+};
+
+} // namespace
+
+#define _SETUP_TEST_ \
+    QRemoteObjectHost basicServer; \
+    QRemoteObjectNode client; \
+    QRemoteObjectRegistryHost registryServer; \
+    setup_models(basicServer, client, registryServer);
+
+class TestModelView: public QObject
+{
+    Q_OBJECT
+
+    QStandardItemModel m_sourceModel;
+    RolenamesListModel m_listModel;
+
+public:
+    void setup_models(QRemoteObjectHost &basicServer,
+                      QRemoteObjectNode &client,
+                      QRemoteObjectRegistryHost &registryServer);
+
+private slots:
+    // NB: The tests have side effects on the models used, and need to be run
+    // in order (they may depend on previous side effects).
+    void initTestCase();
+
+    void testEmptyModel();
+    void testInitialData();
+    void testInitialDataTree();
+    void testHeaderData();
+    void testHeaderDataChange();
+    void testFlags();
+    void testDataChanged();
+    void testDataChangedTree();
+    void testDataInsertion();
+    void testDataInsertionTree();
+    void testSetData();
+    void testSetDataTree();
+    void testDataRemoval();
+    void testDataRemovalTree();
+    void testServerInsertDataTree();
+
+    void testRoleNames();
+
+    void testModelTest_data();
+    void testModelTest();
+    void testSortFilterModel();
+
+    void testSelectionFromReplica();
+    void testSelectionFromSource();
+    void testChildSelection();
+
+    void testCacheData_data();
+    void testCacheData();
+
+    void cleanup();
+};
+
+void TestModelView::initTestCase()
+{
+    QLoggingCategory::setFilterRules("qt.remoteobjects.warning=false");
+
+    static const int modelSize = 20;
+
+    QHash<int,QByteArray> roleNames;
+    roleNames[Qt::DisplayRole] = "text";
+    roleNames[Qt::BackgroundRole] = "background";
+    m_sourceModel.setItemRoleNames(roleNames);
+
+    QStringList list;
+    list.reserve(modelSize);
+
+    QStringList hHeaderList;
+    hHeaderList << QStringLiteral("First Column with spacing") << QStringLiteral("Second Column with spacing");
+    m_sourceModel.setHorizontalHeaderLabels(hHeaderList);
+
+    for (int i = 0; i < modelSize; ++i) {
+        QStandardItem *firstItem = new QStandardItem(QStringLiteral("FancyTextNumber %1").arg(i));
+        QStandardItem *secondItem = new QStandardItem(QStringLiteral("FancyRow2TextNumber %1").arg(i));
+        if (i % 2 == 0)
+            firstItem->setBackground(Qt::red);
+        firstItem->appendRow(addChild(2,getRandomNumber(1, 4)));
+        QList<QStandardItem*> row;
+        row << firstItem << secondItem;
+        m_sourceModel.appendRow(row);
+        list << QStringLiteral("FancyTextNumber %1").arg(i);
+    }
+
+    const int numElements = 1000;
+    for (int i = 0; i < numElements; ++i) {
+        QString name = QString("Data %1").arg(i);
+        QString pid = QString("%1").arg(i);
+        m_listModel.addPair(name, pid);
+    }
+}
+
+void TestModelView::setup_models(QRemoteObjectHost &basicServer, QRemoteObjectNode &client, QRemoteObjectRegistryHost &registryServer)
+{
+    static int port = 65211;
+    static const QString url = QStringLiteral("tcp://127.0.0.1:%1");
+
+    // QStandardItem::flags are stored as data with Qt::UserRole - 1
+    static const QList<int> sourceModelRoles( {Qt::DisplayRole, Qt::BackgroundRole, (Qt::UserRole - 1)} );
+
+    static const QList<int> listModelRoles( {Qt::UserRole, Qt::UserRole+1} );
+
+    //Setup registry
+    //Registry needs to be created first until we get the retry mechanism implemented
+    basicServer.setHostUrl(QUrl(url.arg(port)));
+    registryServer.setRegistryUrl(QUrl(url.arg(port+1)));
+    basicServer.setRegistryUrl(QUrl(url.arg(port+1)));
+    basicServer.enableRemoting(&m_sourceModel, "test", sourceModelRoles);
+    basicServer.enableRemoting(&m_listModel, "testRoleNames", listModelRoles);
+    client.setRegistryUrl(QUrl(url.arg(port+1)));
+    port += 2;
+}
+
+#ifdef SLOW_MODELTEST
+#define MODELTEST_WAIT_TIME 25000
+#else
+#define MODELTEST_WAIT_TIME
+#endif
+
+void TestModelView::testEmptyModel()
+{
+    _SETUP_TEST_
+    QList<int> roles = QList<int>() << Qt::DisplayRole << Qt::BackgroundRole;
+    QStandardItemModel emptyModel;
+    basicServer.enableRemoting(&emptyModel, "emptyModel", roles);
+
+    QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("emptyModel"));
+    model->setRootCacheSize(1000);
+
+    FetchData f(model.data());
+    QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+    compareData(&emptyModel, model.data());
+}
+
+void TestModelView::testInitialData()
+{
+    _SETUP_TEST_
+    QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("test"));
+
+    FetchData f(model.data());
+    QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+    compareData(&m_sourceModel, model.data());
+}
+
+void TestModelView::testInitialDataTree()
+{
+    _SETUP_TEST_
+    QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("test"));
+
+    FetchData f(model.data());
+    QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+    compareTreeData(&m_sourceModel, model.data());
+}
+
+void TestModelView::testHeaderData()
+{
+    _SETUP_TEST_
+    QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("test"));
+
+    FetchData f(model.data());
+    QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+    // ask for all Data members first, so we don't have to wait for update signals
+    QSignalSpy spyHeader(model.data(), &QAbstractItemModelReplica::headerDataChanged);
+    for (int i = 0; i < m_sourceModel.rowCount(); ++i)
+        model->headerData(i, Qt::Vertical, Qt::DisplayRole);
+    for (int i = 0; i < m_sourceModel.columnCount(); ++i)
+        model->headerData(i, Qt::Horizontal, Qt::DisplayRole);
+    spyHeader.wait();
+
+    for (int i = 0; i < m_sourceModel.rowCount(); ++i)
+        QCOMPARE(model->headerData(i, Qt::Vertical, Qt::DisplayRole), m_sourceModel.headerData(i, Qt::Vertical, Qt::DisplayRole));
+    for (int i = 0; i < m_sourceModel.columnCount(); ++i)
+        QCOMPARE(model->headerData(i, Qt::Horizontal, Qt::DisplayRole), m_sourceModel.headerData(i, Qt::Horizontal, Qt::DisplayRole));
+}
+
+void TestModelView::testHeaderDataChange()
+{
+    _SETUP_TEST_
+    QString newHeader = QStringLiteral("New header name");
+    QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("test"));
+
+    FetchData f(model.data());
+    QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+    QVERIFY(model->headerData(0, Qt::Horizontal, Qt::DisplayRole).toString() != newHeader);
+
+    QSignalSpy spyHeader(model.data(), &QAbstractItemModelReplica::headerDataChanged);
+    m_sourceModel.setHeaderData(0, Qt::Horizontal, newHeader, Qt::DisplayRole);
+    spyHeader.wait();
+    QTRY_COMPARE(model->headerData(0, Qt::Horizontal, Qt::DisplayRole).toString(), newHeader);
+
+    spyHeader.clear();
+    m_sourceModel.setHeaderData(1, Qt::Horizontal, newHeader, Qt::DisplayRole);
+    spyHeader.wait();
+    QTRY_COMPARE(model->headerData(1, Qt::Horizontal, Qt::DisplayRole).toString(), newHeader);
+
+    QString anotherHeader = QStringLiteral("Modified header name");
+    m_sourceModel.setHeaderData(0, Qt::Horizontal, anotherHeader, Qt::DisplayRole);
+    spyHeader.wait();
+
+    QTRY_COMPARE(model->headerData(0, Qt::Horizontal, Qt::DisplayRole).toString(), anotherHeader);
+    QCOMPARE(model->headerData(1, Qt::Horizontal, Qt::DisplayRole).toString(), newHeader);
+}
+
+void TestModelView::testDataChangedTree()
+{
+    _SETUP_TEST_
+    QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("test"));
+
+    FetchData f(model.data());
+    QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+    compareTreeData(&m_sourceModel, model.data());
+    QSignalSpy dataChangedSpy(model.data(), &QAbstractItemModelReplica::dataChanged);
+    QSet<int> expected;
+    for (int i = 10; i < 20; ++i) {
+        const QModelIndex parent = m_sourceModel.index(i,0);
+        const int rowCount = m_sourceModel.rowCount(parent);
+        const int colCount = m_sourceModel.columnCount(parent);
+        for (int row = 0; row < rowCount; ++row) {
+            for (int col = 0; col < colCount; ++col) {
+                if (col % 2 == 0)
+                    m_sourceModel.setData(m_sourceModel.index(row, col, parent), QColor(Qt::gray), Qt::BackgroundRole);
+                else
+                    m_sourceModel.setData(m_sourceModel.index(row, col, parent), QColor(Qt::cyan), Qt::BackgroundRole);
+            }
+        }
+        m_sourceModel.setData(m_sourceModel.index(i, 1), QColor(Qt::magenta), Qt::BackgroundRole);
+        expected << i;
+    }
+
+    bool signalsReceived = false;
+    int runs = 0;
+    const int maxRuns = 10;
+    while (runs < maxRuns) {
+        if (dataChangedSpy.wait() &&!dataChangedSpy.isEmpty()) {
+            signalsReceived = true;
+            for (auto args : dataChangedSpy) {
+                int row = args.at(1).value<QModelIndex>().row();
+                if (row && expected.contains(row))
+                    expected.remove(row);
+            }
+            if (expected.size() == 0)
+                break;
+        }
+        ++runs;
+    }
+    QVERIFY(signalsReceived);
+    compareTreeData(&m_sourceModel, model.data());
+}
+
+void TestModelView::testFlags()
+{
+    _SETUP_TEST_
+    QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("test"));
+
+    FetchData f(model.data());
+    QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+    QSignalSpy dataChangedSpy(model.data(),  &QAbstractItemModelReplica::dataChanged);
+    for (int i = 10; i < 20; ++i) {
+        QStandardItem* firstItem = m_sourceModel.item(i, 0);
+        QStandardItem* secondItem = m_sourceModel.item(i, 1);
+        firstItem->setFlags(firstItem->flags() | Qt::ItemIsEnabled | Qt::ItemIsAutoTristate);
+        secondItem->setFlags(firstItem->flags() | Qt::ItemIsEnabled);
+    }
+    bool signalsReceived = false;
+    while (dataChangedSpy.wait()) {
+        signalsReceived = true;
+        if (dataChangedSpy.takeLast().at(1).value<QModelIndex>().row() == 19)
+            break;
+    }
+    QVERIFY(signalsReceived);
+    compareFlags(&m_sourceModel, model.data());
+}
+
+void TestModelView::testDataChanged()
+{
+    _SETUP_TEST_
+    QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("test"));
+
+    FetchData f(model.data());
+    QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+    QSignalSpy dataChangedSpy(model.data(),  &QAbstractItemModelReplica::dataChanged);
+    for (int i = 10; i < 20; ++i)
+        m_sourceModel.setData(m_sourceModel.index(i, 1), QColor(Qt::blue), Qt::BackgroundRole);
+
+    bool signalsReceived = false;
+    while (dataChangedSpy.wait()) {
+        signalsReceived = true;
+        if (dataChangedSpy.takeLast().at(1).value<QModelIndex>().row() == 19)
+            break;
+    }
+    QVERIFY(signalsReceived);
+    compareData(&m_sourceModel, model.data());
+}
+
+void TestModelView::testDataInsertion()
+{
+    _SETUP_TEST_
+    QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("test"));
+
+    FetchData f(model.data());
+    QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+    const int insertedRowsCount = 9;
+    RowsWatcher watcher(model.data(), insertedRowsCount);
+    QList<QModelIndex> pending;
+
+    m_sourceModel.insertRows(2, insertedRowsCount);
+
+    watcher.scheduleRowsToWatch(QModelIndex(), 2, 2 + insertedRowsCount - 1);
+    QVERIFY(watcher.wait());
+    QCOMPARE(m_sourceModel.rowCount(), model->rowCount());
+
+    pending.append(watcher.changedData());
+
+    // change one row to check for inconsistencies
+    m_sourceModel.setData(m_sourceModel.index(0, 1), QColor(Qt::green), Qt::BackgroundRole);
+    m_sourceModel.setData(m_sourceModel.index(0, 1), QLatin1String("foo"), Qt::DisplayRole);
+    pending.append(model->index(0, 1));
+    WaitForDataChanged w(model.data(), pending);
+
+    QVERIFY(w.wait());
+    compareData(&m_sourceModel, model.data());
+}
+
+void TestModelView::testDataInsertionTree()
+{
+    _SETUP_TEST_
+    QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("test"));
+
+    FetchData f(model.data());
+    QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+    const int insertedRowsCount = 9;
+    const int insertedChildRowsCount = 4;
+    RowsWatcher watcher(model.data(), insertedRowsCount + insertedChildRowsCount);
+
+    QList<QModelIndex> pending;
+
+    for (int i = 0; i < insertedRowsCount; ++i) {
+        watcher.scheduleRowsToWatch(QModelIndex(), 2 + i, 2 + i);
+        m_sourceModel.insertRow(2 + i, createInsertionChildren(2, QStringLiteral("insertedintree"), Qt::darkRed));
+        const QModelIndex childIndex = m_sourceModel.index(2 + i, 0);
+        const QModelIndex childIndex2 = m_sourceModel.index(2 + i, 1);
+        pending.append(childIndex);
+        pending.append(childIndex2);
+    }
+    const QModelIndex parent = m_sourceModel.index(10, 0);
+    QStandardItem* parentItem = m_sourceModel.item(10, 0);
+    for (int i = 0; i < insertedChildRowsCount; ++i) {
+        watcher.scheduleRowsToWatch(parent, i, i);
+        parentItem->insertRow(i, createInsertionChildren(2, QStringLiteral("insertedintreedeep"), Qt::darkCyan));
+        const QModelIndex childIndex = m_sourceModel.index(0, 0, parent);
+        const QModelIndex childIndex2 = m_sourceModel.index(0, 1, parent);
+        Q_ASSERT(childIndex.isValid());
+        Q_ASSERT(childIndex2.isValid());
+        pending.append(childIndex);
+        pending.append(childIndex2);
+    }
+
+    QVERIFY(watcher.wait());
+    QCOMPARE(m_sourceModel.rowCount(), model->rowCount());
+
+    pending.append(watcher.changedData());
+
+    // change one row to check for inconsistencies
+
+    pending << m_sourceModel.index(0, 0, parent);
+    WaitForDataChanged w(model.data(), pending);
+    m_sourceModel.setData(m_sourceModel.index(0, 0, parent), QColor(Qt::green), Qt::BackgroundRole);
+    m_sourceModel.setData(m_sourceModel.index(0, 0, parent), QLatin1String("foo"), Qt::DisplayRole);
+
+    QVERIFY(w.wait());
+
+    compareTreeData(&m_sourceModel, model.data());
+}
+
+void TestModelView::testDataRemoval()
+{
+    _SETUP_TEST_
+    QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("test"));
+    qputenv("QTRO_NODES_CACHE_SIZE", "1000");
+    model->setRootCacheSize(1000);
+    FetchData f(model.data());
+    QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+    const QPersistentModelIndex parent = m_sourceModel.index(10, 0);
+    {
+        const int removedRowsCount = 3;
+        RowsWatcher watcher(model.data(), removedRowsCount);
+        m_sourceModel.removeRows(0, removedRowsCount, parent);
+        watcher.scheduleRowsToWatch(parent, 0, removedRowsCount - 1);
+        QVERIFY(watcher.wait());
+        QCOMPARE(m_sourceModel.rowCount(parent), model->rowCount(model->index(10, 0)));
+    }
+    {
+        const int removedRowsCount = 8;
+        RowsWatcher watcher(model.data(), removedRowsCount);
+        m_sourceModel.removeRows(2, removedRowsCount);
+        watcher.scheduleRowsToWatch(QModelIndex(), 2, 2 + removedRowsCount - 1);
+        QVERIFY(watcher.wait());
+        QCOMPARE(m_sourceModel.rowCount(), model->rowCount());
+    }
+
+    // change one row to check for inconsistencies
+
+    QList<QModelIndex> pending;
+    pending << m_sourceModel.index(0, 0, parent);
+    WaitForDataChanged w(model.data(), pending);
+    m_sourceModel.setData(m_sourceModel.index(0, 0, parent), QColor(Qt::green), Qt::BackgroundRole);
+    m_sourceModel.setData(m_sourceModel.index(0, 0, parent), QLatin1String("foo"), Qt::DisplayRole);
+
+    QVERIFY(w.wait());
+
+    compareTreeData(&m_sourceModel, model.data());
+}
+
+void TestModelView::testRoleNames()
+{
+    _SETUP_TEST_
+    QScopedPointer<QAbstractItemModelReplica> repModel( client.acquireModel(QStringLiteral("testRoleNames")));
+    // Set a bigger cache enough to keep all the data otherwise the last test will fail
+    repModel->setRootCacheSize(1500);
+    FetchData f(repModel.data());
+    QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+    // test custom role names
+    QCOMPARE(repModel.data()->roleNames(), m_listModel.roleNames());
+
+    // test data associated with custom roles
+    compareData(&m_listModel,repModel.data());
+}
+
+void TestModelView::testDataRemovalTree()
+{
+    _SETUP_TEST_
+    m_sourceModel.removeRows(2, 4);
+    //Maybe some checks here?
+}
+
+void TestModelView::testServerInsertDataTree()
+{
+    _SETUP_TEST_
+    QList<int> roles = QList<int> { Qt::DisplayRole, Qt::BackgroundRole };
+    QStandardItemModel testTreeModel;
+    basicServer.enableRemoting(&testTreeModel, "testTreeModel", roles);
+
+    QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("testTreeModel"));
+
+    QTRY_COMPARE(testTreeModel.rowCount(), model->rowCount());
+
+    QVERIFY(testTreeModel.insertRow(0));
+    QVERIFY(testTreeModel.insertColumn(0));
+    auto root = testTreeModel.index(0, 0);
+    QVERIFY(testTreeModel.setData(root, QLatin1String("Root"), Qt::DisplayRole));
+    QVERIFY(testTreeModel.setData(root, QColor(Qt::green), Qt::BackgroundRole));
+    QVERIFY(testTreeModel.insertRow(0, root));
+    QVERIFY(testTreeModel.insertColumn(0, root));
+    auto child1 = testTreeModel.index(0, 0, root);
+    QVERIFY(testTreeModel.setData(child1, QLatin1String("Child1"), Qt::DisplayRole));
+    QVERIFY(testTreeModel.setData(child1, QColor(Qt::red), Qt::BackgroundRole));
+
+    QTRY_COMPARE(testTreeModel.rowCount(), model->rowCount());
+
+    FetchData f(model.data());
+    QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+    compareData(&testTreeModel, model.data());
+}
+
+void TestModelView::testModelTest_data()
+{
+    // QtRemoteObjects::InitialAction is a namespace enum.  QTest/QFETCH fail to compile with it as
+    // the column type, so use bool instead.
+    QTest::addColumn<bool>("prefetch");
+
+    QTest::newRow("size only") << false;
+    QTest::newRow("prefetch") << true;
+}
+
+void TestModelView::testModelTest()
+{
+    QFETCH(bool, prefetch);
+    _SETUP_TEST_
+    QtRemoteObjects::InitialAction action = QtRemoteObjects::InitialAction::FetchRootSize;
+    if (prefetch)
+        action = QtRemoteObjects::InitialAction::PrefetchData;
+    QScopedPointer<QAbstractItemModelReplica> repModel( client.acquireModel(QStringLiteral("test"), action));
+    QAbstractItemModelTester test(repModel.data(), QAbstractItemModelTester::FailureReportingMode::Fatal);
+
+    FetchData f(repModel.data());
+    QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+    Q_UNUSED(test)
+}
+
+void TestModelView::testSortFilterModel()
+{
+    _SETUP_TEST_
+    QScopedPointer<QAbstractItemModelReplica> repModel( client.acquireModel(QStringLiteral("test")));
+
+    FetchData f(repModel.data());
+    QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+    QSortFilterProxyModel clientSort;
+    clientSort.setSourceModel(repModel.data());
+    clientSort.setSortRole(Qt::DisplayRole);
+    QSortFilterProxyModel sourceSort;
+    sourceSort.setSourceModel(&m_sourceModel);
+    sourceSort.setSortRole(Qt::DisplayRole);
+
+    compareTreeData(&sourceSort, &clientSort, repModel->availableRoles());
+}
+
+void TestModelView::testSetData()
+{
+    _SETUP_TEST_
+    QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("test"));
+
+    FetchData f(model.data());
+    QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+    compareTreeData(&m_sourceModel, model.data(), model->availableRoles());
+
+    //fetched and verified initial state, now setData on the client
+    QList<QModelIndex> pending;
+    QList<QModelIndex> pendingReplica;
+    for (int row = 0, numRows = model->rowCount(); row < numRows; ++row) {
+        for (int column = 0, numColumns = model->columnCount(); column != numColumns; ++column) {
+            const QModelIndex index = model->index(row, column);
+            const QString newData = QStringLiteral("This entry was changed with setData");
+            QVERIFY(model->setData(index, newData, Qt::DisplayRole));
+            pending.append(m_sourceModel.index(row, column));
+            pendingReplica.append(model->index(row, column));
+        }
+    }
+    WaitForDataChanged waiter(&m_sourceModel, pending);
+    QVERIFY(waiter.wait());
+    WaitForDataChanged waiterReplica(model.data(), pendingReplica);
+    QVERIFY(waiterReplica.wait());
+    compareData(&m_sourceModel, model.data());
+}
+
+void TestModelView::testSetDataTree()
+{
+    _SETUP_TEST_
+    QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("test"));
+
+    FetchData f(model.data());
+    QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+    compareTreeData(&m_sourceModel, model.data(), model->availableRoles());
+
+    //fetched and verified initial state, now setData on the client
+    QList<QModelIndex> pending;
+    QList<QModelIndex> pendingReplica;
+
+    QList<QModelIndex> stack;
+    stack.push_back(QModelIndex());
+    QList<QModelIndex> sourceStack;
+    sourceStack.push_back(QModelIndex());
+
+
+    const QString newData = QStringLiteral("This entry was changed with setData in a tree %1 %2 %3");
+    while (!stack.isEmpty()) {
+        const QModelIndex parent = stack.takeLast();
+        const QModelIndex parentSource = sourceStack.takeLast();
+        for (int row = 0; row < model->rowCount(parent); ++row) {
+            for (int column = 0; column < model->columnCount(parent); ++column) {
+                const QModelIndex index = model->index(row, column, parent);
+                const QModelIndex indexSource = m_sourceModel.index(row, column, parentSource);
+                QVERIFY(model->setData(index, newData.arg(parent.isValid()).arg(row).arg(column), Qt::DisplayRole));
+                pending.append(indexSource);
+                pendingReplica.append(index);
+                if (column == 0) {
+                    stack.push_back(index);
+                    sourceStack.push_back(indexSource);
+                }
+            }
+        }
+    }
+    WaitForDataChanged waiter(&m_sourceModel, pending);
+    QVERIFY(waiter.wait());
+    WaitForDataChanged waiterReplica(model.data(), pendingReplica);
+    QVERIFY(waiterReplica.wait());
+    compareData(&m_sourceModel, model.data());
+}
+
+void TestModelView::testSelectionFromReplica()
+{
+    _SETUP_TEST_
+    QList<int> roles = QList<int> { Qt::DisplayRole, Qt::BackgroundRole };
+    QStandardItemModel simpleModel;
+    for (int i = 0; i < 4; ++i)
+        simpleModel.appendRow(new QStandardItem(QString("item %0").arg(i)));
+    QItemSelectionModel selectionModel(&simpleModel);
+    basicServer.enableRemoting(&simpleModel, "simpleModelFromReplica", roles, &selectionModel);
+
+    QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("simpleModelFromReplica"));
+    QItemSelectionModel *replicaSelectionModel = model->selectionModel();
+
+    FetchData f(model.data());
+    QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+    replicaSelectionModel->setCurrentIndex(model->index(1,0), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current);
+    QTRY_COMPARE(selectionModel.currentIndex().row(), 1);
+}
+
+void TestModelView::testSelectionFromSource()
+{
+    _SETUP_TEST_
+    QList<int> roles = QList<int> { Qt::DisplayRole, Qt::BackgroundRole };
+    QStandardItemModel simpleModel;
+    for (int i = 0; i < 4; ++i)
+        simpleModel.appendRow(new QStandardItem(QString("item %0").arg(i)));
+    QItemSelectionModel selectionModel(&simpleModel);
+    basicServer.enableRemoting(&simpleModel, "simpleModelFromSource", roles, &selectionModel);
+
+    QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("simpleModelFromSource"));
+    QItemSelectionModel *replicaSelectionModel = model->selectionModel();
+
+    FetchData f(model.data());
+    QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+    selectionModel.setCurrentIndex(simpleModel.index(1,0), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current);
+    QTRY_COMPARE(replicaSelectionModel->currentIndex().row(), 1);
+}
+
+void TestModelView::testCacheData_data()
+{
+    QTest::addColumn<QList<int>>("roles");
+
+    QTest::newRow("empty") << QList<int> {};
+    QTest::newRow("all") << QList<int> { Qt::UserRole, Qt::UserRole + 1 };
+}
+
+void TestModelView::testCacheData()
+{
+    QFETCH(QList<int>, roles);
+
+    _SETUP_TEST_
+    QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("testRoleNames", QtRemoteObjects::PrefetchData, roles));
+    model->setRootCacheSize(1000);
+
+    QEventLoop l;
+    connect(model.data(), &QAbstractItemModelReplica::initialized, &l, &QEventLoop::quit);
+    l.exec();
+
+    compareData(&m_listModel, model.data());
+}
+
+void TestModelView::testChildSelection()
+{
+    _SETUP_TEST_
+    QList<int> roles = { Qt::DisplayRole, Qt::BackgroundRole };
+    QStandardItemModel simpleModel;
+    QStandardItem *parentItem = simpleModel.invisibleRootItem();
+    for (int i = 0; i < 4; ++i) {
+        QStandardItem *item = new QStandardItem(QString("item %0").arg(i));
+        parentItem->appendRow(item);
+        parentItem = item;
+    }
+    QItemSelectionModel selectionModel(&simpleModel);
+    basicServer.enableRemoting(&simpleModel, "treeModelFromSource", roles, &selectionModel);
+
+    QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("treeModelFromSource", QtRemoteObjects::PrefetchData, roles));
+    QItemSelectionModel *replicaSelectionModel = model->selectionModel();
+
+    QTRY_COMPARE(simpleModel.rowCount(), model->rowCount());
+    QTRY_COMPARE(model->data(model->index(0, 0)), QVariant(QString("item 0")));
+
+    // select an item not yet "seen" by the replica
+    selectionModel.setCurrentIndex(simpleModel.index(0, 0, simpleModel.index(0,0)), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current);
+    QTRY_COMPARE(replicaSelectionModel->currentIndex().row(), 0);
+    QVERIFY(replicaSelectionModel->currentIndex().parent().isValid());
+}
+
+void TestModelView::cleanup()
+{
+    // wait for delivery of RemoveObject events to the source
+    QTest::qWait(20);
+}
+
+QTEST_MAIN(TestModelView)
+
+#include "tst_modelview.moc"
diff --git a/tests/auto/pods/CMakeLists.txt b/tests/auto/pods/CMakeLists.txt
new file mode 100644 (file)
index 0000000..d95f7d1
--- /dev/null
@@ -0,0 +1,17 @@
+
+#####################################################################
+## tst_pods Test:
+#####################################################################
+
+qt_internal_add_test(tst_pods
+    SOURCES
+        tst_pods.cpp
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+)
+qt6_add_repc_replicas(tst_pods
+    pods.h
+)
+
+## Scopes:
+#####################################################################
diff --git a/tests/auto/pods/pods.h b/tests/auto/pods/pods.h
new file mode 100644 (file)
index 0000000..177bf02
--- /dev/null
@@ -0,0 +1,184 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#pragma once
+// This is an autogenerated file.
+// Do not edit this file, any changes made will be lost the next time it is generated.
+
+#include <QObject>
+
+
+#include <QString>
+class PodI
+{
+    Q_GADGET
+    Q_PROPERTY(int i READ i WRITE setI)
+public:
+    explicit PodI() : _i() {}
+    explicit PodI(int i) : _i(i) {}
+    PodI(const PodI& other)
+    {
+        QtRemoteObjects::copyStoredProperties(&other, this);
+    }
+
+    PodI &operator=(const PodI &other)
+    {
+        if (this != &other)
+            QtRemoteObjects::copyStoredProperties(&other, this);
+        return *this;
+    }
+
+    int i() const { return _i; }
+    void setI(int i) { if (i != _i) { _i = i; } }
+private:
+    int _i;
+};
+
+inline QDataStream &operator<<(QDataStream &ds, const PodI &obj) {
+    QtRemoteObjects::copyStoredProperties(&obj, ds);
+    return ds;
+}
+
+inline QDataStream &operator>>(QDataStream &ds, PodI &obj) {
+    QtRemoteObjects::copyStoredProperties(ds, &obj);
+    return ds;
+}
+
+class PodF
+{
+    Q_GADGET
+    Q_PROPERTY(float f READ f WRITE setF)
+public:
+    explicit PodF() : _f() {}
+    explicit PodF(float f) : _f(f) {}
+    PodF(const PodF& other)
+    {
+        QtRemoteObjects::copyStoredProperties(&other, this);
+    }
+
+    PodF &operator=(const PodF &other)
+    {
+        if (this != &other)
+            QtRemoteObjects::copyStoredProperties(&other, this);
+        return *this;
+    }
+
+    float f() const { return _f; }
+    void setF(float f) { if (f != _f) { _f = f; } }
+private:
+    float _f;
+};
+
+inline QDataStream &operator<<(QDataStream &ds, const PodF &obj) {
+    QtRemoteObjects::copyStoredProperties(&obj, ds);
+    return ds;
+}
+
+inline QDataStream &operator>>(QDataStream &ds, PodF &obj) {
+    QtRemoteObjects::copyStoredProperties(ds, &obj);
+    return ds;
+}
+
+class PodS
+{
+    Q_GADGET
+    Q_PROPERTY(QString s READ s WRITE setS)
+public:
+    explicit PodS() : _s() {}
+    explicit PodS(QString s) : _s(s) {}
+    PodS(const PodS& other)
+    {
+        QtRemoteObjects::copyStoredProperties(&other, this);
+    }
+
+    PodS &operator=(const PodS &other)
+    {
+        if (this != &other)
+            QtRemoteObjects::copyStoredProperties(&other, this);
+        return *this;
+    }
+
+    QString s() const { return _s; }
+    void setS(QString s) { if (s != _s) { _s = s; } }
+private:
+    QString _s;
+};
+
+inline QDataStream &operator<<(QDataStream &ds, const PodS &obj) {
+    QtRemoteObjects::copyStoredProperties(&obj, ds);
+    return ds;
+}
+
+inline QDataStream &operator>>(QDataStream &ds, PodS &obj) {
+    QtRemoteObjects::copyStoredProperties(ds, &obj);
+    return ds;
+}
+
+class PodIFS
+{
+    Q_GADGET
+    Q_PROPERTY(int i READ i WRITE setI)
+    Q_PROPERTY(float f READ f WRITE setF)
+    Q_PROPERTY(QString s READ s WRITE setS)
+public:
+    explicit PodIFS() : _i(), _f(), _s() {}
+    explicit PodIFS(int i, float f, QString s) : _i(i), _f(f), _s(s) {}
+    PodIFS(const PodIFS& other)
+    {
+        QtRemoteObjects::copyStoredProperties(&other, this);
+    }
+
+    PodIFS &operator=(const PodIFS &other)
+    {
+        if (this != &other)
+            QtRemoteObjects::copyStoredProperties(&other, this);
+        return *this;
+    }
+
+    int i() const { return _i; }
+    void setI(int i) { if (i != _i) { _i = i; } }
+    float f() const { return _f; }
+    void setF(float f) { if (f != _f) { _f = f; } }
+    QString s() const { return _s; }
+    void setS(QString s) { if (s != _s) { _s = s; } }
+private:
+    int _i;
+    float _f;
+    QString _s;
+};
+
+inline QDataStream &operator<<(QDataStream &ds, const PodIFS &obj) {
+    QtRemoteObjects::copyStoredProperties(&obj, ds);
+    return ds;
+}
+
+inline QDataStream &operator>>(QDataStream &ds, PodIFS &obj) {
+    QtRemoteObjects::copyStoredProperties(ds, &obj);
+    return ds;
+}
+
diff --git a/tests/auto/pods/tst_pods.cpp b/tests/auto/pods/tst_pods.cpp
new file mode 100644 (file)
index 0000000..08e8236
--- /dev/null
@@ -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: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$
+**
+****************************************************************************/
+
+#include "rep_pods_replica.h"
+
+#include <QTest>
+
+#include <QByteArray>
+#include <QDataStream>
+
+class tst_pods : public QObject {
+    Q_OBJECT
+
+private Q_SLOTS:
+    void testConstructors();
+    void testMarshalling();
+};
+
+
+void tst_pods::testConstructors()
+{
+    PodI pi1;
+    QCOMPARE(pi1.i(), 0);
+
+    PodI pi2(1);
+    QCOMPARE(pi2.i(), 1);
+
+    PodI pi3(pi2);
+    QCOMPARE(pi3.i(), pi2.i());
+}
+
+void tst_pods::testMarshalling()
+{
+    QByteArray ba;
+    QDataStream ds(&ba, QIODevice::ReadWrite);
+
+    {
+        PodI i1(1), i2(2), i3(3), iDeadBeef(0xdeadbeef);
+        ds << i1 << i2 << i3 << iDeadBeef;
+    }
+
+    ds.device()->seek(0);
+
+    {
+        PodI i1, i2, i3, iDeadBeef;
+        ds >> i1 >> i2 >> i3 >> iDeadBeef;
+
+        QCOMPARE(i1.i(), 1);
+        QCOMPARE(i2.i(), 2);
+        QCOMPARE(i3.i(), 3);
+        QCOMPARE(iDeadBeef.i(), int(0xdeadbeef));
+    }
+}
+
+QTEST_APPLESS_MAIN(tst_pods)
+
+#include "tst_pods.moc"
+
diff --git a/tests/auto/proxy/CMakeLists.txt b/tests/auto/proxy/CMakeLists.txt
new file mode 100644 (file)
index 0000000..a1841de
--- /dev/null
@@ -0,0 +1,19 @@
+
+#####################################################################
+## tst_proxy Test:
+#####################################################################
+
+qt_internal_add_test(tst_proxy
+    SOURCES
+        tst_proxy.cpp
+        ../shared/model_utilities.h
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+)
+qt6_add_repc_merged(tst_proxy
+    engine.rep
+    subclass.rep
+)
+
+## Scopes:
+#####################################################################
diff --git a/tests/auto/proxy/engine.rep b/tests/auto/proxy/engine.rep
new file mode 100644 (file)
index 0000000..797943d
--- /dev/null
@@ -0,0 +1,8 @@
+class Engine
+{
+    ENUM EngineType {Null, Gas, Electric, Hybrid};
+    PROP(int cylinders = 4)
+    PROP(bool started)
+    PROP(int rpm)
+    PROP(EngineType type)
+}
diff --git a/tests/auto/proxy/subclass.rep b/tests/auto/proxy/subclass.rep
new file mode 100644 (file)
index 0000000..5a82059
--- /dev/null
@@ -0,0 +1,13 @@
+POD MyPOD(int i, float f, QString s)
+
+class SubClass
+{
+    PROP(MyPOD myPOD)
+}
+
+class ParentClass
+{
+    CLASS subClass(SubClass)
+    MODEL tracks(display)
+}
+
diff --git a/tests/auto/proxy/tst_proxy.cpp b/tests/auto/proxy/tst_proxy.cpp
new file mode 100644 (file)
index 0000000..342e8be
--- /dev/null
@@ -0,0 +1,457 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include "rep_engine_merged.h"
+#include "rep_subclass_merged.h"
+#include "../shared/model_utilities.h"
+
+#include <QtTest/QtTest>
+#include <QRemoteObjectReplica>
+#include <QRemoteObjectNode>
+
+const QUrl localHostUrl = QUrl(QLatin1String("local:testHost"));
+const QUrl tcpHostUrl = QUrl(QLatin1String("tcp://127.0.0.1:9989"));
+const QUrl proxyNodeUrl = QUrl(QLatin1String("tcp://127.0.0.1:12123"));
+const QUrl remoteNodeUrl = QUrl(QLatin1String("tcp://127.0.0.1:23234"));
+const QUrl registryUrl = QUrl(QLatin1String("local:testRegistry"));
+const QUrl proxyHostUrl = QUrl(QLatin1String("local:fromProxy"));
+
+#define SET_NODE_NAME(obj) (obj).setName(QLatin1String(#obj))
+
+class ProxyTest : public QObject
+{
+    Q_OBJECT
+private Q_SLOTS:
+    void cleanup()
+    {
+        // wait for delivery of RemoveObject events to the source
+        QTest::qWait(200);
+    }
+
+    void testProxy_data();
+    void testProxy();
+    void testForwardProxy();
+    void testReverseProxy();
+    // The following should fail to compile, verifying the SourceAPI templates work
+    // for subclasses
+    /*
+    void testSubclass()
+    {
+        QRemoteObjectHost host(localHostUrl);
+
+        struct invalidchild {
+            MyPOD myPOD() { return MyPOD(12, 13.f, QStringLiteral("Yay!")); }
+        };
+        struct badparent {
+            invalidchild *subClass() { return new invalidchild; }
+        } parent;
+        host.enableRemoting<ParentClassSourceAPI>(&parent);
+    }
+    */
+
+    void testTopLevelModel();
+};
+
+void ProxyTest::testProxy_data()
+{
+    QTest::addColumn<bool>("sourceApi");
+    QTest::addColumn<bool>("useProxy");
+    QTest::addColumn<bool>("dynamic");
+
+    QTest::newRow("dynamicApi, no proxy") << false << false << false;
+    QTest::newRow("sourceApi, no proxy") << true << false << false;
+    QTest::newRow("dynamicApi, with proxy") << false << true << false;
+    QTest::newRow("sourceApi, with proxy") << true << true << false;
+    QTest::newRow("dynamicApi, no proxy, dynamicRep") << false << false << true;
+    QTest::newRow("sourceApi, no proxy, dynamicRep") << true << false << true;
+    QTest::newRow("dynamicApi, with proxy, dynamicRep") << false << true << true;
+    QTest::newRow("sourceApi, with proxy, dynamicRep") << true << true << true;
+}
+
+void ProxyTest::testProxy()
+{
+    QFETCH(bool, sourceApi);
+    QFETCH(bool, useProxy);
+    QFETCH(bool, dynamic);
+
+    //Setup Local Registry
+    QRemoteObjectRegistryHost registry(registryUrl);
+    SET_NODE_NAME(registry);
+    //Setup Local Host
+    QRemoteObjectHost host(localHostUrl);
+    SET_NODE_NAME(host);
+    host.setRegistryUrl(registryUrl);
+    EngineSimpleSource engine;
+    engine.setRpm(1234);
+    engine.setType(EngineSimpleSource::Gas);
+    if (sourceApi)
+        host.enableRemoting<EngineSourceAPI>(&engine);
+    else
+        host.enableRemoting(&engine);
+
+    QRemoteObjectHost proxyNode;
+    SET_NODE_NAME(proxyNode);
+    if (useProxy) {
+        proxyNode.setHostUrl(tcpHostUrl);
+        proxyNode.proxy(registryUrl);
+    }
+
+    //Setup Local Replica
+    QRemoteObjectNode client;
+    SET_NODE_NAME(client);
+    if (useProxy)
+        client.connectToNode(tcpHostUrl);
+    else
+        client.setRegistryUrl(registryUrl);
+
+    QScopedPointer<QRemoteObjectReplica> replica;
+    if (!dynamic) {
+        //QLoggingCategory::setFilterRules("qt.remoteobjects*=true");
+        replica.reset(client.acquire<EngineReplica>());
+        QVERIFY(replica->waitForSource(1000));
+
+        EngineReplica *rep = qobject_cast<EngineReplica *>(replica.data());
+
+        //Compare Replica to Source
+        QCOMPARE(rep->rpm(), engine.rpm());
+        QCOMPARE(EngineReplica::EngineType(rep->type()), EngineReplica::Gas);
+
+        //Change Replica and make sure change propagates to source
+        QSignalSpy sourceSpy(&engine, &EngineSimpleSource::rpmChanged);
+        QSignalSpy replicaSpy(rep, &EngineReplica::rpmChanged);
+        rep->pushRpm(42);
+        sourceSpy.wait();
+        QCOMPARE(sourceSpy.count(), 1);
+        QCOMPARE(engine.rpm(), 42);
+
+        // ... and the change makes it back to the replica
+        replicaSpy.wait();
+        QCOMPARE(replicaSpy.count(), 1);
+        QCOMPARE(rep->rpm(), 42);
+    } else {
+        replica.reset(client.acquireDynamic(QStringLiteral("Engine")));
+        QVERIFY(replica->waitForSource(1000));
+
+        //Compare Replica to Source
+        const QMetaObject *metaObject = replica->metaObject();
+        const int rpmIndex = metaObject->indexOfProperty("rpm");
+        Q_ASSERT(rpmIndex != -1);
+        const QMetaProperty rpmMeta =  metaObject->property(rpmIndex);
+        QCOMPARE(rpmMeta.read(replica.data()).value<int>(), engine.rpm());
+        const int typeIndex = metaObject->indexOfProperty("type");
+        Q_ASSERT(typeIndex != -1);
+        const QMetaProperty typeMeta =  metaObject->property(typeIndex);
+        QCOMPARE(typeMeta.read(replica.data()).value<EngineReplica::EngineType>(), EngineReplica::Gas);
+
+        //Change Replica and make sure change propagates to source
+        QSignalSpy sourceSpy(&engine, &EngineSimpleSource::rpmChanged);
+        QSignalSpy replicaSpy(replica.data(), QByteArray(QByteArrayLiteral("2")+rpmMeta.notifySignal().methodSignature().constData()));
+
+        const int rpmPushIndex = metaObject->indexOfMethod("pushRpm(int)");
+        Q_ASSERT(rpmPushIndex != -1);
+        QMetaMethod pushMethod = metaObject->method(rpmPushIndex);
+        Q_ASSERT(pushMethod.isValid());
+        QVERIFY(pushMethod.invoke(replica.data(), Q_ARG(int, 42)));
+
+        sourceSpy.wait();
+        QCOMPARE(sourceSpy.count(), 1);
+        QCOMPARE(engine.rpm(), 42);
+
+        // ... and the change makes it back to the replica
+        replicaSpy.wait();
+        QCOMPARE(replicaSpy.count(), 1);
+        QCOMPARE(rpmMeta.read(replica.data()).value<int>(), engine.rpm());
+    }
+
+    // Make sure disabling the Source cascades the state change
+    bool res = host.disableRemoting(&engine);
+    Q_ASSERT(res);
+    QSignalSpy stateSpy(replica.data(), &QRemoteObjectReplica::stateChanged);
+    stateSpy.wait();
+    QCOMPARE(stateSpy.count(), 1);
+    QCOMPARE(replica->state(), QRemoteObjectReplica::Suspect);
+
+    // Now test subclass Source
+    ParentClassSimpleSource parent;
+    SubClassSimpleSource subclass;
+    const MyPOD initialValue(42, 3.14f, QStringLiteral("SubClass"));
+    subclass.setMyPOD(initialValue);
+    QStringListModel model;
+    model.setStringList(QStringList() << "Track1" << "Track2" << "Track3");
+    parent.setSubClass(&subclass);
+    parent.setTracks(&model);
+    QCOMPARE(subclass.myPOD(), initialValue);
+    if (sourceApi)
+        host.enableRemoting<ParentClassSourceAPI>(&parent);
+    else
+        host.enableRemoting(&parent);
+    if (!dynamic) {
+        replica.reset(client.acquire<ParentClassReplica>());
+        ParentClassReplica *rep = qobject_cast<ParentClassReplica *>(replica.data());
+        QSignalSpy tracksSpy(rep->tracks(), &QAbstractItemModelReplica::initialized);
+        QVERIFY(replica->waitForSource(1000));
+        //QLoggingCategory::setFilterRules("qt.remoteobjects*=false");
+
+        //Compare Replica to Source
+        QVERIFY(rep->subClass() != nullptr);
+        QCOMPARE(rep->subClass()->myPOD(), parent.subClass()->myPOD());
+        QVERIFY(rep->tracks() != nullptr);
+        QVERIFY(tracksSpy.count() || tracksSpy.wait());
+        // Rep file only uses display role, but proxy doesn't forward that yet
+        if (!useProxy)
+            QCOMPARE(rep->tracks()->availableRoles(), QList<int> { Qt::DisplayRole });
+        else {
+            const auto &availableRolesVec = rep->tracks()->availableRoles();
+            QSet<int> availableRoles;
+            for (int r : availableRolesVec)
+                availableRoles.insert(r);
+            const auto &rolesHash = model.roleNames();
+            QSet<int> roles;
+            for (auto it = rolesHash.cbegin(), end = rolesHash.cend(); it != end; ++it)
+                roles.insert(it.key());
+            QCOMPARE(availableRoles, roles);
+        }
+        QList<QModelIndex> pending;
+        QTRY_COMPARE(rep->tracks()->rowCount(), model.rowCount());
+        for (int i = 0; i < rep->tracks()->rowCount(); i++)
+        {
+            // We haven't received any data yet
+            const auto index = rep->tracks()->index(i, 0);
+            QCOMPARE(rep->tracks()->data(index), QVariant());
+            pending.append(index);
+        }
+        if (useProxy) { // A first batch of updates will be the empty proxy values
+            WaitForDataChanged w(rep->tracks(), pending);
+            QVERIFY(w.wait());
+        }
+        WaitForDataChanged w(rep->tracks(), pending);
+        QVERIFY(w.wait());
+        for (int i = 0; i < rep->tracks()->rowCount(); i++)
+        {
+            QTRY_COMPARE(rep->tracks()->data(rep->tracks()->index(i, 0)), model.data(model.index(i), Qt::DisplayRole));
+        }
+
+        //Change SubClass and make sure change propagates
+        SubClassSimpleSource updatedSubclass;
+        const MyPOD updatedValue(-1, 123.456f, QStringLiteral("Updated"));
+        updatedSubclass.setMyPOD(updatedValue);
+        QSignalSpy replicaSpy(rep, &ParentClassReplica::subClassChanged);
+        parent.setSubClass(&updatedSubclass);
+        replicaSpy.wait();
+        QCOMPARE(replicaSpy.count(), 1);
+        QCOMPARE(rep->subClass()->myPOD(), parent.subClass()->myPOD());
+        QCOMPARE(rep->subClass()->myPOD(), updatedValue);
+    } else {
+        replica.reset(client.acquireDynamic(QStringLiteral("ParentClass")));
+        QVERIFY(replica->waitForSource(1000));
+
+        const QMetaObject *metaObject = replica->metaObject();
+        // Verify subClass pointer
+        const int subclassIndex = metaObject->indexOfProperty("subClass");
+        QVERIFY(subclassIndex != -1);
+        const QMetaProperty subclassMeta =  metaObject->property(subclassIndex);
+        QObject *subclassQObjectPtr = subclassMeta.read(replica.data()).value<QObject *>();
+        QVERIFY(subclassQObjectPtr != nullptr);
+        QRemoteObjectDynamicReplica *subclassReplica = qobject_cast<QRemoteObjectDynamicReplica *>(subclassQObjectPtr);
+        QVERIFY(subclassReplica != nullptr);
+        // Verify tracks pointer
+        const int tracksIndex = metaObject->indexOfProperty("tracks");
+        QVERIFY(tracksIndex != -1);
+        const QMetaProperty tracksMeta =  metaObject->property(tracksIndex);
+        QObject *tracksQObjectPtr = tracksMeta.read(replica.data()).value<QObject *>();
+        QVERIFY(tracksQObjectPtr != nullptr);
+        QAbstractItemModelReplica *tracksReplica = qobject_cast<QAbstractItemModelReplica *>(tracksQObjectPtr);
+        QVERIFY(tracksReplica != nullptr);
+
+        // Verify subClass data
+        const int podIndex = subclassReplica->metaObject()->indexOfProperty("myPOD");
+        QVERIFY(podIndex != -1);
+        const QMetaProperty podMeta = subclassReplica->metaObject()->property(podIndex);
+        MyPOD pod = podMeta.read(subclassReplica).value<MyPOD>();
+        QCOMPARE(pod, parent.subClass()->myPOD());
+
+        // Verify tracks data
+        // Rep file only uses display role, but proxy doesn't forward that yet
+        if (!useProxy)
+            QCOMPARE(tracksReplica->availableRoles(), QList<int> { Qt::DisplayRole });
+        else {
+            const auto &availableRolesVec = tracksReplica->availableRoles();
+            QSet<int> availableRoles;
+            for (int r : availableRolesVec)
+                availableRoles.insert(r);
+            const auto &rolesHash = model.roleNames();
+            QSet<int> roles;
+            for (auto it = rolesHash.cbegin(), end = rolesHash.cend(); it != end; ++it)
+                roles.insert(it.key());
+            QCOMPARE(availableRoles, roles);
+        }
+        QTRY_COMPARE(tracksReplica->isInitialized(), true);
+        QSignalSpy dataSpy(tracksReplica, &QAbstractItemModelReplica::dataChanged);
+        QList<QModelIndex> pending;
+        QTRY_COMPARE(tracksReplica->rowCount(), model.rowCount());
+        for (int i = 0; i < tracksReplica->rowCount(); i++)
+        {
+            // We haven't received any data yet
+            const auto index = tracksReplica->index(i, 0);
+            QCOMPARE(tracksReplica->data(index), QVariant());
+            pending.append(index);
+        }
+        if (useProxy) { // A first batch of updates will be the empty proxy values
+            WaitForDataChanged w(tracksReplica, pending);
+            QVERIFY(w.wait());
+        }
+        WaitForDataChanged w(tracksReplica, pending);
+        QVERIFY(w.wait());
+        for (int i = 0; i < tracksReplica->rowCount(); i++)
+        {
+            QCOMPARE(tracksReplica->data(tracksReplica->index(i, 0)), model.data(model.index(i), Qt::DisplayRole));
+        }
+
+        //Change SubClass and make sure change propagates
+        SubClassSimpleSource updatedSubclass;
+        const MyPOD updatedValue(-1, 123.456f, QStringLiteral("Updated"));
+        updatedSubclass.setMyPOD(updatedValue);
+        QSignalSpy replicaSpy(replica.data(), QByteArray(QByteArrayLiteral("2")+subclassMeta.notifySignal().methodSignature().constData()));
+        parent.setSubClass(&updatedSubclass);
+        replicaSpy.wait();
+        QCOMPARE(replicaSpy.count(), 1);
+        subclassQObjectPtr = subclassMeta.read(replica.data()).value<QObject *>();
+        QVERIFY(subclassQObjectPtr != nullptr);
+        subclassReplica = qobject_cast<QRemoteObjectDynamicReplica *>(subclassQObjectPtr);
+        QVERIFY(subclassReplica != nullptr);
+
+        pod = podMeta.read(subclassReplica).value<MyPOD>();
+        QCOMPARE(pod, parent.subClass()->myPOD());
+    }
+    replica.reset();
+}
+
+void ProxyTest::testForwardProxy()
+{
+    // Setup Local Registry
+    QRemoteObjectRegistryHost registry(registryUrl);
+    SET_NODE_NAME(registry);
+
+    // Setup Local Host
+    QRemoteObjectHost host(localHostUrl, registryUrl);
+    SET_NODE_NAME(host);
+
+    // Setup Proxy
+    QRemoteObjectRegistryHost proxyNode(proxyNodeUrl);
+    SET_NODE_NAME(proxyNode);
+    proxyNode.proxy(registryUrl, proxyHostUrl);
+    // Include the reverseProxy to make sure we don't try to send back
+    // proxied objects.
+    proxyNode.reverseProxy();
+
+    // Setup Source
+    EngineSimpleSource engine;
+    engine.setRpm(1234);
+
+    // Setup Remote Node
+    QRemoteObjectHost remoteNode(remoteNodeUrl);
+    SET_NODE_NAME(remoteNode);
+    remoteNode.connectToNode(proxyNodeUrl);
+
+    // Add source
+    host.enableRemoting(&engine);
+
+    // Setup Replica
+    const QScopedPointer<EngineReplica> replica(remoteNode.acquire<EngineReplica>());
+    QTRY_VERIFY(replica->waitForSource(300));
+
+    // Compare Replica to Source
+    QCOMPARE(replica->rpm(), engine.rpm());
+}
+
+void ProxyTest::testReverseProxy()
+{
+    // Setup Local Registry
+    QRemoteObjectRegistryHost registry(registryUrl);
+    SET_NODE_NAME(registry);
+
+    // Setup Local Host
+    QRemoteObjectHost host(localHostUrl, registryUrl);
+    SET_NODE_NAME(host);
+
+    // Setup Proxy
+    QRemoteObjectRegistryHost proxyNode(proxyNodeUrl);
+    SET_NODE_NAME(proxyNode);
+    proxyNode.proxy(registryUrl, proxyHostUrl);
+    proxyNode.reverseProxy();
+
+    // Setup Source
+    EngineSimpleSource engine;
+    engine.setRpm(1234);
+
+    // Setup Remote Node
+    QRemoteObjectHost remoteNode(remoteNodeUrl, proxyNodeUrl);
+    SET_NODE_NAME(remoteNode);
+
+    // Add source
+    remoteNode.enableRemoting(&engine);
+
+    // Setup Replica
+    const QScopedPointer<EngineReplica> replica(host.acquire<EngineReplica>());
+    QTRY_VERIFY(replica->waitForSource(300));
+
+    //Compare Replica to Source
+    QCOMPARE(replica->rpm(), engine.rpm());
+}
+
+void ProxyTest::testTopLevelModel()
+{
+    QRemoteObjectRegistryHost registry(registryUrl);
+
+    //Setup Local Host
+    QRemoteObjectHost host(localHostUrl);
+    SET_NODE_NAME(host);
+    host.setRegistryUrl(registryUrl);
+
+    QStringListModel model;
+    model.setStringList(QStringList() << "Track1" << "Track2" << "Track3");
+    host.enableRemoting(&model, "trackList", QList<int> { Qt::DisplayRole });
+
+    QRemoteObjectHost proxyNode;
+    SET_NODE_NAME(proxyNode);
+    proxyNode.setHostUrl(tcpHostUrl);
+    proxyNode.proxy(registryUrl);
+
+    //Setup Local Replica
+    QRemoteObjectNode client;
+    SET_NODE_NAME(client);
+    client.connectToNode(tcpHostUrl);
+    QAbstractItemModelReplica *replica = client.acquireModel("trackList");
+    QSignalSpy tracksSpy(replica, &QAbstractItemModelReplica::initialized);
+    QVERIFY(tracksSpy.wait());
+    QTRY_COMPARE(replica->rowCount(), model.rowCount());
+}
+
+QTEST_MAIN(ProxyTest)
+
+#include "tst_proxy.moc"
diff --git a/tests/auto/proxy_multiprocess/CMakeLists.txt b/tests/auto/proxy_multiprocess/CMakeLists.txt
new file mode 100644 (file)
index 0000000..55703b1
--- /dev/null
@@ -0,0 +1,5 @@
+
+add_subdirectory(client)
+add_subdirectory(server)
+add_subdirectory(proxy)
+add_subdirectory(tst)
diff --git a/tests/auto/proxy_multiprocess/client/CMakeLists.txt b/tests/auto/proxy_multiprocess/client/CMakeLists.txt
new file mode 100644 (file)
index 0000000..85877e3
--- /dev/null
@@ -0,0 +1,23 @@
+
+#####################################################################
+## proxy_multiprocess_client Binary:
+#####################################################################
+
+qt_internal_add_executable(proxy_multiprocess_client
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        ../namespace.h
+        ../shared.h
+        main.cpp
+    INCLUDE_DIRECTORIES
+        ${CMAKE_CURRENT_SOURCE_DIR}
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+qt6_add_repc_replicas(proxy_multiprocess_client
+    ../subclass.rep
+)
+
+#### Keys ignored in scope 1:.:.:client.pro:<TRUE>:
+# TEMPLATE = "app"
diff --git a/tests/auto/proxy_multiprocess/client/main.cpp b/tests/auto/proxy_multiprocess/client/main.cpp
new file mode 100644 (file)
index 0000000..efc64e2
--- /dev/null
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include "rep_subclass_replica.h"
+#include "../shared.h"
+
+#include <QCoreApplication>
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtTest/QtTest>
+
+static QMap<int, MyPOD> int_map{{1, initialValue},
+                                {16, initialValue}};
+static ParentClassReplica::ActivePositions flags1 = ParentClassReplica::Position::position1;
+static ParentClassReplica::ActivePositions flags2 = ParentClassReplica::Position::position2
+                                                    | ParentClassReplica::Position::position3;
+static QMap<ParentClassReplica::ActivePositions, MyPOD> my_map{{flags1, initialValue},
+                                                               {flags2, initialValue}};
+static QHash<NS2::NamespaceEnum, MyPOD> my_hash{{NS2::NamespaceEnum::Alpha, initialValue},
+                                                {NS2::NamespaceEnum::Charlie, initialValue}};
+
+class tst_Client_Process : public QObject
+{
+    Q_OBJECT
+
+private Q_SLOTS:
+    void initTestCase()
+    {
+        m_repNode.reset(new QRemoteObjectNode);
+        m_repNode->connectToNode(QUrl(QStringLiteral("tcp://127.0.0.1:65213")));
+        m_rep.reset(m_repNode->acquire<ParentClassReplica>());
+        const auto objectMode = qEnvironmentVariable("ObjectMode");
+        qDebug() << "Waiting to connect, mode =" << objectMode;
+        QVERIFY(m_rep->waitForSource());
+    }
+
+    void testSubClass()
+    {
+        const auto objectMode = qEnvironmentVariable("ObjectMode");
+
+        qDebug() << "Starting test" << objectMode;
+        if (objectMode == QLatin1String("ObjectPointer")) {
+            QSignalSpy tracksSpy(m_rep->tracks(), &QAbstractItemModelReplica::initialized);
+            QVERIFY(m_rep->subClass() != nullptr);
+            QCOMPARE(m_rep->subClass()->myPOD(), initialValue);
+            QCOMPARE(m_rep->subClass()->i(), initialI);
+            QVERIFY(m_rep->tracks() != nullptr);
+            QVERIFY(tracksSpy.count() || tracksSpy.wait());
+            QCOMPARE(m_rep->myEnum(), ParentClassReplica::bar);
+            QCOMPARE(m_rep->date(), Qt::RFC2822Date);
+            QCOMPARE(m_rep->nsEnum(), NS::Bravo);
+            QCOMPARE(m_rep->ns2Enum(), NS2::NamespaceEnum::Bravo);
+            QCOMPARE(m_rep->variant(), QVariant::fromValue(42.0f));
+            QCOMPARE(m_rep->simpleList(), QList<QString>() << "one" << "two");
+            QCOMPARE(m_rep->podList(), QList<MyPOD>() << initialValue << initialValue);
+            QCOMPARE(m_rep->intMap(), int_map);
+            QCOMPARE(m_rep->enumMap(), my_map);
+            QCOMPARE(m_rep->podHash(), my_hash);
+        } else {
+            QVERIFY(m_rep->subClass() == nullptr);
+            QVERIFY(m_rep->tracks() == nullptr);
+            QCOMPARE(m_rep->myEnum(), ParentClassReplica::foo);
+            QCOMPARE(m_rep->date(), Qt::ISODate);
+            QCOMPARE(m_rep->nsEnum(), NS::Alpha);
+            QCOMPARE(m_rep->ns2Enum(), NS2::NamespaceEnum::Alpha);
+            QCOMPARE(m_rep->variant(), QVariant());
+        }
+
+        QPoint p(1, 2);
+        auto enumReply = m_rep->enumSlot(p, ParentClassReplica::bar);
+        QVERIFY(enumReply.waitForFinished());
+        QCOMPARE(enumReply.error(), QRemoteObjectPendingCall::NoError);
+        QCOMPARE(enumReply.returnValue(), ParentClassReplica::foobar);
+
+        qDebug() << "Verified expected initial states, sending start.";
+        QSignalSpy enumSpy(m_rep.data(), &ParentClassReplica::enum2);
+        QSignalSpy advanceSpy(m_rep.data(), &ParentClassReplica::advance);
+        auto reply = m_rep->start();
+        QVERIFY(reply.waitForFinished());
+        QVERIFY(reply.error() == QRemoteObjectPendingCall::NoError);
+        QCOMPARE(reply.returnValue(), QVariant::fromValue(true));
+        QVERIFY(enumSpy.wait());
+        QCOMPARE(enumSpy.count(), 1);
+        const auto arguments = enumSpy.takeFirst();
+        QCOMPARE(arguments.at(0), QVariant::fromValue(ParentClassReplica::foo));
+        QCOMPARE(arguments.at(1), QVariant::fromValue(ParentClassReplica::bar));
+
+        QVERIFY(advanceSpy.count() || advanceSpy.wait());
+        QVERIFY(m_rep->subClass() != nullptr);
+        QCOMPARE(m_rep->subClass()->myPOD(), updatedValue);
+        QCOMPARE(m_rep->subClass()->i(), updatedI);
+        QVERIFY(m_rep->tracks() != nullptr);
+        QCOMPARE(m_rep->myEnum(), ParentClassReplica::foobar);
+        QCOMPARE(m_rep->date(), Qt::ISODateWithMs);
+        QCOMPARE(m_rep->nsEnum(), NS::Charlie);
+        QCOMPARE(m_rep->ns2Enum(), NS2::NamespaceEnum::Charlie);
+        QCOMPARE(m_rep->variant(), QVariant::fromValue(podValue));
+        qDebug() << "Verified expected final states, cleaning up.";
+    }
+
+    void cleanupTestCase()
+    {
+        auto reply = m_rep->quit();
+        // Don't verify the wait result, depending on the timing of the server and proxy
+        // closing it may return false.  We just need this process to stay alive long
+        // enough for the packets to be sent.
+        reply.waitForFinished(5000);
+    }
+
+private:
+    QScopedPointer<QRemoteObjectNode> m_repNode;
+    QScopedPointer<ParentClassReplica> m_rep;
+};
+
+QTEST_MAIN(tst_Client_Process)
+
+#include "main.moc"
diff --git a/tests/auto/proxy_multiprocess/namespace.h b/tests/auto/proxy_multiprocess/namespace.h
new file mode 100644 (file)
index 0000000..1b9b59e
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef __PROXY_MULTIPROCESS_NAMESPACE_H__
+#define __PROXY_MULTIPROCESS_NAMESPACE_H__
+
+#include <QMetaType>
+
+namespace NS
+{
+    Q_NAMESPACE
+    enum NamespaceEnum { Alpha=1, Bravo, Charlie };
+    Q_ENUM_NS(NamespaceEnum)
+}
+
+namespace NS2
+{
+    Q_NAMESPACE
+    enum class NamespaceEnum : quint8 { Alpha=1, Bravo, Charlie };
+    Q_ENUM_NS(NamespaceEnum)
+}
+
+#endif // include guard
diff --git a/tests/auto/proxy_multiprocess/proxy/CMakeLists.txt b/tests/auto/proxy_multiprocess/proxy/CMakeLists.txt
new file mode 100644 (file)
index 0000000..29c4559
--- /dev/null
@@ -0,0 +1,18 @@
+
+#####################################################################
+## proxy Binary:
+#####################################################################
+
+qt_internal_add_executable(proxy
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        main.cpp
+    INCLUDE_DIRECTORIES
+        ${CMAKE_CURRENT_SOURCE_DIR}
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+
+#### Keys ignored in scope 1:.:.:proxy.pro:<TRUE>:
+# TEMPLATE = "app"
diff --git a/tests/auto/proxy_multiprocess/proxy/main.cpp b/tests/auto/proxy_multiprocess/proxy/main.cpp
new file mode 100644 (file)
index 0000000..6e0932a
--- /dev/null
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtTest/QtTest>
+
+class tst_Proxy_Process : public QObject
+{
+    Q_OBJECT
+
+private Q_SLOTS:
+    void testRun()
+    {
+        m_hostNode.reset(new QRemoteObjectHost);
+        m_hostNode->setHostUrl(QUrl(QStringLiteral("tcp://127.0.0.1:65213")));
+        m_hostNode->proxy(QUrl("local:testRegistry"));
+
+        // our proxied object should be added, and then later removed when the server shuts down
+        QSignalSpy addSpy(m_hostNode.data(), &QRemoteObjectNode::remoteObjectAdded);
+        QSignalSpy removeSpy(m_hostNode.data(), &QRemoteObjectNode::remoteObjectRemoved);
+        QVERIFY(addSpy.wait());
+        QVERIFY(removeSpy.wait());
+    }
+
+private:
+    QScopedPointer<QRemoteObjectHost> m_hostNode;
+};
+
+QTEST_MAIN(tst_Proxy_Process)
+
+#include "main.moc"
diff --git a/tests/auto/proxy_multiprocess/server/CMakeLists.txt b/tests/auto/proxy_multiprocess/server/CMakeLists.txt
new file mode 100644 (file)
index 0000000..a3436d7
--- /dev/null
@@ -0,0 +1,25 @@
+
+#####################################################################
+## proxy_multiprocess_server Binary:
+#####################################################################
+
+qt_internal_add_executable(proxy_multiprocess_server
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        ${CMAKE_CURRENT_BINARY_DIR}/rep_subclass_source.h
+        ../namespace.h
+        ../shared.h
+        main.cpp
+        mytestserver.cpp mytestserver.h
+    INCLUDE_DIRECTORIES
+        ${CMAKE_CURRENT_SOURCE_DIR}
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+qt6_add_repc_sources(proxy_multiprocess_server
+    ../subclass.rep
+)
+
+#### Keys ignored in scope 1:.:.:server.pro:<TRUE>:
+# TEMPLATE = "app"
diff --git a/tests/auto/proxy_multiprocess/server/main.cpp b/tests/auto/proxy_multiprocess/server/main.cpp
new file mode 100644 (file)
index 0000000..f6429f6
--- /dev/null
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include "mytestserver.h"
+#include "rep_subclass_source.h"
+#include "../shared.h"
+
+#include <QCoreApplication>
+#include <QtTest/QtTest>
+
+static QMap<int, MyPOD> int_map{{1, initialValue},
+                                {16, initialValue}};
+static MyTestServer::ActivePositions flags1 = MyTestServer::Position::position1;
+static MyTestServer::ActivePositions flags2 = MyTestServer::Position::position2
+                                              | MyTestServer::Position::position3;
+static QMap<MyTestServer::ActivePositions, MyPOD> my_map{{flags1, initialValue},
+                                                         {flags2, initialValue}};
+static QHash<NS2::NamespaceEnum, MyPOD> my_hash{{NS2::NamespaceEnum::Alpha, initialValue},
+                                                {NS2::NamespaceEnum::Charlie, initialValue}};
+
+class tst_Server_Process : public QObject
+{
+    Q_OBJECT
+
+private Q_SLOTS:
+    void testRun()
+    {
+        const auto objectMode = qEnvironmentVariable("ObjectMode");
+        bool templated = qEnvironmentVariableIsSet("TEMPLATED_REMOTING");
+
+        qDebug() << "Starting tests:" << objectMode << "templated =" << templated;
+        QRemoteObjectRegistryHost srcNode(QUrl(QStringLiteral("local:testRegistry")));
+
+        MyTestServer parent;
+        SubClassSimpleSource subclass;
+        subclass.setMyPOD(initialValue);
+        subclass.setI(initialI);
+        QStringListModel model;
+        model.setStringList(QStringList() << "Track1" << "Track2" << "Track3");
+        if (objectMode == QLatin1String("ObjectPointer")) {
+            parent.setSubClass(&subclass);
+            parent.setTracks(&model);
+            parent.setMyEnum(ParentClassSource::bar);
+            parent.setDate(Qt::RFC2822Date);
+            parent.setNsEnum(NS::Bravo);
+            parent.setNs2Enum(NS2::NamespaceEnum::Bravo);
+            parent.setVariant(QVariant::fromValue(42.0f));
+            parent.setSimpleList(QList<QString>() << "one" << "two");
+            parent.setPodList(QList<MyPOD>() << initialValue << initialValue);
+            parent.setIntMap(int_map);
+            parent.setEnumMap(my_map);
+            parent.setPodHash(my_hash);
+        }
+
+        if (templated)
+            srcNode.enableRemoting<ParentClassSourceAPI>(&parent);
+        else
+            srcNode.enableRemoting(&parent);
+
+        qDebug() << "Waiting for incoming connections";
+
+        QSignalSpy waitForStartedSpy(&parent, &MyTestServer::startedChanged);
+        QVERIFY(waitForStartedSpy.isValid());
+        QVERIFY(waitForStartedSpy.wait());
+        QCOMPARE(waitForStartedSpy.value(0).value(0).toBool(), true);
+
+        // wait for delivery of events
+        QTest::qWait(200);
+
+        //Change SubClass and make sure change propagates
+        SubClassSimpleSource updatedSubclass;
+        updatedSubclass.setMyPOD(updatedValue);
+        updatedSubclass.setI(updatedI);
+        parent.setSubClass(&updatedSubclass);
+        if (objectMode == QLatin1String("NullPointer"))
+            parent.setTracks(&model);
+        parent.setMyEnum(ParentClassSource::foobar);
+        parent.setDate(Qt::ISODateWithMs);
+        parent.setNsEnum(NS::Charlie);
+        parent.setNs2Enum(NS2::NamespaceEnum::Charlie);
+        parent.setVariant(QVariant::fromValue(podValue));
+        emit parent.enum2(ParentClassSource::foo, ParentClassSource::bar);
+
+        emit parent.advance();
+
+        // wait for quit
+        bool quit = false;
+        connect(&parent, &MyTestServer::quitApp, [&quit]{quit = true;});
+        QTRY_VERIFY_WITH_TIMEOUT(quit, 5000);
+
+        // wait for delivery of events
+        QTest::qWait(200);
+
+        qDebug() << "Done. Shutting down.";
+    }
+};
+
+QTEST_MAIN(tst_Server_Process)
+
+#include "main.moc"
diff --git a/tests/auto/proxy_multiprocess/server/mytestserver.cpp b/tests/auto/proxy_multiprocess/server/mytestserver.cpp
new file mode 100644 (file)
index 0000000..19302ce
--- /dev/null
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include <qdebug.h>
+
+#include "mytestserver.h"
+
+MyTestServer::MyTestServer(QObject *parent)
+    : ParentClassSimpleSource(parent)
+{
+    qDebug() << "Server started";
+}
+
+MyTestServer::~MyTestServer()
+{
+    qDebug() << "Server stopped";
+}
+
+bool MyTestServer::start()
+{
+    setStarted(true);
+    return true;
+}
+
+bool MyTestServer::quit()
+{
+    emit quitApp();
+    return true;
+}
+
+ParentClassSource::MyEnum MyTestServer::enumSlot(QPoint p, MyEnum myEnum)
+{
+    Q_UNUSED(p)
+    Q_UNUSED(myEnum)
+    return ParentClassSource::foobar;
+}
+
+Qt::DateFormat MyTestServer::dateSlot(Qt::DateFormat date)
+{
+    Q_UNUSED(date)
+    return Qt::RFC2822Date;
+}
diff --git a/tests/auto/proxy_multiprocess/server/mytestserver.h b/tests/auto/proxy_multiprocess/server/mytestserver.h
new file mode 100644 (file)
index 0000000..8a4d09b
--- /dev/null
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#ifndef MYTESTSERVER_H
+#define MYTESTSERVER_H
+
+#include <QTimer>
+
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtRemoteObjects/qremoteobjectsource.h>
+
+#include "rep_subclass_source.h"
+
+class MyTestServer : public ParentClassSimpleSource
+{
+    Q_OBJECT
+
+public:
+    MyTestServer(QObject *parent = nullptr);
+    ~MyTestServer() override;
+
+public Q_SLOTS:
+    bool start() override;
+    bool quit() override;
+    MyEnum enumSlot(QPoint p, MyEnum myEnum) override;
+    Qt::DateFormat dateSlot(Qt::DateFormat date) override;
+
+Q_SIGNALS:
+    void quitApp();
+};
+
+#endif // MYTESTSERVER_H
diff --git a/tests/auto/proxy_multiprocess/shared.h b/tests/auto/proxy_multiprocess/shared.h
new file mode 100644 (file)
index 0000000..e0a0a73
--- /dev/null
@@ -0,0 +1,6 @@
+const MyPOD initialValue(MyPOD::Position::position1, 3.14, QStringLiteral("SubClass"));
+const MyPOD updatedValue(MyPOD::Position::position2 | MyPOD::Position::position3, 123.456, QStringLiteral("Updated"));
+const VariantPOD podValue(10, 11);
+const int initialI = 100;
+const int updatedI = 200;
+
diff --git a/tests/auto/proxy_multiprocess/subclass.rep b/tests/auto/proxy_multiprocess/subclass.rep
new file mode 100644 (file)
index 0000000..5fb03d3
--- /dev/null
@@ -0,0 +1,50 @@
+#include <QPoint>
+#include "../namespace.h"
+
+USE_ENUM(Qt::DateFormat)
+USE_ENUM(NS::NamespaceEnum)
+USE_ENUM(NS2::NamespaceEnum)
+
+POD MyPOD{
+    ENUM class Position : unsigned short {position1=1, position2=2, position3=4}
+    FLAG (ActivePositions  Position)
+    ActivePositions positions, float f, QString s
+}
+POD VariantPOD(int i, int j)
+
+class SubClass
+{
+    PROP(MyPOD myPOD)
+    PROP(int i)
+}
+
+class ParentClass
+{
+    ENUM MyEnum {foo=1, bar=3, foobar=6}
+    ENUM class Position : unsigned short {position1=1, position2=2, position3=4}
+    FLAG (ActivePositions  Position)
+    PROP(bool started = false)
+    PROP(MyEnum myEnum=foo)
+    PROP(QVariant variant)
+    PROP(Qt::DateFormat date = Qt::ISODate)
+    PROP(NS::NamespaceEnum nsEnum = NS::Alpha)
+    PROP(NS2::NamespaceEnum ns2Enum = NS2::NamespaceEnum::Alpha)
+    PROP(QList<QString> simpleList)
+    PROP(QList<MyPOD> podList)
+    PROP(QMap<int, MyPOD> intMap)
+    PROP(QMap<ActivePositions, MyPOD> enumMap)
+    PROP(QHash<NS2::NamespaceEnum, MyPOD> podHash)
+
+    SLOT(bool start())
+    SLOT(bool quit())
+    SIGNAL(advance())
+    SIGNAL(enum2(MyEnum myEnum1, MyEnum myEnum2))
+    SLOT(MyEnum enumSlot(QPoint point, MyEnum myEnum))
+
+    SIGNAL(updateDate(Qt::DateFormat date1, Qt::DateFormat date2))
+    SLOT(Qt::DateFormat dateSlot(Qt::DateFormat date))
+
+    CLASS subClass(SubClass)
+    MODEL tracks(display)
+}
+
diff --git a/tests/auto/proxy_multiprocess/tst/CMakeLists.txt b/tests/auto/proxy_multiprocess/tst/CMakeLists.txt
new file mode 100644 (file)
index 0000000..25fae59
--- /dev/null
@@ -0,0 +1,12 @@
+
+#####################################################################
+## tst_proxy_multiprocess Test:
+#####################################################################
+
+qt_internal_add_test(tst_proxy_multiprocess
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        tst_proxy_multiprocess.cpp
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+)
diff --git a/tests/auto/proxy_multiprocess/tst/tst_proxy_multiprocess.cpp b/tests/auto/proxy_multiprocess/tst/tst_proxy_multiprocess.cpp
new file mode 100644 (file)
index 0000000..73cff14
--- /dev/null
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QMetaType>
+#include <QProcess>
+
+#include "../../../shared/testutils.h"
+
+class tst_Proxy_MultiProcess: public QObject
+{
+    Q_OBJECT
+
+public:
+    enum ObjectMode { NullPointer, ObjectPointer };
+    Q_ENUM(ObjectMode)
+
+private slots:
+    void initTestCase()
+    {
+        QVERIFY(TestUtils::init("tst"));
+    }
+
+    void cleanup()
+    {
+        // wait for delivery of RemoveObject events to the source
+        QTest::qWait(200);
+    }
+
+    void testRun_data()
+    {
+        QTest::addColumn<bool>("templated");
+        QTest::addColumn<ObjectMode>("objectMode");
+        QTest::newRow("non-templated, subobject") << false << ObjectPointer;
+        QTest::newRow("templated, subobject") << true << ObjectPointer;
+        QTest::newRow("non-templated, nullptr") << false << NullPointer;
+        QTest::newRow("templated, nullptr") << true << NullPointer;
+    }
+
+    void testRun()
+    {
+        QFETCH(bool, templated);
+        QFETCH(ObjectMode, objectMode);
+
+        qDebug() << "Starting server process";
+        QProcess serverProc;
+        serverProc.setProcessChannelMode(QProcess::ForwardedChannels);
+        QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+        env.insert("ObjectMode", QVariant::fromValue(objectMode).toString());
+        if (templated) {
+            env.insert("TEMPLATED_REMOTING", "true");
+        }
+        serverProc.setProcessEnvironment(env);
+        serverProc.start(TestUtils::findExecutable("proxy_multiprocess_server", "/server"),
+                         QStringList());
+        QVERIFY(serverProc.waitForStarted());
+
+        // wait for server start
+        QTest::qWait(200);
+
+
+        qDebug() << "Starting client process";
+        QProcess clientProc;
+        clientProc.setProcessChannelMode(QProcess::ForwardedChannels);
+        clientProc.setProcessEnvironment(env);
+        clientProc.start(TestUtils::findExecutable("proxy_multiprocess_client", "/client"),
+                         QStringList());
+        QVERIFY(clientProc.waitForStarted());
+
+        // wait for client start
+        QTest::qWait(200);
+
+
+        qDebug() << "Starting proxy process";
+        QProcess proxyProc;
+        proxyProc.setProcessChannelMode(QProcess::ForwardedChannels);
+        proxyProc.start(TestUtils::findExecutable("proxy", "/proxy"),
+                        QStringList());
+        QVERIFY(proxyProc.waitForStarted());
+
+        // wait for proxy start
+        QTest::qWait(200);
+
+
+        QVERIFY(clientProc.waitForFinished());
+        QVERIFY(proxyProc.waitForFinished());
+        QVERIFY(serverProc.waitForFinished());
+
+        QCOMPARE(serverProc.exitCode(), 0);
+        QCOMPARE(proxyProc.exitCode(), 0);
+        QCOMPARE(clientProc.exitCode(), 0);
+    }
+};
+
+QTEST_MAIN(tst_Proxy_MultiProcess)
+
+#include "tst_proxy_multiprocess.moc"
diff --git a/tests/auto/qml/CMakeLists.txt b/tests/auto/qml/CMakeLists.txt
new file mode 100644 (file)
index 0000000..abc7bb0
--- /dev/null
@@ -0,0 +1,3 @@
+
+add_subdirectory(integration)
+add_subdirectory(usertypes)
diff --git a/tests/auto/qml/integration/CMakeLists.txt b/tests/auto/qml/integration/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e4f4d7a
--- /dev/null
@@ -0,0 +1,24 @@
+
+#####################################################################
+## tst_qmlintegration Test:
+#####################################################################
+
+# Collect test data
+file(GLOB_RECURSE test_data_glob
+    RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/data/tst_*)
+list(APPEND test_data ${test_data_glob})
+
+qt_internal_add_test(tst_qmlintegration
+    GUI
+    QMLTEST
+    SOURCES
+        tst_integration.cpp
+    PUBLIC_LIBRARIES
+        Qt::Gui
+    TESTDATA ${test_data}
+)
+
+#### Keys ignored in scope 1:.:.:integration.pro:<TRUE>:
+# OTHER_FILES = "$$PWD/data/*.qml"
+# TEMPLATE = "app"
diff --git a/tests/auto/qml/integration/data/tst_integration.qml b/tests/auto/qml/integration/data/tst_integration.qml
new file mode 100644 (file)
index 0000000..0d46953
--- /dev/null
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+import QtTest 1.1
+import QtRemoteObjects 5.12
+
+TestCase {
+    id: testCase
+
+    Node {
+        id: defaultNode
+    }
+
+    Node {
+        id: nodeWithPersistedStore
+
+        persistedStore: SettingsStore {}
+    }
+
+    name: "testIntegration"
+    function test_integration()
+    {
+        // test defaultNode
+        compare(defaultNode.registryUrl, "")
+        compare(defaultNode.persistedStore, null)
+
+        // test nodeWithPersistedStore
+        compare(nodeWithPersistedStore.registryUrl, "")
+        verify(nodeWithPersistedStore.persistedStore)
+    }
+}
diff --git a/tests/auto/qml/integration/tst_integration.cpp b/tests/auto/qml/integration/tst_integration.cpp
new file mode 100644 (file)
index 0000000..6709f1a
--- /dev/null
@@ -0,0 +1,30 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include <QtQuickTest/quicktest.h>
+QUICK_TEST_MAIN(tst_integration)
diff --git a/tests/auto/qml/usertypes/CMakeLists.txt b/tests/auto/qml/usertypes/CMakeLists.txt
new file mode 100644 (file)
index 0000000..707ff38
--- /dev/null
@@ -0,0 +1,20 @@
+
+#####################################################################
+## tst_usertypes Test:
+#####################################################################
+
+qt_internal_add_test(tst_usertypes
+    SOURCES
+        tst_usertypes.cpp
+    DEFINES
+        SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/\\\"
+    PUBLIC_LIBRARIES
+        Qt::Qml
+        Qt::RemoteObjects
+)
+qt6_add_repc_merged(tst_usertypes
+    usertypes.rep
+)
+
+#### Keys ignored in scope 1:.:.:usertypes.pro:<TRUE>:
+# TEMPLATE = "app"
diff --git a/tests/auto/qml/usertypes/data/MyType.qml b/tests/auto/qml/usertypes/data/MyType.qml
new file mode 100644 (file)
index 0000000..7061c2c
--- /dev/null
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+QtObject {
+    property int value: 39
+}
diff --git a/tests/auto/qml/usertypes/data/complex.qml b/tests/auto/qml/usertypes/data/complex.qml
new file mode 100644 (file)
index 0000000..94c66eb
--- /dev/null
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+import QtRemoteObjects 5.12
+import usertypes 1.0
+
+ComplexTypeReplica {
+    node: Node {
+        registryUrl: "local:testModel"
+    }
+}
diff --git a/tests/auto/qml/usertypes/data/composite.qml b/tests/auto/qml/usertypes/data/composite.qml
new file mode 100644 (file)
index 0000000..b8defd3
--- /dev/null
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+QtObject {
+    property QtObject myTypeOk: MyType {} // this works
+    property MyType myType: MyType {} // this crashes
+    property MyType myType2 // this crashes (ensure solution works with null object)
+}
diff --git a/tests/auto/qml/usertypes/data/extraPropComplex.qml b/tests/auto/qml/usertypes/data/extraPropComplex.qml
new file mode 100644 (file)
index 0000000..bd16bbc
--- /dev/null
@@ -0,0 +1,13 @@
+import QtQuick 2.0
+import QtRemoteObjects 5.12
+import usertypes 1.0
+
+ComplexTypeReplica {
+    // test that the existence of this property doesn't cause issues
+    property QtObject object: QtObject {}
+
+    node: Node {
+        registryUrl: "local:testExtraComplex"
+    }
+}
+
diff --git a/tests/auto/qml/usertypes/data/extraprop.qml b/tests/auto/qml/usertypes/data/extraprop.qml
new file mode 100644 (file)
index 0000000..5c48de3
--- /dev/null
@@ -0,0 +1,12 @@
+import QtQuick 2.0
+import QtRemoteObjects 5.12
+import usertypes 1.0
+
+SimpleClockReplica {
+    property string result: hour // test that the existence of this property doesn't cause issues
+
+    node: Node {
+        registryUrl: "local:test"
+    }
+    onStateChanged: if (state == SimpleClockReplica.Valid) pushHour(10)
+}
diff --git a/tests/auto/qml/usertypes/data/extraprop2.qml b/tests/auto/qml/usertypes/data/extraprop2.qml
new file mode 100644 (file)
index 0000000..35d9d51
--- /dev/null
@@ -0,0 +1,11 @@
+import QtQuick 2.0
+import QtRemoteObjects 5.12
+import usertypes 1.0
+
+SimpleClockReplica {
+    property string result: hour // test that the existence of this property doesn't cause issues
+
+    node: Node {
+        registryUrl: "local:test2"
+    }
+}
diff --git a/tests/auto/qml/usertypes/data/hosted.qml b/tests/auto/qml/usertypes/data/hosted.qml
new file mode 100644 (file)
index 0000000..db1f1fd
--- /dev/null
@@ -0,0 +1,20 @@
+import QtQuick 2.0
+import QtRemoteObjects 5.15
+import usertypes 1.0
+
+Item {
+    SimpleClockSimpleSource {
+        id: clock
+    }
+
+    Host {
+        hostUrl: "local:testHost"
+        Component.onCompleted: enableRemoting(clock)
+    }
+
+    Timer {
+        interval: 500
+        running: true
+        onTriggered: clock.timeUpdated(10, 30)
+    }
+}
diff --git a/tests/auto/qml/usertypes/data/model.qml b/tests/auto/qml/usertypes/data/model.qml
new file mode 100644 (file)
index 0000000..2807d18
--- /dev/null
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+import QtRemoteObjects 5.12
+import usertypes 1.0
+
+TypeWithModelReplica {
+    node: Node {
+        registryUrl: "local:testModel"
+    }
+}
diff --git a/tests/auto/qml/usertypes/data/subObject.qml b/tests/auto/qml/usertypes/data/subObject.qml
new file mode 100644 (file)
index 0000000..fc7eb10
--- /dev/null
@@ -0,0 +1,17 @@
+import QtQuick 2.0
+import QtRemoteObjects 5.12
+import usertypes 1.0
+
+Item {
+    property int result: replica.clock.hour
+
+    property Node sharedNode: Node {
+        registryUrl: "local:testSubObject"
+    }
+
+    property TypeWithSubObjectReplica replica: TypeWithSubObjectReplica {
+        node: sharedNode
+        onStateChanged: if (state == TypeWithSubObjectReplica.Valid) clock.pushHour(7)
+    }
+}
+
diff --git a/tests/auto/qml/usertypes/data/twoReplicas.qml b/tests/auto/qml/usertypes/data/twoReplicas.qml
new file mode 100644 (file)
index 0000000..1516465
--- /dev/null
@@ -0,0 +1,29 @@
+import QtQuick 2.0
+import QtRemoteObjects 5.12
+import usertypes 1.0
+
+Item {
+    property int result: replica.hour
+    property int result2: replica2.hour
+
+    Node {
+        id: sharedNode
+        registryUrl: "local:testTwoReplicas"
+    }
+
+    SimpleClockReplica {
+        id: replica
+        node: sharedNode
+    }
+
+    SimpleClockReplica {
+        id: replica2
+    }
+
+    Timer {
+        running: true
+        interval: 200
+        onTriggered: replica2.node = sharedNode
+    }
+}
+
diff --git a/tests/auto/qml/usertypes/data/watcher.qml b/tests/auto/qml/usertypes/data/watcher.qml
new file mode 100644 (file)
index 0000000..b49d824
--- /dev/null
@@ -0,0 +1,37 @@
+import QtQuick 2.0
+import QtRemoteObjects 5.14
+import usertypes 1.0
+
+TypeWithReplyReplica {
+    property variant result
+    property bool hasError
+
+    node: Node {
+        registryUrl: "local:testWatcher"
+    }
+    onStateChanged: function(state) {
+        if (state != TypeWithReplyReplica.Valid)
+            return;
+        QtRemoteObjects.watch(uppercase("hello"), 1000)
+                       .then(function(value) { hasError = false; result = value },
+                             function(error) { hasError = true })
+    }
+
+    function callSlowFunction() {
+        result = 0
+        hasError = false
+
+        QtRemoteObjects.watch(slowFunction(), 300)
+                       .then(function(value) { hasError = false; result = value },
+                             function(error) { hasError = true })
+    }
+
+    function callComplexFunction() {
+        result = null
+        hasError = false
+
+        QtRemoteObjects.watch(complexReturnType(), 300)
+                       .then(function(value) { hasError = false; result = value },
+                             function(error) { hasError = true })
+    }
+}
diff --git a/tests/auto/qml/usertypes/tst_usertypes.cpp b/tests/auto/qml/usertypes/tst_usertypes.cpp
new file mode 100644 (file)
index 0000000..867f1eb
--- /dev/null
@@ -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: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$
+**
+****************************************************************************/
+
+#include <QString>
+#include <QtTest>
+#include <qqmlengine.h>
+#include <qqmlcomponent.h>
+#include "rep_usertypes_merged.h"
+
+class TypeWithReply : public TypeWithReplySimpleSource
+{
+public:
+    QString uppercase(const QString & input) override {
+        return input.toUpper();
+    }
+    QMap<QString, QString> complexReturnType() override {
+        return QMap<QString, QString>{{"one","1"}};
+    }
+    int slowFunction() override {
+        QTest::qWait(1000);
+        return 15;
+    }
+};
+
+class tst_usertypes : public QObject
+{
+    Q_OBJECT
+
+public:
+    tst_usertypes();
+
+private Q_SLOTS:
+    void extraPropertyInQml();
+    void extraPropertyInQml2();
+    void extraPropertyInQmlComplex();
+    void modelInQml();
+    void subObjectInQml();
+    void complexInQml_data();
+    void complexInQml();
+    void watcherInQml();
+    void hostInQml();
+    void twoReplicas();
+    void remoteCompositeType();
+};
+
+tst_usertypes::tst_usertypes()
+{
+    qmlRegisterType<ComplexTypeReplica>("usertypes", 1, 0, "ComplexTypeReplica");
+}
+
+void tst_usertypes::extraPropertyInQml()
+{
+    qmlRegisterType<SimpleClockReplica>("usertypes", 1, 0, "SimpleClockReplica");
+
+    QRemoteObjectRegistryHost host(QUrl("local:test"));
+    SimpleClockSimpleSource clock;
+    host.enableRemoting(&clock);
+
+    QQmlEngine e;
+    QQmlComponent c(&e, SRCDIR "data/extraprop.qml");
+    QObject *obj = c.create();
+    QVERIFY(obj);
+
+    QTRY_COMPARE_WITH_TIMEOUT(obj->property("result").value<int>(), 10, 1000);
+}
+
+void tst_usertypes::extraPropertyInQml2()
+{
+    qmlRegisterType<SimpleClockReplica>("usertypes", 1, 0, "SimpleClockReplica");
+
+    QRemoteObjectRegistryHost host(QUrl("local:test2"));
+    SimpleClockSimpleSource clock;
+    clock.setHour(10);
+    host.enableRemoting(&clock);
+
+    QQmlEngine e;
+    QQmlComponent c(&e, SRCDIR "data/extraprop2.qml");
+    QObject *obj = c.create();
+    QVERIFY(obj);
+
+    QTRY_COMPARE_WITH_TIMEOUT(obj->property("hour").value<int>(), 10, 1000);
+    QCOMPARE(obj->property("result").value<int>(), 10);
+}
+
+void tst_usertypes::extraPropertyInQmlComplex()
+{
+    QRemoteObjectRegistryHost host(QUrl("local:testExtraComplex"));
+
+    SimpleClockSimpleSource clock;
+    QStringListModel *model = new QStringListModel();
+    model->setStringList(QStringList() << "Track1" << "Track2" << "Track3");
+    ComplexTypeSimpleSource source;
+    source.setClock(&clock);
+    source.setTracks(model);
+    host.enableRemoting(&source);
+
+    QQmlEngine e;
+    QQmlComponent c(&e, SRCDIR "data/extraPropComplex.qml");
+    QObject *obj = c.create();
+    QVERIFY(obj);
+
+    ComplexTypeReplica *rep = qobject_cast<ComplexTypeReplica*>(obj);
+    QVERIFY(rep);
+
+    // don't crash
+    QTRY_VERIFY_WITH_TIMEOUT(rep->isInitialized(), 1000);
+}
+
+void tst_usertypes::modelInQml()
+{
+    qmlRegisterType<TypeWithModelReplica>("usertypes", 1, 0, "TypeWithModelReplica");
+
+    QRemoteObjectRegistryHost host(QUrl("local:testModel"));
+
+    QStringListModel *model = new QStringListModel();
+    model->setStringList(QStringList() << "Track1" << "Track2" << "Track3");
+    TypeWithModelSimpleSource source;
+    source.setTracks(model);
+    host.enableRemoting<TypeWithModelSourceAPI>(&source);
+
+    QQmlEngine e;
+    QQmlComponent c(&e, SRCDIR "data/model.qml");
+    QObject *obj = c.create();
+    QVERIFY(obj);
+
+    QTRY_VERIFY_WITH_TIMEOUT(obj->property("tracks").value<QAbstractItemModelReplica*>() != nullptr, 1000);
+    auto tracks = obj->property("tracks").value<QAbstractItemModelReplica*>();
+    QTRY_VERIFY_WITH_TIMEOUT(tracks->isInitialized(), 1000);
+
+    TypeWithModelReplica *rep = qobject_cast<TypeWithModelReplica *>(obj);
+    QVERIFY(rep->isInitialized());
+}
+
+void tst_usertypes::subObjectInQml()
+{
+    qmlRegisterType<TypeWithSubObjectReplica>("usertypes", 1, 0, "TypeWithSubObjectReplica");
+
+    QRemoteObjectRegistryHost host(QUrl("local:testSubObject"));
+
+    SimpleClockSimpleSource clock;
+    TypeWithSubObjectSimpleSource source;
+    source.setClock(&clock);
+    host.enableRemoting(&source);
+
+    QQmlEngine e;
+    QQmlComponent c(&e, SRCDIR "data/subObject.qml");
+    QObject *obj = c.create();
+    QVERIFY(obj);
+
+    TypeWithSubObjectReplica *replica = obj->property("replica").value<TypeWithSubObjectReplica*>();
+    QVERIFY(replica);
+
+    QTRY_VERIFY_WITH_TIMEOUT(replica->property("clock").value<SimpleClockReplica*>() != nullptr, 1000);
+    QTRY_COMPARE_WITH_TIMEOUT(obj->property("result").toInt(), 7, 1000);
+}
+
+void tst_usertypes::complexInQml_data()
+{
+    QTest::addColumn<bool>("templated");
+    QTest::addColumn<bool>("nullobject");
+    QTest::newRow("non-templated pointer") << false << false;
+    QTest::newRow("templated pointer") << true << false;
+    QTest::newRow("non-templated nullptr") << false << true;
+    QTest::newRow("templated nullptr") << true << true;
+}
+
+void tst_usertypes::complexInQml()
+{
+    QFETCH(bool, templated);
+    QFETCH(bool, nullobject);
+
+    QRemoteObjectRegistryHost host(QUrl("local:testModel"));
+
+    QStringListModel *model = new QStringListModel();
+    model->setStringList(QStringList() << "Track1" << "Track2" << "Track3");
+    QScopedPointer<SimpleClockSimpleSource> clock;
+    if (!nullobject)
+        clock.reset(new SimpleClockSimpleSource());
+    ComplexTypeSimpleSource source;
+    source.setTracks(model);
+    source.setClock(clock.data());
+    if (templated)
+        host.enableRemoting<ComplexTypeSourceAPI>(&source);
+    else
+        host.enableRemoting(&source);
+
+    QQmlEngine e;
+    QQmlComponent c(&e, SRCDIR "data/complex.qml");
+    QObject *obj = c.create();
+    QVERIFY(obj);
+
+    QTRY_VERIFY_WITH_TIMEOUT(obj->property("tracks").value<QAbstractItemModelReplica*>() != nullptr, 1000);
+    auto tracks = obj->property("tracks").value<QAbstractItemModelReplica*>();
+    QTRY_VERIFY_WITH_TIMEOUT(tracks->isInitialized(), 1000);
+    ComplexTypeReplica *rep = qobject_cast<ComplexTypeReplica *>(obj);
+    QVERIFY(rep->waitForSource(300));
+    QCOMPARE(rep->property("before").value<int>(), 0);
+    QCOMPARE(rep->property("after").value<int>(), 42);
+    if (nullobject) {
+        QCOMPARE(rep->clock(), nullptr);
+        QCOMPARE(source.clock(), nullptr);
+    } else {
+        QCOMPARE(source.clock()->hour(), 6);
+        QCOMPARE(rep->clock()->hour(), source.clock()->hour());
+    }
+}
+
+void tst_usertypes::watcherInQml()
+{
+    qmlRegisterType<TypeWithReplyReplica>("usertypes", 1, 0, "TypeWithReplyReplica");
+
+    QRemoteObjectRegistryHost host(QUrl("local:testWatcher"));
+    TypeWithReply source;
+    host.enableRemoting(&source);
+
+    QQmlEngine e;
+    QQmlComponent c(&e, SRCDIR "data/watcher.qml");
+    QObject *obj = c.create();
+    QVERIFY(obj);
+
+    QTRY_COMPARE_WITH_TIMEOUT(obj->property("result").value<QString>(), QString::fromLatin1("HELLO"), 1000);
+    QCOMPARE(obj->property("hasError").value<bool>(), false);
+
+    QMetaObject::invokeMethod(obj, "callSlowFunction");
+    QTRY_COMPARE_WITH_TIMEOUT(obj->property("hasError").value<bool>(), true, 1000);
+    QVERIFY(obj->property("result").value<int>() != 10);
+
+    QMetaObject::invokeMethod(obj, "callComplexFunction");
+    QTRY_VERIFY_WITH_TIMEOUT(!obj->property("result").isNull(), 1000);
+    auto map = obj->property("result").value<QMap<QString,QString>>();
+    QCOMPARE(map.value("one"), QString::fromLatin1("1"));
+    QCOMPARE(obj->property("hasError").value<bool>(), false);
+}
+
+void tst_usertypes::hostInQml()
+{
+    qmlRegisterType<SimpleClockSimpleSource>("usertypes", 1, 0, "SimpleClockSimpleSource");
+
+    QQmlEngine e;
+    QQmlComponent c(&e, SRCDIR "data/hosted.qml");
+    QObject *obj = c.create();
+    QVERIFY(obj);
+
+    QRemoteObjectNode node;
+    node.connectToNode(QUrl("local:testHost"));
+    SimpleClockReplica *replica = node.acquire<SimpleClockReplica>();
+    QTRY_COMPARE_WITH_TIMEOUT(replica->state(), QRemoteObjectReplica::Valid, 1000);
+
+    QSignalSpy spy(replica, &SimpleClockReplica::timeUpdated);
+    spy.wait();
+    QCOMPARE(spy.count(), 1);
+}
+
+void tst_usertypes::twoReplicas()
+{
+    qmlRegisterType<SimpleClockReplica>("usertypes", 1, 0, "SimpleClockReplica");
+
+    QRemoteObjectRegistryHost host(QUrl("local:testTwoReplicas"));
+    SimpleClockSimpleSource clock;
+    clock.setHour(7);
+    host.enableRemoting(&clock);
+
+    QQmlEngine e;
+    QQmlComponent c(&e, SRCDIR "data/twoReplicas.qml");
+    QObject *obj = c.create();
+    QVERIFY(obj);
+
+    QTRY_COMPARE_WITH_TIMEOUT(obj->property("result").value<int>(), 7, 1000);
+    QTRY_COMPARE_WITH_TIMEOUT(obj->property("result2").value<int>(), 7, 1000);
+}
+
+void tst_usertypes::remoteCompositeType()
+{
+    QQmlEngine e;
+    QQmlComponent c(&e, SRCDIR "data/composite.qml");
+    QScopedPointer<QObject> obj(c.create());
+    QVERIFY(obj);
+
+    QRemoteObjectRegistryHost host(QUrl("local:remoteCompositeType"));
+    host.enableRemoting(obj.data(), "composite");
+}
+
+QTEST_MAIN(tst_usertypes)
+
+#include "tst_usertypes.moc"
diff --git a/tests/auto/qml/usertypes/usertypes.rep b/tests/auto/qml/usertypes/usertypes.rep
new file mode 100644 (file)
index 0000000..6bff381
--- /dev/null
@@ -0,0 +1,33 @@
+#include <QtCore>
+
+class SimpleClock
+{
+    PROP(int hour=6);
+    PROP(int minute=30);
+    SIGNAL(timeUpdated(int hour, int minute, int second=0, int millisecond=0));
+};
+
+class TypeWithModel
+{
+    MODEL tracks(display);
+};
+
+class TypeWithSubObject
+{
+    CLASS clock(SimpleClock);
+};
+
+class ComplexType
+{
+    PROP(int before = 0)
+    MODEL tracks(display)
+    CLASS clock(SimpleClock)
+    PROP(int after = 42)
+}
+
+class TypeWithReply
+{
+    SLOT(QString uppercase(const QString &input))
+    SLOT(QMap<QString, QString> complexReturnType())
+    SLOT(int slowFunction())
+};
diff --git a/tests/auto/reconnect/CMakeLists.txt b/tests/auto/reconnect/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5a97510
--- /dev/null
@@ -0,0 +1,4 @@
+
+add_subdirectory(client)
+add_subdirectory(server)
+add_subdirectory(tst)
diff --git a/tests/auto/reconnect/client/CMakeLists.txt b/tests/auto/reconnect/client/CMakeLists.txt
new file mode 100644 (file)
index 0000000..cf2491b
--- /dev/null
@@ -0,0 +1,6 @@
+qt_internal_add_executable(qtro_reconnect_client
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES main.cpp
+    INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}
+    PUBLIC_LIBRARIES Qt::RemoteObjects Qt::Test
+)
diff --git a/tests/auto/reconnect/client/main.cpp b/tests/auto/reconnect/client/main.cpp
new file mode 100644 (file)
index 0000000..1aa4f6e
--- /dev/null
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module 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$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include <QtTest/QtTest>
+#include <QtRemoteObjects/qremoteobjectnode.h>
+
+class tst_Client_Process : public QObject
+{
+    Q_OBJECT
+
+private Q_SLOTS:
+    void testRun()
+    {
+        const QString url = qEnvironmentVariable("RO_URL");
+        QRemoteObjectNode node;
+        node.connectToNode(QUrl(url));
+        QRemoteObjectDynamicReplica *ro = node.acquireDynamic("SourceObj");
+
+        QSignalSpy initSpy(ro, &QRemoteObjectDynamicReplica::initialized);
+        QVERIFY(initSpy.wait());
+        QSignalSpy pongSpy(ro, SIGNAL(pong()));
+        QMetaObject::invokeMethod(ro, "ping");
+        QVERIFY(pongSpy.wait());
+        QMetaObject::invokeMethod(ro, "ping");
+
+        QVERIFY(initSpy.wait());
+        QMetaObject::invokeMethod(ro, "ping");
+        QVERIFY(pongSpy.wait());
+        QMetaObject::invokeMethod(ro, "ping");
+        QTest::qWait(100);
+        delete ro;
+    }
+};
+
+QTEST_MAIN(tst_Client_Process)
+
+#include "main.moc"
diff --git a/tests/auto/reconnect/server/CMakeLists.txt b/tests/auto/reconnect/server/CMakeLists.txt
new file mode 100644 (file)
index 0000000..777d572
--- /dev/null
@@ -0,0 +1,6 @@
+qt_internal_add_executable(qtro_reconnect_server
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES main.cpp
+    INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}
+    PUBLIC_LIBRARIES Qt::RemoteObjects Qt::Test
+)
diff --git a/tests/auto/reconnect/server/main.cpp b/tests/auto/reconnect/server/main.cpp
new file mode 100644 (file)
index 0000000..d1f3f4c
--- /dev/null
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module 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$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include <QtTest/QtTest>
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtRemoteObjects/qremoteobjectsource.h>
+
+
+class SourceObj : public QObject
+{
+    Q_OBJECT
+
+public Q_SLOTS:
+    void ping() { ++m_pingCount; };
+
+Q_SIGNALS:
+    void pong();
+
+public:
+    int m_pingCount = 0;
+};
+
+class tst_Server_Process : public QObject
+{
+    Q_OBJECT
+
+private Q_SLOTS:
+    void testRun()
+    {
+        const QString url = qEnvironmentVariable("RO_URL");
+        QRemoteObjectHost *srcNode = new QRemoteObjectHost(QUrl(url));
+        SourceObj so;
+        so.setObjectName(QStringLiteral("SourceObj"));
+        srcNode->enableRemoting(&so);
+
+        QTRY_VERIFY(so.m_pingCount == 1);
+        emit so.pong();
+        QTRY_VERIFY(so.m_pingCount == 2);
+        delete srcNode;
+
+        srcNode = new QRemoteObjectHost(QUrl(url));
+        srcNode->enableRemoting(&so);
+
+        QTRY_VERIFY(so.m_pingCount == 3);
+        emit so.pong();
+        QTRY_VERIFY(so.m_pingCount == 4);
+        delete srcNode;
+    }
+};
+
+QTEST_MAIN(tst_Server_Process)
+
+#include "main.moc"
diff --git a/tests/auto/reconnect/tst/CMakeLists.txt b/tests/auto/reconnect/tst/CMakeLists.txt
new file mode 100644 (file)
index 0000000..68bf4a5
--- /dev/null
@@ -0,0 +1,5 @@
+qt_internal_add_test(tst_reconnect
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES tst_reconnect.cpp
+    PUBLIC_LIBRARIES Qt::RemoteObjects
+)
diff --git a/tests/auto/reconnect/tst/tst_reconnect.cpp b/tests/auto/reconnect/tst/tst_reconnect.cpp
new file mode 100644 (file)
index 0000000..73f3e38
--- /dev/null
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module 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$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QStandardPaths>
+#include <QProcess>
+#include "../../../shared/testutils.h"
+
+
+class tst_Reconnect: public QObject
+{
+    Q_OBJECT
+
+private slots:
+    void testRun_data()
+    {
+        QTest::addColumn<QString>("url");
+        QTest::addRow("local") << QStringLiteral("local:replica");
+        QTest::addRow("tcp") << QStringLiteral("tcp://127.0.0.1:65217");
+    }
+
+    void testRun()
+    {
+        QFETCH(QString, url);
+
+        QVERIFY(TestUtils::init("tst"));
+
+        QProcess serverProc;
+        serverProc.setProcessChannelMode(QProcess::ForwardedChannels);
+        QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+        env.insert("RO_URL", url);
+        serverProc.setProcessEnvironment(env);
+        serverProc.start(TestUtils::findExecutable("qtro_reconnect_server", "/server"),
+                         QStringList());
+        QVERIFY(serverProc.waitForStarted());
+
+        QProcess clientProc;
+        clientProc.setProcessChannelMode(QProcess::ForwardedChannels);
+        clientProc.setProcessEnvironment(env);
+        clientProc.start(TestUtils::findExecutable("qtro_reconnect_client", "/client"),
+                         QStringList());
+        qDebug() << "Started server and client process on:" << url;
+        QVERIFY(clientProc.waitForStarted());
+
+        QVERIFY(clientProc.waitForFinished());
+        QVERIFY(serverProc.waitForFinished());
+
+        QCOMPARE(serverProc.exitCode(), 0);
+        QCOMPARE(clientProc.exitCode(), 0);
+    }
+};
+
+QTEST_MAIN(tst_Reconnect)
+
+#include "tst_reconnect.moc"
diff --git a/tests/auto/rep_from_header/CMakeLists.txt b/tests/auto/rep_from_header/CMakeLists.txt
new file mode 100644 (file)
index 0000000..17a7a7a
--- /dev/null
@@ -0,0 +1,15 @@
+
+#####################################################################
+## tst_rep_from_header Test:
+#####################################################################
+
+qt_internal_add_test(tst_rep_from_header
+    SOURCES
+        tst_rep_from_header.cpp
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+)
+qt6_reps_from_headers(tst_rep_from_header pods.h)
+
+#### Keys ignored in scope 1:.:.:rep_from_header.pro:<TRUE>:
+# QOBJECT_REP = "$$REP_FILES"
diff --git a/tests/auto/rep_from_header/pods.h b/tests/auto/rep_from_header/pods.h
new file mode 100644 (file)
index 0000000..177bf02
--- /dev/null
@@ -0,0 +1,184 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#pragma once
+// This is an autogenerated file.
+// Do not edit this file, any changes made will be lost the next time it is generated.
+
+#include <QObject>
+
+
+#include <QString>
+class PodI
+{
+    Q_GADGET
+    Q_PROPERTY(int i READ i WRITE setI)
+public:
+    explicit PodI() : _i() {}
+    explicit PodI(int i) : _i(i) {}
+    PodI(const PodI& other)
+    {
+        QtRemoteObjects::copyStoredProperties(&other, this);
+    }
+
+    PodI &operator=(const PodI &other)
+    {
+        if (this != &other)
+            QtRemoteObjects::copyStoredProperties(&other, this);
+        return *this;
+    }
+
+    int i() const { return _i; }
+    void setI(int i) { if (i != _i) { _i = i; } }
+private:
+    int _i;
+};
+
+inline QDataStream &operator<<(QDataStream &ds, const PodI &obj) {
+    QtRemoteObjects::copyStoredProperties(&obj, ds);
+    return ds;
+}
+
+inline QDataStream &operator>>(QDataStream &ds, PodI &obj) {
+    QtRemoteObjects::copyStoredProperties(ds, &obj);
+    return ds;
+}
+
+class PodF
+{
+    Q_GADGET
+    Q_PROPERTY(float f READ f WRITE setF)
+public:
+    explicit PodF() : _f() {}
+    explicit PodF(float f) : _f(f) {}
+    PodF(const PodF& other)
+    {
+        QtRemoteObjects::copyStoredProperties(&other, this);
+    }
+
+    PodF &operator=(const PodF &other)
+    {
+        if (this != &other)
+            QtRemoteObjects::copyStoredProperties(&other, this);
+        return *this;
+    }
+
+    float f() const { return _f; }
+    void setF(float f) { if (f != _f) { _f = f; } }
+private:
+    float _f;
+};
+
+inline QDataStream &operator<<(QDataStream &ds, const PodF &obj) {
+    QtRemoteObjects::copyStoredProperties(&obj, ds);
+    return ds;
+}
+
+inline QDataStream &operator>>(QDataStream &ds, PodF &obj) {
+    QtRemoteObjects::copyStoredProperties(ds, &obj);
+    return ds;
+}
+
+class PodS
+{
+    Q_GADGET
+    Q_PROPERTY(QString s READ s WRITE setS)
+public:
+    explicit PodS() : _s() {}
+    explicit PodS(QString s) : _s(s) {}
+    PodS(const PodS& other)
+    {
+        QtRemoteObjects::copyStoredProperties(&other, this);
+    }
+
+    PodS &operator=(const PodS &other)
+    {
+        if (this != &other)
+            QtRemoteObjects::copyStoredProperties(&other, this);
+        return *this;
+    }
+
+    QString s() const { return _s; }
+    void setS(QString s) { if (s != _s) { _s = s; } }
+private:
+    QString _s;
+};
+
+inline QDataStream &operator<<(QDataStream &ds, const PodS &obj) {
+    QtRemoteObjects::copyStoredProperties(&obj, ds);
+    return ds;
+}
+
+inline QDataStream &operator>>(QDataStream &ds, PodS &obj) {
+    QtRemoteObjects::copyStoredProperties(ds, &obj);
+    return ds;
+}
+
+class PodIFS
+{
+    Q_GADGET
+    Q_PROPERTY(int i READ i WRITE setI)
+    Q_PROPERTY(float f READ f WRITE setF)
+    Q_PROPERTY(QString s READ s WRITE setS)
+public:
+    explicit PodIFS() : _i(), _f(), _s() {}
+    explicit PodIFS(int i, float f, QString s) : _i(i), _f(f), _s(s) {}
+    PodIFS(const PodIFS& other)
+    {
+        QtRemoteObjects::copyStoredProperties(&other, this);
+    }
+
+    PodIFS &operator=(const PodIFS &other)
+    {
+        if (this != &other)
+            QtRemoteObjects::copyStoredProperties(&other, this);
+        return *this;
+    }
+
+    int i() const { return _i; }
+    void setI(int i) { if (i != _i) { _i = i; } }
+    float f() const { return _f; }
+    void setF(float f) { if (f != _f) { _f = f; } }
+    QString s() const { return _s; }
+    void setS(QString s) { if (s != _s) { _s = s; } }
+private:
+    int _i;
+    float _f;
+    QString _s;
+};
+
+inline QDataStream &operator<<(QDataStream &ds, const PodIFS &obj) {
+    QtRemoteObjects::copyStoredProperties(&obj, ds);
+    return ds;
+}
+
+inline QDataStream &operator>>(QDataStream &ds, PodIFS &obj) {
+    QtRemoteObjects::copyStoredProperties(ds, &obj);
+    return ds;
+}
+
diff --git a/tests/auto/rep_from_header/tst_rep_from_header.cpp b/tests/auto/rep_from_header/tst_rep_from_header.cpp
new file mode 100644 (file)
index 0000000..1324035
--- /dev/null
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module 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$
+**
+****************************************************************************/
+
+//#include "rep_pods_replica.h"
+
+#include <QTest>
+
+#include <QByteArray>
+
+class tst_rep_from_header : public QObject {
+    Q_OBJECT
+
+private Q_SLOTS:
+    void testRep_data();
+    void testRep();
+};
+
+void tst_rep_from_header::testRep_data()
+{
+        QTest::addColumn<QString>("actualFile");
+        QTest::addColumn<QByteArrayList>("expectedLines");
+
+        QTest::newRow("pods") << QStringLiteral("pods.rep")
+                              << QByteArrayList{"POD PodI(int i)",
+                                                "POD PodF(float f)",
+                                                "POD PodS(QString s)",
+                                                "POD PodIFS(int i, float f, QString s)",
+                                                ""};
+}
+
+void tst_rep_from_header::testRep()
+{
+    QFETCH(QString, actualFile);
+    QFETCH(QByteArrayList, expectedLines);
+    const auto readFile = [&](const QString &fileName) {
+        QFile f(fileName);
+        f.open(QIODevice::ReadOnly);
+        QByteArrayList lines;
+        while (!f.atEnd())
+            lines.append(f.readLine().trimmed());
+        return lines;
+    };
+
+    QVERIFY2(QFile::exists(actualFile), qPrintable(actualFile));
+
+    QByteArrayList actualLines = readFile(actualFile);
+
+    QVERIFY(actualLines == expectedLines);
+}
+
+QTEST_APPLESS_MAIN(tst_rep_from_header)
+
+#include "tst_rep_from_header.moc"
+
diff --git a/tests/auto/repc/CMakeLists.txt b/tests/auto/repc/CMakeLists.txt
new file mode 100644 (file)
index 0000000..50988e2
--- /dev/null
@@ -0,0 +1,6 @@
+
+add_subdirectory(enums)
+add_subdirectory(pods)
+if(NOT windows)
+    add_subdirectory(signature)
+endif()
diff --git a/tests/auto/repc/enums/CMakeLists.txt b/tests/auto/repc/enums/CMakeLists.txt
new file mode 100644 (file)
index 0000000..dfebce8
--- /dev/null
@@ -0,0 +1,17 @@
+
+#####################################################################
+## tst_enums Test:
+#####################################################################
+
+qt_internal_add_test(tst_enums
+    SOURCES
+        tst_enums.cpp
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+)
+qt6_add_repc_replicas(tst_enums
+    enums.rep
+)
+
+## Scopes:
+#####################################################################
diff --git a/tests/auto/repc/enums/enums.rep b/tests/auto/repc/enums/enums.rep
new file mode 100644 (file)
index 0000000..190c2fe
--- /dev/null
@@ -0,0 +1,6 @@
+
+USE_ENUM(Qt::DayOfWeek)
+
+class TestInterface
+{
+};
diff --git a/tests/auto/repc/enums/tst_enums.cpp b/tests/auto/repc/enums/tst_enums.cpp
new file mode 100644 (file)
index 0000000..6f9b15e
--- /dev/null
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2017-2020 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module 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$
+**
+****************************************************************************/
+
+#include "rep_enums_replica.h"
+
+#include <QTest>
+
+#include <QByteArray>
+#include <QDataStream>
+
+class tst_Enums : public QObject {
+    Q_OBJECT
+
+private Q_SLOTS:
+    void testMarshalling();
+};
+
+void tst_Enums::testMarshalling()
+{
+    QByteArray ba;
+    QDataStream ds(&ba, QIODevice::ReadWrite);
+
+    {
+        const Qt::DayOfWeek format1 = Qt::Monday;
+        const Qt::DayOfWeek format2 = Qt::Tuesday;
+        const Qt::DayOfWeek format3 = Qt::Wednesday;
+        const Qt::DayOfWeek format4 = Qt::Thursday;
+        const Qt::DayOfWeek format5 = Qt::Friday;
+        const Qt::DayOfWeek format6 = Qt::Saturday;
+        const Qt::DayOfWeek format7 = Qt::Sunday;
+
+        ds << format1 << format2 << format3 << format4 << format5 << format6 << format7;
+    }
+
+    ds.device()->seek(0);
+
+    {
+        Qt::DayOfWeek format1, format2, format3, format4, format5, format6, format7;
+
+        ds >> format1 >> format2 >> format3 >> format4 >> format5 >> format6 >> format7;
+
+        QCOMPARE(format1, Qt::Monday);
+        QCOMPARE(format2, Qt::Tuesday);
+        QCOMPARE(format3, Qt::Wednesday);
+        QCOMPARE(format4, Qt::Thursday);
+        QCOMPARE(format5, Qt::Friday);
+        QCOMPARE(format6, Qt::Saturday);
+        QCOMPARE(format7, Qt::Sunday);
+    }
+}
+
+QTEST_APPLESS_MAIN(tst_Enums)
+
+#include "tst_enums.moc"
diff --git a/tests/auto/repc/pods/CMakeLists.txt b/tests/auto/repc/pods/CMakeLists.txt
new file mode 100644 (file)
index 0000000..84746ea
--- /dev/null
@@ -0,0 +1,17 @@
+
+#####################################################################
+## tst_repc_pods Test:
+#####################################################################
+
+qt_internal_add_test(tst_repc_pods
+    SOURCES
+        tst_pods.cpp
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+)
+qt6_add_repc_replicas(tst_repc_pods
+    pods.rep
+)
+
+## Scopes:
+#####################################################################
diff --git a/tests/auto/repc/pods/pods.rep b/tests/auto/repc/pods/pods.rep
new file mode 100644 (file)
index 0000000..9eea324
--- /dev/null
@@ -0,0 +1,12 @@
+#include <QString>
+
+ENUM Test {TRUE, FALSE}
+
+POD PodI(int i)
+POD PodF(float f)
+POD PodS(QString s)
+POD PodIFS(int i, float f, QString s)
+POD PodT(QList<TestEnum::Test> t)
+
+class Container {
+};
diff --git a/tests/auto/repc/pods/tst_pods.cpp b/tests/auto/repc/pods/tst_pods.cpp
new file mode 100644 (file)
index 0000000..71c0ffb
--- /dev/null
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include "rep_pods_replica.h"
+
+#include <QTest>
+
+#include <QByteArray>
+#include <QDataStream>
+
+class tst_Pods : public QObject {
+    Q_OBJECT
+
+private Q_SLOTS:
+    void testConstructors();
+    void testMarshalling();
+    void testProperty();
+};
+
+
+void tst_Pods::testConstructors()
+{
+    PodI pi1;
+    QCOMPARE(pi1.i(), 0);
+
+    PodI pi2(1);
+    QCOMPARE(pi2.i(), 1);
+
+    PodI pi3(pi2);
+    QCOMPARE(pi3.i(), pi2.i());
+}
+
+void tst_Pods::testMarshalling()
+{
+    QByteArray ba;
+    QDataStream ds(&ba, QIODevice::ReadWrite);
+
+    {
+        PodI i1(1), i2(2), i3(3), iDeadBeef(0xdeadbeef);
+        ds << i1 << i2 << i3 << iDeadBeef;
+    }
+
+    ds.device()->seek(0);
+
+    {
+        PodI i1, i2, i3, iDeadBeef;
+        ds >> i1 >> i2 >> i3 >> iDeadBeef;
+
+        QCOMPARE(i1.i(), 1);
+        QCOMPARE(i2.i(), 2);
+        QCOMPARE(i3.i(), 3);
+        QCOMPARE(iDeadBeef.i(), int(0xdeadbeef));
+    }
+}
+
+void tst_Pods::testProperty()
+{
+    ContainerReplica::registerMetatypes();
+
+    PodT pt;
+    QMetaProperty prop = pt.staticMetaObject.property(0);
+    QVERIFY(prop.userType() != 0);
+}
+
+QTEST_APPLESS_MAIN(tst_Pods)
+
+#include "tst_pods.moc"
diff --git a/tests/auto/repc/signature/CMakeLists.txt b/tests/auto/repc/signature/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b5504a1
--- /dev/null
@@ -0,0 +1,22 @@
+
+add_subdirectory(signatureServer)
+add_subdirectory(matchAndQuit)
+add_subdirectory(differentGlobalEnum)
+add_subdirectory(differentClassEnum)
+add_subdirectory(differentPropertyCount)
+add_subdirectory(differentPropertyCountChild)
+add_subdirectory(differentPropertyType)
+add_subdirectory(scrambledProperties)
+add_subdirectory(differentSlotCount)
+add_subdirectory(differentSlotType)
+add_subdirectory(differentSlotParamCount)
+add_subdirectory(differentSlotParamType)
+add_subdirectory(scrambledSlots)
+add_subdirectory(differentSignalCount)
+add_subdirectory(differentSignalParamCount)
+add_subdirectory(differentSignalParamType)
+add_subdirectory(scrambledSignals)
+add_subdirectory(state)
+if(QT_FEATURE_process)
+    add_subdirectory(signatureTests)
+endif()
diff --git a/tests/auto/repc/signature/differentClassEnum/CMakeLists.txt b/tests/auto/repc/signature/differentClassEnum/CMakeLists.txt
new file mode 100644 (file)
index 0000000..dd980ad
--- /dev/null
@@ -0,0 +1,18 @@
+
+#####################################################################
+## differentClassEnum Binary:
+#####################################################################
+
+qt_internal_add_executable(differentClassEnum
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        ../mismatch.cpp
+    INCLUDE_DIRECTORIES
+        ..
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+qt6_add_repc_replicas(differentClassEnum
+    mismatch.rep
+)
diff --git a/tests/auto/repc/signature/differentClassEnum/mismatch.rep b/tests/auto/repc/signature/differentClassEnum/mismatch.rep
new file mode 100644 (file)
index 0000000..e495e0a
--- /dev/null
@@ -0,0 +1,23 @@
+ENUM Test {TRUE, FALSE}
+
+class TestClass
+{
+    ENUM ClassEnum {Null = 2, One, Two}
+
+    PROP(TestEnum::Test testEnum)
+    PROP(ClassEnum classEnum)
+
+    PROP(int prop1);
+    PROP(double prop2);
+
+    SLOT(bool slot1());
+    SLOT(QString slot2());
+
+    SIGNAL(signal1());
+    SIGNAL(signal2());
+
+    SLOT(void ping(const QString &message));
+    SIGNAL(pong(const QString &message));
+
+    SLOT(bool quit());
+};
diff --git a/tests/auto/repc/signature/differentGlobalEnum/CMakeLists.txt b/tests/auto/repc/signature/differentGlobalEnum/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5865e9b
--- /dev/null
@@ -0,0 +1,18 @@
+
+#####################################################################
+## differentGlobalEnum Binary:
+#####################################################################
+
+qt_internal_add_executable(differentGlobalEnum
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        ../mismatch.cpp
+    INCLUDE_DIRECTORIES
+        ..
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+qt6_add_repc_replicas(differentGlobalEnum
+    mismatch.rep
+)
diff --git a/tests/auto/repc/signature/differentGlobalEnum/mismatch.rep b/tests/auto/repc/signature/differentGlobalEnum/mismatch.rep
new file mode 100644 (file)
index 0000000..bb83d08
--- /dev/null
@@ -0,0 +1,31 @@
+ENUM Test {FALSE, TRUE}
+
+class TestChildClass
+{
+    PROP(int prop1);
+    PROP(double prop2);
+};
+
+class TestClass
+{
+    ENUM ClassEnum {Null, One, Two}
+
+    PROP(TestEnum::Test testEnum)
+    PROP(ClassEnum classEnum)
+
+    PROP(int prop1);
+    PROP(double prop2);
+
+    SLOT(bool slot1());
+    SLOT(QString slot2());
+
+    CLASS childProp(TestChildClass);
+
+    SIGNAL(signal1());
+    SIGNAL(signal2());
+
+    SLOT(void ping(const QString &message));
+    SIGNAL(pong(const QString &message));
+
+    SLOT(bool quit());
+};
diff --git a/tests/auto/repc/signature/differentPropertyCount/CMakeLists.txt b/tests/auto/repc/signature/differentPropertyCount/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c413ce0
--- /dev/null
@@ -0,0 +1,18 @@
+
+#####################################################################
+## differentPropertyCount Binary:
+#####################################################################
+
+qt_internal_add_executable(differentPropertyCount
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        ../mismatch.cpp
+    INCLUDE_DIRECTORIES
+        ..
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+qt6_add_repc_replicas(differentPropertyCount
+    mismatch.rep
+)
diff --git a/tests/auto/repc/signature/differentPropertyCount/mismatch.rep b/tests/auto/repc/signature/differentPropertyCount/mismatch.rep
new file mode 100644 (file)
index 0000000..3fdfe03
--- /dev/null
@@ -0,0 +1,32 @@
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+    PROP(int prop1);
+    PROP(double prop2);
+};
+
+class TestClass
+{
+    ENUM ClassEnum {Null, One, Two}
+
+    PROP(TestEnum::Test testEnum)
+    PROP(ClassEnum classEnum)
+
+    PROP(int prop1);
+    PROP(double prop2);
+    PROP(double prop3);
+
+    CLASS childProp(TestChildClass);
+
+    SLOT(bool slot1());
+    SLOT(QString slot2());
+
+    SIGNAL(signal1());
+    SIGNAL(signal2());
+
+    SLOT(void ping(const QString &message));
+    SIGNAL(pong(const QString &message));
+
+    SLOT(bool quit());
+};
diff --git a/tests/auto/repc/signature/differentPropertyCountChild/CMakeLists.txt b/tests/auto/repc/signature/differentPropertyCountChild/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b023e75
--- /dev/null
@@ -0,0 +1,18 @@
+
+#####################################################################
+## differentPropertyCount Binary:
+#####################################################################
+
+qt_internal_add_executable(differentPropertyCountChild
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        ../mismatch.cpp
+    INCLUDE_DIRECTORIES
+        ..
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+qt6_add_repc_replicas(differentPropertyCountChild
+    mismatch.rep
+)
diff --git a/tests/auto/repc/signature/differentPropertyCountChild/differentPropertyCountChild.pro b/tests/auto/repc/signature/differentPropertyCountChild/differentPropertyCountChild.pro
new file mode 100644 (file)
index 0000000..23014de
--- /dev/null
@@ -0,0 +1,5 @@
+include(../mismatch.pri)
+
+TARGET = differentPropertyCountChild
+
+REPC_REPLICA = $$PWD/mismatch.rep
diff --git a/tests/auto/repc/signature/differentPropertyCountChild/mismatch.rep b/tests/auto/repc/signature/differentPropertyCountChild/mismatch.rep
new file mode 100644 (file)
index 0000000..ee03fe5
--- /dev/null
@@ -0,0 +1,30 @@
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+    PROP(double prop2);
+};
+
+class TestClass
+{
+    ENUM ClassEnum {Null, One, Two}
+
+    PROP(TestEnum::Test testEnum)
+    PROP(ClassEnum classEnum)
+
+    PROP(int prop1);
+    PROP(double prop2);
+
+    CLASS childProp(TestChildClass);
+
+    SLOT(bool slot1());
+    SLOT(QString slot2());
+
+    SIGNAL(signal1());
+    SIGNAL(signal2());
+
+    SLOT(void ping(const QString &message));
+    SIGNAL(pong(const QString &message));
+
+    SLOT(bool quit());
+};
diff --git a/tests/auto/repc/signature/differentPropertyType/CMakeLists.txt b/tests/auto/repc/signature/differentPropertyType/CMakeLists.txt
new file mode 100644 (file)
index 0000000..10c0fdd
--- /dev/null
@@ -0,0 +1,18 @@
+
+#####################################################################
+## differentPropertyType Binary:
+#####################################################################
+
+qt_internal_add_executable(differentPropertyType
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        ../mismatch.cpp
+    INCLUDE_DIRECTORIES
+        ..
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+qt6_add_repc_replicas(differentPropertyType
+    mismatch.rep
+)
diff --git a/tests/auto/repc/signature/differentPropertyType/mismatch.rep b/tests/auto/repc/signature/differentPropertyType/mismatch.rep
new file mode 100644 (file)
index 0000000..99ffae3
--- /dev/null
@@ -0,0 +1,31 @@
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+    PROP(int prop1);
+    PROP(double prop2);
+};
+
+class TestClass
+{
+    ENUM ClassEnum {Null, One, Two}
+
+    PROP(TestEnum::Test testEnum)
+    PROP(ClassEnum classEnum)
+
+    PROP(int prop1);
+    PROP(QString prop2);
+
+    SLOT(bool slot1());
+    SLOT(QString slot2());
+
+    CLASS childProp(TestChildClass);
+
+    SIGNAL(signal1());
+    SIGNAL(signal2());
+
+    SLOT(void ping(const QString &message));
+    SIGNAL(pong(const QString &message));
+
+    SLOT(bool quit());
+};
diff --git a/tests/auto/repc/signature/differentSignalCount/CMakeLists.txt b/tests/auto/repc/signature/differentSignalCount/CMakeLists.txt
new file mode 100644 (file)
index 0000000..22e3a15
--- /dev/null
@@ -0,0 +1,18 @@
+
+#####################################################################
+## differentSignalCount Binary:
+#####################################################################
+
+qt_internal_add_executable(differentSignalCount
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        ../mismatch.cpp
+    INCLUDE_DIRECTORIES
+        ..
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+qt6_add_repc_replicas(differentSignalCount
+    mismatch.rep
+)
diff --git a/tests/auto/repc/signature/differentSignalCount/mismatch.rep b/tests/auto/repc/signature/differentSignalCount/mismatch.rep
new file mode 100644 (file)
index 0000000..fdec2a9
--- /dev/null
@@ -0,0 +1,32 @@
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+    PROP(int prop1);
+    PROP(double prop2);
+};
+
+class TestClass
+{
+    ENUM ClassEnum {Null, One, Two}
+
+    PROP(TestEnum::Test testEnum)
+    PROP(ClassEnum classEnum)
+
+    PROP(int prop1);
+    PROP(double prop2);
+
+    CLASS childProp(TestChildClass);
+
+    SLOT(bool slot1());
+    SLOT(QString slot2());
+
+    SIGNAL(signal1());
+    SIGNAL(signal2());
+    SIGNAL(anotherSignal());
+
+    SLOT(void ping(const QString &message));
+    SIGNAL(pong(const QString &message));
+
+    SLOT(bool quit());
+};
diff --git a/tests/auto/repc/signature/differentSignalParamCount/CMakeLists.txt b/tests/auto/repc/signature/differentSignalParamCount/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e3617c4
--- /dev/null
@@ -0,0 +1,18 @@
+
+#####################################################################
+## differentSignalParamCount Binary:
+#####################################################################
+
+qt_internal_add_executable(differentSignalParamCount
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        ../mismatch.cpp
+    INCLUDE_DIRECTORIES
+        ..
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+qt6_add_repc_replicas(differentSignalParamCount
+    mismatch.rep
+)
diff --git a/tests/auto/repc/signature/differentSignalParamCount/mismatch.rep b/tests/auto/repc/signature/differentSignalParamCount/mismatch.rep
new file mode 100644 (file)
index 0000000..4040b6a
--- /dev/null
@@ -0,0 +1,31 @@
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+    PROP(int prop1);
+    PROP(double prop2);
+};
+
+class TestClass
+{
+    ENUM ClassEnum {Null, One, Two}
+
+    PROP(TestEnum::Test testEnum)
+    PROP(ClassEnum classEnum)
+
+    PROP(int prop1);
+    PROP(double prop2);
+
+    SLOT(bool slot1());
+    SLOT(QString slot2());
+
+    CLASS childProp(TestChildClass);
+
+    SIGNAL(signal1());
+    SIGNAL(signal2());
+
+    SLOT(void ping(const QString &message));
+    SIGNAL(pong(const QString &message, int anotherParam));
+
+    SLOT(bool quit());
+};
diff --git a/tests/auto/repc/signature/differentSignalParamType/CMakeLists.txt b/tests/auto/repc/signature/differentSignalParamType/CMakeLists.txt
new file mode 100644 (file)
index 0000000..1a8fcb0
--- /dev/null
@@ -0,0 +1,18 @@
+
+#####################################################################
+## differentSignalParamType Binary:
+#####################################################################
+
+qt_internal_add_executable(differentSignalParamType
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        ../mismatch.cpp
+    INCLUDE_DIRECTORIES
+        ..
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+qt6_add_repc_replicas(differentSignalParamType
+    mismatch.rep
+)
diff --git a/tests/auto/repc/signature/differentSignalParamType/mismatch.rep b/tests/auto/repc/signature/differentSignalParamType/mismatch.rep
new file mode 100644 (file)
index 0000000..0655480
--- /dev/null
@@ -0,0 +1,31 @@
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+    PROP(int prop1);
+    PROP(double prop2);
+};
+
+class TestClass
+{
+    ENUM ClassEnum {Null, One, Two}
+
+    PROP(TestEnum::Test testEnum)
+    PROP(ClassEnum classEnum)
+
+    PROP(int prop1);
+    PROP(double prop2);
+
+    CLASS childProp(TestChildClass);
+
+    SLOT(bool slot1());
+    SLOT(QString slot2());
+
+    SIGNAL(signal1());
+    SIGNAL(signal2());
+
+    SLOT(void ping(const QString &message));
+    SIGNAL(pong(const QByteArray &message));
+
+    SLOT(bool quit());
+};
diff --git a/tests/auto/repc/signature/differentSlotCount/CMakeLists.txt b/tests/auto/repc/signature/differentSlotCount/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6cb2012
--- /dev/null
@@ -0,0 +1,18 @@
+
+#####################################################################
+## differentSlotCount Binary:
+#####################################################################
+
+qt_internal_add_executable(differentSlotCount
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        ../mismatch.cpp
+    INCLUDE_DIRECTORIES
+        ..
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+qt6_add_repc_replicas(differentSlotCount
+    mismatch.rep
+)
diff --git a/tests/auto/repc/signature/differentSlotCount/mismatch.rep b/tests/auto/repc/signature/differentSlotCount/mismatch.rep
new file mode 100644 (file)
index 0000000..046651c
--- /dev/null
@@ -0,0 +1,32 @@
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+    PROP(int prop1);
+    PROP(double prop2);
+};
+
+class TestClass
+{
+    ENUM ClassEnum {Null, One, Two}
+
+    PROP(TestEnum::Test testEnum)
+    PROP(ClassEnum classEnum)
+
+    PROP(int prop1);
+    PROP(double prop2);
+
+    CLASS childProp(TestChildClass);
+
+    SLOT(bool slot1());
+    SLOT(QString slot2());
+    SLOT(void anotherSlot());
+
+    SIGNAL(signal1());
+    SIGNAL(signal2());
+
+    SLOT(void ping(const QString &message));
+    SIGNAL(pong(const QString &message));
+
+    SLOT(bool quit());
+};
diff --git a/tests/auto/repc/signature/differentSlotParamCount/CMakeLists.txt b/tests/auto/repc/signature/differentSlotParamCount/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e7f2adf
--- /dev/null
@@ -0,0 +1,18 @@
+
+#####################################################################
+## differentSlotParamCount Binary:
+#####################################################################
+
+qt_internal_add_executable(differentSlotParamCount
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        ../mismatch.cpp
+    INCLUDE_DIRECTORIES
+        ..
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+qt6_add_repc_replicas(differentSlotParamCount
+    mismatch.rep
+)
diff --git a/tests/auto/repc/signature/differentSlotParamCount/mismatch.rep b/tests/auto/repc/signature/differentSlotParamCount/mismatch.rep
new file mode 100644 (file)
index 0000000..4113986
--- /dev/null
@@ -0,0 +1,31 @@
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+    PROP(int prop1);
+    PROP(double prop2);
+};
+
+class TestClass
+{
+    ENUM ClassEnum {Null, One, Two}
+
+    PROP(TestEnum::Test testEnum)
+    PROP(ClassEnum classEnum)
+
+    PROP(int prop1);
+    PROP(double prop2);
+
+    CLASS childProp(TestChildClass);
+
+    SLOT(bool slot1());
+    SLOT(QString slot2());
+
+    SIGNAL(signal1());
+    SIGNAL(signal2());
+
+    SLOT(void ping(const QString &message, int anotherParam));
+    SIGNAL(pong(const QString &message));
+
+    SLOT(bool quit());
+};
diff --git a/tests/auto/repc/signature/differentSlotParamType/CMakeLists.txt b/tests/auto/repc/signature/differentSlotParamType/CMakeLists.txt
new file mode 100644 (file)
index 0000000..dd2ffde
--- /dev/null
@@ -0,0 +1,18 @@
+
+#####################################################################
+## differentSlotParamType Binary:
+#####################################################################
+
+qt_internal_add_executable(differentSlotParamType
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        ../mismatch.cpp
+    INCLUDE_DIRECTORIES
+        ..
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+qt6_add_repc_replicas(differentSlotParamType
+    mismatch.rep
+)
diff --git a/tests/auto/repc/signature/differentSlotParamType/mismatch.rep b/tests/auto/repc/signature/differentSlotParamType/mismatch.rep
new file mode 100644 (file)
index 0000000..b9e66e6
--- /dev/null
@@ -0,0 +1,31 @@
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+    PROP(int prop1);
+    PROP(double prop2);
+};
+
+class TestClass
+{
+    ENUM ClassEnum {Null, One, Two}
+
+    PROP(TestEnum::Test testEnum)
+    PROP(ClassEnum classEnum)
+
+    PROP(int prop1);
+    PROP(double prop2);
+
+    CLASS childProp(TestChildClass);
+
+    SLOT(bool slot1());
+    SLOT(QString slot2());
+
+    SIGNAL(signal1());
+    SIGNAL(signal2());
+
+    SLOT(void ping(const QByteArray &message));
+    SIGNAL(pong(const QString &message));
+
+    SLOT(bool quit());
+};
diff --git a/tests/auto/repc/signature/differentSlotType/CMakeLists.txt b/tests/auto/repc/signature/differentSlotType/CMakeLists.txt
new file mode 100644 (file)
index 0000000..471baa6
--- /dev/null
@@ -0,0 +1,18 @@
+
+#####################################################################
+## differentSlotType Binary:
+#####################################################################
+
+qt_internal_add_executable(differentSlotType
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        ../mismatch.cpp
+    INCLUDE_DIRECTORIES
+        ..
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+qt6_add_repc_replicas(differentSlotType
+    mismatch.rep
+)
diff --git a/tests/auto/repc/signature/differentSlotType/mismatch.rep b/tests/auto/repc/signature/differentSlotType/mismatch.rep
new file mode 100644 (file)
index 0000000..2165647
--- /dev/null
@@ -0,0 +1,31 @@
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+    PROP(int prop1);
+    PROP(double prop2);
+};
+
+class TestClass
+{
+    ENUM ClassEnum {Null, One, Two}
+
+    PROP(TestEnum::Test testEnum)
+    PROP(ClassEnum classEnum)
+
+    PROP(int prop1);
+    PROP(double prop2);
+
+    CLASS childProp(TestChildClass);
+
+    SLOT(bool slot1());
+    SLOT(int slot2());
+
+    SIGNAL(signal1());
+    SIGNAL(signal2());
+
+    SLOT(void ping(const QString &message));
+    SIGNAL(pong(const QString &message));
+
+    SLOT(bool quit());
+};
diff --git a/tests/auto/repc/signature/matchAndQuit/CMakeLists.txt b/tests/auto/repc/signature/matchAndQuit/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ab1ffa5
--- /dev/null
@@ -0,0 +1,21 @@
+
+#####################################################################
+## matchAndQuit Binary:
+#####################################################################
+
+qt_internal_add_executable(matchAndQuit
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        main.cpp
+    INCLUDE_DIRECTORIES
+        ${CMAKE_CURRENT_SOURCE_DIR}
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+qt6_add_repc_replicas(matchAndQuit
+    ../server.rep
+)
+
+#### Keys ignored in scope 1:.:.:matchAndQuit.pro:<TRUE>:
+# TEMPLATE = "app"
diff --git a/tests/auto/repc/signature/matchAndQuit/main.cpp b/tests/auto/repc/signature/matchAndQuit/main.cpp
new file mode 100644 (file)
index 0000000..d7e1764
--- /dev/null
@@ -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: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$
+**
+****************************************************************************/
+
+#include "rep_server_replica.h"
+
+#include <QCoreApplication>
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtTest/QtTest>
+
+class tst_Match_Process : public QObject
+{
+    Q_OBJECT
+
+private Q_SLOTS:
+    void testRun()
+    {
+        QRemoteObjectNode repNode;
+        repNode.connectToNode(QUrl(QStringLiteral("tcp://127.0.0.1:65214")));
+        QSharedPointer<TestClassReplica> rep(repNode.acquire<TestClassReplica>());
+        QSignalSpy stateChangedSpy(rep.data(), &QRemoteObjectReplica::stateChanged);
+        QVERIFY(rep->waitForSource());
+        QCOMPARE(rep->state(), QRemoteObjectReplica::Valid);
+
+        QVERIFY(rep->quit().waitForFinished());
+        QTRY_COMPARE(rep->state(), QRemoteObjectReplica::Suspect);
+
+        QCOMPARE(stateChangedSpy.count(), 2);
+
+        // Test Default to Valid transition
+        auto args = stateChangedSpy.takeFirst();
+        QCOMPARE(args.count(), 2);
+        QCOMPARE(args.at(0).toInt(), int(QRemoteObjectReplica::Valid));
+        QCOMPARE(args.at(1).toInt(), int(QRemoteObjectReplica::Default));
+
+        // Test Valid to Suspect transition
+        args = stateChangedSpy.takeFirst();
+        QCOMPARE(args.count(), 2);
+        QCOMPARE(args.at(0).toInt(), int(QRemoteObjectReplica::Suspect));
+        QCOMPARE(args.at(1).toInt(), int(QRemoteObjectReplica::Valid));
+    }
+};
+
+QTEST_MAIN(tst_Match_Process)
+
+#include "main.moc"
diff --git a/tests/auto/repc/signature/mismatch.cpp b/tests/auto/repc/signature/mismatch.cpp
new file mode 100644 (file)
index 0000000..f1c5797
--- /dev/null
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include "rep_mismatch_replica.h"
+
+#include <QCoreApplication>
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtTest/QtTest>
+
+class tst_Mismatch_Process : public QObject
+{
+    Q_OBJECT
+
+private Q_SLOTS:
+    void testRun()
+    {
+        QRemoteObjectNode repNode;
+        repNode.connectToNode(QUrl(QStringLiteral("tcp://127.0.0.1:65214")));
+        QTest::ignoreMessage(QtWarningMsg, " Signature mismatch for TestClassReplica \"TestClass\"");
+        QSharedPointer<TestClassReplica> rep(repNode.acquire<TestClassReplica>());
+        QTRY_COMPARE(rep->state(), QRemoteObjectReplica::SignatureMismatch);
+    }
+};
+
+QTEST_MAIN(tst_Mismatch_Process)
+
+#include "mismatch.moc"
diff --git a/tests/auto/repc/signature/mismatch.pri b/tests/auto/repc/signature/mismatch.pri
new file mode 100644 (file)
index 0000000..7517919
--- /dev/null
@@ -0,0 +1,10 @@
+TEMPLATE = app
+QT       += remoteobjects core testlib
+QT       -= gui
+
+DESTDIR = ./
+CONFIG   += c++11
+CONFIG   -= app_bundle
+
+INCLUDEPATH += $$PWD
+SOURCES += $$PWD/mismatch.cpp
diff --git a/tests/auto/repc/signature/scrambledProperties/CMakeLists.txt b/tests/auto/repc/signature/scrambledProperties/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ea08128
--- /dev/null
@@ -0,0 +1,18 @@
+
+#####################################################################
+## scrambledProperties Binary:
+#####################################################################
+
+qt_internal_add_executable(scrambledProperties
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        ../mismatch.cpp
+    INCLUDE_DIRECTORIES
+        ..
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+qt6_add_repc_replicas(scrambledProperties
+    mismatch.rep
+)
diff --git a/tests/auto/repc/signature/scrambledProperties/mismatch.rep b/tests/auto/repc/signature/scrambledProperties/mismatch.rep
new file mode 100644 (file)
index 0000000..18ec5b0
--- /dev/null
@@ -0,0 +1,31 @@
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+    PROP(int prop1);
+    PROP(double prop2);
+};
+
+class TestClass
+{
+    ENUM ClassEnum {Null, One, Two}
+
+    PROP(TestEnum::Test testEnum)
+    PROP(ClassEnum classEnum)
+
+    PROP(double prop2);
+    PROP(int prop1);
+
+    CLASS childProp(TestChildClass);
+
+    SLOT(bool slot1());
+    SLOT(QString slot2());
+
+    SIGNAL(signal1());
+    SIGNAL(signal2());
+
+    SLOT(void ping(const QString &message));
+    SIGNAL(pong(const QString &message));
+
+    SLOT(bool quit());
+};
diff --git a/tests/auto/repc/signature/scrambledSignals/CMakeLists.txt b/tests/auto/repc/signature/scrambledSignals/CMakeLists.txt
new file mode 100644 (file)
index 0000000..240ac5a
--- /dev/null
@@ -0,0 +1,18 @@
+
+#####################################################################
+## scrambledSignals Binary:
+#####################################################################
+
+qt_internal_add_executable(scrambledSignals
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        ../mismatch.cpp
+    INCLUDE_DIRECTORIES
+        ..
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+qt6_add_repc_replicas(scrambledSignals
+    mismatch.rep
+)
diff --git a/tests/auto/repc/signature/scrambledSignals/mismatch.rep b/tests/auto/repc/signature/scrambledSignals/mismatch.rep
new file mode 100644 (file)
index 0000000..45c2d6e
--- /dev/null
@@ -0,0 +1,31 @@
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+    PROP(int prop1);
+    PROP(double prop2);
+};
+
+class TestClass
+{
+    ENUM ClassEnum {Null, One, Two}
+
+    PROP(TestEnum::Test testEnum)
+    PROP(ClassEnum classEnum)
+
+    PROP(int prop1);
+    PROP(double prop2);
+
+    CLASS childProp(TestChildClass);
+
+    SLOT(bool slot1());
+    SLOT(QString slot2());
+
+    SIGNAL(signal2());
+    SIGNAL(signal1());
+
+    SLOT(void ping(const QString &message));
+    SIGNAL(pong(const QString &message));
+
+    SLOT(bool quit());
+};
diff --git a/tests/auto/repc/signature/scrambledSlots/CMakeLists.txt b/tests/auto/repc/signature/scrambledSlots/CMakeLists.txt
new file mode 100644 (file)
index 0000000..32ef1e0
--- /dev/null
@@ -0,0 +1,18 @@
+
+#####################################################################
+## scrambledSlots Binary:
+#####################################################################
+
+qt_internal_add_executable(scrambledSlots
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        ../mismatch.cpp
+    INCLUDE_DIRECTORIES
+        ..
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+qt6_add_repc_replicas(scrambledSlots
+    mismatch.rep
+)
diff --git a/tests/auto/repc/signature/scrambledSlots/mismatch.rep b/tests/auto/repc/signature/scrambledSlots/mismatch.rep
new file mode 100644 (file)
index 0000000..17851ce
--- /dev/null
@@ -0,0 +1,31 @@
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+    PROP(int prop1);
+    PROP(double prop2);
+};
+
+class TestClass
+{
+    ENUM ClassEnum {Null, One, Two}
+
+    PROP(TestEnum::Test testEnum)
+    PROP(ClassEnum classEnum)
+
+    PROP(int prop1);
+    PROP(double prop2);
+
+    CLASS childProp(TestChildClass);
+
+    SLOT(QString slot2());
+    SLOT(bool slot1());
+
+    SIGNAL(signal1());
+    SIGNAL(signal2());
+
+    SLOT(void ping(const QString &message));
+    SIGNAL(pong(const QString &message));
+
+    SLOT(bool quit());
+};
diff --git a/tests/auto/repc/signature/server.rep b/tests/auto/repc/signature/server.rep
new file mode 100644 (file)
index 0000000..251a651
--- /dev/null
@@ -0,0 +1,31 @@
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+    PROP(int prop1);
+    PROP(double prop2);
+};
+
+class TestClass
+{
+    ENUM ClassEnum {Null, One, Two}
+
+    PROP(TestEnum::Test testEnum)
+    PROP(ClassEnum classEnum)
+
+    PROP(int prop1);
+    PROP(double prop2);
+
+    CLASS childProp(TestChildClass);
+
+    SLOT(bool slot1());
+    SLOT(QString slot2());
+
+    SIGNAL(signal1());
+    SIGNAL(signal2());
+
+    SLOT(void ping(const QString &message));
+    SIGNAL(pong(const QString &message));
+
+    SLOT(bool quit());
+};
diff --git a/tests/auto/repc/signature/signatureServer/CMakeLists.txt b/tests/auto/repc/signature/signatureServer/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c23a308
--- /dev/null
@@ -0,0 +1,22 @@
+
+#####################################################################
+## signatureServer Binary:
+#####################################################################
+
+qt_internal_add_executable(signatureServer
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        ${CMAKE_CURRENT_BINARY_DIR}/rep_server_source.h
+        main.cpp
+    INCLUDE_DIRECTORIES
+        ${CMAKE_CURRENT_SOURCE_DIR}
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+qt6_add_repc_sources(signatureServer
+    ../server.rep
+)
+
+#### Keys ignored in scope 1:.:.:signatureServer.pro:<TRUE>:
+# TEMPLATE = "app"
diff --git a/tests/auto/repc/signature/signatureServer/main.cpp b/tests/auto/repc/signature/signatureServer/main.cpp
new file mode 100644 (file)
index 0000000..9db2540
--- /dev/null
@@ -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: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$
+**
+****************************************************************************/
+
+#include "rep_server_source.h"
+
+#include <QCoreApplication>
+#include <QtTest/QtTest>
+
+class MyTestServer : public TestClassSimpleSource
+{
+    Q_OBJECT
+public:
+    bool shouldQuit = false;
+    // TestClassSimpleSource interface
+public slots:
+    bool slot1() override {return true;}
+    QString slot2() override {return QLatin1String("Hello there");}
+    void ping(const QString &message) override
+    {
+        emit pong(message);
+    }
+
+    bool quit() override
+    {
+        qDebug() << "quit() called";
+
+        return shouldQuit = true;
+    }
+};
+
+class tst_Server_Process : public QObject
+{
+    Q_OBJECT
+
+private Q_SLOTS:
+    void testRun()
+    {
+        QRemoteObjectHost srcNode(QUrl(QStringLiteral("tcp://127.0.0.1:65214")));
+        MyTestServer myTestServer{};
+        TestChildClassSimpleSource child;
+        myTestServer.setChildProp(&child);
+
+        srcNode.enableRemoting(&myTestServer);
+
+        qDebug() << "Waiting for incoming connections";
+
+        QTRY_VERIFY_WITH_TIMEOUT(myTestServer.shouldQuit, 20000); // wait up to 20s
+
+        qDebug() << "Stopping server";
+        QTest::qWait(200); // wait for server to send reply to client invoking quit() function
+    }
+};
+
+QTEST_MAIN(tst_Server_Process)
+
+#include "main.moc"
diff --git a/tests/auto/repc/signature/signatureTests/CMakeLists.txt b/tests/auto/repc/signature/signatureTests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..621f212
--- /dev/null
@@ -0,0 +1,12 @@
+
+#####################################################################
+## tst_signature Test:
+#####################################################################
+
+qt_internal_add_test(tst_signature
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        tst_signature.cpp
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+)
diff --git a/tests/auto/repc/signature/signatureTests/tst_signature.cpp b/tests/auto/repc/signature/signatureTests/tst_signature.cpp
new file mode 100644 (file)
index 0000000..ee1e9fb
--- /dev/null
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include "../../../../shared/testutils.h"
+
+#include <QtTest/QtTest>
+#include <QMetaType>
+#include <QProcess>
+
+typedef QLatin1String _;
+class tst_Signature: public QObject
+{
+    Q_OBJECT
+
+private slots:
+    void initTestCase()
+    {
+        QVERIFY(TestUtils::init("signatureTests"));
+        QLoggingCategory::setFilterRules("qt.remoteobjects.warning=false");
+    }
+
+    void cleanup()
+    {
+        // wait for delivery of RemoveObject events to the source
+        QTest::qWait(200);
+    }
+
+    void testRun()
+    {
+        qDebug() << "Starting signatureServer process";
+        QProcess serverProc;
+        serverProc.setProcessChannelMode(QProcess::ForwardedChannels);
+        serverProc.start(TestUtils::findExecutable("signatureServer", "/signatureServer"),
+                         QStringList());
+        QVERIFY(serverProc.waitForStarted());
+
+        // wait for server start
+        QTest::qWait(200);
+
+        const QLatin1String tests[] = {
+            _("differentGlobalEnum"),
+            _("differentClassEnum"),
+            _("differentPropertyCount"),
+            _("differentPropertyCountChild"),
+            _("differentPropertyType"),
+            _("scrambledProperties"),
+            _("differentSlotCount"),
+            _("differentSlotType"),
+            _("differentSlotParamCount"),
+            _("differentSlotParamType"),
+            _("scrambledSlots"),
+            _("differentSignalCount"),
+            _("differentSignalParamCount"),
+            _("differentSignalParamType"),
+            _("scrambledSignals"),
+            _("state"),
+            _("matchAndQuit"), // matchAndQuit should be the last one
+        };
+
+        for (const auto &test : tests) {
+            qDebug() << "Starting" << test << "process";
+            QProcess testProc;
+            testProc.setProcessChannelMode(QProcess::ForwardedChannels);
+            testProc.start(TestUtils::findExecutable(test, "/" + test ),
+                           QStringList());
+            QVERIFY(testProc.waitForStarted());
+            QVERIFY(testProc.waitForFinished());
+            QCOMPARE(testProc.exitCode(), 0);
+        }
+
+        QVERIFY(serverProc.waitForFinished());
+        QCOMPARE(serverProc.exitCode(), 0);
+    }
+};
+
+QTEST_MAIN(tst_Signature)
+
+#include "tst_signature.moc"
diff --git a/tests/auto/repc/signature/state/CMakeLists.txt b/tests/auto/repc/signature/state/CMakeLists.txt
new file mode 100644 (file)
index 0000000..fb31d88
--- /dev/null
@@ -0,0 +1,21 @@
+
+#####################################################################
+## state Binary:
+#####################################################################
+
+qt_internal_add_executable(state
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        main.cpp
+    INCLUDE_DIRECTORIES
+        ${CMAKE_CURRENT_SOURCE_DIR}
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+qt6_add_repc_replicas(state
+    mismatch.rep
+)
+
+#### Keys ignored in scope 1:.:.:state.pro:<TRUE>:
+# TEMPLATE = "app"
diff --git a/tests/auto/repc/signature/state/main.cpp b/tests/auto/repc/signature/state/main.cpp
new file mode 100644 (file)
index 0000000..197a3d5
--- /dev/null
@@ -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: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$
+**
+****************************************************************************/
+
+#include "rep_mismatch_replica.h"
+
+#include <QCoreApplication>
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtTest/QtTest>
+
+class tst_State_Process : public QObject
+{
+    Q_OBJECT
+
+private Q_SLOTS:
+    void testMismatch()
+    {
+        QRemoteObjectNode repNode;
+        repNode.connectToNode(QUrl{QStringLiteral("tcp://127.0.0.1:65214")});
+        QSharedPointer<TestClassReplica> rep{repNode.acquire<TestClassReplica>()};
+        QSignalSpy stateChangedSpy(rep.data(), &QRemoteObjectReplica::stateChanged);
+        QTRY_COMPARE(rep->state(), QRemoteObjectReplica::SignatureMismatch);
+        QCOMPARE(stateChangedSpy.count(), 1);
+        auto args = stateChangedSpy.takeFirst();
+        QCOMPARE(args.count(), 2);
+        QCOMPARE(args.at(0).toInt(), int(QRemoteObjectReplica::SignatureMismatch));
+        QCOMPARE(args.at(1).toInt(), int(QRemoteObjectReplica::Default));
+    }
+
+    void testDynamic()
+    {
+        QRemoteObjectNode repNode;
+        repNode.connectToNode(QUrl{QStringLiteral("tcp://127.0.0.1:65214")});
+        QSharedPointer<QRemoteObjectDynamicReplica> rep{repNode.acquireDynamic("TestClass")};
+        QSignalSpy stateChangedSpy(rep.data(), &QRemoteObjectReplica::stateChanged);
+        QTRY_COMPARE(rep->state(), QRemoteObjectReplica::Valid);
+        QCOMPARE(stateChangedSpy.count(), 1);
+        auto args = stateChangedSpy.takeFirst();
+        QCOMPARE(args.count(), 2);
+        QCOMPARE(args.at(0).toInt(), int(QRemoteObjectReplica::Valid));
+        QCOMPARE(args.at(1).toInt(), int(QRemoteObjectReplica::Uninitialized));
+    }
+};
+
+QTEST_MAIN(tst_State_Process)
+
+#include "main.moc"
diff --git a/tests/auto/repc/signature/state/mismatch.rep b/tests/auto/repc/signature/state/mismatch.rep
new file mode 100644 (file)
index 0000000..17851ce
--- /dev/null
@@ -0,0 +1,31 @@
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+    PROP(int prop1);
+    PROP(double prop2);
+};
+
+class TestClass
+{
+    ENUM ClassEnum {Null, One, Two}
+
+    PROP(TestEnum::Test testEnum)
+    PROP(ClassEnum classEnum)
+
+    PROP(int prop1);
+    PROP(double prop2);
+
+    CLASS childProp(TestChildClass);
+
+    SLOT(QString slot2());
+    SLOT(bool slot1());
+
+    SIGNAL(signal1());
+    SIGNAL(signal2());
+
+    SLOT(void ping(const QString &message));
+    SIGNAL(pong(const QString &message));
+
+    SLOT(bool quit());
+};
diff --git a/tests/auto/repcodegenerator/CMakeLists.txt b/tests/auto/repcodegenerator/CMakeLists.txt
new file mode 100644 (file)
index 0000000..2033a49
--- /dev/null
@@ -0,0 +1,19 @@
+
+#####################################################################
+## tst_repcodegenerator Test:
+#####################################################################
+
+qt_internal_add_test(tst_repcodegenerator
+    SOURCES
+        tst_repcodegenerator.cpp
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+)
+qt6_add_repc_merged(tst_repcodegenerator
+    classwithsignalonlytest.rep
+    preprocessortest.rep
+    classwithreadonlypropertytest.rep
+)
+
+## Scopes:
+#####################################################################
diff --git a/tests/auto/repcodegenerator/classwithreadonlypropertytest.rep b/tests/auto/repcodegenerator/classwithreadonlypropertytest.rep
new file mode 100644 (file)
index 0000000..c713c23
--- /dev/null
@@ -0,0 +1,4 @@
+class MyReadOnlyPropClass
+{
+    PROP(bool myProp READONLY)
+}
diff --git a/tests/auto/repcodegenerator/classwithsignalonlytest.rep b/tests/auto/repcodegenerator/classwithsignalonlytest.rep
new file mode 100644 (file)
index 0000000..46452e4
--- /dev/null
@@ -0,0 +1,4 @@
+class MyClass
+{
+    SIGNAL(mySignal(int))
+}
diff --git a/tests/auto/repcodegenerator/preprocessortest.rep b/tests/auto/repcodegenerator/preprocessortest.rep
new file mode 100644 (file)
index 0000000..6e44c08
--- /dev/null
@@ -0,0 +1,3 @@
+#include <QString>
+
+#define PREPROCESSORTEST_MACRO 1
diff --git a/tests/auto/repcodegenerator/tst_repcodegenerator.cpp b/tests/auto/repcodegenerator/tst_repcodegenerator.cpp
new file mode 100644 (file)
index 0000000..abf007a
--- /dev/null
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include "rep_preprocessortest_merged.h"
+
+#include <QTest>
+
+class tst_RepCodeGenerator : public QObject {
+    Q_OBJECT
+
+private Q_SLOTS:
+    void testPreprocessorTestFile();
+};
+
+void tst_RepCodeGenerator::testPreprocessorTestFile()
+{
+    // could be a compile-time test, but let's just do something here
+    QVERIFY(PREPROCESSORTEST_MACRO);
+}
+
+QTEST_APPLESS_MAIN(tst_RepCodeGenerator)
+
+#include "tst_repcodegenerator.moc"
diff --git a/tests/auto/repfiles/localdatacenter.rep b/tests/auto/repfiles/localdatacenter.rep
new file mode 100644 (file)
index 0000000..0ea7c68
--- /dev/null
@@ -0,0 +1,8 @@
+class LocalDataCenter
+{
+    PROP(int data1);
+    PROP(float data2);
+    PROP(QString data3);
+    PROP(QList<int> data4);
+    SIGNAL(callMe(QList<int> fun));
+};
diff --git a/tests/auto/repfiles/tcpdatacenter.rep b/tests/auto/repfiles/tcpdatacenter.rep
new file mode 100644 (file)
index 0000000..9e3b207
--- /dev/null
@@ -0,0 +1,7 @@
+class TcpDataCenter
+{
+    PROP(int data1);
+    PROP(float data2);
+    PROP(QString data3);
+    PROP(QList<int> data4);
+};
diff --git a/tests/auto/repparser/CMakeLists.txt b/tests/auto/repparser/CMakeLists.txt
new file mode 100644 (file)
index 0000000..a23e0dc
--- /dev/null
@@ -0,0 +1,29 @@
+#####################################################################
+## tst_parser Test:
+#####################################################################
+
+set(REPPARSER_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../src/repparser")
+
+qt_internal_add_test(tst_parser
+    SOURCES
+        tst_parser.cpp
+    INCLUDE_DIRECTORIES
+        ${REPPARSER_DIR}
+    PUBLIC_LIBRARIES
+        Qt::CorePrivate
+)
+
+# QLALR Grammars:
+qt_process_qlalr(
+    tst_parser
+    ${REPPARSER_DIR}/parser.g
+    ""
+)
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(tst_parser CONDITION MSVC
+    COMPILE_OPTIONS
+        /wd4129
+)
diff --git a/tests/auto/repparser/tst_parser.cpp b/tests/auto/repparser/tst_parser.cpp
new file mode 100644 (file)
index 0000000..14b93dd
--- /dev/null
@@ -0,0 +1,661 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include "repparser.h"
+
+#include <QTemporaryFile>
+#include <QTest>
+#include <QTextStream>
+
+Q_DECLARE_METATYPE(ASTProperty::Modifier)
+Q_DECLARE_METATYPE(ASTModelRole)
+
+class tst_Parser : public QObject {
+    Q_OBJECT
+
+private Q_SLOTS:
+    void testBasic_data();
+    void testBasic();
+    void testProperties_data();
+    void testProperties();
+    void testSlots_data();
+    void testSlots();
+    void testSignals_data();
+    void testSignals();
+    void testPods_data();
+    void testPods();
+    void testPods2_data();
+    void testPods2();
+    void testEnums_data();
+    void testEnums();
+    void testTypedEnums_data();
+    void testTypedEnums();
+    void testModels_data();
+    void testModels();
+    void testClasses_data();
+    void testClasses();
+    void testInvalid_data();
+    void testInvalid();
+};
+
+void tst_Parser::testBasic_data()
+{
+    QTest::addColumn<QString>("content");
+
+    //Comment out "empty" tests that fail QLALR parser...
+    //QTest::newRow("empty") << ""; // empty lines are fine...
+    QTest::newRow("preprocessor_line_include") << "#include \"foo\"";
+    QTest::newRow("preprocessor_line_include_spaces") << "#  include \"foo\"";
+    QTest::newRow("preprocessor_line_ifgroup") << "#if 1\n#include \"foo\n#endif";
+    //QTest::newRow("comment") << "//This is a comment";
+    QTest::newRow("enum") << "ENUM MyEnum {test}";
+    QTest::newRow("empty class with comment") << "class MyClass {\n//comment\n}";
+    QTest::newRow("comment, class") << "//comment\nclass MyClass {}";
+    QTest::newRow("include, comment, class") << "#include \"foo\"\n//comment\nclass MyClass {}";
+}
+
+void tst_Parser::testBasic()
+{
+    QFETCH(QString, content);
+
+    QTemporaryFile file;
+    file.open();
+    QTextStream stream(&file);
+    stream << content << Qt::endl;
+    file.seek(0);
+
+    RepParser parser(file);
+    QVERIFY(parser.parse());
+}
+
+void tst_Parser::testProperties_data()
+{
+    QTest::addColumn<QString>("propertyDeclaration");
+    QTest::addColumn<QString>("expectedType");
+    QTest::addColumn<QString>("expectedName");
+    QTest::addColumn<QString>("expectedDefaultValue");
+    QTest::addColumn<ASTProperty::Modifier>("expectedModifier");
+    QTest::addColumn<bool>("expectedPersistence");
+
+    QTest::newRow("default") << "PROP(QString foo)" << "QString" << "foo" << QString() << ASTProperty::ReadPush << false;
+    QTest::newRow("default with comment") << "PROP(QString foo) // my property" << "QString" << "foo" << QString() << ASTProperty::ReadPush << false;
+    QTest::newRow("default with comment above") << "// my property\nPROP(QString foo)" << "QString" << "foo" << QString() << ASTProperty::ReadPush << false;
+    QTest::newRow("default with indented comment above") << "    // my property\nPROP(QString foo)" << "QString" << "foo" << QString() << ASTProperty::ReadPush << false;
+    QTest::newRow("readonly") << "PROP(QString foo READONLY)" << "QString" << "foo" << QString() << ASTProperty::ReadOnly << false;
+    QTest::newRow("constant") << "PROP(QString foo CONSTANT)" << "QString" << "foo" << QString() << ASTProperty::Constant << false;
+    QTest::newRow("readwrite") << "PROP(QString foo READWRITE)" << "QString" << "foo" << QString() << ASTProperty::ReadWrite << false;
+    QTest::newRow("readpush") << "PROP(QString foo READPUSH)" << "QString" << "foo" << QString() << ASTProperty::ReadPush << false;
+    QTest::newRow("persisted") << "PROP(QString foo PERSISTED)" << "QString" << "foo" << QString() << ASTProperty::ReadPush << true;
+    QTest::newRow("readonly, persisted") << "PROP(QString foo READONLY, PERSISTED)" << "QString" << "foo" << QString() << ASTProperty::ReadOnly << true;
+    QTest::newRow("readwrite, persisted") << "PROP(QString foo READWRITE, PERSISTED)" << "QString" << "foo" << QString() << ASTProperty::ReadWrite << true;
+    QTest::newRow("readpush, persisted") << "PROP(QString foo READPUSH, PERSISTED)" << "QString" << "foo" << QString() << ASTProperty::ReadPush << true;
+    QTest::newRow("constant,persisted") << "PROP(QString foo CONSTANT, PERSISTED)" << "QString" << "foo" << QString() << ASTProperty::Constant << true;
+    QTest::newRow("constant,readonly,persisted") << "PROP(QString foo CONSTANT, READONLY, PERSISTED)" << "QString" << "foo" << QString() << ASTProperty::Constant << true;
+    QTest::newRow("readonly,constant,persisted") << "PROP(QString foo READONLY,CONSTANT, PERSISTED)" << "QString" << "foo" << QString() << ASTProperty::Constant << true;
+    QTest::newRow("defaultWithValue") << "PROP(int foo=1)" << "int" << "foo" << "1" << ASTProperty::ReadPush << false;
+    QTest::newRow("readonlyWithValue") << "PROP(int foo=1 READONLY)" << "int" << "foo" << "1" << ASTProperty::ReadOnly << false;
+    QTest::newRow("constantWithValue") << "PROP(int foo=1 CONSTANT)" << "int" << "foo" << "1" << ASTProperty::Constant << false;
+    QTest::newRow("defaultWhitespaces") << "PROP(  QString   foo  )" << "QString" << "foo" << QString() << ASTProperty::ReadPush << false;
+    QTest::newRow("defaultWhitespacesBeforeParentheses") << "PROP     (  QString   foo  )" << "QString" << "foo" << QString() << ASTProperty::ReadPush << false;
+    QTest::newRow("readonlyWhitespaces") << "PROP(  QString   foo   READONLY  )" << "QString" << "foo" << QString() << ASTProperty::ReadOnly << false;
+    QTest::newRow("constantWhitespaces") << "PROP(  QString   foo   CONSTANT  )" << "QString" << "foo" << QString() << ASTProperty::Constant << false;
+    QTest::newRow("defaultWithValueWhitespaces") << "PROP(  int foo  = 1 )" << "int" << "foo" << "1" << ASTProperty::ReadPush << false;
+    QTest::newRow("readonlyWithValueWhitespaces") << "PROP(  int foo = 1 READONLY  )" << "int" << "foo" << "1" << ASTProperty::ReadOnly << false;
+    QTest::newRow("constantWithValueWhitespaces") << "PROP(  int foo = 1 CONSTANT )" << "int" << "foo" << "1" << ASTProperty::Constant << false;
+    QTest::newRow("templatetype") << "PROP(QList<int> bar)" << "QList<int>" << "bar" << QString() << ASTProperty::ReadPush << false;
+    QTest::newRow("nested templatetype") << "PROP(QMap<int, QList<int>> bar)" << "QMap<int, QList<int>>" << "bar" << QString() << ASTProperty::ReadPush << false;
+    QTest::newRow("non-int default value") << "PROP(double foo=1.1 CONSTANT)" << "double" << "foo" << "1.1" << ASTProperty::Constant << false;
+    QTest::newRow("tab") << "PROP(double\tfoo)" << "double" << "foo" << "" << ASTProperty::ReadPush << false;
+    QTest::newRow("two tabs") << "PROP(double\t\tfoo)" << "double" << "foo" << "" << ASTProperty::ReadPush << false;
+    QTest::newRow("stringWithValue") << "PROP(QString foo=\"Hello World\")" << "QString" << "foo"
+                                     << QString("\"Hello World\"") << ASTProperty::ReadPush << false;
+    QTest::newRow("stringWithValueWhitespaces") << "PROP(QString foo   =   \"Hello   World\")"
+                                                << "QString" << "foo" << QString("\"Hello   World\"")
+                                                << ASTProperty::ReadPush << false;
+    QTest::newRow("readonlyStringWithValueWhitespaces") << "PROP(QString foo   =   \"Hello   World\"   READONLY  )"
+                                                        << "QString" << "foo" << "\"Hello   World\""
+                                                        << ASTProperty::ReadOnly << false;
+    QTest::newRow("readonlyStringWithValue") << "PROP(QString foo=\"Hello World\" READONLY)"
+                                             << "QString" << "foo" << "\"Hello World\""
+                                             << ASTProperty::ReadOnly << false;
+}
+
+void tst_Parser::testProperties()
+{
+    QFETCH(QString, propertyDeclaration);
+    QFETCH(QString, expectedType);
+    QFETCH(QString, expectedName);
+    QFETCH(QString, expectedDefaultValue);
+    QFETCH(ASTProperty::Modifier, expectedModifier);
+    QFETCH(bool, expectedPersistence);
+
+    QTemporaryFile file;
+    file.open();
+    QTextStream stream(&file);
+    stream << "class TestClass" << Qt::endl;
+    stream << "{" << Qt::endl;
+    stream << propertyDeclaration << Qt::endl;
+    stream << "};" << Qt::endl;
+    file.seek(0);
+
+    RepParser parser(file);
+    QVERIFY(parser.parse());
+
+    const AST ast = parser.ast();
+    QCOMPARE(ast.classes.count(), 1);
+
+    const ASTClass astClass = ast.classes.first();
+    const QList<ASTProperty> properties = astClass.properties;
+    QCOMPARE(properties.count(), 1);
+
+    const ASTProperty property = properties.first();
+    QCOMPARE(property.type, expectedType);
+    QCOMPARE(property.name, expectedName);
+    QCOMPARE(property.defaultValue, expectedDefaultValue);
+    QCOMPARE(property.modifier, expectedModifier);
+    QCOMPARE(property.persisted, expectedPersistence);
+}
+
+void tst_Parser::testSlots_data()
+{
+    QTest::addColumn<QString>("slotDeclaration");
+    QTest::addColumn<QString>("expectedSlot");
+    QTest::addColumn<bool>("voidWarning");
+    QTest::newRow("slotwithoutspacebeforeparentheses") << "SLOT(test())" << "void test()" << true;
+    QTest::newRow("slotwithspacebeforeparentheses") << "SLOT (test())" << "void test()" << true;
+    QTest::newRow("slotwitharguments") << "SLOT(void test(QString value, int number))" << "void test(QString value, int number)" << false;
+    QTest::newRow("slotwithunnamedarguments") << "SLOT(void test(QString, int))" << "void test(QString __repc_variable_1, int __repc_variable_2)" << false;
+    QTest::newRow("slotwithspaces") << "SLOT(   void test  (QString value, int number)  )" << "void test(QString value, int number)" << false;
+    QTest::newRow("slotwithtemplates") << "SLOT(test(QMap<QString,int> foo))" << "void test(QMap<QString,int> foo)" << true;
+    QTest::newRow("slotwithmultitemplates") << "SLOT(test(QMap<QString,int> foo, QMap<QString,int> bla))" << "void test(QMap<QString,int> foo, QMap<QString,int> bla)" << true;
+    QTest::newRow("slotwithtemplatetemplates") << "SLOT(test(QMap<QList<QString>,int> foo))" << "void test(QMap<QList<QString>,int> foo)" << true;
+    QTest::newRow("slotwithtemplateswithspace") << "SLOT ( test (QMap<QString , int>  foo ) )" << "void test(QMap<QString , int> foo)" << true;
+    QTest::newRow("slotWithConstRefArgument") << "SLOT (test(const QString &val))" << "void test(const QString & val)" << true;
+    QTest::newRow("slotWithRefArgument") << "SLOT (test(QString &val))" << "void test(QString & val)" << true;
+    QTest::newRow("slotwithtemplatetemplatesAndConstRef") << "SLOT(test(const QMap<QList<QString>,int> &foo))" << "void test(const QMap<QList<QString>,int> & foo)" << true;
+    QTest::newRow("slotWithConstRefArgumentAndWithout") << "SLOT (test(const QString &val, int value))" << "void test(const QString & val, int value)" << true;
+}
+
+void tst_Parser::testSlots()
+{
+    QFETCH(QString, slotDeclaration);
+    QFETCH(QString, expectedSlot);
+    QFETCH(bool, voidWarning);
+
+    QTemporaryFile file;
+    file.open();
+    QTextStream stream(&file);
+    stream << "class TestClass" << Qt::endl;
+    stream << "{" << Qt::endl;
+    stream << slotDeclaration << Qt::endl;
+    stream << "};" << Qt::endl;
+    file.seek(0);
+
+    if (voidWarning)
+        QTest::ignoreMessage(QtWarningMsg, "[repc] - Adding 'void' for unspecified return type on test");
+    RepParser parser(file);
+    QVERIFY(parser.parse());
+
+    const AST ast = parser.ast();
+    QCOMPARE(ast.classes.count(), 1);
+
+    const ASTClass astClass = ast.classes.first();
+    const QList<ASTFunction> slotsList = astClass.slotsList;
+    QCOMPARE(slotsList.count(), 1);
+    ASTFunction slot = slotsList.first();
+    QCOMPARE(QString("%1 %2(%3)").arg(slot.returnType).arg(slot.name).arg(slot.paramsAsString()), expectedSlot);
+}
+
+void tst_Parser::testSignals_data()
+{
+    QTest::addColumn<QString>("signalDeclaration");
+    QTest::addColumn<QString>("expectedSignal");
+    QTest::newRow("signalwithoutspacebeforeparentheses") << "SIGNAL(test())" << "test()";
+    QTest::newRow("signalwithspacebeforeparentheses") << "SIGNAL (test())" << "test()";
+    QTest::newRow("signalwitharguments") << "SIGNAL(test(QString value, int value))" << "test(QString value, int value)";
+    QTest::newRow("signalwithtemplates") << "SIGNAL(test(QMap<QString,int> foo))" << "test(QMap<QString,int> foo)";
+    QTest::newRow("signalwithtemplateswithspace") << "SIGNAL ( test (QMap<QString , int>  foo ) )" << "test(QMap<QString , int> foo)";
+    QTest::newRow("signalWithConstRefArgument") << "SIGNAL (test(const QString &val))" << "test(const QString & val)";
+    QTest::newRow("signalWithRefArgument") << "SIGNAL (test(QString &val))" << "test(QString & val)";
+}
+
+void tst_Parser::testSignals()
+{
+    QFETCH(QString, signalDeclaration);
+    QFETCH(QString, expectedSignal);
+
+    QTemporaryFile file;
+    file.open();
+    QTextStream stream(&file);
+    stream << "class TestClass" << Qt::endl;
+    stream << "{" << Qt::endl;
+    stream << signalDeclaration << Qt::endl;
+    stream << "};" << Qt::endl;
+    file.seek(0);
+
+    RepParser parser(file);
+    QVERIFY(parser.parse());
+
+    const AST ast = parser.ast();
+    QCOMPARE(ast.classes.count(), 1);
+
+    const ASTClass astClass = ast.classes.first();
+    const QList<ASTFunction> signalsList = astClass.signalsList;
+    ASTFunction signal = signalsList.first();
+    QCOMPARE(QString("%1(%2)").arg(signal.name).arg(signal.paramsAsString()), expectedSignal);
+}
+
+void tst_Parser::testPods_data()
+{
+    QTest::addColumn<QString>("podsdeclaration");
+    QTest::addColumn<QString>("expectedtypes");
+    QTest::addColumn<QString>("expectedvariables");
+
+    //Variable/Type separate by ";"
+    QTest::newRow("one pod") << "POD preset(int presetNumber)" << "int" << "presetNumber";
+    QTest::newRow("two pod") << "POD preset(int presetNumber, double foo)" << "int;double" << "presetNumber;foo";
+    QTest::newRow("two pod with space") << "POD preset ( int presetNumber , double foo ) " << "int;double" << "presetNumber;foo";
+    QTest::newRow("two pod multiline") << "POD preset(\nint presetNumber,\ndouble foo\n)" << "int;double" << "presetNumber;foo";
+    //Template
+    QTest::newRow("pod template") << "POD preset(QMap<QString,int> foo) " << "QMap<QString,int>" << "foo";
+    QTest::newRow("pod template (QList)") << "POD preset(QList<QString> foo) " << "QList<QString>" << "foo";
+    QTest::newRow("two pod template") << "POD preset(QMap<QString,int> foo, QMap<double,int> bla) " << "QMap<QString,int>;QMap<double,int>" << "foo;bla";
+    QTest::newRow("two pod template with space") << "POD preset( QMap<QString  ,  int >  foo ,   QMap<  double , int > bla ) " << "QMap<QString  ,  int >;QMap<  double , int >" << "foo;bla";
+
+}
+
+void tst_Parser::testPods()
+{
+    QFETCH(QString, podsdeclaration);
+    QFETCH(QString, expectedtypes);
+    QFETCH(QString, expectedvariables);
+
+    QTemporaryFile file;
+    file.open();
+    QTextStream stream(&file);
+    stream << podsdeclaration << Qt::endl;
+    stream << "class TestClass" << Qt::endl;
+    stream << "{" << Qt::endl;
+    stream << "};" << Qt::endl;
+    file.seek(0);
+
+    RepParser parser(file);
+    QVERIFY(parser.parse());
+
+    const AST ast = parser.ast();
+    QCOMPARE(ast.classes.count(), 1);
+
+    QCOMPARE(ast.pods.count(), 1);
+    const POD pods = ast.pods.first();
+    const QList<PODAttribute> podsList = pods.attributes;
+    const QStringList typeList = expectedtypes.split(QLatin1Char(';'));
+    const QStringList variableList = expectedvariables.split(QLatin1Char(';'));
+    QVERIFY(typeList.count() == variableList.count());
+    QVERIFY(podsList.count() == variableList.count());
+    for (int i=0; i < podsList.count(); ++i) {
+        QCOMPARE(podsList.at(i).name, variableList.at(i));
+        QCOMPARE(podsList.at(i).type, typeList.at(i));
+    }
+}
+
+void tst_Parser::testPods2_data()
+{
+    QTest::addColumn<QString>("podsdeclaration");
+    QTest::addColumn<QString>("expectedtypes");
+    QTest::addColumn<QString>("expectedvariables");
+
+    //Variable/Type separate by ";"
+    QTest::newRow("one pod") << "POD preset{int presetNumber}" << "int" << "presetNumber";
+    QTest::newRow("two pod") << "POD preset{int presetNumber, double foo}" << "int;double" << "presetNumber;foo";
+    QTest::newRow("two pod with space") << "POD preset { int presetNumber , double foo } " << "int;double" << "presetNumber;foo";
+    QTest::newRow("two pod multiline") << "POD preset{\nint presetNumber,\ndouble foo\n}" << "int;double" << "presetNumber;foo";
+    //Template
+    QTest::newRow("pod template") << "POD preset{QMap<QString,int> foo} " << "QMap<QString,int>" << "foo";
+    QTest::newRow("pod template (QList)") << "POD preset{QList<QString> foo} " << "QList<QString>" << "foo";
+    QTest::newRow("two pod template") << "POD preset{QMap<QString,int> foo, QMap<double,int> bla} " << "QMap<QString,int>;QMap<double,int>" << "foo;bla";
+    QTest::newRow("two pod template with space") << "POD preset{ QMap<QString  ,  int >  foo ,   QMap<  double , int > bla } " << "QMap<QString,int>;QMap<double,int>" << "foo;bla";
+    //Enum
+    QTest::newRow("enum multiline") << "POD preset{ENUM val {val1 = 1,\nval2,\nval3=12}\nval value,\ndouble foo\n}" << "val;double" << "value;foo";
+
+}
+
+void tst_Parser::testPods2()
+{
+    QFETCH(QString, podsdeclaration);
+    QFETCH(QString, expectedtypes);
+    QFETCH(QString, expectedvariables);
+
+    QTemporaryFile file;
+    file.open();
+    QTextStream stream(&file);
+    stream << podsdeclaration << Qt::endl;
+    stream << "class TestClass" << Qt::endl;
+    stream << "{" << Qt::endl;
+    stream << "};" << Qt::endl;
+    file.seek(0);
+
+    RepParser parser(file);
+    QVERIFY(parser.parse());
+
+    const AST ast = parser.ast();
+    QCOMPARE(ast.classes.count(), 1);
+
+    QCOMPARE(ast.pods.count(), 1);
+    const POD pods = ast.pods.first();
+    const QVector<PODAttribute> podsList = pods.attributes;
+    const QStringList typeList = expectedtypes.split(QLatin1Char(';'));
+    const QStringList variableList = expectedvariables.split(QLatin1Char(';'));
+    QVERIFY(typeList.count() == variableList.count());
+    QVERIFY(podsList.count() == variableList.count());
+    for (int i=0; i < podsList.count(); ++i) {
+        QCOMPARE(podsList.at(i).name, variableList.at(i));
+        QCOMPARE(podsList.at(i).type, typeList.at(i));
+    }
+}
+
+void tst_Parser::testEnums_data()
+{
+    QTest::addColumn<QString>("enumdeclaration");
+    QTest::addColumn<QString>("expectednames");
+    QTest::addColumn<QList<int> >("expectedvalues");
+    QTest::addColumn<int>("expectedmax");
+    QTest::addColumn<bool>("expectedsigned");
+    QTest::addColumn<bool>("inclass");
+
+    for (int i = 0; i <= 1; ++i) {
+        bool inclass = i == 1;
+        QString identifier = inclass ? QLatin1String("%1 in class") : QLatin1String("%1 outside class");
+        //Separate by ";"
+        QTest::newRow(identifier.arg("one enum val").toLatin1()) << "ENUM preset {presetNumber}" << "presetNumber" << (QList<int>() << 0) << 0 << false << inclass;
+        QTest::newRow(identifier.arg("two enum val").toLatin1()) << "ENUM preset {presetNumber, foo}" << "presetNumber;foo" << (QList<int>() << 0 << 1) << 1 << false << inclass;
+        QTest::newRow(identifier.arg("two enum val -1 2nd").toLatin1()) << "ENUM preset {presetNumber, foo = -1}" << "presetNumber;foo" << (QList<int>() << 0 << -1) << 1 << true << inclass;
+        QTest::newRow(identifier.arg("two enum val -1 1st").toLatin1()) << "ENUM preset {presetNumber=-1, foo}" << "presetNumber;foo" << (QList<int>() << -1 << 0) << 1 << true << inclass;
+        QTest::newRow(identifier.arg("two enum val hex").toLatin1()) << "ENUM preset {presetNumber=0xf, foo}" << "presetNumber;foo" << (QList<int>() << 15 << 16) << 16 << false << inclass;
+        QTest::newRow(identifier.arg("two enum val hex").toLatin1()) << "ENUM preset {presetNumber=0xff, foo}" << "presetNumber;foo" << (QList<int>() << 255 << 256) << 256 << false << inclass;
+        QTest::newRow(identifier.arg("two enum val with space").toLatin1()) << "ENUM preset { presetNumber ,  foo } " << "presetNumber;foo" << (QList<int>() << 0 << 1) << 1 << false << inclass;
+        QTest::newRow(identifier.arg("set values").toLatin1()) << "ENUM preset { val1=1 , val3=3, val5=5 } " << "val1;val3;val5" << (QList<int>() << 1 << 3 << 5) << 5 << false << inclass;
+        QTest::newRow(identifier.arg("multiline").toLatin1()) << "ENUM preset {\nval1,\nval2,\nval3\n} " << "val1;val2;val3" << (QList<int>() << 0 << 1 << 2) << 2 << false << inclass;
+        QTest::newRow(identifier.arg("multiline indented").toLatin1()) << "    ENUM preset {\n        val1,\n        val2,\n        val3\n    } " << "val1;val2;val3" << (QList<int>() << 0 << 1 << 2) << 2 << false << inclass;
+    }
+}
+
+void tst_Parser::testEnums()
+{
+    QFETCH(QString, enumdeclaration);
+    QFETCH(QString, expectednames);
+    QFETCH(QList<int>, expectedvalues);
+    QFETCH(int, expectedmax);
+    QFETCH(bool, expectedsigned);
+    QFETCH(bool, inclass);
+
+    QTemporaryFile file;
+    file.open();
+    QTextStream stream(&file);
+    if (!inclass)
+        stream << enumdeclaration << Qt::endl;
+    stream << "class TestClass" << Qt::endl;
+    stream << "{" << Qt::endl;
+    if (inclass)
+        stream << enumdeclaration << Qt::endl;
+    stream << "};" << Qt::endl;
+    file.seek(0);
+
+    RepParser parser(file);
+    QVERIFY(parser.parse());
+
+    const AST ast = parser.ast();
+    QCOMPARE(ast.classes.count(), 1);
+    ASTEnum enums;
+    if (inclass) {
+        const ASTClass astClass = ast.classes.first();
+        QCOMPARE(astClass.enums.count(), 1);
+        enums = astClass.enums.first();
+    } else {
+        QCOMPARE(ast.enums.count(), 1);
+        enums = ast.enums.first();
+    }
+    QVERIFY(enums.isScoped == false);
+    QVERIFY(enums.type.isEmpty());
+    const QList<ASTEnumParam> paramList = enums.params;
+    const QStringList nameList = expectednames.split(QLatin1Char(';'));
+    QVERIFY(nameList.count() == expectedvalues.count());
+    QVERIFY(paramList.count() == expectedvalues.count());
+    for (int i=0; i < paramList.count(); ++i) {
+        QCOMPARE(paramList.at(i).name, nameList.at(i));
+        QCOMPARE(paramList.at(i).value, expectedvalues.at(i));
+    }
+    QCOMPARE(enums.max, expectedmax);
+    QCOMPARE(enums.isSigned, expectedsigned);
+}
+
+void tst_Parser::testTypedEnums_data()
+{
+    QTest::addColumn<QString>("enumdeclaration");
+    QTest::addColumn<QString>("expectedtype");
+    QTest::addColumn<bool>("inclass");
+    QTest::addColumn<bool>("isscoped");
+    QTest::addColumn<bool>("isflag");
+
+    for (int i = 0; i <= 7; ++i) {
+        bool inclass = i % 2 == 1;
+        bool isscoped = i % 4 > 1;
+        bool isflag = i > 3;
+        QString identifier = inclass ? QLatin1String("%1 %2 %3 in class") : QLatin1String("%1 %2 %3 outside class");
+        QString scopeString = isscoped ? QLatin1String("Scoped") : QLatin1String("Non-scoped");
+        QString flagString = isflag ? QLatin1String("Flag") : QLatin1String("Enum");
+        QTest::newRow(identifier.arg(scopeString, flagString, "no type").toLatin1()) << "preset {presetNumber}" << QString() << inclass << isscoped << isflag;
+        QTest::newRow(identifier.arg(scopeString, flagString, "quint16").toLatin1()) << "preset : quint16 {presetNumber}" << "quint16" << inclass << isscoped << isflag;
+        QTest::newRow(identifier.arg(scopeString, flagString, "qint64").toLatin1()) << "preset : qint64 {presetNumber}" << "qint64" << inclass << isscoped << isflag;
+        QTest::newRow(identifier.arg(scopeString, flagString, "unsigned char").toLatin1()) << "preset: unsigned char {presetNumber}" << "unsigned char" << inclass << isscoped << isflag;
+    }
+}
+
+void tst_Parser::testTypedEnums()
+{
+    QFETCH(QString, enumdeclaration);
+    QFETCH(QString, expectedtype);
+    QFETCH(bool, inclass);
+    QFETCH(bool, isscoped);
+    QFETCH(bool, isflag);
+
+    QTemporaryFile file;
+    file.open();
+    QTextStream stream(&file);
+    if (!inclass) {
+        stream << "ENUM " << (isscoped ? "class " : "") << enumdeclaration << Qt::endl;
+        if (isflag)
+            stream << "FLAG(MyFlags preset)" << Qt::endl;
+    }
+    stream << "class TestClass" << Qt::endl;
+    stream << "{" << Qt::endl;
+    if (inclass) {
+        stream << "ENUM " << (isscoped ? "class " : "") << enumdeclaration << Qt::endl;
+        if (isflag)
+            stream << "FLAG(MyFlags preset)" << Qt::endl;
+    }
+    stream << "};" << Qt::endl;
+    file.seek(0);
+
+    RepParser parser(file);
+    QVERIFY(parser.parse());
+
+    const AST ast = parser.ast();
+    QCOMPARE(ast.classes.count(), 1);
+    ASTEnum enums;
+    ASTFlag flags;
+    if (inclass) {
+        const ASTClass astClass = ast.classes.first();
+        QCOMPARE(astClass.enums.count(), 1);
+        enums = astClass.enums.first();
+        if (isflag)
+            flags = astClass.flags.first();
+    } else {
+        QCOMPARE(ast.enums.count(), 1);
+        enums = ast.enums.first();
+        if (isflag)
+            flags = ast.flags.first();
+    }
+    QVERIFY(enums.isScoped == isscoped);
+    QVERIFY(enums.flagIndex == (isflag ? 0 : -1));
+    QVERIFY(flags.name == (isflag ? "MyFlags" : QString{}));
+    QVERIFY(flags._enum == (isflag ? "preset" : QString{}));
+    QCOMPARE(enums.type, expectedtype);
+    const QList<ASTEnumParam> paramList = enums.params;
+    QVERIFY(paramList.count() == 1);
+    for (int i=0; i < paramList.count(); ++i) {
+        QCOMPARE(paramList.at(i).name, "presetNumber");
+        QCOMPARE(paramList.at(i).value, 0);
+    }
+    QCOMPARE(enums.max, 0);
+    QCOMPARE(enums.isSigned, false);
+}
+
+void tst_Parser::testModels_data()
+{
+    QTest::addColumn<QString>("modelDeclaration");
+    QTest::addColumn<QString>("expectedModel");
+    QTest::addColumn<QList<ASTModelRole>>("expectedRoles");
+    QTest::newRow("basicmodel") << "MODEL test(display)" << "test" << QList<ASTModelRole>({{"display"}});
+    QTest::newRow("basicmodelsemicolon") << "MODEL test(display);" << "test" << QList<ASTModelRole>({{"display"}});
+}
+
+void tst_Parser::testModels()
+{
+    QFETCH(QString, modelDeclaration);
+    QFETCH(QString, expectedModel);
+    QFETCH(QList<ASTModelRole>, expectedRoles);
+
+    QTemporaryFile file;
+    file.open();
+    QTextStream stream(&file);
+    stream << "class TestClass" << Qt::endl;
+    stream << "{" << Qt::endl;
+    stream << modelDeclaration << Qt::endl;
+    stream << "};" << Qt::endl;
+    file.seek(0);
+
+    RepParser parser(file);
+    QVERIFY(parser.parse());
+
+    const AST ast = parser.ast();
+    QCOMPARE(ast.classes.count(), 1);
+
+    const ASTClass astClass = ast.classes.first();
+    ASTModel model = astClass.modelMetadata.first();
+    ASTProperty property = astClass.properties.at(model.propertyIndex);
+    QCOMPARE(property.name, expectedModel);
+    int i = 0;
+    for (auto role : model.roles) {
+        QCOMPARE(role.name, expectedRoles.at(i).name);
+        i++;
+    }
+}
+
+void tst_Parser::testClasses_data()
+{
+    QTest::addColumn<QString>("classDeclaration");
+    QTest::addColumn<QString>("expectedType");
+    QTest::addColumn<QString>("expectedName");
+    QTest::newRow("basicclass") << "CLASS sub(subObject)" << "subObject" << "sub";
+}
+
+void tst_Parser::testClasses()
+{
+    QFETCH(QString, classDeclaration);
+    QFETCH(QString, expectedType);
+    QFETCH(QString, expectedName);
+
+    QTemporaryFile file;
+    file.open();
+    QTextStream stream(&file);
+    stream << "class subObject" << Qt::endl;
+    stream << "{" << Qt::endl;
+    stream << "    PROP(int value)" << Qt::endl;
+    stream << "};" << Qt::endl;
+    stream << "class parentObject" << Qt::endl;
+    stream << "{" << Qt::endl;
+    stream << classDeclaration << Qt::endl;
+    stream << "};" << Qt::endl;
+    file.seek(0);
+
+    RepParser parser(file);
+    QVERIFY(parser.parse());
+
+    const AST ast = parser.ast();
+    QCOMPARE(ast.classes.count(), 2);
+
+    const ASTClass astSub = ast.classes.value(0);
+    const ASTClass astObj = ast.classes.value(1);
+    const ASTProperty property = astObj.properties.at(astObj.subClassPropertyIndices.at(0));
+    QCOMPARE(property.name, expectedName);
+    QCOMPARE(property.type, expectedType);
+}
+
+void tst_Parser::testInvalid_data()
+{
+    QTest::addColumn<QString>("content");
+    QTest::addColumn<QString>("warning");
+
+    QTest::newRow("pod_invalid") << "POD (int foo)" << ".?Unknown token encountered";
+    QTest::newRow("pod_unbalancedparens") << "POD foo(int foo" << ".?Unknown token encountered";
+    QTest::newRow("pod_inclass") << "class Foo\n{\nPOD foo(int)\n}" << ".?POD: Can only be used in global scope";
+    QTest::newRow("class_noidentifier") << "class\n{\n}" << ".?Unknown token encountered";
+    QTest::newRow("class_nested") << "class Foo\n{\nclass Bar\n}" << ".?class: Cannot be nested";
+    QTest::newRow("prop_outsideclass") << "PROP(int foo)" << ".?PROP: Can only be used in class scope";
+    QTest::newRow("prop_toomanyargs") << "class Foo\n{\nPROP(int int foo)\n}" << ".?Invalid property declaration: flag foo is unknown";
+    QTest::newRow("prop_toomanymodifiers") << "class Foo\n{\nPROP(int foo READWRITE, READONLY)\n}" << ".?Invalid property declaration: combination not allowed .READWRITE, READONLY.";
+    QTest::newRow("prop_noargs") << "class Foo\n{\nPROP()\n}" << ".?Unknown token encountered";
+    QTest::newRow("prop_unbalancedparens") << "class Foo\n{\nPROP(int foo\n}" << ".?Unknown token encountered";
+    QTest::newRow("signal_outsideclass") << "SIGNAL(foo())" << ".?SIGNAL: Can only be used in class scope";
+    QTest::newRow("signal_noargs") << "class Foo\n{\nSIGNAL()\n}" << ".?Unknown token encountered";
+    QTest::newRow("slot_outsideclass") << "SLOT(void foo())" << ".?SLOT: Can only be used in class scope";
+    QTest::newRow("slot_noargs") << "class Foo\n{\nSLOT()\n}" << ".?Unknown token encountered";
+    QTest::newRow("model_outsideclass") << "MODEL foo" << ".?Unknown token encountered";
+    QTest::newRow("class_outsideclass") << "CLASS foo" << ".?Unknown token encountered";
+    QTest::newRow("preprecessor_line_inclass") << "class Foo\n{\n#define foo\n}" << ".?Unknown token encountered";
+}
+
+void tst_Parser::testInvalid()
+{
+    QFETCH(QString, content);
+    QFETCH(QString, warning);
+
+    QTest::ignoreMessage(QtWarningMsg, QRegularExpression(warning));
+    QTemporaryFile file;
+    file.open();
+    QTextStream stream(&file);
+    stream << content << Qt::endl;
+    file.seek(0);
+
+    RepParser parser(file);
+    QVERIFY(!parser.parse());
+}
+
+QTEST_APPLESS_MAIN(tst_Parser)
+
+#include "tst_parser.moc"
diff --git a/tests/auto/restart/CMakeLists.txt b/tests/auto/restart/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5a97510
--- /dev/null
@@ -0,0 +1,4 @@
+
+add_subdirectory(client)
+add_subdirectory(server)
+add_subdirectory(tst)
diff --git a/tests/auto/restart/client/CMakeLists.txt b/tests/auto/restart/client/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ff4f90b
--- /dev/null
@@ -0,0 +1,21 @@
+
+#####################################################################
+## restart_client Binary:
+#####################################################################
+
+qt_internal_add_executable(restart_client
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        main.cpp
+    INCLUDE_DIRECTORIES
+        ${CMAKE_CURRENT_SOURCE_DIR}
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+qt6_add_repc_replicas(restart_client
+    ../subclass.rep
+)
+
+#### Keys ignored in scope 1:.:.:client.pro:<TRUE>:
+# TEMPLATE = "app"
diff --git a/tests/auto/restart/client/main.cpp b/tests/auto/restart/client/main.cpp
new file mode 100644 (file)
index 0000000..c520131
--- /dev/null
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include "rep_subclass_replica.h"
+
+#include <QCoreApplication>
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtTest/QtTest>
+
+class tst_Client_Process : public QObject
+{
+    Q_OBJECT
+
+private Q_SLOTS:
+    void initTestCase()
+    {
+        QLoggingCategory::setFilterRules("qt.remoteobjects.warning=true");
+        m_repNode.reset(new QRemoteObjectNode);
+        m_repNode->connectToNode(QUrl(QStringLiteral("tcp://127.0.0.1:65217")));
+        m_rep.reset(m_repNode->acquire<ParentClassReplica>());
+        connect(m_rep.data(), &QRemoteObjectReplica::stateChanged, [this](QRemoteObjectReplica::State state, QRemoteObjectReplica::State previousState) {
+            qDebug() << "**** stateChanged" << state << previousState;
+            if (state == QRemoteObjectReplica::Suspect) {
+                qWarning() << "Replica suspect";
+                this->serverRestarted = true;
+            } else if (state == QRemoteObjectReplica::Valid) {
+                if (this->serverRestarted) {
+                    qWarning() << "Replica valid again";
+                    auto reply = m_rep->start();
+                }
+            }
+        });
+        QVERIFY(m_rep->waitForSource());
+    }
+
+    void testRun()
+    {
+        const auto objectMode = qEnvironmentVariable("ObjectMode");
+
+        qWarning() << "From client";
+        const MyPOD initialValue(42, 3.14f, QStringLiteral("SubClass"));
+        if (objectMode == QLatin1String("ObjectPointer")) {
+            QSignalSpy tracksSpy(m_rep->tracks(), &QAbstractItemModelReplica::initialized);
+            QVERIFY(m_rep->subClass() != nullptr);
+            QCOMPARE(m_rep->subClass()->myPOD(), initialValue);
+            QVERIFY(m_rep->tracks() != nullptr);
+            QVERIFY(tracksSpy.count() || tracksSpy.wait());
+        } else {
+            QVERIFY(m_rep->subClass() == nullptr);
+            QVERIFY(m_rep->tracks() == nullptr);
+        }
+        auto reply = m_rep->start();
+        QVERIFY(reply.waitForFinished());
+
+        QSignalSpy advanceSpy(m_rep.data(), SIGNAL(advance()));
+        QVERIFY(advanceSpy.wait());
+        if (objectMode == QLatin1String("ObjectPointer")) {
+            QVERIFY(m_rep->subClass() != nullptr);
+            QCOMPARE(m_rep->subClass()->myPOD(), initialValue);
+            QVERIFY(m_rep->tracks() != nullptr);
+        } else {
+            QVERIFY(m_rep->subClass() == nullptr);
+            QVERIFY(m_rep->tracks() == nullptr);
+        }
+    }
+
+    void cleanupTestCase()
+    {
+        auto reply = m_rep->quit();
+        QVERIFY(reply.waitForFinished());
+    }
+
+private:
+    QScopedPointer<QRemoteObjectNode> m_repNode;
+    QScopedPointer<ParentClassReplica> m_rep;
+    bool serverRestarted = false;
+};
+
+QTEST_MAIN(tst_Client_Process)
+
+#include "main.moc"
diff --git a/tests/auto/restart/server/CMakeLists.txt b/tests/auto/restart/server/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9a7f9fb
--- /dev/null
@@ -0,0 +1,22 @@
+
+#####################################################################
+## restart_server Binary:
+#####################################################################
+
+qt_internal_add_executable(restart_server
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        main.cpp
+        mytestserver.cpp mytestserver.h
+    INCLUDE_DIRECTORIES
+        ${CMAKE_CURRENT_SOURCE_DIR}
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+        Qt::Test
+)
+qt6_add_repc_sources(restart_server
+    ../subclass.rep
+)
+
+#### Keys ignored in scope 1:.:.:server.pro:<TRUE>:
+# TEMPLATE = "app"
diff --git a/tests/auto/restart/server/main.cpp b/tests/auto/restart/server/main.cpp
new file mode 100644 (file)
index 0000000..9924ebc
--- /dev/null
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include "mytestserver.h"
+#include "rep_subclass_source.h"
+
+#include <QCoreApplication>
+#include <QtTest/QtTest>
+
+class tst_Server_Process : public QObject
+{
+    Q_OBJECT
+
+private Q_SLOTS:
+    void testRun()
+    {
+        const auto runMode = qEnvironmentVariable("RunMode");
+        const auto objectMode = qEnvironmentVariable("ObjectMode");
+
+        QRemoteObjectHost srcNode(QUrl(QStringLiteral("tcp://127.0.0.1:65217")));
+        MyTestServer myTestServer;
+        SubClassSimpleSource subclass;
+        QStringListModel model;
+        const MyPOD initialValue(42, 3.14f, QStringLiteral("SubClass"));
+        if (objectMode == QLatin1String("ObjectPointer")) {
+            subclass.setMyPOD(initialValue);
+            model.setStringList(QStringList() << "Track1" << "Track2" << "Track3");
+            myTestServer.setSubClass(&subclass);
+            myTestServer.setTracks(&model);
+        }
+        srcNode.enableRemoting(&myTestServer);
+
+        qDebug() << "Waiting for incoming connections";
+
+        QSignalSpy waitForStartedSpy(&myTestServer, &MyTestServer::startedChanged);
+        QVERIFY(waitForStartedSpy.isValid());
+        QVERIFY(waitForStartedSpy.wait());
+        QCOMPARE(waitForStartedSpy.value(0).value(0).toBool(), true);
+
+        // wait for delivery of events
+        QTest::qWait(200);
+
+        qDebug() << "Client connected";
+        if (runMode != QLatin1String("Baseline")) {
+            qDebug() << "Server quitting" << runMode;
+            if (runMode == QLatin1String("ServerRestartFatal"))
+                qFatal("Fatal");
+            QCoreApplication::exit();
+            return;
+        }
+        emit myTestServer.advance();
+
+        // wait for quit
+        bool quit = false;
+        connect(&myTestServer, &MyTestServer::quitApp, [&quit]{quit = true;});
+        QTRY_VERIFY_WITH_TIMEOUT(quit, 5000);
+
+        // wait for delivery of events
+        QTest::qWait(200);
+
+        qDebug() << "Done. Shutting down.";
+    }
+};
+
+QTEST_MAIN(tst_Server_Process)
+
+#include "main.moc"
diff --git a/tests/auto/restart/server/mytestserver.cpp b/tests/auto/restart/server/mytestserver.cpp
new file mode 100644 (file)
index 0000000..b0c75ab
--- /dev/null
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include <qdebug.h>
+
+#include "mytestserver.h"
+#include "rep_subclass_source.h"
+
+MyTestServer::MyTestServer(QObject *parent)
+    : ParentClassSimpleSource(parent)
+{
+    qDebug() << "Server started";
+}
+
+MyTestServer::~MyTestServer()
+{
+    qDebug() << "Server stopped";
+}
+
+bool MyTestServer::start()
+{
+    setStarted(true);
+    return true;
+}
+
+bool MyTestServer::quit()
+{
+    emit quitApp();
+    return true;
+}
diff --git a/tests/auto/restart/server/mytestserver.h b/tests/auto/restart/server/mytestserver.h
new file mode 100644 (file)
index 0000000..df044c1
--- /dev/null
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#ifndef MYTESTSERVER_H
+#define MYTESTSERVER_H
+
+#include <QTimer>
+
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtRemoteObjects/qremoteobjectsource.h>
+
+#include "rep_subclass_source.h"
+
+class MyTestServer : public ParentClassSimpleSource
+{
+    Q_OBJECT
+
+public:
+    MyTestServer(QObject *parent = nullptr);
+    ~MyTestServer() override;
+
+public Q_SLOTS:
+    bool start() override;
+    bool quit() override;
+
+Q_SIGNALS:
+    void quitApp();
+};
+
+#endif // MYTESTSERVER_H
diff --git a/tests/auto/restart/subclass.rep b/tests/auto/restart/subclass.rep
new file mode 100644 (file)
index 0000000..1ebbd6e
--- /dev/null
@@ -0,0 +1,19 @@
+POD MyPOD(int i, float f, QString s)
+
+class SubClass
+{
+    PROP(MyPOD myPOD)
+}
+
+class ParentClass
+{
+    PROP(bool started = false)
+
+    SLOT(bool start())
+    SLOT(bool quit())
+    SIGNAL(advance())
+
+    CLASS subClass(SubClass)
+    MODEL tracks(display)
+}
+
diff --git a/tests/auto/restart/tst/CMakeLists.txt b/tests/auto/restart/tst/CMakeLists.txt
new file mode 100644 (file)
index 0000000..8ad2d4c
--- /dev/null
@@ -0,0 +1,12 @@
+
+#####################################################################
+## tst_restart Test:
+#####################################################################
+
+qt_internal_add_test(tst_restart
+    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+    SOURCES
+        tst_restart.cpp
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+)
diff --git a/tests/auto/restart/tst/tst_restart.cpp b/tests/auto/restart/tst/tst_restart.cpp
new file mode 100644 (file)
index 0000000..2222cb6
--- /dev/null
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QMetaType>
+#include <QProcess>
+
+#include "../../../shared/testutils.h"
+
+class tst_Restart: public QObject
+{
+    Q_OBJECT
+
+public:
+    enum RunMode { Baseline, ServerRestartGraceful, ServerRestartFatal };
+    enum ObjectMode { NullPointer, ObjectPointer };
+    Q_ENUM(RunMode)
+    Q_ENUM(ObjectMode)
+
+private slots:
+    void initTestCase()
+    {
+        QVERIFY(TestUtils::init("tst"));
+        QLoggingCategory::setFilterRules("qt.remoteobjects.warning=false");
+    }
+
+    void cleanup()
+    {
+        // wait for delivery of RemoveObject events to the source
+        QTest::qWait(200);
+    }
+
+    void testRun_data()
+    {
+        QTest::addColumn<RunMode>("runMode");
+        QTest::addColumn<ObjectMode>("objectMode");
+        auto runModeMeta = QMetaEnum::fromType<RunMode>();
+        auto objectModeMeta = QMetaEnum::fromType<ObjectMode>();
+        for (int i = 0; i < runModeMeta.keyCount(); i++) {
+            for (int j = 0; j < objectModeMeta.keyCount(); j++) {
+                auto ba = QByteArray(runModeMeta.valueToKey(i));
+                ba = ba.append("_").append(objectModeMeta.valueToKey(j));
+                QTest::newRow(ba.data()) << static_cast<RunMode>(i) << static_cast<ObjectMode>(j);
+            }
+        }
+    }
+
+    void testRun()
+    {
+        QFETCH(RunMode, runMode);
+        QFETCH(ObjectMode, objectMode);
+
+        qDebug() << "Starting server process" << runMode;
+        bool serverRestart = runMode == ServerRestartFatal || runMode == ServerRestartGraceful;
+        QProcess serverProc;
+        serverProc.setProcessChannelMode(QProcess::ForwardedChannels);
+        QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+        env.insert("RunMode", QVariant::fromValue(runMode).toString());
+        env.insert("ObjectMode", QVariant::fromValue(objectMode).toString());
+        serverProc.setProcessEnvironment(env);
+        serverProc.start(TestUtils::findExecutable("restart_server", "/server"),
+                         QStringList());
+        QVERIFY(serverProc.waitForStarted());
+
+        // wait for server start
+        QTest::qWait(200);
+
+        qDebug() << "Starting client process";
+        QProcess clientProc;
+        clientProc.setProcessChannelMode(QProcess::ForwardedChannels);
+        clientProc.setProcessEnvironment(env);
+        clientProc.start(TestUtils::findExecutable("restart_client", "/client"),
+                         QStringList());
+        QVERIFY(clientProc.waitForStarted());
+
+        if (serverRestart) {
+            env.insert("RunMode", QVariant::fromValue(Baseline).toString()); // Don't include ServerRestart environment variable this time
+            qDebug() << "Waiting for server exit";
+            QVERIFY(serverProc.waitForFinished());
+            if (runMode == ServerRestartFatal)
+                QVERIFY(serverProc.exitCode() != 0);
+            else
+                QCOMPARE(serverProc.exitCode(), 0);
+            qDebug() << "Restarting server";
+            serverProc.setProcessEnvironment(env);
+            serverProc.start(TestUtils::findExecutable("restart_server", "/server"),
+                             QStringList());
+            QVERIFY(serverProc.waitForStarted());
+        }
+
+        QVERIFY(clientProc.waitForFinished());
+        QVERIFY(serverProc.waitForFinished());
+
+        QCOMPARE(serverProc.exitCode(), 0);
+        QCOMPARE(clientProc.exitCode(), 0);
+    }
+};
+
+QTEST_MAIN(tst_Restart)
+
+#include "tst_restart.moc"
diff --git a/tests/auto/shared/model_utilities.h b/tests/auto/shared/model_utilities.h
new file mode 100644 (file)
index 0000000..707b074
--- /dev/null
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QModelIndex>
+
+// Helper class which can be used by tests for starting a task and
+// waiting for its completion. It takes care of running an event
+// loop while waiting, until finished() method is called (or the
+// timeout is reached).
+class WaitHelper : public QObject
+{
+    Q_OBJECT
+
+public:
+    WaitHelper() { m_promise.start(); }
+
+    ~WaitHelper()
+    {
+        if (m_promise.future().isRunning())
+            m_promise.finish();
+    }
+
+    /*
+        Starts an event loop and waits until finish() method is called
+        or the timeout is reached.
+    */
+    bool wait(int timeout = 30000)
+    {
+        if (m_promise.future().isFinished())
+            return true;
+
+        QFutureWatcher<void> watcher;
+        QSignalSpy watcherSpy(&watcher, &QFutureWatcher<void>::finished);
+        watcher.setFuture(m_promise.future());
+        return watcherSpy.wait(timeout);
+    }
+
+protected:
+    /*
+        The derived classes need to call this method to stop waiting.
+    */
+    void finish() { m_promise.finish(); }
+
+private:
+    QPromise<void> m_promise;
+};
+
+namespace {
+
+inline bool compareIndices(const QModelIndex &lhs, const QModelIndex &rhs)
+{
+    QModelIndex left = lhs;
+    QModelIndex right = rhs;
+    while (left.row() == right.row() && left.column() == right.column() && left.isValid() && right.isValid()) {
+        left = left.parent();
+        right = right.parent();
+    }
+    if (left.isValid() || right.isValid())
+        return false;
+    return true;
+}
+
+struct WaitForDataChanged : public WaitHelper
+{
+    WaitForDataChanged(const QAbstractItemModel *model, const QList<QModelIndex> &pending)
+        : WaitHelper(), m_model(model), m_pending(pending)
+    {
+        connect(m_model, &QAbstractItemModel::dataChanged, this,
+                [this](const QModelIndex &topLeft, const QModelIndex &bottomRight,
+                       const QList<int> &roles) {
+                    Q_UNUSED(roles)
+
+                    checkAndRemoveRange(topLeft, bottomRight);
+                    if (m_pending.isEmpty())
+                        finish();
+                });
+    }
+
+    void checkAndRemoveRange(const QModelIndex &topLeft, const QModelIndex &bottomRight)
+    {
+        QVERIFY(topLeft.parent() == bottomRight.parent());
+        const auto isInRange = [topLeft, bottomRight] (const QModelIndex &pending) noexcept -> bool {
+            if (pending.isValid()  && compareIndices(pending.parent(), topLeft.parent())) {
+                const bool fitLeft = topLeft.column() <= pending.column();
+                const bool fitRight = bottomRight.column() >= pending.column();
+                const bool fitTop = topLeft.row() <= pending.row();
+                const bool fitBottom = bottomRight.row() >= pending.row();
+                if (fitLeft && fitRight && fitTop && fitBottom)
+                    return true;
+            }
+            return false;
+        };
+        m_pending.erase(std::remove_if(m_pending.begin(), m_pending.end(), isInRange),
+                        m_pending.end());
+    }
+
+private:
+    const QAbstractItemModel *m_model = nullptr;
+    QList<QModelIndex> m_pending;
+};
+
+} // namespace
diff --git a/tests/auto/subclassreplica/CMakeLists.txt b/tests/auto/subclassreplica/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6a59195
--- /dev/null
@@ -0,0 +1,19 @@
+
+#####################################################################
+## tst_subclassreplicatest Test:
+#####################################################################
+
+qt_internal_add_test(tst_subclassreplicatest
+    SOURCES
+        tst_subclassreplicatest.cpp
+    DEFINES
+        SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/\\\"
+    PUBLIC_LIBRARIES
+        Qt::RemoteObjects
+)
+qt6_add_repc_merged(tst_subclassreplicatest
+    class.rep
+)
+
+#### Keys ignored in scope 1:.:.:subclassreplica.pro:<TRUE>:
+# TEMPLATE = "app"
diff --git a/tests/auto/subclassreplica/class.rep b/tests/auto/subclassreplica/class.rep
new file mode 100644 (file)
index 0000000..7de0c65
--- /dev/null
@@ -0,0 +1,14 @@
+class SubClass
+{
+    PROP(int value)
+}
+class ParentClass
+{
+    CLASS sub1(SubClass)
+    CLASS sub2(SubClass)
+}
+
+class OtherParentClass
+{
+    CLASS sub1(SubClass)
+}
diff --git a/tests/auto/subclassreplica/tst_subclassreplicatest.cpp b/tests/auto/subclassreplica/tst_subclassreplicatest.cpp
new file mode 100644 (file)
index 0000000..d35207d
--- /dev/null
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include <QString>
+#include <QtTest>
+#include "rep_class_merged.h"
+
+class SubClassReplicaTest : public QObject
+{
+    Q_OBJECT
+
+public:
+    SubClassReplicaTest();
+
+private Q_SLOTS:
+    void basicFunctions();
+    void basicFunctions_data();
+};
+
+SubClassReplicaTest::SubClassReplicaTest()
+{
+}
+
+void SubClassReplicaTest::basicFunctions_data()
+{
+    QTest::addColumn<bool>("templated");
+    QTest::addColumn<bool>("nullobject");
+    QTest::newRow("non-templated pointer") << false << false;
+    QTest::newRow("templated pointer") << true << false;
+    QTest::newRow("non-templated nullptr") << false << true;
+    QTest::newRow("templated nullptr") << true << true;
+}
+
+void SubClassReplicaTest::basicFunctions()
+{
+    QFETCH(bool, templated);
+    QFETCH(bool, nullobject);
+
+    QRemoteObjectRegistryHost host(QUrl("local:test"));
+    SubClassSimpleSource subclass1, subclass2;
+    ParentClassSimpleSource parent;
+    parent.setSub1(&subclass1);
+
+    SubClassSimpleSource subclass3;
+    subclass3.setValue(4);
+    OtherParentClassSimpleSource otherParent;
+    otherParent.setSub1(&subclass3);
+    host.enableRemoting(&otherParent, "OtherParent1");
+
+    SubClassSimpleSource subclass4;
+    subclass4.setValue(15);
+    OtherParentClassSimpleSource otherParent2;
+    otherParent2.setSub1(&subclass4);
+    host.enableRemoting(&otherParent2, "OtherParent2");
+
+    if (nullobject)
+        parent.setSub2(nullptr);
+    else
+        parent.setSub2(&subclass2);
+    if (templated)
+        host.enableRemoting<ParentClassSourceAPI>(&parent);
+    else
+        host.enableRemoting(&parent);
+
+    QRemoteObjectNode client(QUrl("local:test"));
+    const QScopedPointer<ParentClassReplica> replica(client.acquire<ParentClassReplica>());
+    QVERIFY(replica->waitForSource(1000));
+
+    auto sub1 = replica->sub1();
+    QSignalSpy spy(sub1, &SubClassReplica::valueChanged);
+    subclass1.setValue(10);
+    QVERIFY(spy.wait());
+    QCOMPARE(subclass1.value(), sub1->value());
+    if (nullobject) {
+        QCOMPARE(replica->sub2(), nullptr);
+        QCOMPARE(parent.sub2(), nullptr);
+    } else
+        QCOMPARE(subclass2.value(), replica->sub2()->value());
+
+    const QScopedPointer<OtherParentClassReplica> otherReplica(client.acquire<OtherParentClassReplica>("OtherParent1"));
+    QVERIFY(otherReplica->waitForSource(1000));
+
+    const QScopedPointer<OtherParentClassReplica> otherReplica2(client.acquire<OtherParentClassReplica>("OtherParent2"));
+    QVERIFY(otherReplica2->waitForSource(1000));
+
+    QCOMPARE(otherReplica->sub1()->value(), 4);
+    QCOMPARE(otherReplica2->sub1()->value(), 15);
+    otherReplica->sub1()->pushValue(19);
+    otherReplica2->sub1()->pushValue(24);
+    QTRY_COMPARE(subclass4.value(), 24);
+    QTRY_COMPARE(subclass3.value(), 19);
+}
+
+QTEST_MAIN(SubClassReplicaTest)
+
+#include "tst_subclassreplicatest.moc"
diff --git a/tests/global/global.cfg b/tests/global/global.cfg
new file mode 100644 (file)
index 0000000..65feefb
--- /dev/null
@@ -0,0 +1,5 @@
+<config>
+<modules>
+<module name="QtRemoteObjects"           qtname="remoteobjects"/>
+</modules>
+</config>
diff --git a/tests/shared/testutils.h b/tests/shared/testutils.h
new file mode 100644 (file)
index 0000000..1655c3f
--- /dev/null
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#ifndef TESTUTILS_H
+#define TESTUTILS_H
+
+#include <QDebug>
+#include <QString>
+#include <QDir>
+#include <QStandardPaths>
+#include <QCoreApplication>
+
+namespace TestUtils {
+
+QString subFolder;
+QString rootFolder;
+
+bool init(const QString &folder)
+{
+    if (!TestUtils::rootFolder.isEmpty())
+        return true;
+    const auto appPath = QCoreApplication::applicationDirPath();
+    auto dir = QDir(appPath);
+    while (dir.dirName() != folder) {
+        TestUtils::subFolder.prepend(dir.dirName()).prepend('/');
+        if (!dir.cdUp())
+            return false;
+    }
+    dir.cdUp();
+    TestUtils::rootFolder = dir.absolutePath();
+    return true;
+}
+
+QString findExecutable(const QString &executableName, const QString &folder)
+{
+    const auto path = QStandardPaths::findExecutable(executableName, {TestUtils::rootFolder + folder + TestUtils::subFolder});
+    if (!path.isEmpty()) {
+        return path;
+    }
+
+    qWarning() << "Could not find executable:" << executableName << "in " << TestUtils::rootFolder + folder + TestUtils::subFolder;
+    return QString();
+}
+
+}
+
+#endif // TESTUTILS_H
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
new file mode 100644 (file)
index 0000000..35d041a
--- /dev/null
@@ -0,0 +1,5 @@
+# Generated from tools.pro.
+
+if(QT_FEATURE_commandlineparser)
+    add_subdirectory(repc)
+endif()
diff --git a/tools/repc/.prev_CMakeLists.txt b/tools/repc/.prev_CMakeLists.txt
new file mode 100644 (file)
index 0000000..e697e42
--- /dev/null
@@ -0,0 +1,44 @@
+# Generated from repc.pro.
+
+#####################################################################
+## repc Tool:
+#####################################################################
+
+qt_get_tool_target_name(target_name repc)
+qt_add_tool(${target_name}
+    TARGET_DESCRIPTION "Qt Remote Objects Compiler"
+    SOURCES
+        cppcodegenerator.cpp cppcodegenerator.h
+        main.cpp
+        repcodegenerator.cpp repcodegenerator.h
+        utils.cpp utils.h
+    DEFINES
+        QT_NO_CAST_FROM_ASCII
+        QT_NO_CAST_FROM_BYTEARRAY
+        QT_NO_CAST_TO_ASCII
+        QT_NO_URL_CAST_FROM_STRING
+        RO_INSTALL_HEADERS=\"$$[QT_INSTALL_HEADERS]/QtRemoteObjects\"
+    INCLUDE_DIRECTORIES
+        ${CMAKE_SOURCE_DIR}/src/repparser
+    PUBLIC_LIBRARIES
+        Qt::CorePrivate
+)
+
+# QLALR Grammars:
+qt_process_qlalr(
+    repc
+    ${CMAKE_SOURCE_DIR}/src/repparser/parser.g
+    ""
+)
+
+#### Keys ignored in scope 1:.:.:repc.pro:<TRUE>:
+# QMAKE_TARGET_DESCRIPTION = "Qt Remote Objects Compiler"
+# _OPTION = "host_build"
+
+## Scopes:
+#####################################################################
+
+qt_extend_target(${target_name} CONDITION MSVC
+    COMPILE_OPTIONS
+        /wd4129
+)
diff --git a/tools/repc/CMakeLists.txt b/tools/repc/CMakeLists.txt
new file mode 100644 (file)
index 0000000..4527f51
--- /dev/null
@@ -0,0 +1,48 @@
+# Generated from repc.pro.
+
+#####################################################################
+## repc Tool:
+#####################################################################
+
+set(REPPARSER_DIR "${PROJECT_SOURCE_DIR}/src/repparser")
+
+qt_get_tool_target_name(target_name repc)
+qt_internal_add_tool(${target_name}
+    TARGET_DESCRIPTION "Qt Remote Objects Compiler"
+    TOOLS_TARGET RemoteObjects # special case
+    INSTALL_DIR "${INSTALL_LIBEXECDIR}"
+    SOURCES
+        cppcodegenerator.cpp cppcodegenerator.h
+        main.cpp
+        repcodegenerator.cpp repcodegenerator.h
+        utils.cpp utils.h
+    DEFINES
+        QT_NO_CAST_FROM_ASCII
+        QT_NO_CAST_FROM_BYTEARRAY
+        QT_NO_CAST_TO_ASCII
+        QT_NO_URL_CAST_FROM_STRING
+        RO_INSTALL_HEADERS=\"$$[QT_INSTALL_HEADERS]/QtRemoteObjects\"
+    INCLUDE_DIRECTORIES
+        ${REPPARSER_DIR}
+    PUBLIC_LIBRARIES
+        Qt::CorePrivate
+)
+
+# QLALR Grammars:
+qt_process_qlalr(
+    ${target_name}
+    "${REPPARSER_DIR}/parser.g"
+    ""
+)
+
+#### Keys ignored in scope 1:.:.:repc.pro:<TRUE>:
+# QMAKE_TARGET_DESCRIPTION = "Qt Remote Objects Compiler"
+# _OPTION = "host_build"
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(${target_name} CONDITION MSVC
+    COMPILE_OPTIONS
+        /wd4129
+)
diff --git a/tools/repc/cppcodegenerator.cpp b/tools/repc/cppcodegenerator.cpp
new file mode 100644 (file)
index 0000000..afbe400
--- /dev/null
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include <qiodevice.h>
+#include <qjsonarray.h>
+#include <qjsonvalue.h>
+
+#include "cppcodegenerator.h"
+#include "utils.h"
+
+QT_BEGIN_NAMESPACE
+
+CppCodeGenerator::CppCodeGenerator(QIODevice *outputDevice)
+    : m_outputDevice(outputDevice)
+{
+    Q_ASSERT(m_outputDevice);
+}
+
+void CppCodeGenerator::generate(const QJsonArray &classList, bool alwaysGenerateClass /* = false */)
+{
+    for (const QJsonValue cdef : classList)
+        m_outputDevice->write(generateClass(cdef, alwaysGenerateClass));
+
+    m_outputDevice->write("\n");
+}
+
+QT_END_NAMESPACE
diff --git a/tools/repc/cppcodegenerator.h b/tools/repc/cppcodegenerator.h
new file mode 100644 (file)
index 0000000..892ed5b
--- /dev/null
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#ifndef CPPCODEGENERATOR_H
+#define CPPCODEGENERATOR_H
+
+QT_BEGIN_NAMESPACE
+class QJsonArray;
+class QIODevice;
+
+class CppCodeGenerator
+{
+public:
+    CppCodeGenerator(QIODevice *outputDevice);
+
+    void generate(const QJsonArray &classList, bool alwaysGenerateClass = false);
+
+private:
+    QIODevice *m_outputDevice;
+};
+
+QT_END_NAMESPACE
+
+#endif // CPPCODEGENERATOR_H
diff --git a/tools/repc/main.cpp b/tools/repc/main.cpp
new file mode 100644 (file)
index 0000000..0ad99e1
--- /dev/null
@@ -0,0 +1,267 @@
+/****************************************************************************
+**
+** Copyright (C) 2017-2020 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module 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$
+**
+****************************************************************************/
+
+#include <qcommandlineoption.h>
+#include <qcommandlineparser.h>
+#include <qcoreapplication.h>
+#include <qfileinfo.h>
+#include <qjsondocument.h>
+#include <qjsonobject.h>
+#include <qjsonarray.h>
+
+#include "cppcodegenerator.h"
+#include "repcodegenerator.h"
+#include "repparser.h"
+#include "utils.h"
+
+#include <cstdio>
+
+#define PROGRAM_NAME  "repc"
+#define REPC_VERSION  "1.0.0"
+
+enum Mode {
+    InRep = 1,
+    InJson = 2,
+    OutRep = 4,
+    OutSource = 8,
+    OutReplica = 16,
+    OutMerged = OutSource | OutReplica
+};
+
+static const QLatin1String REP("rep");
+static const QLatin1String JSON("json");
+static const QLatin1String REPLICA("replica");
+static const QLatin1String SOURCE("source");
+static const QLatin1String MERGED("merged");
+
+QT_USE_NAMESPACE
+
+int main(int argc, char **argv)
+{
+    QCoreApplication app(argc, argv);
+    QCoreApplication::setApplicationVersion(QString::fromLatin1(REPC_VERSION));
+
+    QString outputFile;
+    QString inputFile;
+    int mode = 0;
+    QCommandLineParser parser;
+    parser.setApplicationDescription(QStringLiteral("repc tool v%1 (Qt %2).\n")
+                                     .arg(QStringLiteral(REPC_VERSION), QString::fromLatin1(QT_VERSION_STR)));
+    parser.addHelpOption();
+    parser.addVersionOption();
+    QCommandLineOption inputTypeOption(QStringLiteral("i"));
+    inputTypeOption.setDescription(QLatin1String("Input file type:\n"
+                                                  "rep: replicant template files.\n"
+                                                  "json: JSON output from moc of a Qt header file."));
+    inputTypeOption.setValueName(QStringLiteral("rep|json"));
+    parser.addOption(inputTypeOption);
+
+    QCommandLineOption outputTypeOption(QStringLiteral("o"));
+    outputTypeOption.setDescription(QLatin1String("Output file type:\n"
+                                                   "source: generates source header. Is incompatible with \"-i src\" option.\n"
+                                                   "replica: generates replica header.\n"
+                                                   "merged: generates combined replica/source header.\n"
+                                                   "rep: generates replicant template file from C++ QOject classes. Is not compatible with \"-i rep\" option."));
+    outputTypeOption.setValueName(QStringLiteral("source|replica|merged|rep"));
+    parser.addOption(outputTypeOption);
+
+    QCommandLineOption includePathOption(QStringLiteral("I"));
+    includePathOption.setDescription(QStringLiteral("Add dir to the include path for header files. This parameter is needed only if the input file type is src (.h file)."));
+    includePathOption.setValueName(QStringLiteral("dir"));
+    parser.addOption(includePathOption);
+
+    QCommandLineOption alwaysClassOption(QStringLiteral("c"));
+    alwaysClassOption.setDescription(QStringLiteral("Always output `class` type for .rep files and never `POD`."));
+    parser.addOption(alwaysClassOption);
+
+    QCommandLineOption debugOption(QStringLiteral("d"));
+    debugOption.setDescription(QStringLiteral("Print out parsing debug information (for troubleshooting)."));
+    parser.addOption(debugOption);
+
+    parser.addPositionalArgument(QStringLiteral("[json-file/rep-file]"),
+            QStringLiteral("Input json/rep file to read from, otherwise stdin."));
+
+    parser.addPositionalArgument(QStringLiteral("[rep-file/header-file]"),
+            QStringLiteral("Output header/rep file to write to, otherwise stdout."));
+
+    parser.process(app.arguments());
+
+    const QStringList files = parser.positionalArguments();
+
+    if (files.count() > 2) {
+        fprintf(stderr, "%s", qPrintable(QLatin1String(PROGRAM_NAME ": Too many input, output files specified: '") + files.join(QStringLiteral("' '")) + QStringLiteral("\'.\n")));
+        parser.showHelp(1);
+    }
+
+    if (parser.isSet(inputTypeOption)) {
+        const QString &inputType = parser.value(inputTypeOption);
+        if (inputType == REP)
+            mode = InRep;
+        else if (inputType == JSON)
+            mode = InJson;
+        else {
+            fprintf(stderr, PROGRAM_NAME ": Unknown input type\"%s\".\n", qPrintable(inputType));
+            parser.showHelp(1);
+        }
+    }
+
+    if (parser.isSet(outputTypeOption)) {
+        const QString &outputType = parser.value(outputTypeOption);
+        if (outputType == REP)
+            mode |= OutRep;
+        else if (outputType == REPLICA)
+            mode |= OutReplica;
+        else if (outputType == SOURCE)
+            mode |= OutSource;
+        else if (outputType == MERGED)
+            mode |= OutMerged;
+        else {
+            fprintf(stderr, PROGRAM_NAME ": Unknown output type\"%s\".\n", qPrintable(outputType));
+            parser.showHelp(1);
+        }
+    }
+
+    switch (files.count()) {
+    case 2:
+        outputFile = files.last();
+        if (!(mode & (OutRep | OutSource | OutReplica))) {
+            // try to figure out the Out mode from file extension
+            if (outputFile.endsWith(QLatin1String(".rep")))
+                mode |= OutRep;
+        }
+        Q_FALLTHROUGH();
+    case 1:
+        inputFile = files.first();
+        if (!(mode & (InRep | InJson))) {
+            // try to figure out the In mode from file extension
+            if (inputFile.endsWith(QLatin1String(".rep")))
+                mode |= InRep;
+            else
+                mode |= InJson;
+        }
+        break;
+    }
+    // check mode sanity
+    if (!(mode & (InRep | InJson))) {
+        fprintf(stderr, PROGRAM_NAME ": Unknown input type, please use -i option to specify one.\n");
+        parser.showHelp(1);
+    }
+    if (!(mode & (OutRep | OutSource | OutReplica))) {
+        fprintf(stderr, PROGRAM_NAME ": Unknown output type, please use -o option to specify one.\n");
+        parser.showHelp(1);
+    }
+    if (mode & InRep && mode & OutRep) {
+        fprintf(stderr, PROGRAM_NAME ": Invalid input/output type combination, both are rep files.\n");
+        parser.showHelp(1);
+    }
+    if (mode & InJson && mode & OutSource) {
+        fprintf(stderr, PROGRAM_NAME ": Invalid input/output type combination, both are source header files.\n");
+        parser.showHelp(1);
+    }
+
+    QFile input;
+    if (inputFile.isEmpty()) {
+        inputFile = QStringLiteral("<stdin>");
+        input.open(stdin, QIODevice::ReadOnly);
+    } else {
+        input.setFileName(inputFile);
+        if (!input.open(QIODevice::ReadOnly)) {
+            fprintf(stderr, PROGRAM_NAME ": %s: No such file.\n", qPrintable(inputFile));
+            return 1;
+        }
+    }
+
+    QFile output;
+    if (outputFile.isEmpty()) {
+        output.open(stdout, QIODevice::WriteOnly);
+    } else {
+        output.setFileName(outputFile);
+        if (!output.open(QIODevice::WriteOnly)) {
+            fprintf(stderr, PROGRAM_NAME ": could not open output file '%s': %s.\n",
+                    qPrintable(outputFile), qPrintable(output.errorString()));
+            return 1;
+        }
+    }
+
+    if (mode & InJson) {
+        QJsonDocument doc(QJsonDocument::fromJson(input.readAll()));
+        input.close();
+        if (!doc.isObject()) {
+            fprintf(stderr, PROGRAM_NAME ": Unable to read json input.\n");
+            return 0;
+        }
+
+        QJsonObject json = doc.object();
+
+        if (!json.contains(QLatin1String("classes")) || !json[QLatin1String("classes")].isArray()) {
+            fprintf(stderr, PROGRAM_NAME ": No QObject classes found.\n");
+            return 0;
+        }
+
+        QJsonArray classes = json[QLatin1String("classes")].toArray();
+
+        if (mode & OutRep) {
+            CppCodeGenerator generator(&output);
+            generator.generate(classes, parser.isSet(alwaysClassOption));
+        } else {
+            Q_ASSERT(mode & OutReplica);
+            RepCodeGenerator generator(&output, classList2AST(classes));
+            generator.generate(RepCodeGenerator::REPLICA, outputFile);
+        }
+    } else {
+        Q_ASSERT(!(mode & OutRep));
+        RepParser repparser(input);
+        if (parser.isSet(debugOption))
+            repparser.setDebug();
+        if (!repparser.parse()) {
+            fprintf(stderr, PROGRAM_NAME ": %s:%d: error: %s\n", qPrintable(inputFile), repparser.lineNumber(), qPrintable(repparser.errorString()));
+            // if everything is okay and only the input was malformed => remove the output file
+            // let's not create an empty file -- make sure the build system tries to run repc again
+            // this is the same behavior other code generators exhibit (e.g. flex)
+            output.remove();
+            return 1;
+        }
+
+        input.close();
+
+        RepCodeGenerator generator(&output, repparser.ast());
+        if ((mode & OutMerged) == OutMerged)
+            generator.generate(RepCodeGenerator::MERGED, outputFile);
+        else if (mode & OutReplica)
+            generator.generate(RepCodeGenerator::REPLICA, outputFile);
+        else if (mode & OutSource)
+            generator.generate(RepCodeGenerator::SOURCE, outputFile);
+        else {
+            fprintf(stderr, PROGRAM_NAME ": Unknown mode.\n");
+            return 1;
+        }
+    }
+
+    output.close();
+    return 0;
+}
diff --git a/tools/repc/repc.pro b/tools/repc/repc.pro
new file mode 100644 (file)
index 0000000..d3bcc43
--- /dev/null
@@ -0,0 +1,25 @@
+option(host_build)
+include(moc_copy/moc.pri)
+QT = core-private
+
+DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII QT_NO_CAST_FROM_BYTEARRAY QT_NO_URL_CAST_FROM_STRING
+DEFINES += RO_INSTALL_HEADERS=$$shell_quote(\"$$clean_path($$[QT_INSTALL_HEADERS]/QtRemoteObjects)\")
+msvc: QMAKE_CXXFLAGS += /wd4129
+
+CONFIG += qlalr
+QLALRSOURCES += $$QTRO_SOURCE_TREE/src/repparser/parser.g
+INCLUDEPATH += $$QTRO_SOURCE_TREE/src/repparser
+
+SOURCES += \
+    main.cpp \
+    repcodegenerator.cpp \
+    cppcodegenerator.cpp \
+    utils.cpp
+
+HEADERS += \
+    repcodegenerator.h \
+    cppcodegenerator.h \
+    utils.h
+
+QMAKE_TARGET_DESCRIPTION = "Qt Remote Objects Compiler"
+load(qt_tool)
diff --git a/tools/repc/repcodegenerator.cpp b/tools/repc/repcodegenerator.cpp
new file mode 100644 (file)
index 0000000..e3b9ad3
--- /dev/null
@@ -0,0 +1,1522 @@
+/****************************************************************************
+**
+** Copyright (C) 2017-2020 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module 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$
+**
+****************************************************************************/
+
+#include "repcodegenerator.h"
+
+#include <QFileInfo>
+#include <QMetaType>
+#include <QCryptographicHash>
+#include <QRegularExpression>
+
+using namespace Qt;
+
+QT_BEGIN_NAMESPACE
+
+template <typename C>
+static int accumulatedSizeOfNames(const C &c)
+{
+    int result = 0;
+    for (const auto &e : c)
+        result += e.name.size();
+    return result;
+}
+
+template <typename C>
+static int accumulatedSizeOfTypes(const C &c)
+{
+    int result = 0;
+    for (const auto &e : c)
+        result += e.type.size();
+    return result;
+}
+
+static QString cap(QString name)
+{
+    if (!name.isEmpty())
+        name[0] = name[0].toUpper();
+    return name;
+}
+
+static bool isClassEnum(const ASTClass &classContext, const QString &typeName)
+{
+    for (const ASTEnum &astEnum : classContext.enums) {
+        if (astEnum.name == typeName) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+static bool hasScopedEnum(const ASTClass &classContext)
+{
+    for (const ASTEnum &astEnum : classContext.enums) {
+        if (astEnum.isScoped) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+static bool hasScopedEnum(const POD &pod)
+{
+    for (const ASTEnum &astEnum : pod.enums) {
+        if (astEnum.isScoped) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+static QString fullyQualifiedName(const ASTClass& classContext, const QString &className,
+                                  const QString &typeName)
+{
+    static const QRegularExpression re = QRegularExpression(QLatin1String("([^<>,\\s]+)"));
+    QString copy = typeName;
+    qsizetype offset = 0;
+    for (const QRegularExpressionMatch &match : re.globalMatch(typeName)) {
+        if (isClassEnum(classContext, match.captured(1))) {
+            copy.insert(match.capturedStart(1) + offset, className + QStringLiteral("::"));
+            offset += className.length() + 2;
+        }
+    }
+    return copy;
+}
+
+// for enums we need to transform signal/slot arguments to include the class scope
+static QList<ASTFunction> transformEnumParams(const ASTClass& classContext,
+                                              const QList<ASTFunction> &methodList,
+                                              const QString &typeName) {
+    QList<ASTFunction> localList = methodList;
+    for (ASTFunction &astFunction : localList) {
+        for (ASTDeclaration &astParam : astFunction.params) {
+            for (const ASTEnum &astEnum : classContext.enums) {
+                if (astEnum.name == astParam.type) {
+                    astParam.type = typeName + QStringLiteral("::") + astParam.type;
+                }
+            }
+        }
+    }
+    return localList;
+}
+
+/*
+  Returns \c true if the type is a built-in type.
+*/
+static bool isBuiltinType(const QString &type)
+ {
+    const auto metaType = QMetaType::fromName(type.toLatin1().constData());
+    if (!metaType.isValid())
+        return false;
+    return (metaType.id() < QMetaType::User);
+}
+
+RepCodeGenerator::RepCodeGenerator(QIODevice *outputDevice, const AST &ast)
+    : m_stream(outputDevice), m_ast(ast)
+{
+}
+
+QByteArray RepCodeGenerator::classSignature(const ASTClass &ac)
+{
+    return m_ast.typeSignatures[ac.name];
+}
+
+void RepCodeGenerator::generate(Mode mode, QString fileName)
+{
+    if (fileName.isEmpty())
+        m_stream << "#pragma once" << Qt::endl << Qt::endl;
+    else {
+        fileName = QFileInfo(fileName).fileName();
+        fileName = fileName.toUpper();
+        fileName.replace(QLatin1Char('.'), QLatin1Char('_'));
+        m_stream << "#ifndef " << fileName << Qt::endl;
+        m_stream << "#define " << fileName << Qt::endl << Qt::endl;
+    }
+
+    generateHeader(mode);
+    for (const ASTEnum &en : m_ast.enums)
+        generateEnumGadget(en, QStringLiteral("%1Enum").arg(en.name));
+    for (const POD &pod : m_ast.pods)
+        generatePOD(pod);
+
+    QSet<QString> metaTypes;
+    QSet<QString> enumTypes;
+    for (const POD &pod : m_ast.pods) {
+        metaTypes << pod.name;
+        // We register from within the code generated for classes, not PODs
+        // Thus, for enums/flags in PODs, we need the to prefix with the POD
+        // name.  The enumTypes set is used to make sure we don't try to
+        // register the non-prefixed name if it is used as a member variable
+        // type.
+        for (const ASTEnum &en : pod.enums) {
+            metaTypes << QLatin1String("%1::%2").arg(pod.name, en.name);
+            enumTypes << en.name;
+        }
+        for (const ASTFlag &flag : pod.flags) {
+            metaTypes << QLatin1String("%1::%2").arg(pod.name, flag.name);
+            enumTypes << flag.name;
+        }
+        for (const PODAttribute &attribute : pod.attributes) {
+            if (!enumTypes.contains(attribute.type))
+                metaTypes << attribute.type;
+        }
+    }
+    const QString metaTypeRegistrationCode = generateMetaTypeRegistration(metaTypes);
+
+    for (const ASTClass &astClass : m_ast.classes) {
+        QSet<QString> classMetaTypes;
+        QSet<QString> pendingMetaTypes;
+        for (const ASTEnum &en : astClass.enums)
+            classMetaTypes << en.name;
+        for (const ASTProperty &property : astClass.properties) {
+            if (property.isPointer)
+                continue;
+            classMetaTypes << property.type;
+        }
+        const auto extractClassMetaTypes = [&](const ASTFunction &function) {
+            classMetaTypes << function.returnType;
+            pendingMetaTypes << function.returnType;
+            for (const ASTDeclaration &decl : function.params) {
+                classMetaTypes << decl.type;
+
+                // Collect types packaged by Qt containers, to register their metatypes if needed
+                QRegularExpression re(
+                        QStringLiteral("(QList|QMap|QHash)<\\s*([\\w]+)\\s*(,\\s*([\\w]+))?\\s*>"));
+                QRegularExpressionMatch m = re.match(decl.type);
+                if (m.hasMatch()) {
+                    if (auto captured = m.captured(2);
+                        !captured.isNull() && !metaTypes.contains(captured)) {
+                        classMetaTypes << captured;
+                    }
+                    if (auto captured = m.captured(4);
+                        !captured.isNull() && !metaTypes.contains(captured)) {
+                        classMetaTypes << captured;
+                    }
+                }
+            }
+        };
+        for (const ASTFunction &function : astClass.signalsList)
+            extractClassMetaTypes(function);
+        for (const ASTFunction &function : astClass.slotsList)
+            extractClassMetaTypes(function);
+
+        const QString classMetaTypeRegistrationCode = metaTypeRegistrationCode
+                + generateMetaTypeRegistration(classMetaTypes);
+        const QString replicaMetaTypeRegistrationCode = classMetaTypeRegistrationCode
+                + generateMetaTypeRegistrationForPending(pendingMetaTypes);
+
+        if (mode == MERGED) {
+            generateClass(REPLICA, astClass, replicaMetaTypeRegistrationCode);
+            generateClass(SOURCE, astClass, classMetaTypeRegistrationCode);
+            generateClass(SIMPLE_SOURCE, astClass, classMetaTypeRegistrationCode);
+            generateSourceAPI(astClass);
+        } else {
+            generateClass(mode, astClass, mode == REPLICA ? replicaMetaTypeRegistrationCode
+                                                          : classMetaTypeRegistrationCode);
+            if (mode == SOURCE) {
+                generateClass(SIMPLE_SOURCE, astClass, classMetaTypeRegistrationCode);
+                generateSourceAPI(astClass);
+            }
+        }
+    }
+
+    m_stream << Qt::endl;
+    if (!fileName.isEmpty())
+        m_stream << "#endif // " << fileName << Qt::endl;
+}
+
+void RepCodeGenerator::generateHeader(Mode mode)
+{
+    m_stream <<
+        "// This is an autogenerated file.\n"
+        "// Do not edit this file, any changes made will be lost the next time it is generated.\n"
+        "\n"
+        "#include <QtCore/qobject.h>\n"
+        "#include <QtCore/qdatastream.h>\n"
+        "#include <QtCore/qvariant.h>\n"
+        "#include <QtCore/qmetatype.h>\n";
+    bool hasModel = false;
+    for (auto c : m_ast.classes)
+    {
+        if (c.modelMetadata.count() > 0)
+        {
+            hasModel = true;
+            break;
+        }
+    }
+    if (hasModel)
+        m_stream << "#include <QtCore/qabstractitemmodel.h>\n";
+    m_stream << "\n"
+                "#include <QtRemoteObjects/qremoteobjectnode.h>\n";
+
+    if (mode == MERGED) {
+        m_stream << "#include <QtRemoteObjects/qremoteobjectpendingcall.h>\n";
+        m_stream << "#include <QtRemoteObjects/qremoteobjectreplica.h>\n";
+        m_stream << "#include <QtRemoteObjects/qremoteobjectsource.h>\n";
+        if (hasModel)
+            m_stream << "#include <QtRemoteObjects/qremoteobjectabstractitemmodelreplica.h>\n";
+    } else if (mode == REPLICA) {
+        m_stream << "#include <QtRemoteObjects/qremoteobjectpendingcall.h>\n";
+        m_stream << "#include <QtRemoteObjects/qremoteobjectreplica.h>\n";
+        if (hasModel)
+            m_stream << "#include <QtRemoteObjects/qremoteobjectabstractitemmodelreplica.h>\n";
+    } else
+        m_stream << "#include <QtRemoteObjects/qremoteobjectsource.h>\n";
+    m_stream << "\n";
+
+    m_stream << m_ast.preprocessorDirectives.join(QLatin1Char('\n'));
+    m_stream << "\n";
+}
+
+static QString formatTemplateStringArgTypeNameCapitalizedName(int numberOfTypeOccurrences,
+                                                              int numberOfNameOccurrences,
+                                                              QString templateString,
+                                                              const POD &pod)
+{
+    QString out;
+    const int LengthOfPlaceholderText = 2;
+    Q_ASSERT(templateString.count(QRegularExpression(QStringLiteral("%\\d")))
+                                  == numberOfNameOccurrences + numberOfTypeOccurrences);
+    const auto expectedOutSize
+            = numberOfNameOccurrences * accumulatedSizeOfNames(pod.attributes)
+            + numberOfTypeOccurrences * accumulatedSizeOfTypes(pod.attributes)
+            + pod.attributes.size() * (templateString.size()
+                                       - (numberOfNameOccurrences + numberOfTypeOccurrences)
+                                       * LengthOfPlaceholderText);
+    out.reserve(expectedOutSize);
+    for (const PODAttribute &a : pod.attributes)
+        out += templateString.arg(a.type, a.name, cap(a.name));
+    return out;
+}
+
+QString RepCodeGenerator::formatQPropertyDeclarations(const POD &pod)
+{
+    QString prop = QStringLiteral("    Q_PROPERTY(%1 %2 READ %2 WRITE set%3)\n");
+    return formatTemplateStringArgTypeNameCapitalizedName(1, 3, prop, pod);
+}
+
+QString RepCodeGenerator::formatConstructors(const POD &pod)
+{
+    QString initializerString = QStringLiteral(": ");
+    QString defaultInitializerString = initializerString;
+    QString argString;
+    for (const PODAttribute &a : pod.attributes) {
+        initializerString += QString::fromLatin1("m_%1(%1), ").arg(a.name);
+        defaultInitializerString += QString::fromLatin1("m_%1(), ").arg(a.name);
+        argString += QString::fromLatin1("%1 %2, ").arg(a.type, a.name);
+    }
+    argString.chop(2);
+    initializerString.chop(2);
+    defaultInitializerString.chop(2);
+
+    return QString::fromLatin1("    %1() %2 {}\n"
+                   "    explicit %1(%3) %4 {}\n")
+            .arg(pod.name, defaultInitializerString, argString, initializerString);
+}
+
+QString RepCodeGenerator::formatPropertyGettersAndSetters(const POD &pod)
+{
+    QString templateString
+            = QString::fromLatin1("    %1 %2() const { return m_%2; }\n"
+                                  "    void set%3(%1 %2) { if (%2 != m_%2) { m_%2 = %2; } }\n");
+    return formatTemplateStringArgTypeNameCapitalizedName(2, 8, qMove(templateString), pod);
+}
+
+QString RepCodeGenerator::formatDataMembers(const POD &pod)
+{
+    QString out;
+    const QString prefix = QStringLiteral("    ");
+    const QString infix  = QStringLiteral(" m_");
+    const QString suffix = QStringLiteral(";\n");
+    const auto expectedOutSize
+            = accumulatedSizeOfNames(pod.attributes)
+            + accumulatedSizeOfTypes(pod.attributes)
+            + pod.attributes.size() * (prefix.size() + infix.size() + suffix.size());
+    out.reserve(expectedOutSize);
+    for (const PODAttribute &a : pod.attributes) {
+        out += prefix;
+        out += a.type;
+        out += infix;
+        out += a.name;
+        out += suffix;
+    }
+    Q_ASSERT(out.size() == expectedOutSize);
+    return out;
+}
+
+QString RepCodeGenerator::formatDebugOperator(const POD &pod)
+{
+    QString props;
+    int count = 0;
+    for (const PODAttribute &attribute : pod.attributes) {
+        if (count++ > 0)
+            props.append(QLatin1String(" << \", \""));
+        props.append(QLatin1String(" << \"%1: \" << obj.%1()").arg(attribute.name));
+    }
+
+    return QLatin1String("inline QDebug operator<<(QDebug dbg, const %1 &obj) {\n" \
+                         "    dbg.nospace() << \"%1(\" %2 << \")\";\n" \
+                         "    return dbg.maybeSpace();\n}\n\n").arg(pod.name, props);
+}
+
+QString RepCodeGenerator::formatMarshallingOperators(const POD &pod)
+{
+    return QLatin1String("inline QDataStream &operator<<(QDataStream &ds, const ") + pod.name
+           + QLatin1String(" &obj) {\n"
+           "    QtRemoteObjects::copyStoredProperties(&obj, ds);\n"
+           "    return ds;\n"
+           "}\n"
+           "\n"
+           "inline QDataStream &operator>>(QDataStream &ds, ") + pod.name
+           + QLatin1String(" &obj) {\n"
+           "    QtRemoteObjects::copyStoredProperties(ds, &obj);\n"
+           "    return ds;\n"
+           "}\n")
+           ;
+}
+
+QString RepCodeGenerator::typeForMode(const ASTProperty &property, RepCodeGenerator::Mode mode)
+{
+    if (!property.isPointer)
+        return property.type;
+
+    if (property.type.startsWith(QStringLiteral("QAbstractItemModel")))
+        return mode == REPLICA ? property.type + QStringLiteral("Replica*")
+                               : property.type + QStringLiteral("*");
+
+    switch (mode) {
+    case REPLICA: return property.type + QStringLiteral("Replica*");
+    case SIMPLE_SOURCE:
+        Q_FALLTHROUGH();
+    case SOURCE: return property.type + QStringLiteral("Source*");
+    default: qCritical("Invalid mode");
+    }
+
+    return QStringLiteral("InvalidPropertyName");
+}
+
+void RepCodeGenerator::generateSimpleSetter(const ASTProperty &property, bool generateOverride)
+{
+    if (!generateOverride)
+        m_stream << "    virtual ";
+    else
+        m_stream << "    ";
+    m_stream << "void set" << cap(property.name) << "(" << typeForMode(property, SIMPLE_SOURCE)
+             << " " << property.name << ")";
+    if (generateOverride)
+        m_stream << " override";
+    m_stream << Qt::endl;
+    m_stream << "    {" << Qt::endl;
+    m_stream << "        if (" << property.name << " != m_" << property.name << ") {" << Qt::endl;
+    m_stream << "            m_" << property.name << " = " << property.name << ";" << Qt::endl;
+    m_stream << "            Q_EMIT " << property.name << "Changed(m_" << property.name << ");"
+             << Qt::endl;
+    m_stream << "        }" << Qt::endl;
+    m_stream << "    }" << Qt::endl;
+}
+
+void RepCodeGenerator::generatePOD(const POD &pod)
+{
+    QStringList equalityCheck;
+    for (const PODAttribute &attr : pod.attributes)
+        equalityCheck << QStringLiteral("left.%1() == right.%1()").arg(attr.name);
+    m_stream << "class " << pod.name << "\n"
+                "{\n"
+                "    Q_GADGET\n"
+             << "\n"
+             <<      formatQPropertyDeclarations(pod);
+    if (hasScopedEnum(pod)) // See https://bugreports.qt.io/browse/QTBUG-73360
+        m_stream << "    Q_CLASSINFO(\"RegisterEnumClassesUnscoped\", \"false\")\n";
+    m_stream << "public:\n";
+    generateDeclarationsForEnums(pod.enums);
+    for (auto &flag : pod.flags) {
+        m_stream << "    Q_DECLARE_FLAGS(" << flag.name << ", " << flag._enum << ")\n";
+        m_stream << "    Q_FLAG(" << flag.name << ")\n";
+    }
+    m_stream <<      formatConstructors(pod)
+             <<      formatPropertyGettersAndSetters(pod)
+             << "private:\n"
+             <<      formatDataMembers(pod)
+             << "};\n"
+             << "\n"
+             << "inline bool operator==(const " << pod.name << " &left, const " << pod.name <<
+                " &right) Q_DECL_NOTHROW {\n"
+             << "    return " << equalityCheck.join(QStringLiteral(" && ")) << ";\n"
+             << "}\n"
+             << "inline bool operator!=(const " << pod.name << " &left, const " << pod.name <<
+                " &right) Q_DECL_NOTHROW {\n"
+             << "    return !(left == right);\n"
+             << "}\n"
+             << "\n"
+             << formatDebugOperator(pod)
+             << formatMarshallingOperators(pod);
+    for (auto &flag : pod.flags)
+        m_stream << "Q_DECLARE_OPERATORS_FOR_FLAGS(" << pod.name << "::" << flag.name << ")\n";
+    m_stream << "\n";
+}
+
+QString getEnumType(const ASTEnum &en)
+{
+    if (!en.type.isEmpty())
+        return en.type;
+    if (en.isSigned) {
+        if (en.max < 0x7F)
+            return QStringLiteral("qint8");
+        if (en.max < 0x7FFF)
+            return QStringLiteral("qint16");
+        return QStringLiteral("qint32");
+    } else {
+        if (en.max < 0xFF)
+            return QStringLiteral("quint8");
+        if (en.max < 0xFFFF)
+            return QStringLiteral("quint16");
+        return QStringLiteral("quint32");
+    }
+}
+
+void RepCodeGenerator::generateDeclarationsForEnums(const QList<ASTEnum> &enums,
+                                                    bool generateQENUM)
+{
+    if (!generateQENUM) {
+        m_stream << "    // You need to add this enum as well as Q_ENUM to your" << Qt::endl;
+        m_stream << "    // QObject class in order to use .rep enums over QtRO for" << Qt::endl;
+        m_stream << "    // non-repc generated QObjects." << Qt::endl;
+    }
+
+    for (const ASTEnum &en : enums) {
+        m_stream << "    enum " << (en.isScoped ? "class " : "") << en.name
+                 << (en.type.isEmpty() ? "" : " : ") << en.type << " {\n";
+        for (const ASTEnumParam &p : en.params)
+            m_stream << "        " << p.name << " = " << p.value << ",\n";
+
+        m_stream << "    };\n";
+
+        if (generateQENUM)
+            m_stream << "    Q_ENUM(" << en.name << ")\n";
+    }
+}
+
+void RepCodeGenerator::generateEnumGadget(const ASTEnum &en, const QString &className)
+{
+    m_stream << "class " << className << "\n"
+                "{\n"
+                "    Q_GADGET\n";
+    if (en.isScoped)
+        m_stream << "    Q_CLASSINFO(\"RegisterEnumClassesUnscoped\", \"false\")\n";
+    m_stream << "    " << className << "();\n"
+                "\n"
+                "public:\n";
+
+    auto enums = QList<ASTEnum>() << en;
+    generateDeclarationsForEnums(enums);
+    if (en.flagIndex >= 0) {
+        auto flag = m_ast.flags.at(en.flagIndex);
+        m_stream << "    Q_DECLARE_FLAGS(" << flag.name << ", " << flag._enum << ")\n";
+        m_stream << "    Q_FLAG(" << flag.name << ")\n";
+        m_stream << "};\n\n";
+        m_stream << "Q_DECLARE_OPERATORS_FOR_FLAGS(" << className << "::" << flag.name << ")\n\n";
+    } else {
+        m_stream << "};\n\n";
+    }
+}
+
+QString RepCodeGenerator::generateMetaTypeRegistration(const QSet<QString> &metaTypes)
+{
+    QString out;
+    const QString qRegisterMetaType = QStringLiteral("        qRegisterMetaType<");
+    const QString lineEnding = QStringLiteral(">();\n");
+    for (const QString &metaType : metaTypes) {
+        if (isBuiltinType(metaType))
+            continue;
+
+        out += qRegisterMetaType;
+        out += metaType;
+        out += lineEnding;
+    }
+    return out;
+}
+
+QString RepCodeGenerator::generateMetaTypeRegistrationForPending(const QSet<QString> &metaTypes)
+{
+    QString out;
+    if (!metaTypes.isEmpty())
+        out += QLatin1String("        qRegisterMetaType<QRemoteObjectPendingCall>();\n");
+    const QString qRegisterMetaType =
+        QStringLiteral("        qRegisterMetaType<QRemoteObjectPendingReply<%1>>();\n");
+    const QString qRegisterConverterConditional =
+        QStringLiteral("        if (!QMetaType::hasRegisteredConverterFunction<"
+                       "QRemoteObjectPendingReply<%1>, QRemoteObjectPendingCall>())\n");
+    const QString qRegisterConverter =
+        QStringLiteral("            QMetaType::registerConverter<QRemoteObjectPendingReply<%1>"
+                       ", QRemoteObjectPendingCall>();\n");
+    for (const QString &metaType : metaTypes) {
+        out += qRegisterMetaType.arg(metaType);
+        out += qRegisterConverterConditional.arg(metaType);
+        out += qRegisterConverter.arg(metaType);
+    }
+    return out;
+}
+
+void RepCodeGenerator::generateClass(Mode mode, const ASTClass &astClass,
+                                     const QString &metaTypeRegistrationCode)
+{
+    const QString className = (astClass.name + (mode == REPLICA ?
+                               QStringLiteral("Replica") : mode == SOURCE ?
+                               QStringLiteral("Source") : QStringLiteral("SimpleSource")));
+    if (mode == REPLICA)
+        m_stream << "class " << className << " : public QRemoteObjectReplica" << Qt::endl;
+    else if (mode == SIMPLE_SOURCE)
+        m_stream << "class " << className << " : public " << astClass.name << "Source"
+                 << Qt::endl;
+    else
+        m_stream << "class " << className << " : public QObject" << Qt::endl;
+
+    m_stream << "{\n";
+    m_stream << "    Q_OBJECT\n";
+    if (hasScopedEnum(astClass)) // See https://bugreports.qt.io/browse/QTBUG-73360
+        m_stream << "    Q_CLASSINFO(\"RegisterEnumClassesUnscoped\", \"false\")\n";
+    if (mode != SIMPLE_SOURCE) {
+        m_stream << "    Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_TYPE, \"" << astClass.name
+                 << "\")" << Qt::endl;
+        m_stream << "    Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_SIGNATURE, \""
+                 << QLatin1String(classSignature(astClass)) << "\")" << Qt::endl;
+        for (int i = 0; i < astClass.modelMetadata.count(); i++) {
+            const auto model = astClass.modelMetadata.at(i);
+            const auto modelName = astClass.properties.at(model.propertyIndex).name;
+            if (!model.roles.isEmpty()) {
+                QStringList list;
+                for (auto role : model.roles)
+                    list << role.name;
+                m_stream << QString::fromLatin1("    Q_CLASSINFO(\"%1_ROLES\", \"%2\")")
+                            .arg(modelName.toUpper(), list.join(QChar::fromLatin1('|')))
+                         << Qt::endl;
+            }
+        }
+
+
+        //First output properties
+        for (const ASTProperty &property : astClass.properties) {
+            m_stream << "    Q_PROPERTY(" << typeForMode(property, mode) << " " << property.name
+                     << " READ " << property.name;
+            if (property.modifier == ASTProperty::Constant) {
+                if (mode == REPLICA) // We still need to notify when we get the initial value
+                    m_stream << " NOTIFY " << property.name << "Changed";
+                else
+                    m_stream << " CONSTANT";
+            } else if (property.modifier == ASTProperty::ReadOnly)
+                m_stream << " NOTIFY " << property.name << "Changed";
+            else if (property.modifier == ASTProperty::ReadWrite)
+                m_stream << " WRITE set" << cap(property.name) << " NOTIFY " << property.name
+                         << "Changed";
+            else if (property.modifier == ASTProperty::ReadPush ||
+                     property.modifier == ASTProperty::SourceOnlySetter) {
+                if (mode == REPLICA) // The setter slot isn't known to the PROP
+                    m_stream << " NOTIFY " << property.name << "Changed";
+                else // The Source can use the setter, since non-asynchronous
+                    m_stream << " WRITE set" << cap(property.name) << " NOTIFY "
+                             << property.name << "Changed";
+            }
+            m_stream << ")" << Qt::endl;
+        }
+
+        if (!astClass.enums.isEmpty()) {
+            m_stream << "" << Qt::endl;
+            m_stream << "public:" << Qt::endl;
+            generateDeclarationsForEnums(astClass.enums);
+            for (const auto &flag : astClass.flags) {
+                m_stream << "    Q_DECLARE_FLAGS(" << flag.name << ", " << flag._enum << ")\n";
+                m_stream << "    Q_FLAG(" << flag.name << ")\n";
+            }
+        }
+    }
+
+    m_stream << "" << Qt::endl;
+    m_stream << "public:" << Qt::endl;
+
+    if (mode == REPLICA) {
+        m_stream << "    " << className << "() : QRemoteObjectReplica() { initialize(); }"
+                 << Qt::endl;
+        m_stream << "    static void registerMetatypes()" << Qt::endl;
+        m_stream << "    {" << Qt::endl;
+        m_stream << "        static bool initialized = false;" << Qt::endl;
+        m_stream << "        if (initialized)" << Qt::endl;
+        m_stream << "            return;" << Qt::endl;
+        m_stream << "        initialized = true;" << Qt::endl;
+
+        if (!metaTypeRegistrationCode.isEmpty())
+            m_stream << metaTypeRegistrationCode << Qt::endl;
+
+        m_stream << "    }" << Qt::endl;
+
+        if (astClass.hasPointerObjects())
+        {
+            m_stream << "    void setNode(QRemoteObjectNode *node) override" << Qt::endl;
+            m_stream << "    {" << Qt::endl;
+            m_stream << "        QRemoteObjectReplica::setNode(node);" << Qt::endl;
+            for (int index = 0; index < astClass.properties.count(); ++index) {
+                const ASTProperty &property = astClass.properties.at(index);
+                if (!property.isPointer)
+                    continue;
+                const QString acquireName = astClass.name + QLatin1String("::") + property.name;
+                if (astClass.subClassPropertyIndices.contains(index))
+                    m_stream << QString::fromLatin1("        setChild(%1, QVariant::fromValue("
+                                "node->acquire<%2Replica>(QRemoteObjectStringLiterals::CLASS()"
+                                ".arg(\"%3\"))));")
+                                .arg(QString::number(index), property.type, acquireName)
+                             << Qt::endl;
+                else
+                    m_stream << QString::fromLatin1("        setChild(%1, QVariant::fromValue("
+                                "node->acquireModel(QRemoteObjectStringLiterals::MODEL()"
+                                ".arg(\"%2\"))));")
+                                .arg(QString::number(index), acquireName) << Qt::endl;
+                m_stream << "        Q_EMIT " << property.name << "Changed(" << property.name
+                         << "()" << ");" << Qt::endl;
+
+            }
+            m_stream << "    }" << Qt::endl;
+        }
+        m_stream << "" << Qt::endl;
+        m_stream << "private:" << Qt::endl;
+        m_stream << "    " << className
+                 << "(QRemoteObjectNode *node, const QString &name = QString())" << Qt::endl;
+        m_stream << "        : QRemoteObjectReplica(ConstructWithNode)" << Qt::endl;
+        m_stream << "    {" << Qt::endl;
+        m_stream << "        initializeNode(node, name);" << Qt::endl;
+        for (int index = 0; index < astClass.properties.count(); ++index) {
+            const ASTProperty &property = astClass.properties.at(index);
+            if (!property.isPointer)
+                continue;
+            const QString acquireName = astClass.name + QLatin1String("::") + property.name;
+            if (astClass.subClassPropertyIndices.contains(index))
+                m_stream << QString::fromLatin1("        setChild(%1, QVariant::fromValue("
+                            "node->acquire<%2Replica>(QRemoteObjectStringLiterals::CLASS()"
+                            ".arg(\"%3\"))));")
+                            .arg(QString::number(index), property.type, acquireName) << Qt::endl;
+            else
+                m_stream << QString::fromLatin1("        setChild(%1, QVariant::fromValue("
+                            "node->acquireModel(QRemoteObjectStringLiterals::MODEL()"
+                            ".arg(\"%2\"))));")
+                            .arg(QString::number(index), acquireName) << Qt::endl;
+        }
+        m_stream << "    }" << Qt::endl;
+
+        m_stream << "" << Qt::endl;
+
+        m_stream << "    void initialize() override" << Qt::endl;
+        m_stream << "    {" << Qt::endl;
+        m_stream << "        " << className << "::registerMetatypes();" << Qt::endl;
+        m_stream << "        QVariantList properties;" << Qt::endl;
+        m_stream << "        properties.reserve(" << astClass.properties.size() << ");"
+                 << Qt::endl;
+        for (const ASTProperty &property : astClass.properties) {
+            if (property.isPointer)
+                m_stream << "        properties << QVariant::fromValue(("
+                         << typeForMode(property, mode) << ")" << property.defaultValue
+                         << ");" << Qt::endl;
+            else
+                m_stream << "        properties << QVariant::fromValue("
+                         << typeForMode(property, mode) << "(" << property.defaultValue
+                         << "));" << Qt::endl;
+        }
+        int nPersisted = 0;
+        if (astClass.hasPersisted) {
+            m_stream << "        QVariantList stored = retrieveProperties(QStringLiteral(\""
+                     << astClass.name << "\"), \"" << classSignature(astClass) << "\");"
+                     << Qt::endl;
+            m_stream << "        if (!stored.isEmpty()) {" << Qt::endl;
+            for (int i = 0; i < astClass.properties.size(); i++) {
+                if (astClass.properties.at(i).persisted) {
+                    m_stream << "            properties[" << i << "] = stored.at(" << nPersisted
+                             << ");" << Qt::endl;
+                    nPersisted++;
+                }
+            }
+            m_stream << "        }" << Qt::endl;
+        }
+        m_stream << "        setProperties(std::move(properties));" << Qt::endl;
+        m_stream << "    }" << Qt::endl;
+    } else if (mode == SOURCE) {
+        m_stream << "    explicit " << className
+                 << "(QObject *parent = nullptr) : QObject(parent)" << Qt::endl;
+        m_stream << "    {" << Qt::endl;
+        if (!metaTypeRegistrationCode.isEmpty())
+            m_stream << metaTypeRegistrationCode << Qt::endl;
+        m_stream << "    }" << Qt::endl;
+    } else {
+        QList<int> constIndices;
+        for (int index = 0; index < astClass.properties.count(); ++index) {
+            const ASTProperty &property = astClass.properties.at(index);
+            if (property.modifier == ASTProperty::Constant)
+                constIndices.append(index);
+        }
+        if (constIndices.isEmpty()) {
+            m_stream << "    explicit " << className << "(QObject *parent = nullptr) : "
+                     << astClass.name << "Source(parent)" << Qt::endl;
+        } else {
+            QStringList parameters;
+            for (int index : constIndices) {
+                const ASTProperty &property = astClass.properties.at(index);
+                parameters.append(QString::fromLatin1("%1 %2 = %3")
+                                  .arg(typeForMode(property, SOURCE), property.name,
+                                       property.defaultValue));
+            }
+            parameters.append(QStringLiteral("QObject *parent = nullptr"));
+            m_stream << "    explicit " << className << "("
+                     << parameters.join(QStringLiteral(", ")) << ") : " << astClass.name
+                     << "Source(parent)" << Qt::endl;
+        }
+        for (const ASTProperty &property : astClass.properties) {
+            if (property.modifier == ASTProperty::Constant)
+                m_stream << "    , m_" << property.name << "(" << property.name << ")"
+                         << Qt::endl;
+            else
+                m_stream << "    , m_" << property.name << "(" << property.defaultValue << ")"
+                         << Qt::endl;
+        }
+        m_stream << "    {" << Qt::endl;
+        m_stream << "    }" << Qt::endl;
+    }
+
+    m_stream << "" << Qt::endl;
+    m_stream << "public:" << Qt::endl;
+
+    if (mode == REPLICA && astClass.hasPersisted) {
+        m_stream << "    ~" << className << "() override {" << Qt::endl;
+        m_stream << "        QVariantList persisted;" << Qt::endl;
+        for (int i = 0; i < astClass.properties.size(); i++) {
+            if (astClass.properties.at(i).persisted) {
+                m_stream << "        persisted << propAsVariant(" << i << ");" << Qt::endl;
+            }
+        }
+        m_stream << "        persistProperties(QStringLiteral(\"" << astClass.name << "\"), \""
+                 << classSignature(astClass) << "\", persisted);" << Qt::endl;
+        m_stream << "    }" << Qt::endl;
+    } else {
+        m_stream << "    ~" << className << "() override = default;" << Qt::endl;
+    }
+    m_stream << "" << Qt::endl;
+
+    //Next output getter/setter
+    if (mode == REPLICA) {
+        int i = 0;
+        for (const ASTProperty &property : astClass.properties) {
+            auto type = typeForMode(property, mode);
+            if (type == QLatin1String("QVariant")) {
+                m_stream << "    " << type << " " << property.name << "() const" << Qt::endl;
+                m_stream << "    {" << Qt::endl;
+                m_stream << "        return propAsVariant(" << i << ");" << Qt::endl;
+                m_stream << "    }" << Qt::endl;
+            } else {
+                m_stream << "    " << type << " " << property.name << "() const" << Qt::endl;
+                m_stream << "    {" << Qt::endl;
+                m_stream << "        const QVariant variant = propAsVariant(" << i << ");"
+                         << Qt::endl;
+                m_stream << "        if (!variant.canConvert<" << type << ">()) {" << Qt::endl;
+                m_stream << "            qWarning() << \"QtRO cannot convert the property "
+                         << property.name << " to type " << type << "\";" << Qt::endl;
+                m_stream << "        }" << Qt::endl;
+                m_stream << "        return variant.value<" << type << " >();" << Qt::endl;
+                m_stream << "    }" << Qt::endl;
+            }
+            i++;
+            if (property.modifier == ASTProperty::ReadWrite) {
+                m_stream << "" << Qt::endl;
+                m_stream << "    void set" << cap(property.name) << "(" << property.type << " "
+                         << property.name << ")" << Qt::endl;
+                m_stream << "    {" << Qt::endl;
+                m_stream << "        static int __repc_index = " << className
+                         << "::staticMetaObject.indexOfProperty(\"" << property.name << "\");"
+                         << Qt::endl;
+                m_stream << "        QVariantList __repc_args;" << Qt::endl;
+                m_stream << "        __repc_args << QVariant::fromValue(" << property.name << ");"
+                         << Qt::endl;
+                m_stream << "        send(QMetaObject::WriteProperty, __repc_index, __repc_args);"
+                         << Qt::endl;
+                m_stream << "    }" << Qt::endl;
+            }
+            m_stream << "" << Qt::endl;
+        }
+    } else if (mode == SOURCE) {
+        for (const ASTProperty &property : astClass.properties)
+            m_stream << "    virtual " << typeForMode(property, mode) << " " << property.name
+                     << "() const = 0;" << Qt::endl;
+        for (const ASTProperty &property : astClass.properties) {
+            if (property.modifier == ASTProperty::ReadWrite ||
+                    property.modifier == ASTProperty::ReadPush ||
+                    property.modifier == ASTProperty::SourceOnlySetter)
+                m_stream << "    virtual void set" << cap(property.name) << "("
+                         << typeForMode(property, mode) << " " << property.name << ") = 0;"
+                         << Qt::endl;
+        }
+    } else {
+        for (const ASTProperty &property : astClass.properties)
+            m_stream << "    " << typeForMode(property, mode) << " " << property.name
+                     << "() const override { return m_"
+                << property.name << "; }" << Qt::endl;
+        for (const ASTProperty &property : astClass.properties) {
+            if (property.modifier == ASTProperty::ReadWrite ||
+                    property.modifier == ASTProperty::ReadPush ||
+                    property.modifier == ASTProperty::SourceOnlySetter) {
+                generateSimpleSetter(property);
+            }
+        }
+    }
+
+    if (mode != SIMPLE_SOURCE) {
+        //Next output property signals
+        if (!astClass.properties.isEmpty() || !astClass.signalsList.isEmpty()) {
+            m_stream << "" << Qt::endl;
+            m_stream << "Q_SIGNALS:" << Qt::endl;
+            for (const ASTProperty &property : astClass.properties) {
+                if (property.modifier != ASTProperty::Constant)
+                    m_stream
+                        << "    void " << property.name << "Changed("
+                        << fullyQualifiedName(astClass, className, typeForMode(property, mode))
+                        << " " << property.name << ");" << Qt::endl;
+            }
+
+            const auto signalsList = transformEnumParams(astClass, astClass.signalsList,
+                                                         className);
+            for (const ASTFunction &signal : signalsList)
+                m_stream << "    void " << signal.name << "(" << signal.paramsAsString() << ");"
+                         << Qt::endl;
+
+            // CONSTANT source properties still need an onChanged signal on the Replica side to
+            // update (once) when the value is initialized.  Put these last, so they don't mess
+            // up the signal index order
+            for (const ASTProperty &property : astClass.properties) {
+                if (mode == REPLICA && property.modifier == ASTProperty::Constant)
+                    m_stream
+                        << "    void " << property.name << "Changed("
+                        << fullyQualifiedName(astClass, className, typeForMode(property, mode))
+                        << " " << property.name << ");" << Qt::endl;
+            }
+        }
+        bool hasWriteSlots = false;
+        for (const ASTProperty &property : astClass.properties) {
+            if (property.modifier == ASTProperty::ReadPush) {
+                hasWriteSlots = true;
+                break;
+            }
+        }
+        if (hasWriteSlots || !astClass.slotsList.isEmpty()) {
+            m_stream << "" << Qt::endl;
+            m_stream << "public Q_SLOTS:" << Qt::endl;
+            for (const ASTProperty &property : astClass.properties) {
+                if (property.modifier == ASTProperty::ReadPush) {
+                    const auto type = fullyQualifiedName(astClass, className, property.type);
+                    if (mode != REPLICA) {
+                        m_stream << "    virtual void push" << cap(property.name) << "(" << type
+                                 << " " << property.name << ")" << Qt::endl;
+                        m_stream << "    {" << Qt::endl;
+                        m_stream << "        set" << cap(property.name) << "(" << property.name
+                                 << ");" << Qt::endl;
+                        m_stream << "    }" << Qt::endl;
+                    } else {
+                        m_stream << "    void push" << cap(property.name) << "(" << type << " "
+                                 << property.name << ")" << Qt::endl;
+                        m_stream << "    {" << Qt::endl;
+                        m_stream << "        static int __repc_index = " << className
+                                 << "::staticMetaObject.indexOfSlot(\"push" << cap(property.name)
+                                 << "(" << type << ")\");" << Qt::endl;
+                        m_stream << "        QVariantList __repc_args;" << Qt::endl;
+                        m_stream << "        __repc_args << QVariant::fromValue(" << property.name
+                                 << ");" << Qt::endl;
+                        m_stream << "        send(QMetaObject::InvokeMetaMethod, __repc_index,"
+                                 << " __repc_args);" << Qt::endl;
+                        m_stream << "    }" << Qt::endl;
+                    }
+                }
+            }
+            const auto slotsList = transformEnumParams(astClass, astClass.slotsList, className);
+            for (const ASTFunction &slot : slotsList) {
+                const auto returnType = fullyQualifiedName(astClass, className, slot.returnType);
+                if (mode != REPLICA) {
+                    m_stream << "    virtual " << returnType << " " << slot.name << "("
+                             << slot.paramsAsString() << ") = 0;" << Qt::endl;
+                } else {
+                    // TODO: Discuss whether it is a good idea to special-case for void here,
+                    const bool isVoid = slot.returnType == QStringLiteral("void");
+
+                    if (isVoid)
+                        m_stream << "    void " << slot.name << "(" << slot.paramsAsString()
+                                 << ")" << Qt::endl;
+                    else
+                        m_stream << "    QRemoteObjectPendingReply<" << returnType << "> "
+                                 << slot.name << "(" << slot.paramsAsString()<< ")" << Qt::endl;
+                    m_stream << "    {" << Qt::endl;
+                    m_stream << "        static int __repc_index = " << className
+                             << "::staticMetaObject.indexOfSlot(\"" << slot.name << "("
+                             << slot.paramsAsString(ASTFunction::Normalized) << ")\");"
+                             << Qt::endl;
+                    m_stream << "        QVariantList __repc_args;" << Qt::endl;
+                    const auto &paramNames = slot.paramNames();
+                    if (!paramNames.isEmpty()) {
+                        m_stream << "        __repc_args" << Qt::endl;
+                        for (const QString &name : paramNames)
+                            m_stream << "            << " << "QVariant::fromValue(" << name << ")"
+                                     << Qt::endl;
+                        m_stream << "        ;" << Qt::endl;
+                    }
+                    if (isVoid)
+                        m_stream << "        send(QMetaObject::InvokeMetaMethod, __repc_index,"
+                                 << " __repc_args);" << Qt::endl;
+                    else
+                        m_stream << "        return QRemoteObjectPendingReply<" << returnType
+                                 << ">(sendWithReply(QMetaObject::InvokeMetaMethod, __repc_index,"
+                                 << " __repc_args));" << Qt::endl;
+                    m_stream << "    }" << Qt::endl;
+                }
+            }
+        }
+    } else {
+        if (!astClass.properties.isEmpty()) {
+            bool addProtected = true;
+            for (const ASTProperty &property : astClass.properties) {
+                if (property.modifier == ASTProperty::ReadOnly) {
+                    if (addProtected) {
+                        m_stream << "" << Qt::endl;
+                        m_stream << "protected:" << Qt::endl;
+                        addProtected = false;
+                    }
+                    generateSimpleSetter(property, false);
+                }
+            }
+        }
+    }
+
+    m_stream << "" << Qt::endl;
+    m_stream << "private:" << Qt::endl;
+
+    //Next output data members
+    if (mode == SIMPLE_SOURCE) {
+        for (const ASTProperty &property : astClass.properties)
+            m_stream << "    " << typeForMode(property, SOURCE) << " " << "m_" << property.name
+                     << ";" << Qt::endl;
+    }
+
+    if (mode != SIMPLE_SOURCE)
+        m_stream << "    friend class QT_PREPEND_NAMESPACE(QRemoteObjectNode);" << Qt::endl;
+
+    m_stream << "};\n\n";
+    if (mode != SIMPLE_SOURCE) {
+        for (const ASTFlag &flag : astClass.flags)
+            m_stream << "Q_DECLARE_OPERATORS_FOR_FLAGS(" << className << "::" << flag.name
+                     << ")\n\n";
+    }
+}
+
+void RepCodeGenerator::generateSourceAPI(const ASTClass &astClass)
+{
+    const QString className = astClass.name + QStringLiteral("SourceAPI");
+    m_stream << QStringLiteral("template <class ObjectType>") << Qt::endl;
+    m_stream << QString::fromLatin1("struct %1 : public SourceApiMap").arg(className) << Qt::endl;
+    m_stream << QStringLiteral("{") << Qt::endl;
+    if (!astClass.enums.isEmpty()) {
+        // Include enum definition in SourceAPI
+        generateDeclarationsForEnums(astClass.enums, false);
+    }
+    for (const auto &flag : astClass.flags)
+        m_stream << QLatin1String("    typedef QFlags<typename ObjectType::%1> %2;")
+                    .arg(flag._enum, flag.name) << Qt::endl;
+    m_stream << QString::fromLatin1("    %1(ObjectType *object, const QString &name = "
+                                    "QLatin1String(\"%2\"))").arg(className, astClass.name)
+             << Qt::endl;
+    m_stream << QStringLiteral("        : SourceApiMap(), m_name(name)") << Qt::endl;
+    m_stream << QStringLiteral("    {") << Qt::endl;
+    if (!astClass.hasPointerObjects())
+        m_stream << QStringLiteral("        Q_UNUSED(object)") << Qt::endl;
+
+    const auto enumCount = astClass.enums.count();
+    const auto totalCount = enumCount + astClass.flags.count();
+    for (int i : astClass.subClassPropertyIndices) {
+        const ASTProperty &child = astClass.properties.at(i);
+        m_stream << QString::fromLatin1("        using %1_type_t = typename std::remove_pointer<"
+                                        "decltype(object->%1())>::type;")
+                                        .arg(child.name) << Qt::endl;
+    }
+    m_stream << QString::fromLatin1("        m_enums[0] = %1;").arg(totalCount) << Qt::endl;
+    for (qsizetype i = 0; i < enumCount; ++i) {
+        const auto enumerator = astClass.enums.at(i);
+        m_stream << QString::fromLatin1("        m_enums[%1] = ObjectType::staticMetaObject."
+                                        "indexOfEnumerator(\"%2\");")
+                                        .arg(i+1).arg(enumerator.name) << Qt::endl;
+    }
+    for (qsizetype i = enumCount; i < totalCount; ++i) {
+        const auto flag = astClass.flags.at(i - enumCount);
+        m_stream << QString::fromLatin1("        m_enums[%1] = ObjectType::staticMetaObject."
+                                        "indexOfEnumerator(\"%2\");")
+                                        .arg(i+1).arg(flag.name) << Qt::endl;
+    }
+    const auto propCount = astClass.properties.count();
+    m_stream << QString::fromLatin1("        m_properties[0] = %1;").arg(propCount) << Qt::endl;
+    QList<ASTProperty> onChangeProperties;
+    QList<qsizetype> propertyChangeIndex;
+    for (qsizetype i = 0; i < propCount; ++i) {
+        const ASTProperty &prop = astClass.properties.at(i);
+        const QString propTypeName =
+            fullyQualifiedName(astClass, QStringLiteral("typename ObjectType"),
+                               typeForMode(prop, SOURCE));
+        m_stream << QString::fromLatin1("        m_properties[%1] = "
+                                        "QtPrivate::qtro_property_index<ObjectType>("
+                                        "&ObjectType::%2, static_cast<%3 (QObject::*)()>(nullptr)"
+                                        ",\"%2\");")
+                                        .arg(QString::number(i+1), prop.name, propTypeName)
+                 << Qt::endl;
+        if (prop.modifier == prop.ReadWrite) //Make sure we have a setter function
+            m_stream << QStringLiteral("        QtPrivate::qtro_method_test<ObjectType>("
+                                       "&ObjectType::set%1, static_cast<void (QObject::*)(%2)>"
+                                       "(nullptr));")
+                                       .arg(cap(prop.name), propTypeName) << Qt::endl;
+        if (prop.modifier != prop.Constant) { //Make sure we have an onChange signal
+            m_stream << QStringLiteral("        QtPrivate::qtro_method_test<ObjectType>("
+                                       "&ObjectType::%1Changed, static_cast<void (QObject::*)()>("
+                                       "nullptr));")
+                                       .arg(prop.name) << Qt::endl;
+            onChangeProperties << prop;
+            propertyChangeIndex << i + 1; //m_properties[0] is the count, so index is one higher
+        }
+    }
+    const auto signalCount = astClass.signalsList.count();
+    const auto changedCount = onChangeProperties.size();
+    m_stream << QString::fromLatin1("        m_signals[0] = %1;")
+                                    .arg(signalCount+onChangeProperties.size()) << Qt::endl;
+    for (qsizetype i = 0; i < changedCount; ++i)
+        m_stream
+            << QString::fromLatin1("        m_signals[%1] = QtPrivate::qtro_signal_index"
+                                   "<ObjectType>(&ObjectType::%2Changed, static_cast<void"
+                                   "(QObject::*)(%3)>(nullptr),m_signalArgCount+%4,"
+                                   "&m_signalArgTypes[%4]);")
+                                   .arg(QString::number(i+1), onChangeProperties.at(i).name,
+                                        fullyQualifiedName(astClass,
+                                                           QStringLiteral("typename ObjectType"),
+                                                           typeForMode(onChangeProperties.at(i),
+                                                                       SOURCE)),
+                                        QString::number(i))
+            << Qt::endl;
+
+    QList<ASTFunction> signalsList = transformEnumParams(astClass, astClass.signalsList,
+                                                         QStringLiteral("typename ObjectType"));
+    for (qsizetype i = 0; i < signalCount; ++i) {
+        const ASTFunction &sig = signalsList.at(i);
+        m_stream << QString::fromLatin1("        m_signals[%1] = QtPrivate::qtro_signal_index"
+                                        "<ObjectType>(&ObjectType::%2, static_cast<void "
+                                        "(QObject::*)(%3)>(nullptr),m_signalArgCount+%4,"
+                                        "&m_signalArgTypes[%4]);")
+                                        .arg(QString::number(changedCount+i+1), sig.name,
+                                             sig.paramsAsString(ASTFunction::Normalized),
+                                             QString::number(changedCount+i))
+                 << Qt::endl;
+    }
+    const auto slotCount = astClass.slotsList.count();
+    QList<ASTProperty> pushProps;
+    for (const ASTProperty &property : astClass.properties) {
+        if (property.modifier == ASTProperty::ReadPush)
+            pushProps << property;
+    }
+    const auto pushCount = pushProps.count();
+    const auto methodCount = slotCount + pushCount;
+    m_stream << QString::fromLatin1("        m_methods[0] = %1;").arg(methodCount) << Qt::endl;
+    const QString objType = QStringLiteral("typename ObjectType::");
+    for (qsizetype i = 0; i < pushCount; ++i) {
+        const ASTProperty &prop = pushProps.at(i);
+        const QString propTypeName = fullyQualifiedName(astClass,
+                                                        QStringLiteral("typename ObjectType"),
+                                                        prop.type);
+        m_stream <<
+            QString::fromLatin1("        m_methods[%1] = QtPrivate::qtro_method_index"
+                                "<ObjectType>(&ObjectType::push%2, static_cast<void "
+                                "(QObject::*)(%3)>(nullptr),\"push%2(%4)\","
+                                "m_methodArgCount+%5,&m_methodArgTypes[%5]);")
+                                .arg(QString::number(i+1), cap(prop.name), propTypeName,
+                                     // we don't want "typename ObjectType::" in the signature
+                                     QString(propTypeName).remove(objType),
+                                     QString::number(i))
+                 << Qt::endl;
+    }
+
+    QList<ASTFunction> slotsList = transformEnumParams(astClass, astClass.slotsList,
+                                                       QStringLiteral("typename ObjectType"));
+    for (qsizetype i = 0; i < slotCount; ++i) {
+        const ASTFunction &slot = slotsList.at(i);
+        const QString params = slot.paramsAsString(ASTFunction::Normalized);
+        m_stream << QString::fromLatin1("        m_methods[%1] = QtPrivate::qtro_method_index"
+                                        "<ObjectType>(&ObjectType::%2, static_cast<void "
+                                        "(QObject::*)(%3)>(nullptr),\"%2(%4)\","
+                                        "m_methodArgCount+%5,&m_methodArgTypes[%5]);")
+                                        .arg(QString::number(i+pushCount+1), slot.name, params,
+                                        // we don't want "typename ObjectType::" in the signature
+                                        QString(params).remove(objType),
+                                        QString::number(i+pushCount))
+                 << Qt::endl;
+    }
+    for (const auto &model : astClass.modelMetadata) {
+        const ASTProperty &property = astClass.properties.at(model.propertyIndex);
+        m_stream << QString::fromLatin1("        m_models << ModelInfo({object->%1(),")
+                                        .arg(property.name) << Qt::endl;
+        m_stream << QString::fromLatin1("                               QStringLiteral(\"%1\"),")
+                                        .arg(property.name) << Qt::endl;
+        QStringList list;
+        if (!model.roles.isEmpty()) {
+            for (auto role : model.roles)
+                list << role.name;
+        }
+        m_stream <<
+            QString::fromLatin1("                               QByteArrayLiteral(\"%1\")});")
+                                .arg(list.join(QChar::fromLatin1('|'))) << Qt::endl;
+    }
+    for (int i : astClass.subClassPropertyIndices) {
+        const ASTProperty &child = astClass.properties.at(i);
+        m_stream <<
+            QString::fromLatin1("        m_subclasses << new %2SourceAPI<%1_type_t>(object->%1(),"
+                                " QStringLiteral(\"%1\"));")
+                                .arg(child.name, child.type) << Qt::endl;
+    }
+    m_stream << QStringLiteral("    }") << Qt::endl;
+    m_stream << QStringLiteral("") << Qt::endl;
+    m_stream << QString::fromLatin1("    QString name() const override { return m_name; }")
+             << Qt::endl;
+    m_stream << QString::fromLatin1("    QString typeName() const override { "
+                                    "return QStringLiteral(\"%1\"); }")
+                                    .arg(astClass.name) << Qt::endl;
+    m_stream << QStringLiteral("    int enumCount() const override { return m_enums[0]; }")
+             << Qt::endl;
+    m_stream <<
+        QStringLiteral("    int propertyCount() const override { return m_properties[0]; }")
+        << Qt::endl;
+    m_stream << QStringLiteral("    int signalCount() const override { return m_signals[0]; }")
+             << Qt::endl;
+    m_stream << QStringLiteral("    int methodCount() const override { return m_methods[0]; }")
+             << Qt::endl;
+    m_stream << QStringLiteral("    int sourceEnumIndex(int index) const override") << Qt::endl;
+    m_stream << QStringLiteral("    {") << Qt::endl;
+    m_stream << QStringLiteral("        if (index < 0 || index >= m_enums[0])") << Qt::endl;
+    m_stream << QStringLiteral("            return -1;") << Qt::endl;
+    m_stream << QStringLiteral("        return m_enums[index+1];") << Qt::endl;
+    m_stream << QStringLiteral("    }") << Qt::endl;
+    m_stream << QStringLiteral("    int sourcePropertyIndex(int index) const override")
+             << Qt::endl;
+    m_stream << QStringLiteral("    {") << Qt::endl;
+    m_stream << QStringLiteral("        if (index < 0 || index >= m_properties[0])") << Qt::endl;
+    m_stream << QStringLiteral("            return -1;") << Qt::endl;
+    m_stream << QStringLiteral("        return m_properties[index+1];") << Qt::endl;
+    m_stream << QStringLiteral("    }") << Qt::endl;
+    m_stream << QStringLiteral("    int sourceSignalIndex(int index) const override") << Qt::endl;
+    m_stream << QStringLiteral("    {") << Qt::endl;
+    m_stream << QStringLiteral("        if (index < 0 || index >= m_signals[0])") << Qt::endl;
+    m_stream << QStringLiteral("            return -1;") << Qt::endl;
+    m_stream << QStringLiteral("        return m_signals[index+1];") << Qt::endl;
+    m_stream << QStringLiteral("    }") << Qt::endl;
+    m_stream << QStringLiteral("    int sourceMethodIndex(int index) const override") << Qt::endl;
+    m_stream << QStringLiteral("    {") << Qt::endl;
+    m_stream << QStringLiteral("        if (index < 0 || index >= m_methods[0])") << Qt::endl;
+    m_stream << QStringLiteral("            return -1;") << Qt::endl;
+    m_stream << QStringLiteral("        return m_methods[index+1];") << Qt::endl;
+    m_stream << QStringLiteral("    }") << Qt::endl;
+    if (signalCount+changedCount > 0) {
+        m_stream << QStringLiteral("    int signalParameterCount(int index) const override")
+                 << Qt::endl;
+        m_stream << QStringLiteral("    {") << Qt::endl;
+        m_stream << QStringLiteral("        if (index < 0 || index >= m_signals[0])") << Qt::endl;
+        m_stream << QStringLiteral("            return -1;") << Qt::endl;
+        m_stream << QStringLiteral("        return m_signalArgCount[index];") << Qt::endl;
+        m_stream << QStringLiteral("    }") << Qt::endl;
+        m_stream << QStringLiteral("    int signalParameterType(int sigIndex, int paramIndex) "
+                                   "const override") << Qt::endl;
+        m_stream << QStringLiteral("    {") << Qt::endl;
+        m_stream << QStringLiteral("        if (sigIndex < 0 || sigIndex >= m_signals[0] || "
+                                   "paramIndex < 0 || paramIndex >= m_signalArgCount[sigIndex])")
+                 << Qt::endl;
+        m_stream << QStringLiteral("            return -1;") << Qt::endl;
+        m_stream << QStringLiteral("        return m_signalArgTypes[sigIndex][paramIndex];")
+                 << Qt::endl;
+        m_stream << QStringLiteral("    }") << Qt::endl;
+    } else {
+        m_stream << QStringLiteral("    int signalParameterCount(int index) const override "
+                                   "{ Q_UNUSED(index) return -1; }") << Qt::endl;
+        m_stream << QStringLiteral("    int signalParameterType(int sigIndex, int paramIndex) "
+                                   "const override") << Qt::endl;
+        m_stream << QStringLiteral("    { Q_UNUSED(sigIndex) Q_UNUSED(paramIndex) return -1; }")
+                 << Qt::endl;
+    }
+    if (methodCount > 0) {
+        m_stream << QStringLiteral("    int methodParameterCount(int index) const override")
+                 << Qt::endl;
+        m_stream << QStringLiteral("    {") << Qt::endl;
+        m_stream << QStringLiteral("        if (index < 0 || index >= m_methods[0])") << Qt::endl;
+        m_stream << QStringLiteral("            return -1;") << Qt::endl;
+        m_stream << QStringLiteral("        return m_methodArgCount[index];") << Qt::endl;
+        m_stream << QStringLiteral("    }") << Qt::endl;
+        m_stream << QStringLiteral("    int methodParameterType(int methodIndex, int paramIndex) "
+                                   "const override") << Qt::endl;
+        m_stream << QStringLiteral("    {") << Qt::endl;
+        m_stream <<
+            QStringLiteral("        if (methodIndex < 0 || methodIndex >= m_methods[0] || "
+                           "paramIndex < 0 || paramIndex >= m_methodArgCount[methodIndex])")
+            << Qt::endl;
+        m_stream << QStringLiteral("            return -1;") << Qt::endl;
+        m_stream << QStringLiteral("        return m_methodArgTypes[methodIndex][paramIndex];")
+                 << Qt::endl;
+        m_stream << QStringLiteral("    }") << Qt::endl;
+    } else {
+        m_stream << QStringLiteral("    int methodParameterCount(int index) const override { "
+                                   "Q_UNUSED(index) return -1; }") << Qt::endl;
+        m_stream << QStringLiteral("    int methodParameterType(int methodIndex, int paramIndex) "
+                                   "const override") << Qt::endl;
+        m_stream <<
+            QStringLiteral("    { Q_UNUSED(methodIndex) Q_UNUSED(paramIndex) return -1; }")
+            << Qt::endl;
+    }
+    //propertyIndexFromSignal method
+    m_stream << QStringLiteral("    int propertyIndexFromSignal(int index) const override")
+             << Qt::endl;
+    m_stream << QStringLiteral("    {") << Qt::endl;
+    if (!propertyChangeIndex.isEmpty()) {
+        m_stream << QStringLiteral("        switch (index) {") << Qt::endl;
+        for (int i = 0; i < propertyChangeIndex.size(); ++i)
+            m_stream << QString::fromLatin1("        case %1: return m_properties[%2];")
+                        .arg(i).arg(propertyChangeIndex.at(i)) << Qt::endl;
+        m_stream << QStringLiteral("        }") << Qt::endl;
+    } else
+        m_stream << QStringLiteral("        Q_UNUSED(index)") << Qt::endl;
+    m_stream << QStringLiteral("        return -1;") << Qt::endl;
+    m_stream << QStringLiteral("    }") << Qt::endl;
+    //propertyRawIndexFromSignal method
+    m_stream << QStringLiteral("    int propertyRawIndexFromSignal(int index) const override")
+             << Qt::endl;
+    m_stream << QStringLiteral("    {") << Qt::endl;
+    if (!propertyChangeIndex.isEmpty()) {
+        m_stream << QStringLiteral("        switch (index) {") << Qt::endl;
+        for (int i = 0; i < propertyChangeIndex.size(); ++i)
+            m_stream << QString::fromLatin1("        case %1: return %2;").arg(i)
+                        .arg(propertyChangeIndex.at(i)-1) << Qt::endl;
+        m_stream << QStringLiteral("        }") << Qt::endl;
+    } else
+        m_stream << QStringLiteral("        Q_UNUSED(index)") << Qt::endl;
+    m_stream << QStringLiteral("        return -1;") << Qt::endl;
+    m_stream << QStringLiteral("    }") << Qt::endl;
+
+    //signalSignature method
+    m_stream << QStringLiteral("    const QByteArray signalSignature(int index) const override")
+             << Qt::endl;
+    m_stream << QStringLiteral("    {") << Qt::endl;
+    if (signalCount+changedCount > 0) {
+        m_stream << QStringLiteral("        switch (index) {") << Qt::endl;
+        for (int i = 0; i < changedCount; ++i) {
+            const ASTProperty &prop = onChangeProperties.at(i);
+            if (isClassEnum(astClass, prop.type))
+                m_stream <<
+                    QString::fromLatin1("        case %1: return QByteArrayLiteral(\"%2"
+                                        "Changed($1)\").replace(\"$1\", "
+                                        "QtPrivate::qtro_enum_signature<ObjectType>(\"%3\"));")
+                                        .arg(QString::number(i), prop.name, prop.type)
+                    << Qt::endl;
+            else
+                m_stream <<
+                    QString::fromLatin1("        case %1: return QByteArrayLiteral(\"%2"
+                                        "Changed(%3)\");")
+                                        .arg(QString::number(i), prop.name,
+                                             typeForMode(prop, SOURCE))
+                    << Qt::endl;
+        }
+        for (int i = 0; i < signalCount; ++i)
+        {
+            const ASTFunction &sig = astClass.signalsList.at(i);
+            auto paramsAsString = sig.paramsAsString(ASTFunction::Normalized);
+            const auto paramsAsList = paramsAsString.split(QLatin1String(","));
+            int enumCount = 0;
+            QString enumString;
+            for (int j = 0; j < paramsAsList.count(); j++) {
+                auto const p = paramsAsList.at(j);
+                if (isClassEnum(astClass, p)) {
+                    paramsAsString.replace(paramsAsString.indexOf(p), p.size(),
+                                           QStringLiteral("$%1").arg(enumCount));
+                    enumString.append(QString::fromLatin1(".replace(\"$%1\", QtPrivate::"
+                                                          "qtro_enum_signature<ObjectType>"
+                                                          "(\"%2\"))")
+                                                          .arg(enumCount++)
+                                                          .arg(paramsAsList.at(j)));
+                }
+            }
+            m_stream <<
+                QString::fromLatin1("        case %1: return QByteArrayLiteral(\"%2(%3)\")%4;")
+                                    .arg(QString::number(i+changedCount), sig.name,
+                                         paramsAsString, enumString) << Qt::endl;
+        }
+        m_stream << QStringLiteral("        }") << Qt::endl;
+    } else
+        m_stream << QStringLiteral("        Q_UNUSED(index)") << Qt::endl;
+    m_stream << QStringLiteral("        return QByteArrayLiteral(\"\");") << Qt::endl;
+    m_stream << QStringLiteral("    }") << Qt::endl;
+
+    //signalParameterNames method
+    m_stream <<
+        QStringLiteral("    QByteArrayList signalParameterNames(int index) const override")
+        << Qt::endl;
+    m_stream << QStringLiteral("    {") << Qt::endl;
+    m_stream << QStringLiteral("        if (index < 0 || index >= m_signals[0])") << Qt::endl;
+    m_stream << QStringLiteral("            return QByteArrayList();") << Qt::endl;
+    m_stream << QStringLiteral("        return ObjectType::staticMetaObject.method(m_signals["
+                               "index + 1]).parameterNames();") << Qt::endl;
+    m_stream << QStringLiteral("    }") << Qt::endl;
+
+    //methodSignature method
+    m_stream << QStringLiteral("    const QByteArray methodSignature(int index) const override")
+             << Qt::endl;
+    m_stream << QStringLiteral("    {") << Qt::endl;
+    if (methodCount > 0) {
+        m_stream << QStringLiteral("        switch (index) {") << Qt::endl;
+        for (int i = 0; i < pushCount; ++i)
+        {
+            const ASTProperty &prop = pushProps.at(i);
+            if (isClassEnum(astClass, prop.type))
+                m_stream << QString::fromLatin1("        case %1: return QByteArrayLiteral(\"push"
+                                                "%2($1)\").replace(\"$1\", QtPrivate::"
+                                                "qtro_enum_signature<ObjectType>(\"%3\"));")
+                                                .arg(QString::number(i), prop.name, prop.type)
+                         << Qt::endl;
+            else
+                m_stream <<
+                    QString::fromLatin1("        case %1: return QByteArrayLiteral(\"push"
+                                        "%2(%3)\");")
+                                        .arg(QString::number(i), cap(prop.name), prop.type)
+                    << Qt::endl;
+        }
+        for (int i = 0; i < slotCount; ++i)
+        {
+            const ASTFunction &slot = astClass.slotsList.at(i);
+            auto paramsAsString = slot.paramsAsString(ASTFunction::Normalized);
+            const auto paramsAsList = paramsAsString.split(QLatin1String(","));
+            int enumCount = 0;
+            QString enumString;
+            for (int j = 0; j < paramsAsList.count(); j++) {
+                auto const p = paramsAsList.at(j);
+                if (isClassEnum(astClass, p)) {
+                    paramsAsString.replace(paramsAsString.indexOf(p), p.size(),
+                                           QStringLiteral("$%1").arg(enumCount));
+                    enumString.append(QString::fromLatin1(".replace(\"$%1\", QtPrivate::"
+                                                          "qtro_enum_signature<ObjectType>"
+                                                          "(\"%2\"))")
+                                                          .arg(enumCount++)
+                                                          .arg(paramsAsList.at(j)));
+                }
+            }
+            m_stream << QString::fromLatin1("        case %1: return QByteArrayLiteral(\"%2(%3)"
+                                            "\")%4;")
+                                            .arg(QString::number(i+pushCount), slot.name,
+                                                 paramsAsString, enumString) << Qt::endl;
+        }
+        m_stream << QStringLiteral("        }") << Qt::endl;
+    } else
+        m_stream << QStringLiteral("        Q_UNUSED(index)") << Qt::endl;
+    m_stream << QStringLiteral("        return QByteArrayLiteral(\"\");") << Qt::endl;
+    m_stream << QStringLiteral("    }") << Qt::endl;
+
+    //methodType method
+    m_stream << QStringLiteral("    QMetaMethod::MethodType methodType(int) const override")
+             << Qt::endl;
+    m_stream << QStringLiteral("    {") << Qt::endl;
+    m_stream << QStringLiteral("        return QMetaMethod::Slot;") << Qt::endl;
+    m_stream << QStringLiteral("    }") << Qt::endl;
+
+    //methodParameterNames method
+    m_stream <<
+        QStringLiteral("    QByteArrayList methodParameterNames(int index) const override")
+        << Qt::endl;
+    m_stream << QStringLiteral("    {") << Qt::endl;
+    m_stream << QStringLiteral("        if (index < 0 || index >= m_methods[0])") << Qt::endl;
+    m_stream << QStringLiteral("            return QByteArrayList();") << Qt::endl;
+    m_stream << QStringLiteral("        return ObjectType::staticMetaObject.method(m_methods["
+                               "index + 1]).parameterNames();") << Qt::endl;
+    m_stream << QStringLiteral("    }") << Qt::endl;
+
+    //typeName method
+    m_stream << QStringLiteral("    const QByteArray typeName(int index) const override")
+             << Qt::endl;
+    m_stream << QStringLiteral("    {") << Qt::endl;
+    if (methodCount > 0) {
+        m_stream << QStringLiteral("        switch (index) {") << Qt::endl;
+        for (int i = 0; i < pushCount; ++i)
+        {
+            m_stream <<
+                QString::fromLatin1("        case %1: return QByteArrayLiteral(\"void\");")
+                .arg(QString::number(i)) << Qt::endl;
+        }
+        for (int i = 0; i < slotCount; ++i)
+        {
+            const ASTFunction &slot = astClass.slotsList.at(i);
+            if (isClassEnum(astClass, slot.returnType))
+                m_stream <<
+                    QString::fromLatin1("        case %1: return QByteArrayLiteral(\"$1\")"
+                                        ".replace(\"$1\", QtPrivate::qtro_enum_signature"
+                                        "<ObjectType>(\"%2\"));")
+                                        .arg(QString::number(i+pushCount), slot.returnType)
+                    << Qt::endl;
+            else
+                m_stream <<
+                    QString::fromLatin1("        case %1: return QByteArrayLiteral(\"%2\");")
+                    .arg(QString::number(i+pushCount), slot.returnType) << Qt::endl;
+        }
+        m_stream << QStringLiteral("        }") << Qt::endl;
+    } else
+        m_stream << QStringLiteral("        Q_UNUSED(index)") << Qt::endl;
+    m_stream << QStringLiteral("        return QByteArrayLiteral(\"\");") << Qt::endl;
+    m_stream << QStringLiteral("    }") << Qt::endl;
+
+    //objectSignature method
+    m_stream <<
+        QStringLiteral("    QByteArray objectSignature() const override { return QByteArray{\"")
+        << QLatin1String(classSignature(astClass))
+        << QStringLiteral("\"}; }") << Qt::endl;
+
+    m_stream << QStringLiteral("") << Qt::endl;
+    m_stream << QString::fromLatin1("    int m_enums[%1];").arg(totalCount + 1) << Qt::endl;
+    m_stream << QString::fromLatin1("    int m_properties[%1];").arg(propCount+1) << Qt::endl;
+    m_stream << QString::fromLatin1("    int m_signals[%1];").arg(signalCount+changedCount+1)
+             << Qt::endl;
+    m_stream << QString::fromLatin1("    int m_methods[%1];").arg(methodCount+1) << Qt::endl;
+    m_stream << QString::fromLatin1("    const QString m_name;") << Qt::endl;
+    if (signalCount+changedCount > 0) {
+        m_stream << QString::fromLatin1("    int m_signalArgCount[%1];")
+                                        .arg(signalCount+changedCount) << Qt::endl;
+        m_stream << QString::fromLatin1("    const int* m_signalArgTypes[%1];")
+                                        .arg(signalCount+changedCount) << Qt::endl;
+    }
+    if (methodCount > 0) {
+        m_stream << QString::fromLatin1("    int m_methodArgCount[%1];").arg(methodCount)
+                 << Qt::endl;
+        m_stream << QString::fromLatin1("    const int* m_methodArgTypes[%1];").arg(methodCount)
+                 << Qt::endl;
+    }
+    m_stream << QStringLiteral("};") << Qt::endl;
+    m_stream << "" << Qt::endl;
+}
+
+QT_END_NAMESPACE
diff --git a/tools/repc/repcodegenerator.h b/tools/repc/repcodegenerator.h
new file mode 100644 (file)
index 0000000..caf94c2
--- /dev/null
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#ifndef REPCODEGENERATOR_H
+#define REPCODEGENERATOR_H
+
+#include "repparser.h"
+
+#include <QList>
+#include <QSet>
+#include <QString>
+#include <QTextStream>
+
+QT_BEGIN_NAMESPACE
+
+class QIODevice;
+
+class RepCodeGenerator
+{
+public:
+    enum Mode
+    {
+        REPLICA,
+        SOURCE,
+        SIMPLE_SOURCE,
+        MERGED
+    };
+
+    RepCodeGenerator(QIODevice *outputDevice, const AST &ast);
+
+    void generate(Mode mode, QString fileName);
+
+    QByteArray classSignature(const ASTClass &ac);
+private:
+    void generateHeader(Mode mode);
+    QString generateMetaTypeRegistration(const QSet<QString> &metaTypes);
+    QString generateMetaTypeRegistrationForPending(const QSet<QString> &metaTypes);
+
+    void generateSimpleSetter(const ASTProperty &property, bool generateOverride = true);
+    void generatePOD(const POD &pod);
+    void generateEnumGadget(const ASTEnum &en, const QString &className);
+    void generateDeclarationsForEnums(const QList<ASTEnum> &enums, bool generateQENUM=true);
+    QString formatQPropertyDeclarations(const POD &pod);
+    QString formatConstructors(const POD &pod);
+    QString formatPropertyGettersAndSetters(const POD &pod);
+    QString formatSignals(const POD &pod);
+    QString formatDataMembers(const POD &pod);
+    QString formatDebugOperator(const POD &pod);
+    QString formatMarshallingOperators(const POD &pod);
+    QString typeForMode(const ASTProperty &property, Mode mode);
+
+    void generateClass(Mode mode, const ASTClass &astClasses,
+                       const QString &metaTypeRegistrationCode);
+    void generateSourceAPI(const ASTClass &astClass);
+
+private:
+    QTextStream m_stream;
+    AST m_ast;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/tools/repc/utils.cpp b/tools/repc/utils.cpp
new file mode 100644 (file)
index 0000000..1fbad74
--- /dev/null
@@ -0,0 +1,289 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#include <qjsonvalue.h>
+#include <qjsonarray.h>
+#include <qjsonobject.h>
+
+#include "utils.h"
+#include "repparser.h"
+
+
+#define _(X) QLatin1String(X)
+
+QT_BEGIN_NAMESPACE
+
+namespace JSON
+{
+    enum Types {
+        Any,
+        Array,
+        Object,
+        String,
+        Bool
+    };
+
+    static QJsonValue _Sub(const QJsonValue &json, const char *key, JSON::Types type=JSON::Any) {
+        if (json.isUndefined())
+            qCritical() << "Invalid metadata json file. Unexpected Undefined value when looking for key:" << key;
+        if (!json.isObject())
+            qCritical() << "Invalid metadata json file. Input (" << json << ") is not an object when looking for key:" << key;
+        QJsonValue value = json.toObject()[_(key)];
+        switch (type) {
+            case JSON::Any: break;
+            case JSON::Array:
+                if (!value.isArray())
+                    qCritical() << "Invalid metadata json file. Value (" << value << ") is not an array when looking for key:" << key;
+                break;
+            case JSON::Object:
+                if (!value.isObject())
+                    qCritical() << "Invalid metadata json file. Value (" << value << ") is not an object when looking for key:" << key;
+                break;
+            case JSON::String:
+                if (!value.isString())
+                    qCritical() << "Invalid metadata json file. Value (" << value << ") is not a string when looking for key:" << key;
+                break;
+            case JSON::Bool:
+                if (!value.isBool())
+                    qCritical() << "Invalid metadata json file. Value (" << value << ") is not a bool when looking for key:" << key;
+                break;
+        }
+        return value;
+    }
+
+    static bool _Contains(const QJsonValue &json, const char *key) {
+        if (json.isUndefined())
+            qCritical() << "Invalid metadata json file. Unexpected Undefined value when looking for key:" << key;
+        if (!json.isObject())
+            qCritical() << "Invalid metadata json file. Input (" << json << ") is not an object when looking for key:" << key;
+        return json.toObject().contains(_(key));
+    }
+
+    static bool _Empty(const QJsonValue &json, const char *key) {
+        if (!_Contains(json, key))
+            return true;
+        const auto value = _Sub(json, key);
+        if (!value.isArray())
+            qCritical() << "Invalid metadata json file." << key << "is not an array.";
+        return value.toArray().count() == 0;
+    }
+
+    static QJsonArray _Array(const QJsonValue &json, const char *key) { return _Sub(json, key, JSON::Array).toArray(); }
+    static QString _String(const QJsonValue &json, const char *key) { return _Sub(json, key, JSON::String).toString(); }
+    static QByteArray _Bytes(const QJsonValue &json, const char *key) { return _Sub(json, key, JSON::String).toString().toLatin1(); }
+    static bool _Bool(const QJsonValue &json, const char *key) { return _Sub(json, key, JSON::Bool).toBool(); }
+    static bool _Bool(const QJsonValue &json, const char *key, bool missingValue) {
+        if (!_Contains(json, key))
+            return missingValue;
+        bool res = _Bool(json, key);
+        return res;
+    }
+}
+
+using namespace JSON;
+
+static QByteArray join(const QByteArrayList &array, const QByteArray &separator)
+{
+    QByteArray res;
+    const auto sz = array.size();
+    if (!sz)
+        return res;
+    for (qsizetype i = 0; i < sz - 1; i++)
+        res += array.at(i) + separator;
+    res += array.at(sz - 1);
+    return res;
+}
+
+static QByteArrayList generateProperties(const QJsonArray &properties, bool isPod=false)
+{
+    QByteArrayList ret;
+    for (const QJsonValue prop : properties) {
+        if (!isPod && !_Contains(prop, "notify") && !_Bool(prop, "constant")) {
+            qWarning() << "Skipping property" << _String(prop, "name") << "because it is non-notifiable & non-constant";
+            continue; // skip non-notifiable properties
+        }
+        QByteArray output = _Bytes(prop, "type") + " " + _Bytes(prop, "name");
+        if (_Bool(prop, "constant"))
+            output += " CONSTANT";
+        if (!_Contains(prop, "write") && _Contains(prop, "read."))
+            output += " READONLY";
+        ret << output;
+    }
+    return ret;
+}
+
+static QByteArray generateFunctions(const QByteArray &type, const QJsonArray &functions)
+{
+    QByteArray ret;
+    for (const QJsonValue func : functions) {
+        ret += type + "(" + _Bytes(func, "returnType") + " " + _Bytes(func, "name") + "(";
+        const auto arguments = _Array(func, "arguments");
+        for (const QJsonValue arg : arguments)
+            ret += _Bytes(arg, "type") + " " + _Bytes(arg, "name") + ", ";
+        if (arguments.count())
+            ret.chop(2);
+        ret += "));\n";
+    }
+    return ret;
+}
+
+const auto filterNotPublic = [](const QJsonValue &value) {
+    return _String(value, "access") != QStringLiteral("public"); };
+
+static QJsonArray cleanedSignalList(const QJsonValue &cls)
+{
+    if (_Empty(cls, "signals"))
+        return QJsonArray();
+
+    auto signalList = _Array(cls, "signals");
+    if (_Empty(cls, "properties"))
+        return signalList;
+
+    const auto props = _Array(cls, "properties");
+    const auto filterNotify = [&props](const QJsonValue &value) {
+        const auto filter = [&value](const QJsonValue &prop) {
+            return _Sub(value, "name") == _Sub(prop, "notify"); };
+        return std::find_if(props.begin(), props.end(), filter) != props.end(); };
+    for (auto it = signalList.begin(); it != signalList.end(); /* blank */ ) {
+        if (filterNotify(*it))
+            it = signalList.erase(it);
+        else if (filterNotPublic(*it))
+            it = signalList.erase(it);
+        else
+            it++;
+    }
+    return signalList;
+}
+
+static QJsonArray cleanedSlotList(const QJsonValue &cls)
+{
+    if (_Empty(cls, "slots"))
+        return QJsonArray();
+
+    auto slotList = _Array(cls, "slots");
+    if (!_Empty(cls, "properties"))
+        return slotList;
+
+    const auto props = _Array(cls, "properties");
+    const auto filterWrite = [&props](const QJsonValue &value) {
+        const auto filter = [&value](const QJsonValue &prop) {
+            const auto args = _Array(prop, "arguments");
+            return _Sub(value, "name") == _Sub(prop, "write") &&
+                args.count() == 1 && _Sub(args.at(0), "type") == _Sub(prop, "type"); };
+        return std::find_if(props.begin(), props.end(), filter) != props.end(); };
+    for (auto it = slotList.begin(); it != slotList.end(); /* blank */ ) {
+        if (filterWrite(*it))
+            it = slotList.erase(it);
+        else if (filterNotPublic(*it))
+            it = slotList.erase(it);
+        else
+            it++;
+    }
+    return slotList;
+}
+
+QByteArray generateClass(const QJsonValue &cls, bool alwaysGenerateClass)
+{
+    if (_Bool(cls, "gadget", false) || alwaysGenerateClass ||
+            (_Empty(cls, "signals") && _Empty(cls, "slots")))
+        return "POD " + _Bytes(cls, "className") + "(" + join(generateProperties(_Array(cls, "properties"), true), ", ") + ")\n";
+
+    QByteArray ret("class " + _Bytes(cls, "className") + "\n{\n");
+    if (!_Empty(cls, "properties"))
+        ret += "    PROP(" + join(generateProperties(_Array(cls, "properties")), ");\n    PROP(") + ");\n";
+    ret += generateFunctions("    SLOT", cleanedSlotList(cls));
+    ret += generateFunctions("    SIGNAL", cleanedSignalList(cls));
+    ret += "}\n";
+    return ret;
+}
+
+static QList<PODAttribute> propertyList2PODAttributes(const QJsonArray &list)
+{
+    QList<PODAttribute> ret;
+    for (const QJsonValue prop : list)
+        ret.push_back(PODAttribute(_String(prop, "type"), _String(prop, "name")));
+    return ret;
+}
+
+QList<ASTProperty> propertyList2AstProperties(const QJsonArray &list)
+{
+    QList<ASTProperty> ret;
+    for (const QJsonValue property : list) {
+        if (!_Contains(property, "notify") && !_Bool(property, "constant")) {
+            qWarning() << "Skipping property" << _String(property, "name") << "because it is non-notifiable & non-constant";
+            continue; // skip non-notifiable properties
+        }
+        ASTProperty prop;
+        prop.name = _String(property, "name");
+        prop.type = _String(property, "type");
+        prop.modifier = _Bool(property, "constant")
+                        ? ASTProperty::Constant
+                        : !_Contains(property, "write") && _Contains(property, "read")
+                          ? ASTProperty::ReadOnly
+                          : ASTProperty::ReadWrite;
+        ret.push_back(prop);
+    }
+    return ret;
+}
+
+QList<ASTFunction> functionList2AstFunctionList(const QJsonArray &list)
+{
+    QList<ASTFunction> ret;
+    for (const QJsonValue function : list) {
+        ASTFunction func;
+        func.name = _String(function, "name");
+        func.returnType = _String(function, "returnType");
+        const auto arguments = _Array(function, "arguments");
+        for (const QJsonValue arg : arguments)
+            func.params.push_back(ASTDeclaration(_String(arg, "type"), _String(arg, "name")));
+        ret.push_back(func);
+    }
+    return ret;
+}
+
+AST classList2AST(const QJsonArray &classes)
+{
+    AST ret;
+    for (const QJsonValue cls : classes) {
+        if (_Empty(cls, "signals") && _Empty(cls, "slots")) {
+            POD pod;
+            pod.name = _String(cls, "className");
+            pod.attributes = propertyList2PODAttributes(_Array(cls, "properties"));
+            ret.pods.push_back(pod);
+        } else {
+            ASTClass cl(_String(cls, "className"));
+            cl.properties = propertyList2AstProperties(_Array(cls, "properties"));
+            cl.signalsList = functionList2AstFunctionList(cleanedSignalList(cls));
+            cl.slotsList = functionList2AstFunctionList(cleanedSlotList(cls));
+            ret.classes.push_back(cl);
+        }
+    }
+    return ret;
+}
+
+QT_END_NAMESPACE
diff --git a/tools/repc/utils.h b/tools/repc/utils.h
new file mode 100644 (file)
index 0000000..236f60e
--- /dev/null
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** 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: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$
+**
+****************************************************************************/
+
+#ifndef UTILS_H
+#define UTILS_H
+
+#include <QByteArray>
+
+QT_BEGIN_NAMESPACE
+class QJsonValue;
+class QJsonArray;
+struct AST;
+
+QByteArray generateClass(const QJsonValue &cls, bool alwaysGenerateClass = false);
+AST classList2AST(const QJsonArray &classes);
+QT_END_NAMESPACE
+
+#endif // UTILS_H
diff --git a/tools/tools.pro b/tools/tools.pro
new file mode 100644 (file)
index 0000000..05d9dfa
--- /dev/null
@@ -0,0 +1,4 @@
+TEMPLATE = subdirs
+qtConfig(commandlineparser): {
+    SUBDIRS += repc
+}