summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore17
-rw-r--r--.qmake.conf3
-rw-r--r--examples/RemoteObjects/ClientApp/ClientApp.desktop11
-rw-r--r--examples/RemoteObjects/ClientApp/ClientApp.pro13
-rw-r--r--examples/RemoteObjects/ClientApp/ClientApp64.pngbin0 -> 3400 bytes
-rw-r--r--examples/RemoteObjects/ClientApp/ClientApp80.pngbin0 -> 4945 bytes
-rw-r--r--examples/RemoteObjects/ClientApp/ClientApp_harmattan.desktop11
-rw-r--r--examples/RemoteObjects/ClientApp/clientapp.qrc9
-rw-r--r--examples/RemoteObjects/ClientApp/main.cpp56
-rw-r--r--examples/RemoteObjects/ClientApp/qml/plugins.qml62
-rw-r--r--examples/RemoteObjects/ClientApp/qml/plugins0.qml48
-rw-r--r--examples/RemoteObjects/ClientApp/qml/plugins1.qml60
-rw-r--r--examples/RemoteObjects/ClientApp/qml/plugins2.qml71
-rw-r--r--examples/RemoteObjects/CppClient/CppClient.pro19
-rw-r--r--examples/RemoteObjects/CppClient/TimeModel.rep12
-rw-r--r--examples/RemoteObjects/CppClient/main.cpp90
-rw-r--r--examples/RemoteObjects/RemoteObjects.pro11
-rw-r--r--examples/RemoteObjects/TimeModel.rep12
-rw-r--r--examples/RemoteObjects/plugins/imports/TimeExample/Clock.qml88
-rw-r--r--examples/RemoteObjects/plugins/imports/TimeExample/center.pngbin0 -> 765 bytes
-rw-r--r--examples/RemoteObjects/plugins/imports/TimeExample/clock.pngbin0 -> 20653 bytes
-rw-r--r--examples/RemoteObjects/plugins/imports/TimeExample/hour.pngbin0 -> 625 bytes
-rw-r--r--examples/RemoteObjects/plugins/imports/TimeExample/minute.pngbin0 -> 625 bytes
-rw-r--r--examples/RemoteObjects/plugins/imports/TimeExample/qmldir3
-rw-r--r--examples/RemoteObjects/plugins/plugin.cpp130
-rw-r--r--examples/RemoteObjects/plugins/plugins.pro28
-rw-r--r--examples/RemoteObjects/plugins/plugins.qml62
-rw-r--r--examples/RemoteObjects/plugins/plugins0.qml48
-rw-r--r--examples/RemoteObjects/plugins/plugins1.qml60
-rw-r--r--examples/RemoteObjects/plugins/plugins2.qml71
-rw-r--r--examples/RemoteObjects/server/TimeModel.cpp81
-rw-r--r--examples/RemoteObjects/server/TimeModel.h62
-rw-r--r--examples/RemoteObjects/server/main.cpp95
-rw-r--r--examples/RemoteObjects/server/server.pro13
-rw-r--r--examples/examples.pro3
-rw-r--r--mkspecs/features/features.pro4
-rw-r--r--mkspecs/features/remoteobjects_repc.prf3
-rw-r--r--mkspecs/features/repcclient.pri4
-rw-r--r--mkspecs/features/repccommon.pri53
-rw-r--r--mkspecs/features/repcserver.pri4
-rw-r--r--mkspecs/mkspecs.pro3
-rw-r--r--qtremoteobjects.pro4
-rw-r--r--src/remoteobjects/doc/images/README1
-rw-r--r--src/remoteobjects/doc/qtremoteobjects.qdocconf43
-rw-r--r--src/remoteobjects/doc/snipplets/README1
-rw-r--r--src/remoteobjects/doc/src/qtremoteobjects.qdoc50
-rw-r--r--src/remoteobjects/qconnectionabstractfactory_p.h87
-rw-r--r--src/remoteobjects/qconnectionabstractserver.cpp114
-rw-r--r--src/remoteobjects/qconnectionabstractserver_p.h112
-rw-r--r--src/remoteobjects/qconnectionclientfactory.cpp279
-rw-r--r--src/remoteobjects/qconnectionclientfactory_p.h163
-rw-r--r--src/remoteobjects/qconnectionserverfactory.cpp217
-rw-r--r--src/remoteobjects/qconnectionserverfactory_p.h140
-rw-r--r--src/remoteobjects/qregistrysource.cpp92
-rw-r--r--src/remoteobjects/qregistrysource_p.h77
-rw-r--r--src/remoteobjects/qremoteobjectdynamicreplica.cpp136
-rw-r--r--src/remoteobjects/qremoteobjectdynamicreplica.h66
-rw-r--r--src/remoteobjects/qremoteobjectnode.cpp690
-rw-r--r--src/remoteobjects/qremoteobjectnode.h113
-rw-r--r--src/remoteobjects/qremoteobjectnode_p.h112
-rw-r--r--src/remoteobjects/qremoteobjectregistry.cpp100
-rw-r--r--src/remoteobjects/qremoteobjectregistry.h78
-rw-r--r--src/remoteobjects/qremoteobjectreplica.cpp404
-rw-r--r--src/remoteobjects/qremoteobjectreplica.h87
-rw-r--r--src/remoteobjects/qremoteobjectreplica_p.h135
-rw-r--r--src/remoteobjects/qremoteobjectsource.cpp264
-rw-r--r--src/remoteobjects/qremoteobjectsource.h77
-rw-r--r--src/remoteobjects/qremoteobjectsource_p.h116
-rw-r--r--src/remoteobjects/qremoteobjectsourceio.cpp219
-rw-r--r--src/remoteobjects/qremoteobjectsourceio_p.h95
-rw-r--r--src/remoteobjects/qtremoteobjectglobal.cpp526
-rw-r--r--src/remoteobjects/qtremoteobjectglobal.h261
-rw-r--r--src/remoteobjects/remoteobjects.pro51
-rw-r--r--src/src.pro2
-rw-r--r--sync.profile18
-rw-r--r--tests/auto/auto.pro2
-rw-r--r--tests/auto/cmake/CMakeLists.txt12
-rw-r--r--tests/auto/cmake/cmake.pro5
-rw-r--r--tests/auto/cmake/test_qremoteobjects_module/CMakeLists.txt32
-rw-r--r--tests/auto/cmake/test_qremoteobjects_module/main.cpp49
-rw-r--r--tests/auto/integration/.gitignore1
-rw-r--r--tests/auto/integration/Engine.cpp52
-rw-r--r--tests/auto/integration/Engine.h58
-rw-r--r--tests/auto/integration/RemoteObjectTest.h229
-rw-r--r--tests/auto/integration/Speedometer.cpp51
-rw-r--r--tests/auto/integration/Speedometer.h58
-rw-r--r--tests/auto/integration/engine.rep5
-rw-r--r--tests/auto/integration/integration.pro24
-rw-r--r--tests/auto/integration/speedometer.rep5
-rw-r--r--tests/auto/repc/pods/.gitignore1
-rw-r--r--tests/auto/repc/pods/pods.pro13
-rw-r--r--tests/auto/repc/pods/pods.rep6
-rw-r--r--tests/auto/repc/pods/tst_pods.cpp117
-rw-r--r--tests/auto/repc/repc.pro2
-rw-r--r--tests/auto/repfiles/localdatacenter.rep8
-rw-r--r--tests/auto/repfiles/tcpdatacenter.rep8
-rw-r--r--tests/tests.pro3
-rw-r--r--tools/repc/RepCodeGenerator.cpp460
-rw-r--r--tools/repc/RepCodeGenerator.h89
-rw-r--r--tools/repc/RepParser.cpp196
-rw-r--r--tools/repc/RepParser.h131
-rw-r--r--tools/repc/main.cpp89
-rw-r--r--tools/repc/repc.pro6
-rw-r--r--tools/tools.pro2
104 files changed, 7964 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..59e8a79
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,17 @@
+Makefile
+Makefile.*
+release/
+debug/
+*.o
+*.so.*
+*.dll
+*.lib
+*.so
+moc_*
+*.moc
+*.pro.user
+
+rep_*_replicant.h
+rep_*_prime.h
+
+/repc/repc
diff --git a/.qmake.conf b/.qmake.conf
new file mode 100644
index 0000000..889750c
--- /dev/null
+++ b/.qmake.conf
@@ -0,0 +1,3 @@
+load(qt_build_config)
+CONFIG += qt_example_installs
+MODULE_VERSION = 5.4.0
diff --git a/examples/RemoteObjects/ClientApp/ClientApp.desktop b/examples/RemoteObjects/ClientApp/ClientApp.desktop
new file mode 100644
index 0000000..e85a515
--- /dev/null
+++ b/examples/RemoteObjects/ClientApp/ClientApp.desktop
@@ -0,0 +1,11 @@
+[Desktop Entry]
+Encoding=UTF-8
+Version=1.0
+Type=Application
+Terminal=false
+Name=ClientApp
+Exec=/opt/ClientApp/bin/ClientApp
+Icon=ClientApp64
+X-Window-Icon=
+X-HildonDesk-ShowInToolbar=true
+X-Osso-Type=application/x-executable
diff --git a/examples/RemoteObjects/ClientApp/ClientApp.pro b/examples/RemoteObjects/ClientApp/ClientApp.pro
new file mode 100644
index 0000000..1dc091c
--- /dev/null
+++ b/examples/RemoteObjects/ClientApp/ClientApp.pro
@@ -0,0 +1,13 @@
+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/ClientApp64.png b/examples/RemoteObjects/ClientApp/ClientApp64.png
new file mode 100644
index 0000000..707d5c4
--- /dev/null
+++ b/examples/RemoteObjects/ClientApp/ClientApp64.png
Binary files differ
diff --git a/examples/RemoteObjects/ClientApp/ClientApp80.png b/examples/RemoteObjects/ClientApp/ClientApp80.png
new file mode 100644
index 0000000..6ad8096
--- /dev/null
+++ b/examples/RemoteObjects/ClientApp/ClientApp80.png
Binary files differ
diff --git a/examples/RemoteObjects/ClientApp/ClientApp_harmattan.desktop b/examples/RemoteObjects/ClientApp/ClientApp_harmattan.desktop
new file mode 100644
index 0000000..d3da899
--- /dev/null
+++ b/examples/RemoteObjects/ClientApp/ClientApp_harmattan.desktop
@@ -0,0 +1,11 @@
+[Desktop Entry]
+Encoding=UTF-8
+Version=1.0
+Type=Application
+Terminal=false
+Name=ClientApp
+Exec=/usr/bin/single-instance /opt/ClientApp/bin/ClientApp
+Icon=/usr/share/icons/hicolor/80x80/apps/ClientApp80.png
+X-Window-Icon=
+X-HildonDesk-ShowInToolbar=true
+X-Osso-Type=application/x-executable
diff --git a/examples/RemoteObjects/ClientApp/clientapp.qrc b/examples/RemoteObjects/ClientApp/clientapp.qrc
new file mode 100644
index 0000000..7e6bf64
--- /dev/null
+++ b/examples/RemoteObjects/ClientApp/clientapp.qrc
@@ -0,0 +1,9 @@
+<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>
+ <qresource prefix="/images"/>
+</RCC>
diff --git a/examples/RemoteObjects/ClientApp/main.cpp b/examples/RemoteObjects/ClientApp/main.cpp
new file mode 100644
index 0000000..0721f50
--- /dev/null
+++ b/examples/RemoteObjects/ClientApp/main.cpp
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $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
index 0000000..87318a6
--- /dev/null
+++ b/examples/RemoteObjects/ClientApp/qml/plugins.qml
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Item {
+ width: 200
+ height: 400
+ property int counter: 0;
+ MouseArea {
+ anchors.fill: parent
+ onClicked:
+ {
+ counter = (counter + 1) % 3;
+ console.log(counter);
+ pageLoader.source = "plugins"+counter+".qml"
+ }
+ }
+ Loader {
+ id: pageLoader
+ source: "plugins0.qml"
+ }
+}
+//![0]
diff --git a/examples/RemoteObjects/ClientApp/qml/plugins0.qml b/examples/RemoteObjects/ClientApp/qml/plugins0.qml
new file mode 100644
index 0000000..958ae9f
--- /dev/null
+++ b/examples/RemoteObjects/ClientApp/qml/plugins0.qml
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick 2.0
+
+Rectangle {
+ width: 200
+ height: 400
+ color: "blue"
+}
+//![0]
diff --git a/examples/RemoteObjects/ClientApp/qml/plugins1.qml b/examples/RemoteObjects/ClientApp/qml/plugins1.qml
new file mode 100644
index 0000000..c9a9237
--- /dev/null
+++ b/examples/RemoteObjects/ClientApp/qml/plugins1.qml
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick 2.0
+import TimeExample 1.0 // import types from the plugin
+
+Rectangle {
+ width: 200
+ height: 400
+ color: "blue"
+ Clock { // this class is defined in QML (imports/TimeExample/Clock.qml)
+ id: clock1
+ anchors.top: parent.top
+ Time { // this class is defined in C++ (plugin.cpp)
+ id: time
+ }
+
+ hours: time.hour
+ minutes: time.minute
+
+ }
+}
+//![0]
diff --git a/examples/RemoteObjects/ClientApp/qml/plugins2.qml b/examples/RemoteObjects/ClientApp/qml/plugins2.qml
new file mode 100644
index 0000000..55acb8a
--- /dev/null
+++ b/examples/RemoteObjects/ClientApp/qml/plugins2.qml
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Digia Plc and its Subsidiary(-ies) 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/CppClient.pro b/examples/RemoteObjects/CppClient/CppClient.pro
new file mode 100644
index 0000000..05a89b9
--- /dev/null
+++ b/examples/RemoteObjects/CppClient/CppClient.pro
@@ -0,0 +1,19 @@
+QT += core
+
+REPC_REPLICA += TimeModel.rep
+QT += remoteobjects
+
+QT -= gui
+
+TARGET = CppClient
+CONFIG -= app_bundle
+
+TEMPLATE = app
+
+SOURCES += main.cpp
+
+OTHER_FILES += \
+ TimeModel.rep
+
+target.path = $$[QT_INSTALL_EXAMPLES]/RemoteObjects/CppClient
+INSTALLS += target
diff --git a/examples/RemoteObjects/CppClient/TimeModel.rep b/examples/RemoteObjects/CppClient/TimeModel.rep
new file mode 100644
index 0000000..fa7e612
--- /dev/null
+++ b/examples/RemoteObjects/CppClient/TimeModel.rep
@@ -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(SetTimeZone(int zn));
+};
diff --git a/examples/RemoteObjects/CppClient/main.cpp b/examples/RemoteObjects/CppClient/main.cpp
new file mode 100644
index 0000000..ee7ec65
--- /dev/null
+++ b/examples/RemoteObjects/CppClient/main.cpp
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include <QTimer>
+#include "rep_TimeModel_replica.h"
+
+class tester : public QObject
+{
+ Q_OBJECT
+public:
+ tester() : QObject(Q_NULLPTR)
+ {
+ QRemoteObjectNode m_client = QRemoteObjectNode::createNodeConnectedToRegistry();;
+ ptr1.reset(m_client.acquire< MinuteTimerReplica >());
+ ptr2.reset(m_client.acquire< MinuteTimerReplica >());
+ ptr3.reset(m_client.acquire< MinuteTimerReplica >());
+ QTimer::singleShot(0,this,SLOT(clear()));
+ QTimer::singleShot(1,this,SLOT(clear()));
+ QTimer::singleShot(10000,this,SLOT(clear()));
+ QTimer::singleShot(11000,this,SLOT(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/RemoteObjects.pro b/examples/RemoteObjects/RemoteObjects.pro
new file mode 100644
index 0000000..da12899
--- /dev/null
+++ b/examples/RemoteObjects/RemoteObjects.pro
@@ -0,0 +1,11 @@
+TEMPLATE = subdirs
+CONFIG += debug_and_release ordered
+SUBDIRS = \
+ server \
+ CppClient
+
+qtHaveModule(quick) {
+ SUBDIRS += \
+ plugins \
+ ClientApp
+}
diff --git a/examples/RemoteObjects/TimeModel.rep b/examples/RemoteObjects/TimeModel.rep
new file mode 100644
index 0000000..fa7e612
--- /dev/null
+++ b/examples/RemoteObjects/TimeModel.rep
@@ -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(SetTimeZone(int zn));
+};
diff --git a/examples/RemoteObjects/plugins/imports/TimeExample/Clock.qml b/examples/RemoteObjects/plugins/imports/TimeExample/Clock.qml
new file mode 100644
index 0000000..ca57cae
--- /dev/null
+++ b/examples/RemoteObjects/plugins/imports/TimeExample/Clock.qml
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Rectangle {
+ id: clock
+ width: 200; height: 200; color: "gray"
+
+ property alias city: cityLabel.text
+ property variant hours
+ property variant minutes
+ property variant shift : 0
+
+ Image { id: background; source: "clock.png" }
+
+ Image {
+ x: 92.5; y: 27
+ source: "hour.png"
+ transform: Rotation {
+ id: hourRotation
+ origin.x: 7.5; origin.y: 73;
+ angle: (clock.hours * 30) + (clock.minutes * 0.5)
+ Behavior on angle {
+ SpringAnimation{ spring: 2; damping: 0.2; modulus: 360 }
+ }
+ }
+ }
+
+ Image {
+ x: 93.5; y: 17
+ source: "minute.png"
+ transform: Rotation {
+ id: minuteRotation
+ origin.x: 6.5; origin.y: 83;
+ angle: clock.minutes * 6
+ Behavior on angle {
+ SpringAnimation{ spring: 2; damping: 0.2; modulus: 360 }
+ }
+ }
+ }
+
+ Image {
+ anchors.centerIn: background; source: "center.png"
+ }
+
+ Text {
+ id: cityLabel; font.bold: true; font.pixelSize: 14; y:200; color: "white"
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+}
diff --git a/examples/RemoteObjects/plugins/imports/TimeExample/center.png b/examples/RemoteObjects/plugins/imports/TimeExample/center.png
new file mode 100644
index 0000000..7fbd802
--- /dev/null
+++ b/examples/RemoteObjects/plugins/imports/TimeExample/center.png
Binary files differ
diff --git a/examples/RemoteObjects/plugins/imports/TimeExample/clock.png b/examples/RemoteObjects/plugins/imports/TimeExample/clock.png
new file mode 100644
index 0000000..462edac
--- /dev/null
+++ b/examples/RemoteObjects/plugins/imports/TimeExample/clock.png
Binary files differ
diff --git a/examples/RemoteObjects/plugins/imports/TimeExample/hour.png b/examples/RemoteObjects/plugins/imports/TimeExample/hour.png
new file mode 100644
index 0000000..f8061a1
--- /dev/null
+++ b/examples/RemoteObjects/plugins/imports/TimeExample/hour.png
Binary files differ
diff --git a/examples/RemoteObjects/plugins/imports/TimeExample/minute.png b/examples/RemoteObjects/plugins/imports/TimeExample/minute.png
new file mode 100644
index 0000000..1297ec7
--- /dev/null
+++ b/examples/RemoteObjects/plugins/imports/TimeExample/minute.png
Binary files differ
diff --git a/examples/RemoteObjects/plugins/imports/TimeExample/qmldir b/examples/RemoteObjects/plugins/imports/TimeExample/qmldir
new file mode 100644
index 0000000..252e662
--- /dev/null
+++ b/examples/RemoteObjects/plugins/imports/TimeExample/qmldir
@@ -0,0 +1,3 @@
+module TimeExample
+Clock 1.0 Clock.qml
+plugin qmlqtimeexampleplugin
diff --git a/examples/RemoteObjects/plugins/plugin.cpp b/examples/RemoteObjects/plugins/plugin.cpp
new file mode 100644
index 0000000..0415fc3
--- /dev/null
+++ b/examples/RemoteObjects/plugins/plugin.cpp
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $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.
+
+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=0) : QObject(parent), d_ptr(Q_NULLPTR)
+ {
+ d_ptr.reset(m_client.acquire< MinuteTimerReplica >());
+ connect(d_ptr.data(), SIGNAL(onHourChanged()), this, SIGNAL(timeChanged()));
+ connect(d_ptr.data(), SIGNAL(onMinuteChanged()), this, SIGNAL(timeChanged()));
+ connect(d_ptr.data(), SIGNAL(timeChanged()), this, SIGNAL(timeChanged()));
+ connect(d_ptr.data(), SIGNAL(timeChanged2(QTime)), this, SLOT(test(QTime)));
+ connect(d_ptr.data(), SIGNAL(sendCustom(PresetInfo)), this, SLOT(testCustom(PresetInfo)));
+ }
+
+ ~TimeModel()
+ {
+ }
+
+ int minute() const { return d_ptr->minute(); }
+ int hour() const { return d_ptr->hour(); }
+ bool isValid() const { return d_ptr->isReplicaValid(); }
+
+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)
+ {
+ Q_UNUSED(engine);
+ Q_UNUSED(uri);
+ Q_ASSERT(uri == QLatin1String("TimeExample"));
+ engine->addImportPath(QStringLiteral("qrc:/qml"));
+ m_client = QRemoteObjectNode::createNodeConnectedToRegistry();
+ }
+ void registerTypes(const char *uri)
+ {
+ 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
index 0000000..ce1518f
--- /dev/null
+++ b/examples/RemoteObjects/plugins/plugins.pro
@@ -0,0 +1,28 @@
+QT += qml remoteobjects
+
+TEMPLATE = lib
+CONFIG += plugin
+
+REPC_REPLICA += $$PWD/../TimeModel.rep
+
+DESTDIR = imports/TimeExample
+TARGET = qmlqtimeexampleplugin
+
+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_HOST_PREFIX]/qml/plugins
+target.path += $$[QT_HOST_PREFIX]/qml/TimeExample
+pluginfiles.path += $$[QT_HOST_PREFIX]/qml/TimeExample
+
+INSTALLS += target pluginfiles
+
+contains(QT_CONFIG, c++11): CONFIG += c++11
diff --git a/examples/RemoteObjects/plugins/plugins.qml b/examples/RemoteObjects/plugins/plugins.qml
new file mode 100644
index 0000000..87318a6
--- /dev/null
+++ b/examples/RemoteObjects/plugins/plugins.qml
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Item {
+ width: 200
+ height: 400
+ property int counter: 0;
+ MouseArea {
+ anchors.fill: parent
+ onClicked:
+ {
+ counter = (counter + 1) % 3;
+ console.log(counter);
+ pageLoader.source = "plugins"+counter+".qml"
+ }
+ }
+ Loader {
+ id: pageLoader
+ source: "plugins0.qml"
+ }
+}
+//![0]
diff --git a/examples/RemoteObjects/plugins/plugins0.qml b/examples/RemoteObjects/plugins/plugins0.qml
new file mode 100644
index 0000000..958ae9f
--- /dev/null
+++ b/examples/RemoteObjects/plugins/plugins0.qml
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick 2.0
+
+Rectangle {
+ width: 200
+ height: 400
+ color: "blue"
+}
+//![0]
diff --git a/examples/RemoteObjects/plugins/plugins1.qml b/examples/RemoteObjects/plugins/plugins1.qml
new file mode 100644
index 0000000..c9a9237
--- /dev/null
+++ b/examples/RemoteObjects/plugins/plugins1.qml
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick 2.0
+import TimeExample 1.0 // import types from the plugin
+
+Rectangle {
+ width: 200
+ height: 400
+ color: "blue"
+ Clock { // this class is defined in QML (imports/TimeExample/Clock.qml)
+ id: clock1
+ anchors.top: parent.top
+ Time { // this class is defined in C++ (plugin.cpp)
+ id: time
+ }
+
+ hours: time.hour
+ minutes: time.minute
+
+ }
+}
+//![0]
diff --git a/examples/RemoteObjects/plugins/plugins2.qml b/examples/RemoteObjects/plugins/plugins2.qml
new file mode 100644
index 0000000..55acb8a
--- /dev/null
+++ b/examples/RemoteObjects/plugins/plugins2.qml
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Digia Plc and its Subsidiary(-ies) 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/server/TimeModel.cpp b/examples/RemoteObjects/server/TimeModel.cpp
new file mode 100644
index 0000000..1654a1a
--- /dev/null
+++ b/examples/RemoteObjects/server/TimeModel.cpp
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "TimeModel.h"
+
+MinuteTimer::MinuteTimer(QObject *parent) : MinuteTimerSource(parent)
+{
+ 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.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(int zn)
+{
+ qDebug()<<"SetTimeZone"<<zn;
+ if (zn != zone)
+ {
+ zone = zn;
+ }
+}
diff --git a/examples/RemoteObjects/server/TimeModel.h b/examples/RemoteObjects/server/TimeModel.h
new file mode 100644
index 0000000..67c87c0
--- /dev/null
+++ b/examples/RemoteObjects/server/TimeModel.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore>
+#include "rep_TimeModel_source.h"
+
+class MinuteTimer : public MinuteTimerSource
+{
+ Q_OBJECT
+public:
+ MinuteTimer(QObject *parent=Q_NULLPTR);
+ virtual ~MinuteTimer();
+
+public slots:
+ virtual void SetTimeZone(int zn);
+
+protected:
+ void timerEvent(QTimerEvent *);
+
+private:
+ QTime time;
+ QBasicTimer timer;
+ int zone;
+};
diff --git a/examples/RemoteObjects/server/main.cpp b/examples/RemoteObjects/server/main.cpp
new file mode 100644
index 0000000..15f76a2
--- /dev/null
+++ b/examples/RemoteObjects/server/main.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $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
+ QRemoteObjectNode node = QRemoteObjectNode::createRegistryHostNode();
+ QRemoteObjectNode node2 = QRemoteObjectNode::createHostNodeConnectedToRegistry();
+ MinuteTimer timer;
+ node2.enableRemoting(&timer);
+
+ Q_UNUSED(timer);
+ return app.exec();
+}
diff --git a/examples/RemoteObjects/server/server.pro b/examples/RemoteObjects/server/server.pro
new file mode 100644
index 0000000..9d624fd
--- /dev/null
+++ b/examples/RemoteObjects/server/server.pro
@@ -0,0 +1,13 @@
+CONFIG += console
+
+
+REPC_SOURCE += ../TimeModel.rep
+QT = remoteobjects core
+
+SOURCES += TimeModel.cpp main.cpp
+HEADERS += TimeModel.h
+
+contains(QT_CONFIG, c++11): CONFIG += c++11
+
+target.path = $$[QT_INSTALL_EXAMPLES]/RemoteObjects/Server
+INSTALLS += target
diff --git a/examples/examples.pro b/examples/examples.pro
new file mode 100644
index 0000000..698f31d
--- /dev/null
+++ b/examples/examples.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+SUBDIRS = \
+ RemoteObjects
diff --git a/mkspecs/features/features.pro b/mkspecs/features/features.pro
new file mode 100644
index 0000000..8fc706b
--- /dev/null
+++ b/mkspecs/features/features.pro
@@ -0,0 +1,4 @@
+prf.files = remoteobjects_repc.prf repcclient.pri repcserver.pri repccommon.pri
+prf.path = $$[QT_INSTALL_DATA]/mkspecs/features
+INSTALLS += prf
+TEMPLATE = subdirs
diff --git a/mkspecs/features/remoteobjects_repc.prf b/mkspecs/features/remoteobjects_repc.prf
new file mode 100644
index 0000000..183cc16
--- /dev/null
+++ b/mkspecs/features/remoteobjects_repc.prf
@@ -0,0 +1,3 @@
+include(repcclient.pri)
+include(repcserver.pri)
+
diff --git a/mkspecs/features/repcclient.pri b/mkspecs/features/repcclient.pri
new file mode 100644
index 0000000..2a95b2e
--- /dev/null
+++ b/mkspecs/features/repcclient.pri
@@ -0,0 +1,4 @@
+repc_type = replica
+repc_option = -r
+
+include(repccommon.pri)
diff --git a/mkspecs/features/repccommon.pri b/mkspecs/features/repccommon.pri
new file mode 100644
index 0000000..c176822
--- /dev/null
+++ b/mkspecs/features/repccommon.pri
@@ -0,0 +1,53 @@
+qtPrepareTool(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
+ for(subent, $$list($$unique(files))) {
+
+ !contains(subent, .*\\w\\.rep$) {
+ warning("Invalid REPC $${repc_type}: '$$subent', please use '*.rep' instead.")
+ next()
+ }
+ $$input_list += $$subent
+ }
+}
+
+for(group, groups) {
+ GROUP = $$upper($$group)
+ input_list = $${GROUP}_LIST
+
+ $${group}_header.output = $$QMAKE_MOD_REPC${QMAKE_FILE_BASE}_$${repc_type}.h
+ $${group}_header.commands = $$QMAKE_REPC $$repc_option -i ${QMAKE_FILE_NAME} -o ${QMAKE_FILE_OUT}
+ $${group}_header.depends = ${QMAKE_FILE_NAME} $$QT_TOOL.repc.binary
+ $${group}_header.variable_out = $${GROUP}_HEADERS
+ $${group}_header.input = $$input_list
+
+ $${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
+ $${group}_moc.name = $$moc_header.name
+
+ QMAKE_EXTRA_COMPILERS += $${group}_header $${group}_moc
+}
diff --git a/mkspecs/features/repcserver.pri b/mkspecs/features/repcserver.pri
new file mode 100644
index 0000000..f5d8dfd
--- /dev/null
+++ b/mkspecs/features/repcserver.pri
@@ -0,0 +1,4 @@
+repc_type = source
+repc_option = -s
+
+include(repccommon.pri)
diff --git a/mkspecs/mkspecs.pro b/mkspecs/mkspecs.pro
new file mode 100644
index 0000000..95262a0
--- /dev/null
+++ b/mkspecs/mkspecs.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+
+SUBDIRS += features
diff --git a/qtremoteobjects.pro b/qtremoteobjects.pro
new file mode 100644
index 0000000..c2e2b6b
--- /dev/null
+++ b/qtremoteobjects.pro
@@ -0,0 +1,4 @@
+CONFIG += examples_need_tools tests_need_tools
+load(qt_parts)
+
+SUBDIRS += mkspecs
diff --git a/src/remoteobjects/doc/images/README b/src/remoteobjects/doc/images/README
new file mode 100644
index 0000000..aec41a2
--- /dev/null
+++ b/src/remoteobjects/doc/images/README
@@ -0,0 +1 @@
+Put all documentation images into this folder.
diff --git a/src/remoteobjects/doc/qtremoteobjects.qdocconf b/src/remoteobjects/doc/qtremoteobjects.qdocconf
new file mode 100644
index 0000000..69392af
--- /dev/null
+++ b/src/remoteobjects/doc/qtremoteobjects.qdocconf
@@ -0,0 +1,43 @@
+include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
+
+project = QtRemoteObjects
+description = Qt RemoteObjects 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 = qtremoteobjects
+qhp.QtRemoteObjects.indexTitle = Qt RemoteObjects
+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 = classes
+qhp.QtRemoteObjects.subprojects.classes.title = C++ Classes
+qhp.QtRemoteObjects.subprojects.classes.indexTitle = Qt RemoteObjects C++ Classes
+qhp.QtRemoteObjects.subprojects.classes.selectors = class fake:headerfile
+qhp.QtRemoteObjects.subprojects.classes.sortPages = true
+
+depends += qtcore \
+ qtdoc
+
+tagfile = ../../../doc/qtremoteobjects/qtremoteobjects.tagsi
+
+headerdirs += .. \
+ ../../remoteobjects
+
+sourcedirs += .. \
+ ../../remoteobjects
+
+exampledirs += ../../../examples/RemoteObjects \
+ snippets/
+
+examplesinstallpath = RemoteObjects
+
+imagedirs += images
+
+navigation.landingpage = "Qt RemoteObjects"
+navigation.cppclassespage = "Qt RemoteObjects C++ Classes"
diff --git a/src/remoteobjects/doc/snipplets/README b/src/remoteobjects/doc/snipplets/README
new file mode 100644
index 0000000..72ad410
--- /dev/null
+++ b/src/remoteobjects/doc/snipplets/README
@@ -0,0 +1 @@
+Put all snipplets into this folder.
diff --git a/src/remoteobjects/doc/src/qtremoteobjects.qdoc b/src/remoteobjects/doc/src/qtremoteobjects.qdoc
new file mode 100644
index 0000000..231ebd2
--- /dev/null
+++ b/src/remoteobjects/doc/src/qtremoteobjects.qdoc
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \module QtRemoteObjects
+ \title Qt RemoteObjects C++ Classes
+ \ingroup modules
+ \qtvariable remote objects
+
+ \brief The Qt RemoteObjects module provides functionality for remoting QObjects.
+
+*/
diff --git a/src/remoteobjects/qconnectionabstractfactory_p.h b/src/remoteobjects/qconnectionabstractfactory_p.h
new file mode 100644
index 0000000..b681695
--- /dev/null
+++ b/src/remoteobjects/qconnectionabstractfactory_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCONNECTIONABSTRACTFACTORY_P_H
+#define QCONNECTIONABSTRACTFACTORY_P_H
+
+#include <QHash>
+
+QT_BEGIN_NAMESPACE
+
+class QObject;
+
+template <class OutputType, class IndexType = QString>
+class QConnectionAbstractFactory
+{
+ Q_DISABLE_COPY(QConnectionAbstractFactory)
+
+public:
+ QConnectionAbstractFactory() {}
+
+ template<class T>
+ void registerProduct(const IndexType &scheme)
+ {
+ m_mapping[scheme] = &createInstance<T>;
+ }
+
+ OutputType *create(const IndexType &type, QObject *parent = Q_NULLPTR) const
+ {
+ typename QHash<IndexType, FactoryFunction>::const_iterator res = m_mapping.find(type);
+ if (res != m_mapping.end())
+ return (*res)(parent);
+ else
+ return Q_NULLPTR;
+ }
+
+private:
+ typedef OutputType* (*FactoryFunction)(QObject*);
+ QHash<IndexType, FactoryFunction> m_mapping;
+
+ template<class Type>
+ static OutputType* createInstance(QObject *parent)
+ {
+ return new Type(parent);
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/remoteobjects/qconnectionabstractserver.cpp b/src/remoteobjects/qconnectionabstractserver.cpp
new file mode 100644
index 0000000..672bd2e
--- /dev/null
+++ b/src/remoteobjects/qconnectionabstractserver.cpp
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qconnectionabstractserver_p.h"
+#include "qtremoteobjectglobal.h"
+
+QT_BEGIN_NAMESPACE
+
+ServerIoDevice::ServerIoDevice(QObject *parent)
+ : QObject(parent), m_isClosing(false), m_curReadSize(0), m_packet(Q_NULLPTR)
+{
+}
+
+ServerIoDevice::~ServerIoDevice()
+{
+ if (m_packet)
+ delete m_packet;
+}
+
+bool ServerIoDevice::read()
+{
+ qCDebug(QT_REMOTEOBJECT) << "ServerIODevice::read()" << m_curReadSize << bytesAvailable();
+
+ QDataStream in(connection());
+ if (m_curReadSize == 0) {
+ if (bytesAvailable() < static_cast<int>(sizeof(quint32)))
+ return false;
+
+ in >> m_curReadSize;
+ }
+
+ qCDebug(QT_REMOTEOBJECT) << "ServerIODevice::read()-looking for map" << m_curReadSize << bytesAvailable();
+
+ if (bytesAvailable() < m_curReadSize)
+ return false;
+
+ m_curReadSize = 0;
+ if (m_packet)
+ delete m_packet;
+ m_packet = QRemoteObjectPackets::QRemoteObjectPacket::fromDataStream(in);
+ return m_packet && m_packet->id != QRemoteObjectPackets::QRemoteObjectPacket::Invalid;
+}
+
+void ServerIoDevice::close()
+{
+ m_isClosing = true;
+ doClose();
+}
+
+void ServerIoDevice::write(const QByteArray &data)
+{
+ if (connection()->isOpen() && !m_isClosing)
+ connection()->write(data);
+}
+
+qint64 ServerIoDevice::bytesAvailable()
+{
+ return connection()->bytesAvailable();
+}
+
+QRemoteObjectPackets::QRemoteObjectPacket *ServerIoDevice::packet() const
+{
+ return m_packet;
+}
+
+
+QConnectionAbstractServer::QConnectionAbstractServer(QObject *parent)
+ : QObject(parent)
+{
+}
+
+QConnectionAbstractServer::~QConnectionAbstractServer()
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/remoteobjects/qconnectionabstractserver_p.h b/src/remoteobjects/qconnectionabstractserver_p.h
new file mode 100644
index 0000000..4d55f56
--- /dev/null
+++ b/src/remoteobjects/qconnectionabstractserver_p.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCONNECTIONABSTRACTSERVER_P_H
+#define QCONNECTIONABSTRACTSERVER_P_H
+
+#include <QAbstractSocket>
+#include <QDataStream>
+#include <QIODevice>
+#include <QLocalSocket>
+#include <QObject>
+#include <QTcpSocket>
+#include <QVariant>
+#include "qtremoteobjectglobal.h"
+
+QT_BEGIN_NAMESPACE
+
+//The Qt servers create QIODevice derived classes from handleConnection.
+//The problem is that they behave differently, so this class adds some
+//consistency.
+class ServerIoDevice : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(ServerIoDevice)
+
+public:
+ explicit ServerIoDevice(QObject *parent = Q_NULLPTR);
+ virtual ~ServerIoDevice();
+
+ bool read();
+
+ virtual void write(const QByteArray &data);
+ void close();
+ virtual qint64 bytesAvailable();
+ QRemoteObjectPackets::QRemoteObjectPacket *packet() const;
+ virtual QIODevice *connection() const = 0;
+
+Q_SIGNALS:
+ void disconnected();
+ void readyRead();
+
+protected:
+ virtual void doClose() = 0;
+
+private:
+ bool m_isClosing;
+ quint32 m_curReadSize;
+ QRemoteObjectPackets::QRemoteObjectPacket *m_packet;
+};
+
+
+class QConnectionAbstractServer : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QConnectionAbstractServer)
+
+public:
+ explicit QConnectionAbstractServer(QObject *parent = Q_NULLPTR);
+ virtual ~QConnectionAbstractServer();
+
+ virtual bool hasPendingConnections() const = 0;
+ virtual ServerIoDevice* nextPendingConnection() = 0;
+ virtual QUrl address() const = 0;
+ virtual bool listen(const QUrl &address) = 0;
+ virtual QAbstractSocket::SocketError serverError() const = 0;
+ virtual void close() = 0;
+
+Q_SIGNALS:
+ void newConnection();
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/remoteobjects/qconnectionclientfactory.cpp b/src/remoteobjects/qconnectionclientfactory.cpp
new file mode 100644
index 0000000..23e1527
--- /dev/null
+++ b/src/remoteobjects/qconnectionclientfactory.cpp
@@ -0,0 +1,279 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qconnectionclientfactory_p.h"
+#include "qtremoteobjectglobal.h"
+
+#include <QDataStream>
+#include <QHostAddress>
+#include <QHostInfo>
+
+QT_BEGIN_NAMESPACE
+
+ClientIoDevice::ClientIoDevice(QObject *parent)
+ : QObject(parent), m_isClosing(false), m_curReadSize(0), m_packet(Q_NULLPTR)
+{
+}
+
+ClientIoDevice::~ClientIoDevice()
+{
+ if (m_packet)
+ delete m_packet;
+}
+
+void ClientIoDevice::close()
+{
+ m_isClosing = true;
+ doClose();
+}
+
+bool ClientIoDevice::read()
+{
+ qCDebug(QT_REMOTEOBJECT) << "ClientIODevice::read()" << m_curReadSize << bytesAvailable();
+
+ QDataStream in(connection());
+ if (m_curReadSize == 0) {
+ if (bytesAvailable() < static_cast<int>(sizeof(quint32)))
+ return false;
+
+ in >> m_curReadSize;
+ }
+
+ qCDebug(QT_REMOTEOBJECT) << "ClientIODevice::read()-looking for map" << m_curReadSize << bytesAvailable();
+
+ if (bytesAvailable() < m_curReadSize)
+ return false;
+
+ m_curReadSize = 0;
+ if (m_packet)
+ delete m_packet;
+ m_packet = QRemoteObjectPackets::QRemoteObjectPacket::fromDataStream(in);
+ return m_packet && m_packet->id != QRemoteObjectPackets::QRemoteObjectPacket::Invalid;
+}
+
+void ClientIoDevice::write(const QByteArray &data)
+{
+ connection()->write(data);
+}
+
+qint64 ClientIoDevice::bytesAvailable()
+{
+ return connection()->bytesAvailable();
+}
+
+QRemoteObjectPackets::QRemoteObjectPacket *ClientIoDevice::packet() const
+{
+ return m_packet;
+}
+
+QUrl ClientIoDevice::url() const
+{
+ return m_url;
+}
+
+void ClientIoDevice::addSource(const QString &name)
+{
+ m_remoteObjects.insert(name);
+}
+
+void ClientIoDevice::removeSource(const QString &name)
+{
+ m_remoteObjects.remove(name);
+}
+
+QSet<QString> ClientIoDevice::remoteObjects() const
+{
+ return m_remoteObjects;
+}
+
+
+LocalClientIo::LocalClientIo(QObject *parent)
+ : ClientIoDevice(parent)
+{
+ connect(&m_socket, SIGNAL(readyRead()), this, SIGNAL(readyRead()));
+ connect(&m_socket, SIGNAL(error(QLocalSocket::LocalSocketError)), this, SLOT(onError(QLocalSocket::LocalSocketError)));
+ connect(&m_socket, SIGNAL(stateChanged(QLocalSocket::LocalSocketState)), this, SLOT(onStateChanged(QLocalSocket::LocalSocketState)));
+}
+
+LocalClientIo::~LocalClientIo()
+{
+ close();
+}
+
+QIODevice *LocalClientIo::connection()
+{
+ return &m_socket;
+}
+
+void LocalClientIo::doClose()
+{
+ if (m_socket.isOpen()) {
+ connect(&m_socket, SIGNAL(disconnected()), this, SLOT(deleteLater()));
+ m_socket.disconnectFromServer();
+ } else {
+ this->deleteLater();
+ }
+}
+
+void LocalClientIo::connectToServer()
+{
+ if (!isOpen())
+ m_socket.connectToServer(url().path());
+}
+
+bool LocalClientIo::isOpen()
+{
+ return !isClosing() && m_socket.isOpen();
+}
+
+void LocalClientIo::onError(QLocalSocket::LocalSocketError error)
+{
+ qCDebug(QT_REMOTEOBJECT) << "onError" << error;
+
+ switch (error) {
+ case QLocalSocket::ServerNotFoundError: //Host not there, wait and try again
+ emit shouldReconnect(this);
+ break;
+ case QLocalSocket::ConnectionError:
+ case QLocalSocket::ConnectionRefusedError:
+ //... TODO error reporting
+ break;
+ default:
+ break;
+ }
+}
+
+void LocalClientIo::onStateChanged(QLocalSocket::LocalSocketState state)
+{
+ if (state == QLocalSocket::ClosingState && !isClosing()) {
+ m_socket.abort();
+ emit shouldReconnect(this);
+ }
+}
+
+
+TcpClientIo::TcpClientIo(QObject *parent)
+ : ClientIoDevice(parent)
+{
+ connect(&m_socket, SIGNAL(readyRead()), this, SIGNAL(readyRead()));
+ connect(&m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError)));
+ connect(&m_socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onStateChanged(QAbstractSocket::SocketState)));
+}
+
+TcpClientIo::~TcpClientIo()
+{
+ close();
+}
+
+QIODevice *TcpClientIo::connection()
+{
+ return &m_socket;
+}
+
+void TcpClientIo::doClose()
+{
+ if (m_socket.isOpen()) {
+ connect(&m_socket, SIGNAL(disconnected()), this, SLOT(deleteLater()));
+ m_socket.disconnectFromHost();
+ } else {
+ this->deleteLater();
+ }
+}
+
+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, url().port());
+}
+
+bool TcpClientIo::isOpen()
+{
+ return (!isClosing() && m_socket.isOpen());
+}
+
+void TcpClientIo::onError(QAbstractSocket::SocketError error)
+{
+ qCDebug(QT_REMOTEOBJECT) << "onError" << error;
+
+ switch (error) {
+ case QAbstractSocket::HostNotFoundError: //Host not there, wait and try again
+ emit shouldReconnect(this);
+ break;
+ case QAbstractSocket::AddressInUseError:
+ case QAbstractSocket::ConnectionRefusedError:
+ //... TODO error reporting
+ break;
+ default:
+ break;
+ }
+}
+
+void TcpClientIo::onStateChanged(QAbstractSocket::SocketState state)
+{
+ if (state == QAbstractSocket::ClosingState && !isClosing()) {
+ m_socket.abort();
+ emit shouldReconnect(this);
+ }
+}
+
+
+QConnectionClientFactory::QConnectionClientFactory()
+{
+ registerProduct<LocalClientIo>(QRemoteObjectStringLiterals::local());
+ registerProduct<TcpClientIo>(QRemoteObjectStringLiterals::tcp());
+}
+
+ClientIoDevice *QConnectionClientFactory::createDevice(const QUrl &url, QObject *parent)
+{
+ ClientIoDevice *res = QConnectionAbstractFactory::create(url.scheme(), parent);
+ res->m_url = url;
+ return res;
+}
+
+QT_END_NAMESPACE
diff --git a/src/remoteobjects/qconnectionclientfactory_p.h b/src/remoteobjects/qconnectionclientfactory_p.h
new file mode 100644
index 0000000..5fa0cce
--- /dev/null
+++ b/src/remoteobjects/qconnectionclientfactory_p.h
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCONNECTIONCLIENTFACTORY_P_H
+#define QCONNECTIONCLIENTFACTORY_P_H
+
+#include "qconnectionabstractfactory_p.h"
+#include "qtremoteobjectglobal.h"
+
+#include <QLocalSocket>
+#include <QObject>
+#include <QTcpSocket>
+#include <QUrl>
+#include <QVariant>
+
+QT_BEGIN_NAMESPACE
+
+class ClientIoDevice : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(ClientIoDevice)
+
+public:
+ explicit ClientIoDevice(QObject *parent = Q_NULLPTR);
+ virtual ~ClientIoDevice();
+
+ bool read();
+ virtual void write(const QByteArray &data);
+ void close();
+ virtual void connectToServer() = 0;
+ virtual qint64 bytesAvailable();
+
+ QRemoteObjectPackets::QRemoteObjectPacket *packet() const;
+ QUrl url() const;
+ void addSource(const QString &);
+ void removeSource(const QString &);
+ QSet<QString> remoteObjects() const;
+
+ virtual bool isOpen() = 0;
+ virtual QIODevice *connection() = 0;
+
+Q_SIGNALS:
+ void disconnected();
+ void readyRead();
+ void shouldReconnect(ClientIoDevice*);
+protected:
+ virtual void doClose() = 0;
+ inline bool isClosing();
+
+private:
+ bool m_isClosing;
+ QUrl m_url;
+
+private:
+ friend class QConnectionClientFactory;
+
+ quint32 m_curReadSize;
+ QRemoteObjectPackets::QRemoteObjectPacket* m_packet;
+ QSet<QString> m_remoteObjects;
+};
+
+bool ClientIoDevice::isClosing()
+{
+ return m_isClosing;
+}
+
+class LocalClientIo : public ClientIoDevice
+{
+ Q_OBJECT
+
+public:
+ explicit LocalClientIo(QObject *parent = Q_NULLPTR);
+ ~LocalClientIo();
+
+ QIODevice *connection() Q_DECL_OVERRIDE;
+ void connectToServer() Q_DECL_OVERRIDE;
+ bool isOpen() Q_DECL_OVERRIDE;
+
+public Q_SLOTS:
+ void onError(QLocalSocket::LocalSocketError error);
+ void onStateChanged(QLocalSocket::LocalSocketState state);
+
+protected:
+ void doClose() Q_DECL_OVERRIDE;
+private:
+ QLocalSocket m_socket;
+};
+
+
+class TcpClientIo : public ClientIoDevice
+{
+ Q_OBJECT
+
+public:
+ explicit TcpClientIo(QObject *parent = Q_NULLPTR);
+ ~TcpClientIo();
+
+ QIODevice *connection() Q_DECL_OVERRIDE;
+ void connectToServer() Q_DECL_OVERRIDE;
+ bool isOpen() Q_DECL_OVERRIDE;
+
+public Q_SLOTS:
+ void onError(QAbstractSocket::SocketError error);
+ void onStateChanged(QAbstractSocket::SocketState state);
+
+protected:
+ void doClose() Q_DECL_OVERRIDE;
+
+private:
+ QTcpSocket m_socket;
+};
+
+class QConnectionClientFactory : public QConnectionAbstractFactory<ClientIoDevice>
+{
+ Q_DISABLE_COPY(QConnectionClientFactory)
+
+public:
+ QConnectionClientFactory();
+
+ ClientIoDevice *createDevice(const QUrl &url, QObject *parent = Q_NULLPTR);
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/remoteobjects/qconnectionserverfactory.cpp b/src/remoteobjects/qconnectionserverfactory.cpp
new file mode 100644
index 0000000..f211ee7
--- /dev/null
+++ b/src/remoteobjects/qconnectionserverfactory.cpp
@@ -0,0 +1,217 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qconnectionserverfactory_p.h"
+
+#include <qcompilerdetection.h>
+#include <QHostInfo>
+#include <QIODevice>
+#include <QLocalServer>
+#include <QTcpServer>
+#include <QtGlobal>
+
+#ifdef Q_OS_LINUX
+#include <QFile>
+#include <QDir>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+LocalServerIo::LocalServerIo(QLocalSocket *conn, QObject *parent)
+ : ServerIoDevice(parent), m_connection(conn)
+{
+ m_connection->setParent(this);
+ connect(conn, SIGNAL(readyRead()), this, SIGNAL(readyRead()));
+ connect(conn, SIGNAL(disconnected()), this, SIGNAL(disconnected()));
+}
+
+QIODevice *LocalServerIo::connection() const
+{
+ return m_connection;
+}
+
+void LocalServerIo::doClose()
+{
+ m_connection->disconnectFromServer();
+}
+
+
+TcpServerIo::TcpServerIo(QTcpSocket *conn, QObject *parent)
+ : ServerIoDevice(parent), m_connection(conn)
+{
+ m_connection->setParent(this);
+ connect(conn, SIGNAL(readyRead()), this, SIGNAL(readyRead()));
+ connect(conn, SIGNAL(disconnected()), this, SIGNAL(disconnected()));
+}
+
+QIODevice *TcpServerIo::connection() const
+{
+ return m_connection;
+}
+
+void TcpServerIo::doClose()
+{
+ m_connection->disconnectFromHost();
+}
+
+
+LocalServerImpl::LocalServerImpl(QObject *parent)
+ : QConnectionAbstractServer(parent)
+{
+ connect(&m_server, SIGNAL(newConnection()), this, SIGNAL(newConnection()));
+}
+
+LocalServerImpl::~LocalServerImpl()
+{
+ m_server.close();
+}
+
+ServerIoDevice *LocalServerImpl::nextPendingConnection()
+{
+ if (!m_server.isListening())
+ return Q_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_LINUX
+ QFile socketFile(QDir::tempPath() + QDir::separator() + address.path());
+ socketFile.remove();
+#endif
+ return m_server.listen(address.path());
+}
+
+QAbstractSocket::SocketError LocalServerImpl::serverError() const
+{
+ return m_server.serverError();
+}
+
+void LocalServerImpl::close()
+{
+ close();
+}
+
+
+TcpServerImpl::TcpServerImpl(QObject *parent)
+ : QConnectionAbstractServer(parent)
+{
+ connect(&m_server, SIGNAL(newConnection()), this, SIGNAL(newConnection()));
+}
+
+TcpServerImpl::~TcpServerImpl()
+{
+ close();
+}
+
+ServerIoDevice *TcpServerImpl::nextPendingConnection()
+{
+ if (!m_server.isListening())
+ return Q_NULLPTR;
+
+ return new TcpServerIo(m_server.nextPendingConnection());
+}
+
+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()) {
+ const QList<QHostAddress> addresses = QHostInfo::fromName(address.host()).addresses();;
+ Q_ASSERT(addresses.size() >= 1);
+ host = addresses.first();
+ m_originalUrl = address;
+ }
+
+ return m_server.listen(host, address.port());
+}
+
+QAbstractSocket::SocketError TcpServerImpl::serverError() const
+{
+ return m_server.serverError();
+}
+
+void TcpServerImpl::close()
+{
+ m_server.close();
+}
+
+QConnectionServerFactory::QConnectionServerFactory()
+{
+ registerProduct<LocalServerImpl>(QRemoteObjectStringLiterals::local());
+ registerProduct<TcpServerImpl>(QRemoteObjectStringLiterals::tcp());
+}
+
+QConnectionAbstractServer *QConnectionServerFactory::createServer(const QUrl &url, QObject *parent)
+{
+ return create(url, parent);
+}
+
+QConnectionAbstractServer *QConnectionServerFactory::create(const QUrl &url, QObject *parent)
+{
+ return QConnectionAbstractFactory::create(url.scheme(), parent);
+}
+
+QT_END_NAMESPACE
diff --git a/src/remoteobjects/qconnectionserverfactory_p.h b/src/remoteobjects/qconnectionserverfactory_p.h
new file mode 100644
index 0000000..4d4638a
--- /dev/null
+++ b/src/remoteobjects/qconnectionserverfactory_p.h
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCONNECTIONSERVERFACTORY_P_H
+#define QCONNECTIONSERVERFACTORY_P_H
+
+#include "qconnectionabstractfactory_p.h"
+#include "qconnectionabstractserver_p.h"
+
+#include <QLocalServer>
+#include <QTcpServer>
+#include <QUrl>
+
+QT_BEGIN_NAMESPACE
+
+class LocalServerIo : public ServerIoDevice
+{
+public:
+ explicit LocalServerIo(QLocalSocket *conn, QObject *parent = Q_NULLPTR);
+
+ QIODevice *connection() const Q_DECL_OVERRIDE;
+protected:
+ void doClose() Q_DECL_OVERRIDE;
+
+private:
+ QLocalSocket *m_connection;
+};
+
+
+class TcpServerIo : public ServerIoDevice
+{
+public:
+ explicit TcpServerIo(QTcpSocket *conn, QObject *parent = Q_NULLPTR);
+
+ QIODevice *connection() const Q_DECL_OVERRIDE;
+protected:
+ void doClose() Q_DECL_OVERRIDE;
+
+private:
+ QTcpSocket *m_connection;
+};
+
+
+class LocalServerImpl : public QConnectionAbstractServer
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(LocalServerImpl)
+
+public:
+ explicit LocalServerImpl(QObject *parent);
+ ~LocalServerImpl();
+
+ bool hasPendingConnections() const Q_DECL_OVERRIDE;
+ ServerIoDevice *nextPendingConnection() Q_DECL_OVERRIDE;
+ QUrl address() const Q_DECL_OVERRIDE;
+ bool listen(const QUrl &address) Q_DECL_OVERRIDE;
+ QAbstractSocket::SocketError serverError() const Q_DECL_OVERRIDE;
+ void close() Q_DECL_OVERRIDE;
+
+private:
+ QLocalServer m_server;
+};
+
+
+class TcpServerImpl : public QConnectionAbstractServer
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(TcpServerImpl)
+
+public:
+ explicit TcpServerImpl(QObject *parent);
+ ~TcpServerImpl();
+
+ bool hasPendingConnections() const Q_DECL_OVERRIDE;
+ ServerIoDevice *nextPendingConnection() Q_DECL_OVERRIDE;
+ QUrl address() const Q_DECL_OVERRIDE;
+ bool listen(const QUrl &address) Q_DECL_OVERRIDE;
+ QAbstractSocket::SocketError serverError() const Q_DECL_OVERRIDE;
+ void close() Q_DECL_OVERRIDE;
+
+private:
+ QTcpServer m_server;
+ QUrl m_originalUrl; // necessary because of a QHostAddress bug
+};
+
+
+class QConnectionServerFactory : public QConnectionAbstractFactory<QConnectionAbstractServer>
+{
+ Q_DISABLE_COPY(QConnectionServerFactory)
+
+public:
+ QConnectionServerFactory();
+ QConnectionAbstractServer *createServer(const QUrl &url, QObject *parent = Q_NULLPTR);
+ static void registerScheme(const QString &scheme);
+
+private:
+ QConnectionAbstractServer *create(const QUrl &url, QObject *parent);
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/remoteobjects/qregistrysource.cpp b/src/remoteobjects/qregistrysource.cpp
new file mode 100644
index 0000000..95fa12e
--- /dev/null
+++ b/src/remoteobjects/qregistrysource.cpp
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qregistrysource_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QRegistrySource::QRegistrySource(QObject *parent)
+ : QRemoteObjectSource(parent)
+{
+ qRegisterMetaTypeStreamOperators<QRemoteObjectSourceLocation>();
+ qRegisterMetaTypeStreamOperators<QRemoteObjectSourceLocations>();
+}
+
+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)
+{
+ QVector<QString> results;
+ typedef QRemoteObjectSourceLocations::const_iterator CustomIterator;
+ const CustomIterator end = m_sourceLocations.constEnd();
+ for (CustomIterator it = m_sourceLocations.constBegin(); it != end; ++it)
+ if (it.value() == url)
+ results.push_back(it.key());
+ Q_FOREACH (const QString &res, results)
+ m_sourceLocations.remove(res);
+}
+
+void QRegistrySource::addSource(const QRemoteObjectSourceLocation &entry)
+{
+ qCDebug(QT_REMOTEOBJECT) << "An entry was added to the RegistrySource" << entry;
+ if (!m_sourceLocations.contains(entry.first)) {
+ 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] == entry.second) {
+ m_sourceLocations.remove(entry.first);
+ emit remoteObjectRemoved(entry);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/remoteobjects/qregistrysource_p.h b/src/remoteobjects/qregistrysource_p.h
new file mode 100644
index 0000000..f44b6d2
--- /dev/null
+++ b/src/remoteobjects/qregistrysource_p.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREGISTRYSOURCE_P_H
+#define QREGISTRYSOURCE_P_H
+
+#include "qremoteobjectsource.h"
+
+QT_BEGIN_NAMESPACE
+
+class QRegistrySource : public QRemoteObjectSource
+{
+ Q_OBJECT
+ Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_TYPE, "Registry")
+
+ Q_PROPERTY(QRemoteObjectSourceLocations sourceLocations READ sourceLocations)
+
+public:
+ explicit QRegistrySource(QObject *parent = Q_NULLPTR);
+ ~QRegistrySource();
+
+ 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/qremoteobjectdynamicreplica.cpp b/src/remoteobjects/qremoteobjectdynamicreplica.cpp
new file mode 100644
index 0000000..eb8aaac
--- /dev/null
+++ b/src/remoteobjects/qremoteobjectdynamicreplica.cpp
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qremoteobjectdynamicreplica.h"
+#include "qremoteobjectreplica_p.h"
+
+#include <QDebug>
+#include <QMetaProperty>
+
+QT_BEGIN_NAMESPACE
+
+QRemoteObjectDynamicReplica::QRemoteObjectDynamicReplica(QObject *parent)
+ : QRemoteObjectReplica(parent)
+{
+}
+
+QRemoteObjectDynamicReplica::~QRemoteObjectDynamicReplica()
+{
+}
+
+const QMetaObject* QRemoteObjectDynamicReplica::metaObject() const
+{
+ Q_D(const QRemoteObjectReplica);
+
+ return d->m_metaObject ? d->m_metaObject : QRemoteObjectReplica::metaObject();
+}
+
+void *QRemoteObjectDynamicReplica::qt_metacast(const char *name)
+{
+ Q_D(QRemoteObjectReplica);
+
+ if (!name)
+ return 0;
+
+ if (!strcmp(name, "QRemoteObjectDynamicReplica"))
+ return static_cast<void*>(const_cast<QRemoteObjectDynamicReplica*>(this));
+
+ // not entirely sure that one is needed... TODO: check
+ if (QString::fromLatin1(name) == d->m_objectName)
+ return static_cast<void*>(const_cast<QRemoteObjectDynamicReplica*>(this));
+
+ return QObject::qt_metacast(name);
+}
+
+int QRemoteObjectDynamicReplica::qt_metacall(QMetaObject::Call call, int id, void **argv)
+{
+ Q_D(QRemoteObjectReplica);
+
+ int saved_id = id;
+ id = QRemoteObjectReplica::qt_metacall(call, id, argv);
+ if (id < 0 || d->m_metaObject == Q_NULLPTR)
+ return id;
+
+ if (call == QMetaObject::ReadProperty || call == QMetaObject::WriteProperty) {
+ QMetaProperty mp = metaObject()->property(saved_id);
+ int &status = *reinterpret_cast<int *>(argv[2]);
+
+ if (call == QMetaObject::WriteProperty) {
+ QVariantList args;
+ args << QVariant(mp.userType(), argv[0]);
+ QRemoteObjectReplica::send(QMetaObject::WriteProperty, saved_id, args);
+ } else {
+ const QVariant value = propAsVariant(id);
+ QMetaType::construct(mp.userType(), argv[0], value.data());
+ const bool readStatus = true;
+ // Caller supports QVariant returns? Then we can also report errors
+ // by storing an invalid variant.
+ if (!readStatus && argv[1]) {
+ status = 0;
+ reinterpret_cast<QVariant*>(argv[1])->clear();
+ }
+ }
+
+ id = -1;
+ } else if (call == QMetaObject::InvokeMetaMethod) {
+ const int methodType = d->m_remoteObjectMethodTypes.at(id);
+
+ if (methodType == QMetaMethod::Signal) {
+ // signal relay from Source world to Replica
+ QMetaObject::activate(this, d->m_metaObject, id, argv);
+
+ } else if (methodType == QMetaMethod::Slot || methodType == QMetaMethod::Method) {
+ // method relay from Replica to Source
+ qCDebug(QT_REMOTEOBJECT) << "method" << d->m_metaObject->method(saved_id).name() << "invoked";
+
+ QVariantList args;
+ for (int i = 1; i <= d->m_methodArgumentTypes.at(id).size(); ++i) {
+ args << QVariant(d->m_methodArgumentTypes.at(id)[i-1], argv[i]);
+ }
+
+ QRemoteObjectReplica::send(QMetaObject::InvokeMetaMethod, saved_id, args);
+ }
+ }
+
+ return id;
+}
+
+QT_END_NAMESPACE
diff --git a/src/remoteobjects/qremoteobjectdynamicreplica.h b/src/remoteobjects/qremoteobjectdynamicreplica.h
new file mode 100644
index 0000000..e676468
--- /dev/null
+++ b/src/remoteobjects/qremoteobjectdynamicreplica.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDYNAMICREMOTEOBJECT_H
+#define QDYNAMICREMOTEOBJECT_H
+
+#include "qremoteobjectreplica.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q_REMOTEOBJECTS_EXPORT QRemoteObjectDynamicReplica : public QRemoteObjectReplica
+{
+public:
+ ~QRemoteObjectDynamicReplica();
+
+ const QMetaObject *metaObject() const Q_DECL_OVERRIDE;
+ void *qt_metacast(const char *name) Q_DECL_OVERRIDE;
+ int qt_metacall(QMetaObject::Call call, int id, void **argv) Q_DECL_OVERRIDE;
+
+private:
+ explicit QRemoteObjectDynamicReplica(QObject *parent = Q_NULLPTR);
+ friend class QRemoteObjectNodePrivate;
+ friend class QRemoteObjectNode;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/remoteobjects/qremoteobjectnode.cpp b/src/remoteobjects/qremoteobjectnode.cpp
new file mode 100644
index 0000000..5e4924d
--- /dev/null
+++ b/src/remoteobjects/qremoteobjectnode.cpp
@@ -0,0 +1,690 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qremoteobjectnode.h"
+#include "qremoteobjectnode_p.h"
+
+#include "qremoteobjectregistry.h"
+#include "qremoteobjectdynamicreplica.h"
+#include "qregistrysource_p.h"
+#include "qremoteobjectreplica_p.h"
+#include "qremoteobjectsource_p.h"
+
+#include <QMetaProperty>
+
+QT_BEGIN_NAMESPACE
+
+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();
+}
+
+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;
+}
+
+QRemoteObjectNodePrivate::QRemoteObjectNodePrivate()
+ : QObject(Q_NULLPTR)
+ , retryInterval(250)
+ , m_lastError(QRemoteObjectNode::NoError)
+{
+ connect(&clientRead, SIGNAL(mapped(QObject*)), this, SLOT(onClientRead(QObject*)));
+}
+
+QRemoteObjectNodePrivate::~QRemoteObjectNodePrivate()
+{
+ Q_FOREACH (ClientIoDevice *conn, knownNodes) {
+ conn->close();
+ conn->deleteLater();
+ }
+}
+
+QRemoteObjectSourceLocations QRemoteObjectNodePrivate::remoteObjectAddresses() const
+{
+ if (!registrySource.isNull())
+ return registrySource->sourceLocations();
+ else if (!registry.isNull())
+ return registry->sourceLocations();
+ return QRemoteObjectSourceLocations();
+}
+
+void QRemoteObjectNodePrivate::timerEvent(QTimerEvent*)
+{
+ Q_FOREACH (ClientIoDevice *conn, pendingReconnect) {
+ if (conn->isOpen())
+ pendingReconnect.remove(conn);
+ else
+ conn->connectToServer();
+ }
+
+ if (pendingReconnect.isEmpty())
+ reconnectTimer.stop();
+
+ qCDebug(QT_REMOTEOBJECT) << "timerEvent" << pendingReconnect.size();
+}
+
+QRemoteObjectReplica *QRemoteObjectNodePrivate::acquire(const QMetaObject *meta, QRemoteObjectReplica *instance, const QString &name)
+{
+ qCDebug(QT_REMOTEOBJECT) << "Starting acquire for" << name;
+ isInitialized.storeRelease(1);
+ openConnectionIfNeeded(name);
+ QMutexLocker locker(&mutex);
+ if (hasInstance(name)) {
+ qCDebug(QT_REMOTEOBJECT)<<"Acquire - using existing instance";
+ QSharedPointer<QRemoteObjectReplicaPrivate> rep = replicas.value(name).toStrongRef();
+ Q_ASSERT(rep);
+ instance->d_ptr = rep;
+ rep->configurePrivate(instance);
+ } else {
+ QMap<QString, QRemoteObjectSourcePrivate*>::const_iterator mapIt;
+ if (!remoteObjectIo.isNull() && map_contains(remoteObjectIo->m_remoteObjects, name, mapIt)) {
+ QInProcessReplicaPrivate *rp = new QInProcessReplicaPrivate(name, meta);
+ instance->d_ptr.reset(rp);
+ rp->configurePrivate(instance);
+ connectReplica(mapIt.value()->m_object, instance);
+ rp->connectionToSource = mapIt.value();
+ } else {
+ QConnectedReplicaPrivate *rp = new QConnectedReplicaPrivate(name, meta);
+ instance->d_ptr.reset(rp);
+ rp->configurePrivate(instance);
+ if (connectedSources.contains(name)) { //Either we have a peer connections, or existing connection via registry
+ rp->setConnection(connectedSources[name]);
+ } else if (remoteObjectAddresses().contains(name)) { //No existing connection, but we know we can connect via registry
+ initConnection(remoteObjectAddresses()[name]); //This will try the connection, and if successful, the remoteObjects will be sent
+ //The link to the replica will be handled then
+ }
+ }
+ instance->initialize();
+ replicas.insert(name, instance->d_ptr.toWeakRef());
+ qCDebug(QT_REMOTEOBJECT) << "Acquire - Created new instance" << name<<remoteObjectAddresses();
+ }
+ return instance;
+}
+
+const QRemoteObjectRegistry *QRemoteObjectNode::registry() const
+{
+ return d_ptr->registry.data();
+}
+
+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);
+
+ qCDebug(QT_REMOTEOBJECT) << 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());
+ qCDebug(QT_REMOTEOBJECT) << 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;
+
+ qCDebug(QT_REMOTEOBJECT) << sig << res;
+ }
+
+ qCDebug(QT_REMOTEOBJECT) << "# connections =" << nConnections;
+}
+
+void QRemoteObjectNodePrivate::openConnectionIfNeeded(const QString &name)
+{
+ qCDebug(QT_REMOTEOBJECT) << Q_FUNC_INFO << name << this;
+ if (remoteObjectAddresses().contains(name)) {
+ initConnection(remoteObjectAddresses()[name]);
+ qCDebug(QT_REMOTEOBJECT) << "openedConnection" << remoteObjectAddresses()[name];
+ }
+}
+
+void QRemoteObjectNodePrivate::initConnection(const QUrl &address)
+{
+ if (requestedUrls.contains(address)) {
+ qCWarning(QT_REMOTEOBJECT) << "Connection already initialized for " << address.toString();
+ return;
+ }
+
+ requestedUrls.insert(address);
+
+ ClientIoDevice *connection = m_factory.createDevice(address, this);
+ Q_ASSERT_X(connection, Q_FUNC_INFO, "Could not create IODevice for client");
+
+ knownNodes.insert(connection);
+ qCDebug(QT_REMOTEOBJECT) << "Replica Connection isValid" << connection->isOpen();
+ connect(connection, SIGNAL(shouldReconnect(ClientIoDevice*)), this, SLOT(onShouldReconnect(ClientIoDevice*)));
+ connection->connectToServer();
+ connect(connection, SIGNAL(readyRead()), &clientRead, SLOT(map()));
+ clientRead.setMapping(connection, connection);
+}
+
+bool QRemoteObjectNodePrivate::hasInstance(const QString &name)
+{
+ if (!replicas.contains(name))
+ return false;
+
+ QSharedPointer<QRemoteObjectReplicaPrivate> rep = replicas.value(name).toStrongRef();
+ if (!rep) { //already deleted
+ replicas.remove(name);
+ return false;
+ }
+
+ return true;
+}
+
+void QRemoteObjectNodePrivate::onRemoteObjectSourceAdded(const QRemoteObjectSourceLocation &entry)
+{
+ qCDebug(QT_REMOTEOBJECT) <<"onRemoteObjectSourceAdded"<< entry << replicas<<replicas.contains(entry.first);
+ if (!entry.first.isEmpty()) {
+ QRemoteObjectSourceLocations locs = registry->propAsVariant(0).value<QRemoteObjectSourceLocations>();
+ locs[entry.first] = entry.second;
+ //TODO Is there a way to extend QRemoteObjectSourceLocations in place?
+ registry->setProperty(0, QVariant::fromValue(locs));
+ qCDebug(QT_REMOTEOBJECT) << "onRemoteObjectSourceAdded, now locations =" << registry->propAsVariant(0).value<QRemoteObjectSourceLocations>()<<locs;
+ }
+ if (replicas.contains(entry.first)) //We have a replica waiting on this remoteObject
+ {
+ QSharedPointer<QRemoteObjectReplicaPrivate> rep = replicas.value(entry.first).toStrongRef();
+ if (!rep) { //replica has been deleted, remove from list
+ replicas.remove(entry.first);
+ return;
+ }
+
+ initConnection(entry.second);
+
+ qCDebug(QT_REMOTEOBJECT) << "Called initConnection due to new RemoteObjectSource added via registry" << entry.first;
+ }
+}
+
+void QRemoteObjectNodePrivate::onRemoteObjectSourceRemoved(const QRemoteObjectSourceLocation &entry)
+{
+ if (!entry.first.isEmpty()) {
+ QRemoteObjectSourceLocations locs = registry->propAsVariant(0).value<QRemoteObjectSourceLocations>();
+ locs.remove(entry.first);
+ registry->setProperty(0, QVariant::fromValue(locs));
+ }
+}
+
+void QRemoteObjectNodePrivate::onRegistryInitialized()
+{
+ qCDebug(QT_REMOTEOBJECT) << "Registry Initialized" << remoteObjectAddresses();
+
+ QHashIterator<QString, QUrl> i(remoteObjectAddresses());
+ while (i.hasNext()) {
+ i.next();
+ if (replicas.contains(i.key())) //We have a replica waiting on this remoteObject
+ {
+ QSharedPointer<QRemoteObjectReplicaPrivate> rep = replicas.value(i.key()).toStrongRef();
+ if (rep && !requestedUrls.contains(i.value()))
+ initConnection(i.value());
+ else if (!rep) //replica has been deleted, remove from list
+ replicas.remove(i.key());
+
+ continue;
+ }
+ }
+}
+
+void QRemoteObjectNodePrivate::onShouldReconnect(ClientIoDevice *ioDevice)
+{
+ pendingReconnect.insert(ioDevice);
+
+ Q_FOREACH (const QString &remoteObject, ioDevice->remoteObjects()) {
+ connectedSources.remove(remoteObject);
+ ioDevice->removeSource(remoteObject);
+ if (replicas.contains(remoteObject)) { //We have a replica waiting on this remoteObject
+ QSharedPointer<QRemoteObjectReplicaPrivate> rep = replicas.value(remoteObject).toStrongRef();
+ QConnectedReplicaPrivate *cRep = static_cast<QConnectedReplicaPrivate*>(rep.data());
+ if (rep && !cRep->connectionToSource.isNull()) {
+ cRep->setDisconnected();
+ } else if (!rep) {
+ replicas.remove(remoteObject);
+ }
+ }
+ }
+ if (!reconnectTimer.isActive()) {
+ reconnectTimer.start(retryInterval, this);
+ qCDebug(QT_REMOTEOBJECT) << "Starting reconnect timer";
+ }
+}
+
+void QRemoteObjectNodePrivate::onClientRead(QObject *obj)
+{
+ ClientIoDevice *connection = qobject_cast<ClientIoDevice*>(obj);
+ Q_ASSERT(connection);
+
+ if (!connection->read())
+ return;
+
+ using namespace QRemoteObjectPackets;
+
+ const QRemoteObjectPacket* packet = connection->packet();
+ switch (packet->id) {
+ case QRemoteObjectPacket::ObjectList:
+ {
+ const QObjectListPacket *p = static_cast<const QObjectListPacket *>(packet);
+ const QSet<QString> newObjects = p->objects.toSet();
+ qCDebug(QT_REMOTEOBJECT) << "newObjects:" << newObjects;
+ Q_FOREACH (const QString &remoteObject, newObjects) {
+ qCDebug(QT_REMOTEOBJECT) << " connectedSources.contains("<<remoteObject<<")"<<connectedSources.contains(remoteObject)<<replicas.contains(remoteObject);
+ if (!connectedSources.contains(remoteObject)) {
+ connectedSources[remoteObject] = connection;
+ connection->addSource(remoteObject);
+ if (replicas.contains(remoteObject)) //We have a replica waiting on this remoteObject
+ {
+ QSharedPointer<QRemoteObjectReplicaPrivate> rep = replicas.value(remoteObject).toStrongRef();
+ QConnectedReplicaPrivate *cRep = static_cast<QConnectedReplicaPrivate*>(rep.data());
+ if (rep && cRep->connectionToSource.isNull())
+ {
+ qCDebug(QT_REMOTEOBJECT) << "Test" << remoteObject<<replicas.keys();
+ qCDebug(QT_REMOTEOBJECT) << cRep;
+ cRep->setConnection(connection);
+ } else if (!rep) { //replica has been deleted, remove from list
+ replicas.remove(remoteObject);
+ }
+
+ continue;
+ }
+ }
+ }
+ break;
+ }
+ case QRemoteObjectPacket::InitPacket:
+ {
+ const QInitPacket *p = static_cast<const QInitPacket *>(packet);
+ const QString object = p->name;
+ qCDebug(QT_REMOTEOBJECT) << "InitObject-->" <<object << this;
+ QSharedPointer<QRemoteObjectReplicaPrivate> rep = replicas.value(object).toStrongRef();
+ if (rep)
+ {
+ QConnectedReplicaPrivate *cRep = static_cast<QConnectedReplicaPrivate*>(rep.data());
+ cRep->initialize(p->packetData);
+ } else { //replica has been deleted, remove from list
+ replicas.remove(object);
+ }
+ break;
+ }
+ case QRemoteObjectPacket::InitDynamicPacket:
+ {
+ const QInitDynamicPacket *p = static_cast<const QInitDynamicPacket *>(packet);
+ const QString object = p->name;
+ qCDebug(QT_REMOTEOBJECT) << "InitObject-->" <<object << this;
+ QSharedPointer<QRemoteObjectReplicaPrivate> rep = replicas.value(object).toStrongRef();
+ if (rep)
+ {
+ QConnectedReplicaPrivate *cRep = static_cast<QConnectedReplicaPrivate*>(rep.data());
+ cRep->initializeMetaObject(p);
+
+ } else { //replica has been deleted, remove from list
+ replicas.remove(object);
+ }
+ break;
+ }
+ case QRemoteObjectPacket::RemoveObject:
+ {
+ const QRemoveObjectPacket *p = static_cast<const QRemoveObjectPacket *>(packet);
+ qCDebug(QT_REMOTEOBJECT) << "RemoveObject-->" << p->name << this;
+ connectedSources.remove(p->name);
+ connection->removeSource(p->name);
+ if (replicas.contains(p->name)) { //We have a replica waiting on this remoteObject
+ QSharedPointer<QRemoteObjectReplicaPrivate> rep = replicas.value(p->name).toStrongRef();
+ QConnectedReplicaPrivate *cRep = static_cast<QConnectedReplicaPrivate*>(rep.data());
+ if (rep && !cRep->connectionToSource.isNull()) {
+ cRep->connectionToSource.clear();
+ if (cRep->isReplicaValid()) {
+ //Changed from receiving to not receiving
+ cRep->emitValidChanged();
+ }
+ } else if (!rep) {
+ replicas.remove(p->name);
+ }
+ }
+ break;
+ }
+ case QRemoteObjectPacket::PropertyChangePacket:
+ {
+ const QPropertyChangePacket *p = static_cast<const QPropertyChangePacket *>(packet);
+ const QString object = p->name;
+ qCDebug(QT_REMOTEOBJECT) << "PropertyChange-->" << p->name << QString::fromLatin1(p->propertyName.constData());
+ QSharedPointer<QRemoteObjectReplicaPrivate> rep = replicas.value(object).toStrongRef();
+ if (rep)
+ {
+ const int offset = rep->m_metaObject->propertyOffset();
+ const int index = rep->m_metaObject->indexOfProperty(p->propertyName.constData())-offset;
+ rep->setProperty(index, p->value);
+ } else { //replica has been deleted, remove from list
+ replicas.remove(p->name);
+ }
+ break;
+ }
+ case QRemoteObjectPacket::InvokePacket:
+ {
+ const QInvokePacket *p = static_cast<const QInvokePacket *>(packet);
+ QSharedPointer<QRemoteObjectReplicaPrivate> rep = replicas.value(p->name).toStrongRef();
+ if (rep)
+ {
+ static QVariant null(QMetaType::QObjectStar, (void*)0);
+
+ // Qt usually supports 9 arguments, so ten should be usually safe
+ QVarLengthArray<void*, 10> param(p->args.size() + 1);
+ param[0] = null.data(); //Never a return value
+ for (int i = 0; i < p->args.size(); i++) {
+ param[i + 1] = const_cast<void *>(p->args[i].data());
+ }
+ qCDebug(QT_REMOTEOBJECT) << "Replica Invoke-->" << p->name << rep->m_metaObject->method(p->index+rep->m_methodOffset).name() << p->index << rep->m_methodOffset;
+ QMetaObject::activate(rep.data(), rep->metaObject(), p->index+rep->m_methodOffset, param.data());
+ } else { //replica has been deleted, remove from list
+ replicas.remove(p->name);
+ }
+ break;
+ }
+ }
+
+ if (connection->bytesAvailable()) //have bytes left over, so recurse
+ onClientRead(connection);
+}
+
+
+QRemoteObjectNode::QRemoteObjectNode()
+ : d_ptr(new QRemoteObjectNodePrivate)
+{
+ qRegisterMetaTypeStreamOperators<QVector<int> >();
+}
+
+QRemoteObjectNode::QRemoteObjectNode(const QUrl &hostAddress, const QUrl &registryAddress)
+ : d_ptr(new QRemoteObjectNodePrivate)
+{
+ qRegisterMetaTypeStreamOperators<QVector<int> >();
+ if (!hostAddress.isEmpty()) {
+ setHostUrl(hostAddress);
+ if (hostAddress == registryAddress) {
+ hostRegistry();
+ return;
+ }
+ }
+
+ if (!registryAddress.isEmpty())
+ setRegistryUrl(registryAddress);
+}
+
+QRemoteObjectNode::~QRemoteObjectNode()
+{
+}
+
+QUrl QRemoteObjectNode::hostUrl() const
+{
+ if (d_ptr->remoteObjectIo.isNull())
+ return QUrl();
+
+ return d_ptr->remoteObjectIo->serverAddress();
+}
+
+bool QRemoteObjectNode::setHostUrl(const QUrl &hostAddress)
+{
+ if (!d_ptr->remoteObjectIo.isNull()) {
+ d_ptr->m_lastError = ServerAlreadyCreated;
+ return false;
+ }
+ else if (d_ptr->isInitialized.loadAcquire()) {
+ d_ptr->m_lastError = RegistryAlreadyHosted;
+ return false;
+ }
+
+ d_ptr->remoteObjectIo.reset(new QRemoteObjectSourceIo(hostAddress));
+ //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(d_ptr->remoteObjectIo.data(), SIGNAL(remoteObjectAdded(QRemoteObjectSourceLocation)), d_ptr.data(), SIGNAL(remoteObjectAdded(QRemoteObjectSourceLocation)));
+ QObject::connect(d_ptr->remoteObjectIo.data(), SIGNAL(remoteObjectRemoved(QRemoteObjectSourceLocation)), d_ptr.data(), SIGNAL(remoteObjectRemoved(QRemoteObjectSourceLocation)));
+
+ return true;
+}
+
+QRemoteObjectNode::ErrorCode QRemoteObjectNode::lastError() const
+{
+ return d_ptr->m_lastError;
+}
+
+QUrl QRemoteObjectNode::registryUrl() const
+{
+ return d_ptr->registryAddress;
+}
+
+bool QRemoteObjectNode::setRegistryUrl(const QUrl &registryAddress)
+{
+ if (d_ptr->isInitialized.loadAcquire() || ! d_ptr->registry.isNull()) {
+ d_ptr->m_lastError = RegistryAlreadyHosted;
+ return false;
+ }
+
+ connect(registryAddress);
+ d_ptr->registryAddress = registryAddress;
+ d_ptr->setRegistry(acquire<QRemoteObjectRegistry>());
+ //Connect remoteObject[Added/Removed] to the registry Slot
+ QObject::connect(d_ptr.data(), SIGNAL(remoteObjectAdded(QRemoteObjectSourceLocation)), d_ptr->registry.data(), SLOT(addSource(QRemoteObjectSourceLocation)));
+ QObject::connect(d_ptr.data(), SIGNAL(remoteObjectRemoved(QRemoteObjectSourceLocation)), d_ptr->registry.data(), SLOT(removeSource(QRemoteObjectSourceLocation)));
+ //TODO - what should happen if you register a RemoteObjectSource on the Registry node, but the RegistrySource isn't connected?
+ //Possible to have a way to cache the values, so they can be sent when a connection is made
+ //Or, return false on enableRemoting, with an error about not having the registry?
+ //Or possible to get the list of RemoteObjectSources from remoteObjectIo, and send when the connection is made (use that as the cache)
+ return d_ptr->registry->waitForSource();
+}
+
+void QRemoteObjectNodePrivate::setRegistry(QRemoteObjectRegistry *reg)
+{
+ registry.reset(reg);
+ //Make sure when we get the registry initialized, we update our replicas
+ QObject::connect(reg, SIGNAL(initialized()), this, SLOT(onRegistryInitialized()));
+ //Make sure we handle new RemoteObjectSources on Registry...
+ QObject::connect(reg, SIGNAL(remoteObjectAdded(QRemoteObjectSourceLocation)), this, SLOT(onRemoteObjectSourceAdded(QRemoteObjectSourceLocation)));
+ QObject::connect(reg, SIGNAL(remoteObjectRemoved(QRemoteObjectSourceLocation)), this, SLOT(onRemoteObjectSourceRemoved(QRemoteObjectSourceLocation)));
+}
+
+bool QRemoteObjectNode::hostRegistry()
+{
+ if (d_ptr->remoteObjectIo.isNull()) {
+ d_ptr->m_lastError = ServerAlreadyCreated;
+ return false;
+ }
+ else if (d_ptr->isInitialized.loadAcquire() || !d_ptr->registry.isNull()) {
+ d_ptr->m_lastError = RegistryAlreadyHosted;
+ return false;
+ }
+
+ QRegistrySource *remoteObject = new QRegistrySource;
+ enableRemoting(remoteObject);
+ d_ptr->registryAddress = d_ptr->remoteObjectIo->serverAddress();
+ d_ptr->registrySource.reset(remoteObject);
+ //Connect RemoteObjectSourceIo->remoteObject[Added/Removde] to the registry Slot
+ QObject::connect(d_ptr.data(), SIGNAL(remoteObjectAdded(QRemoteObjectSourceLocation)), d_ptr->registrySource.data(), SLOT(addSource(QRemoteObjectSourceLocation)));
+ QObject::connect(d_ptr.data(), SIGNAL(remoteObjectRemoved(QRemoteObjectSourceLocation)), d_ptr->registrySource.data(), SLOT(removeSource(QRemoteObjectSourceLocation)));
+ QObject::connect(d_ptr->remoteObjectIo.data(), SIGNAL(serverRemoved(QUrl)),d_ptr->registrySource.data(), SLOT(removeServer(QUrl)));
+ //onAdd/Remove update the known remoteObjects list in the RegistrySource, so no need to connect to the RegistrySource remoteObjectAdded/Removed signals
+ d_ptr->setRegistry(acquire<QRemoteObjectRegistry>());
+ return true;
+}
+
+QRemoteObjectNode QRemoteObjectNode::createHostNode(const QUrl &hostAddress)
+{
+ return QRemoteObjectNode(hostAddress, QUrl());
+}
+
+QRemoteObjectNode QRemoteObjectNode::createRegistryHostNode(const QUrl &hostAddress)
+{
+ return QRemoteObjectNode(hostAddress, hostAddress);
+}
+
+QRemoteObjectNode QRemoteObjectNode::createNodeConnectedToRegistry(const QUrl &registryAddress)
+{
+ return QRemoteObjectNode(QUrl(), registryAddress);
+}
+
+QRemoteObjectNode QRemoteObjectNode::createHostNodeConnectedToRegistry(const QUrl &hostAddress, const QUrl &registryAddress)
+{
+ if (hostAddress == registryAddress) { //Assume hosting registry is NOT intended
+ QRemoteObjectNode node(hostAddress, QUrl());
+ node.d_ptr->m_lastError = UnintendedRegistryHosting;
+ return node;
+ }
+
+ return QRemoteObjectNode(hostAddress, registryAddress);
+}
+
+void QRemoteObjectNode::connect(const QUrl &address)
+{
+ d_ptr->initConnection(address);
+}
+
+QRemoteObjectDynamicReplica *QRemoteObjectNode::acquire(const QString &name)
+{
+ QRemoteObjectDynamicReplica *instance = new QRemoteObjectDynamicReplica;
+ return static_cast<QRemoteObjectDynamicReplica*>(d_ptr->acquire(Q_NULLPTR, instance, name));
+}
+
+bool QRemoteObjectNode::enableRemoting(QRemoteObjectSource *remoteObject)
+{
+ if (d_ptr->remoteObjectIo.isNull()) {
+ d_ptr->m_lastError = OperationNotValidOnClientNode;
+ return false;
+ }
+
+ const int ind = remoteObject->metaObject()->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE);
+ const QString name = QString::fromLatin1(remoteObject->metaObject()->classInfo(ind).value());
+
+ d_ptr->isInitialized.storeRelease(1);
+
+ return d_ptr->remoteObjectIo->enableRemoting(remoteObject, &QRemoteObjectSource::staticMetaObject, name);
+}
+
+bool QRemoteObjectNode::enableRemoting(QObject *object, const QMetaObject *_meta)
+{
+ if (d_ptr->remoteObjectIo.isNull()) {
+ d_ptr->m_lastError = OperationNotValidOnClientNode;
+ return false;
+ }
+
+ const QMetaObject *meta = _meta;
+ QString name;
+ if (!meta) { //If meta isn't provided, we need to search for an object that has RemoteObject CLASSINFO
+ meta = object->metaObject();
+ int ind = meta->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE);
+ while (meta && ind == -1) {
+ meta = meta->superClass();
+ if (meta)
+ ind = meta->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE);
+ }
+ if (meta) {
+ name = QString::fromLatin1(meta->classInfo(ind).value());
+ meta = meta->superClass(); //We want the parent of the class that has ClassInfo, since we want to forward
+ //the object_type API
+ } else {
+ name = object->objectName();
+ if (name.isEmpty()) {
+ d_ptr->m_lastError = MissingObjectName;
+ qCWarning(QT_REMOTEOBJECT) << "enableRemoting() Error: Unable to Replicate an object that does not have objectName() set.";
+ return false;
+ }
+ meta = object->metaObject()->superClass(); //*Assume* we only want object's API forwarded
+ }
+ } else {
+ name = object->objectName();
+ if (name.isEmpty()) {
+ d_ptr->m_lastError = MissingObjectName;
+ qCWarning(QT_REMOTEOBJECT) << "enableRemoting() Error: Unable to Replicate an object that does not have objectName() set.";
+ return false;
+ }
+ const QMetaObject *check = object->metaObject();
+ if (check == meta) {
+ qCWarning(QT_REMOTEOBJECT) << "enableRemoting() Error: The QMetaObject pointer provided is for object. An ancestor of object should be used.";
+ return false;
+ }
+ while (check && check != meta)
+ check = check->superClass();
+ if (!check) { //Oops, meta is not a superclass of object
+ qCWarning(QT_REMOTEOBJECT) << "enableRemoting() Error: The QMetaObject must be an ancestor of object.";
+ return false;
+ }
+ }
+
+ return d_ptr->remoteObjectIo->enableRemoting(object, meta, name);
+}
+
+bool QRemoteObjectNode::disableRemoting(QObject *remoteObject)
+{
+ if (d_ptr->remoteObjectIo.isNull()) {
+ d_ptr->m_lastError = OperationNotValidOnClientNode;
+ return false;
+ }
+
+ QRemoteObjectSourcePrivate *pp = remoteObject->findChild<QRemoteObjectSourcePrivate *>(QString(), Qt::FindDirectChildrenOnly);
+ if (!pp) //We must be calling unregister before register was called.
+ return false;
+
+ if (!d_ptr->remoteObjectIo->disableRemoting(pp)) {
+ d_ptr->m_lastError = SourceNotRegistered;
+ return false;
+ }
+
+ return true;
+}
+
+QRemoteObjectReplica *QRemoteObjectNode::acquire(const QMetaObject *replicaMeta, QRemoteObjectReplica *instance)
+{
+ return d_ptr->acquire(replicaMeta, instance, name(replicaMeta));
+}
+
+QT_END_NAMESPACE
diff --git a/src/remoteobjects/qremoteobjectnode.h b/src/remoteobjects/qremoteobjectnode.h
new file mode 100644
index 0000000..2a5dced
--- /dev/null
+++ b/src/remoteobjects/qremoteobjectnode.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTEOBJECTNODE_H
+#define QREMOTEOBJECTNODE_H
+
+#include "qtremoteobjectglobal.h"
+
+#include "qremoteobjectregistry.h"
+#include "qremoteobjectdynamicreplica.h"
+
+#include <QSharedPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QRemoteObjectSource;
+class QRemoteObjectReplica;
+class QRemoteObjectNodePrivate;
+
+class Q_REMOTEOBJECTS_EXPORT QRemoteObjectNode
+{
+public:
+
+ enum ErrorCode{
+ NoError,
+ RegistryNotAcquired,
+ RegistryAlreadyHosted,
+ NodeIsNoServer,
+ ServerAlreadyCreated,
+ UnintendedRegistryHosting,
+ OperationNotValidOnClientNode,
+ SourceNotRegistered,
+ MissingObjectName
+ };
+
+ QRemoteObjectNode();
+ ~QRemoteObjectNode();
+
+ //TODO maybe set defaults from a #define to allow override?
+ static QRemoteObjectNode createHostNode(const QUrl &hostAddress = QUrl(QString::fromLatin1("local:replica")));
+ static QRemoteObjectNode createRegistryHostNode(const QUrl &hostAddress = QUrl(QString::fromLatin1("local:registry")));
+ static QRemoteObjectNode createNodeConnectedToRegistry(const QUrl &registryAddress = QUrl(QString::fromLatin1("local:registry")));
+ static QRemoteObjectNode createHostNodeConnectedToRegistry(const QUrl &hostAddress = QUrl(QString::fromLatin1("local:replica")),
+ const QUrl &registryAddress = QUrl(QString::fromLatin1("local:registry")));
+ QUrl hostUrl() const;
+ bool setHostUrl(const QUrl &hostAddress);
+ QUrl registryUrl() const;
+ bool setRegistryUrl(const QUrl &registryAddress);
+ bool hostRegistry();
+ void connect(const QUrl &address=QUrl(QString::fromLatin1("local:replica")));
+ const QRemoteObjectRegistry *registry() const;
+ template < class ObjectType >
+ ObjectType *acquire()
+ {
+ ObjectType* replica = new ObjectType;
+ return qobject_cast< ObjectType* >(acquire(&ObjectType::staticMetaObject, replica));
+ }
+ QRemoteObjectDynamicReplica *acquire(const QString &name);
+
+ bool enableRemoting(QRemoteObjectSource *remoteObject);
+ bool enableRemoting(QObject *object, const QMetaObject *meta = Q_NULLPTR);
+ bool disableRemoting(QObject *remoteObject);
+
+ ErrorCode lastError() const;
+
+private:
+ QRemoteObjectNode(const QUrl &hostAddress, const QUrl &registryAddress);
+ QRemoteObjectReplica *acquire(const QMetaObject *, QRemoteObjectReplica *);
+
+ QSharedPointer<QRemoteObjectNodePrivate> d_ptr;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/remoteobjects/qremoteobjectnode_p.h b/src/remoteobjects/qremoteobjectnode_p.h
new file mode 100644
index 0000000..aa28cef
--- /dev/null
+++ b/src/remoteobjects/qremoteobjectnode_p.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTEOBJECTNODE_P_H
+#define QREMOTEOBJECTNODE_P_H
+
+#include "qconnectionclientfactory_p.h"
+#include "qremoteobjectsourceio_p.h"
+#include "qremoteobjectreplica.h"
+#include "qremoteobjectnode.h"
+
+#include <QBasicTimer>
+#include <QMutex>
+#include <QSharedPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QRemoteObjectRegistry;
+class QRegistrySource;
+
+class QRemoteObjectNodePrivate : public QObject
+{
+ Q_OBJECT
+
+public:
+ QRemoteObjectNodePrivate();
+ virtual ~QRemoteObjectNodePrivate();
+
+ QRemoteObjectSourceLocations remoteObjectAddresses() const;
+
+ void timerEvent(QTimerEvent*);
+
+ QRemoteObjectReplica *acquire(const QMetaObject *, QRemoteObjectReplica *, const QString &);
+
+ void connectReplica(QObject *object, QRemoteObjectReplica *instance);
+ void openConnectionIfNeeded(const QString &name);
+
+ void initConnection(const QUrl &address);
+ bool hasInstance(const QString &name);
+ void setRegistry(QRemoteObjectRegistry *);
+
+Q_SIGNALS:
+ void remoteObjectAdded(const QRemoteObjectSourceLocation &);
+ void remoteObjectRemoved(const QRemoteObjectSourceLocation &);
+
+public Q_SLOTS:
+ void onClientRead(QObject *obj);
+ void onRemoteObjectSourceAdded(const QRemoteObjectSourceLocation &entry);
+ void onRemoteObjectSourceRemoved(const QRemoteObjectSourceLocation &entry);
+ void onRegistryInitialized();
+ void onShouldReconnect(ClientIoDevice *ioDevice);
+
+public:
+ QAtomicInt isInitialized;
+ QScopedPointer<QRemoteObjectSourceIo> remoteObjectIo;
+ QMutex mutex;
+ QUrl registryAddress;
+ QHash<QString, QWeakPointer<QRemoteObjectReplicaPrivate> > replicas;
+ QConnectionClientFactory m_factory;
+ QMap<QString, ClientIoDevice*> connectedSources;
+ QSet<ClientIoDevice*> knownNodes;
+ QSet<ClientIoDevice*> pendingReconnect;
+ QSet<QUrl> requestedUrls;
+ QSignalMapper clientRead;
+ QScopedPointer<QRemoteObjectRegistry> registry;
+ QScopedPointer<QRegistrySource> registrySource;
+ int retryInterval;
+ QBasicTimer reconnectTimer;
+ QRemoteObjectNode::ErrorCode m_lastError;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/remoteobjects/qremoteobjectregistry.cpp b/src/remoteobjects/qremoteobjectregistry.cpp
new file mode 100644
index 0000000..f292070
--- /dev/null
+++ b/src/remoteobjects/qremoteobjectregistry.cpp
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qremoteobjectregistry.h"
+#include "qremoteobjectreplica_p.h"
+
+#include <QDataStream>
+
+QT_BEGIN_NAMESPACE
+
+QRemoteObjectRegistry::QRemoteObjectRegistry(QObject *parent) : QRemoteObjectReplica(parent)
+{
+}
+
+QRemoteObjectRegistry::~QRemoteObjectRegistry()
+{}
+
+void QRemoteObjectRegistry::initialize()
+{
+ qRegisterMetaType<QRemoteObjectSourceLocation>();
+ qRegisterMetaTypeStreamOperators<QRemoteObjectSourceLocation>();
+ qRegisterMetaType<QRemoteObjectSourceLocations>();
+ qRegisterMetaTypeStreamOperators<QRemoteObjectSourceLocations>();
+ QVariantList properties;
+ properties.reserve(3);
+ properties << QVariant::fromValue(QRemoteObjectSourceLocations());
+ properties << QVariant::fromValue(QRemoteObjectSourceLocation());
+ properties << QVariant::fromValue(QRemoteObjectSourceLocation());
+ setProperties(properties);
+}
+
+QRemoteObjectSourceLocations QRemoteObjectRegistry::sourceLocations() const
+{
+ return propAsVariant(0).value<QRemoteObjectSourceLocations>();
+}
+
+void QRemoteObjectRegistry::addSource(const QRemoteObjectSourceLocation &entry)
+{
+ if (!isInitialized()) {
+ bool res = waitForSource();
+ if (!res)
+ return; //FIX What to do here?
+ }
+ 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);
+}
+
+void QRemoteObjectRegistry::removeSource(const QRemoteObjectSourceLocation &entry)
+{
+ 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);
+}
+
+QT_END_NAMESPACE
diff --git a/src/remoteobjects/qremoteobjectregistry.h b/src/remoteobjects/qremoteobjectregistry.h
new file mode 100644
index 0000000..4e21cb8
--- /dev/null
+++ b/src/remoteobjects/qremoteobjectregistry.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTEOBJECTREGISTRY_P_H
+#define QREMOTEOBJECTREGISTRY_P_H
+
+#include "qremoteobjectreplica.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q_REMOTEOBJECTS_EXPORT QRemoteObjectRegistry : public QRemoteObjectReplica
+{
+ Q_OBJECT
+ Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_TYPE, "Registry")
+
+ Q_PROPERTY(QRemoteObjectSourceLocations sourceLocations READ sourceLocations)
+
+ friend class QRemoteObjectNode;
+
+public:
+ ~QRemoteObjectRegistry();
+ void initialize() Q_DECL_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);
+
+private:
+ explicit QRemoteObjectRegistry(QObject *parent = Q_NULLPTR);
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/remoteobjects/qremoteobjectreplica.cpp b/src/remoteobjects/qremoteobjectreplica.cpp
new file mode 100644
index 0000000..1f34a16
--- /dev/null
+++ b/src/remoteobjects/qremoteobjectreplica.cpp
@@ -0,0 +1,404 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qremoteobjectreplica.h"
+#include "qremoteobjectreplica_p.h"
+#include "qremoteobjectdynamicreplica.h"
+#include "qconnectionclientfactory_p.h"
+#include "qremoteobjectsource_p.h"
+#include "private/qmetaobjectbuilder_p.h"
+
+#include <QCoreApplication>
+#include <QDataStream>
+#include <QVariant>
+#include <QMetaProperty>
+#include <QThread>
+#include <QTime>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QRemoteObjectPackets;
+
+QRemoteObjectReplicaPrivate::QRemoteObjectReplicaPrivate(const QString &name, const QMetaObject *meta)
+ : QObject(Q_NULLPTR), m_objectName(name), m_metaObject(meta),
+ m_methodOffset(meta ? QRemoteObjectReplica::staticMetaObject.methodCount() : QRemoteObjectDynamicReplica::staticMetaObject.methodCount()),
+ m_propertyOffset(meta ? QRemoteObjectReplica::staticMetaObject.propertyCount() : QRemoteObjectDynamicReplica::staticMetaObject.propertyCount())
+{
+}
+
+QRemoteObjectReplicaPrivate::~QRemoteObjectReplicaPrivate()
+{
+ if (m_metaObject && qstrcmp(m_metaObject->className(), "QRemoteObjectDynamicReplica") == 0)
+ delete m_metaObject;
+}
+
+QConnectedReplicaPrivate::QConnectedReplicaPrivate(const QString &name, const QMetaObject *meta)
+ : QRemoteObjectReplicaPrivate(name, meta), isSet(0), connectionToSource(Q_NULLPTR)
+{
+}
+
+QConnectedReplicaPrivate::~QConnectedReplicaPrivate()
+{
+ if (!connectionToSource.isNull()) {
+ qCDebug(QT_REMOTEOBJECT) << "Replica deleted: sending RemoveObject to RemoteObjectSource" << m_objectName;
+ QRemoveObjectPacket packet(m_objectName);
+ sendCommand(&packet);
+ }
+}
+
+bool QRemoteObjectReplicaPrivate::isDynamicReplica() const
+{
+ return m_metaObject == Q_NULLPTR;
+}
+
+void QConnectedReplicaPrivate::sendCommand(const QRemoteObjectPacket *packet)
+{
+ Q_ASSERT(!connectionToSource.isNull());
+
+ if (!connectionToSource->isOpen())
+ return;
+
+ connectionToSource->write(packet->serialize());
+}
+
+void QConnectedReplicaPrivate::initialize(const QByteArray &packetData)
+{
+ qCDebug(QT_REMOTEOBJECT) << "initialize()" << m_propertyStorage.size();
+ quint32 nParam, len;
+ QDataStream in(packetData);
+ in >> nParam;
+ QVector<int> signalList;
+ QVariant value;
+ const int offset = m_metaObject->propertyOffset();
+ for (quint32 i = 0; i < nParam; ++i) {
+ in >> len;
+ qint64 pos = in.device()->pos();
+ const int index = m_metaObject->indexOfProperty(packetData.constData()+pos) - offset;
+ in.skipRawData(len); //Skip property name char *, since we used it in-place ^^
+ in >> value;
+ qCDebug(QT_REMOTEOBJECT) << " in loop" << index << m_propertyStorage.size();
+ if (index >= 0 && m_propertyStorage[index] != value) {
+ m_propertyStorage[index] = value;
+ int notifyIndex = m_metaObject->property(index+offset).notifySignalIndex();
+ if (notifyIndex >= 0)
+ signalList.append(notifyIndex);
+ }
+ qCDebug(QT_REMOTEOBJECT) << "SETPROPERTY" << index << m_metaObject->property(index+offset).name() << value.typeName() << value.toString();
+ }
+
+ //Note: Because we are generating the notify signals ourselves, we know there will be no parameters
+ //This allows us to pass noArgs to qt_metacall
+ void *noArgs[] = {0};
+ Q_FOREACH (int index, signalList) {
+ qCDebug(QT_REMOTEOBJECT) << " Before activate" << index << m_metaObject->property(index).name();
+ QMetaObject::activate(this, metaObject(), index, noArgs);
+ }
+
+ //initialized and validChanged need to be sent manually, since they are not in the derived classes
+ if (isSet.fetchAndStoreRelease(2) > 0) {
+ //We are already initialized, now we are valid again
+ emitValidChanged();
+ } else {
+ //We need to send the initialized signal, too
+ emitInitialized();
+ emitValidChanged();
+ }
+ qCDebug(QT_REMOTEOBJECT) << "isSet = true";
+}
+
+void QRemoteObjectReplicaPrivate::emitValidChanged()
+{
+ const static int validChangedIndex = QRemoteObjectReplica::staticMetaObject.indexOfMethod("onIsReplicaValidChanged()");
+ Q_ASSERT(validChangedIndex != -1);
+ void *noArgs[] = {0};
+ QMetaObject::activate(this, metaObject(), validChangedIndex, noArgs);
+}
+
+void QRemoteObjectReplicaPrivate::emitInitialized()
+{
+ const static int initializedIndex = QRemoteObjectReplica::staticMetaObject.indexOfMethod("initialized()");
+ Q_ASSERT(initializedIndex != -1);
+ void *noArgs[] = {0};
+ QMetaObject::activate(this, metaObject(), initializedIndex, noArgs);
+}
+
+void QRemoteObjectReplicaPrivate::initializeMetaObject(const QInitDynamicPacket *packet)
+{
+ Q_ASSERT(!m_metaObject);
+
+ QMetaObjectBuilder builder;
+ builder.setClassName("QRemoteObjectDynamicReplica");
+ builder.setSuperClass(&QRemoteObjectReplica::staticMetaObject);
+ builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
+
+ QVector<QPair<QByteArray, QVariant> > propertyValues;
+ m_metaObject = packet->createMetaObject(builder, m_remoteObjectMethodTypes, m_methodArgumentTypes, &propertyValues);
+ //rely on order of properties;
+ QVariantList list;
+ typedef QPair<QByteArray, QVariant> PropertyPair;
+ foreach (const PropertyPair &pair, propertyValues)
+ list << pair.second;
+ setProperties(list);
+}
+
+void QConnectedReplicaPrivate::initializeMetaObject(const QInitDynamicPacket *packet)
+{
+ QRemoteObjectReplicaPrivate::initializeMetaObject(packet);
+ foreach (QRemoteObjectReplica *obj, m_parentsNeedingConnect)
+ configurePrivate(obj);
+ m_parentsNeedingConnect.clear();
+ void *noArgs[] = {0};
+ for (int index = 0; index < metaObject()->propertyCount(); ++index) {
+ qCDebug(QT_REMOTEOBJECT) << " Before activate" << index << m_metaObject->property(index).name();
+ QMetaObject::activate(this, metaObject(), index, noArgs);
+ }
+ //initialized and validChanged need to be sent manually, since they are not in the derived classes
+ if (isSet.fetchAndStoreRelease(2) > 0) {
+ //We are already initialized, now we are valid again
+ emitValidChanged();
+ } else {
+ //We need to send the initialized signal, too
+ emitInitialized();
+ emitValidChanged();
+ }
+ qCDebug(QT_REMOTEOBJECT) << "isSet = true";
+}
+
+bool QConnectedReplicaPrivate::isInitialized() const
+{
+ return isSet.load() > 0;
+}
+
+bool QConnectedReplicaPrivate::isReplicaValid() const
+{
+ qCDebug(QT_REMOTEOBJECT) << "isReplicaValid()" << isSet.load();
+
+ return isSet.load() == 2;
+}
+
+bool QConnectedReplicaPrivate::waitForSource(int timeout)
+{
+ if (isSet.load() != 2) {
+ QTime t;
+ t.start();
+
+ while (isSet.load() != 2) {
+ if (t.elapsed() > timeout) {
+ qCWarning(QT_REMOTEOBJECT) << "Timeout waiting for client to get set" << m_objectName;
+ return false;
+ }
+
+ qApp->processEvents(QEventLoop::ExcludeUserInputEvents, 10);
+ }
+ }
+
+ return true;
+}
+
+void QConnectedReplicaPrivate::_q_send(QMetaObject::Call call, int index, const QVariantList &args)
+{
+ Q_ASSERT(call == QMetaObject::InvokeMetaMethod || call == QMetaObject::WriteProperty);
+
+ if (call == QMetaObject::InvokeMetaMethod) {
+ qCDebug(QT_REMOTEOBJECT) << "Send" << call << this->m_metaObject->method(index).name() << index << args << connectionToSource;
+ QInvokePacket package = QInvokePacket(m_objectName, call, index - m_methodOffset, args);
+ sendCommand(&package);
+ } else {
+ qCDebug(QT_REMOTEOBJECT) << "Send" << call << this->m_metaObject->property(index).name() << index << args << connectionToSource;
+ QInvokePacket package = QInvokePacket(m_objectName, call, index - m_propertyOffset, args);
+ sendCommand(&package);
+ }
+}
+
+const QVariant QConnectedReplicaPrivate::getProperty(int i) const
+{
+ return m_propertyStorage[i];
+}
+
+void QConnectedReplicaPrivate::setProperties(const QVariantList &properties)
+{
+ Q_ASSERT(m_propertyStorage.isEmpty());
+ m_propertyStorage.reserve(properties.length());
+ m_propertyStorage = properties;
+}
+
+void QConnectedReplicaPrivate::setProperty(int i, const QVariant &prop)
+{
+ m_propertyStorage[i] = prop;
+}
+
+void QConnectedReplicaPrivate::setConnection(ClientIoDevice *conn)
+{
+ if (connectionToSource.isNull()) {
+ connectionToSource = conn;
+ qCDebug(QT_REMOTEOBJECT) << "setConnection started" << conn << m_objectName;
+ }
+ requestRemoteObjectSource();
+}
+
+void QConnectedReplicaPrivate::setDisconnected()
+{
+ connectionToSource.clear();
+ if (isSet.fetchAndStoreRelease(1) == 2)
+ emitValidChanged();
+}
+
+void QConnectedReplicaPrivate::requestRemoteObjectSource()
+{
+ QAddObjectPacket packet(m_objectName, isDynamicReplica());
+ sendCommand(&packet);
+}
+
+void QRemoteObjectReplicaPrivate::configurePrivate(QRemoteObjectReplica *rep)
+{
+ for (int i = QRemoteObjectReplica::staticMetaObject.methodOffset(); i < m_metaObject->methodCount(); i++) {
+ QMetaMethod mm = m_metaObject->method(i);
+ if (mm.methodType() == QMetaMethod::Signal) {
+ const bool res = QMetaObject::connect(this, i, rep, i, Qt::DirectConnection, 0);
+ qCDebug(QT_REMOTEOBJECT) << " Connect"<<i<<res<<mm.name();
+ Q_UNUSED(res);
+ }
+ }
+}
+
+void QConnectedReplicaPrivate::configurePrivate(QRemoteObjectReplica *rep)
+{
+ if (m_metaObject)
+ QRemoteObjectReplicaPrivate::configurePrivate(rep);
+ else
+ m_parentsNeedingConnect.append(rep);
+}
+
+QRemoteObjectReplica::QRemoteObjectReplica(QObject *parent) : QObject(parent)
+{
+}
+
+QRemoteObjectReplica::~QRemoteObjectReplica()
+{
+}
+
+void QRemoteObjectReplica::send(QMetaObject::Call call, int index, const QVariantList &args)
+{
+ Q_D(QRemoteObjectReplica);
+
+ d->_q_send(call, index, args);
+}
+
+const QVariant QRemoteObjectReplica::propAsVariant(int i) const
+{
+ Q_D(const QRemoteObjectReplica);
+ return d->getProperty(i);
+}
+
+void QRemoteObjectReplica::setProperties(const QVariantList &properties)
+{
+ Q_D(QRemoteObjectReplica);
+ d->setProperties(properties);
+}
+
+void QRemoteObjectReplica::setProperty(int i, const QVariant &prop)
+{
+ Q_D(QRemoteObjectReplica);
+ d->setProperty(i, prop);
+}
+
+bool QRemoteObjectReplica::isInitialized() const
+{
+ Q_D(const QRemoteObjectReplica);
+
+ return d->isInitialized();
+}
+
+void QRemoteObjectReplica::initialize()
+{
+}
+
+bool QRemoteObjectReplica::isReplicaValid() const
+{
+ Q_D(const QRemoteObjectReplica);
+
+ return d->isReplicaValid();
+}
+
+bool QRemoteObjectReplica::waitForSource(int timeout)
+{
+ Q_D(QRemoteObjectReplica);
+
+ return d->waitForSource(timeout);
+}
+
+QInProcessReplicaPrivate::QInProcessReplicaPrivate(const QString &name, const QMetaObject *meta) : QRemoteObjectReplicaPrivate(name, meta)
+{
+}
+
+QInProcessReplicaPrivate::~QInProcessReplicaPrivate()
+{
+}
+
+const QVariant QInProcessReplicaPrivate::getProperty(int i) const
+{
+ Q_ASSERT(connectionToSource);
+ Q_ASSERT(connectionToSource->m_object);
+ const int index = i + connectionToSource->m_propertyOffset;
+ Q_ASSERT(index >= 0 && index < connectionToSource->m_object->metaObject()->propertyCount());
+ return connectionToSource->m_object->metaObject()->property(index).read(connectionToSource->m_object);
+}
+
+void QInProcessReplicaPrivate::setProperties(const QVariantList &)
+{
+ //TODO some verification here maybe?
+}
+
+void QInProcessReplicaPrivate::setProperty(int i, const QVariant &property)
+{
+ Q_ASSERT(connectionToSource);
+ Q_ASSERT(connectionToSource->m_object);
+ const int index = i+connectionToSource->m_propertyOffset;
+ Q_ASSERT(index >= 0 && index < connectionToSource->m_object->metaObject()->propertyCount());
+ connectionToSource->m_object->metaObject()->property(index).write(connectionToSource->m_object, property);
+}
+
+void QInProcessReplicaPrivate::_q_send(QMetaObject::Call call, int index, const QVariantList &args)
+{
+ connectionToSource->invoke(call, index, args);
+}
+
+QT_END_NAMESPACE
diff --git a/src/remoteobjects/qremoteobjectreplica.h b/src/remoteobjects/qremoteobjectreplica.h
new file mode 100644
index 0000000..0d0e92c
--- /dev/null
+++ b/src/remoteobjects/qremoteobjectreplica.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQREMOTEOBJECTREPLICA_H
+#define QQREMOTEOBJECTREPLICA_H
+
+#include "qtremoteobjectglobal.h"
+
+#include <QSharedPointer>
+#include <QtCore/qnamespace.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRemoteObjectReplicaPrivate;
+
+class Q_REMOTEOBJECTS_EXPORT QRemoteObjectReplica : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool isReplicaValid READ isReplicaValid NOTIFY onIsReplicaValidChanged)
+
+public:
+ virtual ~QRemoteObjectReplica();
+
+ bool isReplicaValid() const;
+ bool waitForSource(int timeout = 100);
+ bool isInitialized() const;
+ virtual void initialize();
+
+Q_SIGNALS:
+ void onIsReplicaValidChanged();
+ void initialized();
+
+protected:
+ explicit QRemoteObjectReplica(QObject *parent = Q_NULLPTR);
+
+ void send(QMetaObject::Call call, int index, const QVariantList &args);
+protected:
+ void setProperty(int i, const QVariant &);
+ void setProperties(const QVariantList &);
+ const QVariant propAsVariant(int i) const;
+ Q_DECLARE_PRIVATE(QRemoteObjectReplica)
+ QSharedPointer<QRemoteObjectReplicaPrivate> d_ptr;
+private:
+ friend class QRemoteObjectNodePrivate;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/remoteobjects/qremoteobjectreplica_p.h b/src/remoteobjects/qremoteobjectreplica_p.h
new file mode 100644
index 0000000..f2451e3
--- /dev/null
+++ b/src/remoteobjects/qremoteobjectreplica_p.h
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTEOBJECTREPLICA_P_H
+#define QREMOTEOBJECTREPLICA_P_H
+
+#include "qremoteobjectreplica.h"
+#include <QPointer>
+#include <QVector>
+#include <qcompilerdetection.h>
+#include "qtremoteobjectglobal.h"
+
+QT_BEGIN_NAMESPACE
+
+class QRemoteObjectReplica;
+class QRemoteObjectSourcePrivate;
+class ClientIoDevice;
+
+using namespace QRemoteObjectPackets;
+
+class QRemoteObjectReplicaPrivate : public QObject
+{
+public:
+ explicit QRemoteObjectReplicaPrivate(const QString &name, const QMetaObject *);
+ virtual ~QRemoteObjectReplicaPrivate();
+
+ bool isDynamicReplica() const;
+
+ virtual const QVariant getProperty(int i) const = 0;
+ virtual void setProperties(const QVariantList &) = 0;
+ virtual void setProperty(int i, const QVariant &) = 0;
+ virtual bool isShortCircuit() const = 0;
+ virtual bool isInitialized() const { return true; }
+ virtual bool isReplicaValid() const { return true; }
+ virtual bool waitForSource(int) { return true; }
+ virtual void configurePrivate(QRemoteObjectReplica *);
+ void emitValidChanged();
+ void emitInitialized();
+
+ virtual void _q_send(QMetaObject::Call call, int index, const QVariantList &args) = 0;
+
+ //Dynamic replica functions
+ virtual void initializeMetaObject(const QInitDynamicPacket *packet);
+
+ QString m_objectName;
+ const QMetaObject *m_metaObject;
+
+ //Dynamic Replica data
+ QVector<QVector<int> > m_methodArgumentTypes;
+ QVector<int> m_remoteObjectMethodTypes;
+ int m_methodOffset, m_propertyOffset;
+};
+
+class QConnectedReplicaPrivate : public QRemoteObjectReplicaPrivate
+{
+public:
+ explicit QConnectedReplicaPrivate(const QString &name, const QMetaObject *);
+ virtual ~QConnectedReplicaPrivate();
+ const QVariant getProperty(int i) const Q_DECL_OVERRIDE;
+ void setProperties(const QVariantList &) Q_DECL_OVERRIDE;
+ void setProperty(int i, const QVariant &) Q_DECL_OVERRIDE;
+ bool isShortCircuit() const Q_DECL_OVERRIDE { return false; }
+ bool isInitialized() const Q_DECL_OVERRIDE;
+ bool isReplicaValid() const Q_DECL_OVERRIDE;
+ bool waitForSource(int timeout) Q_DECL_OVERRIDE;
+ void initialize(const QByteArray &);
+ void configurePrivate(QRemoteObjectReplica *) Q_DECL_OVERRIDE;
+ void requestRemoteObjectSource();
+ void sendCommand(const QRemoteObjectPackets::QRemoteObjectPacket *packet);
+ void setConnection(ClientIoDevice *conn);
+ void setDisconnected();
+ void _q_send(QMetaObject::Call call, int index, const QVariantList &args) Q_DECL_OVERRIDE;
+ void initializeMetaObject(const QInitDynamicPacket *packet) Q_DECL_OVERRIDE;
+ QAtomicInt isSet;
+ QVector<QRemoteObjectReplica *> m_parentsNeedingConnect;
+ QVariantList m_propertyStorage;
+ QPointer<ClientIoDevice> connectionToSource;
+};
+
+class QInProcessReplicaPrivate : public QRemoteObjectReplicaPrivate
+{
+public:
+ explicit QInProcessReplicaPrivate(const QString &name, const QMetaObject *);
+ virtual ~QInProcessReplicaPrivate();
+
+ const QVariant getProperty(int i) const Q_DECL_OVERRIDE;
+ void setProperties(const QVariantList &) Q_DECL_OVERRIDE;
+ void setProperty(int i, const QVariant &) Q_DECL_OVERRIDE;
+ bool isShortCircuit() const Q_DECL_OVERRIDE { return true; }
+
+ virtual void _q_send(QMetaObject::Call call, int index, const QVariantList &args);
+ QPointer<QRemoteObjectSourcePrivate> connectionToSource;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/remoteobjects/qremoteobjectsource.cpp b/src/remoteobjects/qremoteobjectsource.cpp
new file mode 100644
index 0000000..ca03e18
--- /dev/null
+++ b/src/remoteobjects/qremoteobjectsource.cpp
@@ -0,0 +1,264 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qremoteobjectsource.h"
+#include "qremoteobjectsource_p.h"
+
+#include "qconnectionabstractserver_p.h"
+#include "qtremoteobjectglobal.h"
+
+#include <QMetaProperty>
+#include <QVarLengthArray>
+
+#include <algorithm>
+#include <iterator>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QRemoteObjectPackets;
+
+static QVector<int> parameter_types(const QMetaMethod &member)
+{
+ QVector<int> types;
+ types.reserve(member.parameterCount());
+ for (int i = 0; i < member.parameterCount(); ++i) {
+ const int tp = member.parameterType(i);
+ if (tp == QMetaType::UnknownType) {
+ Q_ASSERT(tp != QMetaType::Void); // void parameter => metaobject is corrupt
+ qCWarning(QT_REMOTEOBJECT) <<"Don't know how to handle "
+ << member.parameterTypes().at(i).constData()
+ << ", use qRegisterMetaType to register it.";
+
+ }
+ types << tp;
+ }
+ return types;
+}
+
+QRemoteObjectSourcePrivate::QRemoteObjectSourcePrivate(QObject *obj, QMetaObject const *meta, const QString &name)
+ : QObject(obj),
+ args(meta->methodCount()),
+ m_name(name),
+ m_object(obj),
+ m_meta(meta),
+ m_methodOffset(meta == obj->metaObject() ? meta->methodOffset() : meta->methodCount()),
+ m_propertyOffset(meta == obj->metaObject() ? meta->propertyOffset() : meta->propertyCount())
+{
+ if (!obj) {
+ qCWarning(QT_REMOTEOBJECT) << "QRemoteObjectSourcePrivate: Cannot replicate a NULL object" << name;
+ return;
+ }
+
+ const QMetaObject *them = obj->metaObject();
+ for (int idx = m_propertyOffset; idx < them->propertyCount(); ++idx) {
+ const QMetaProperty mp = them->property(idx);
+ qCDebug(QT_REMOTEOBJECT) << "Property option" << idx << mp.name() << mp.isWritable() << mp.hasNotifySignal() << mp.notifySignalIndex();
+ if (mp.hasNotifySignal())
+ propertyFromNotifyIndex.insert(mp.notifySignalIndex(), mp);
+ }
+
+ args.reserve(them->methodCount() - m_methodOffset);
+
+ for (int idx = m_methodOffset; idx < them->methodCount(); ++idx) {
+ const QMetaMethod mm = them->method(idx);
+ qCDebug(QT_REMOTEOBJECT) << "Connection option" << idx << mm.name();
+
+ if (mm.methodType() != QMetaMethod::Signal)
+ 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.
+ if (!QMetaObject::connect(obj, idx, this, m_methodOffset, Qt::DirectConnection, 0)) {
+ qCWarning(QT_REMOTEOBJECT) << "QRemoteObjectSourcePrivate: QMetaObject::connect returned false. Unable to connect.";
+ return;
+ }
+
+ args.push_back(parameter_types(mm));
+
+ qCDebug(QT_REMOTEOBJECT) << "Connection made" << idx << mm.name();
+ }
+}
+
+QRemoteObjectSourcePrivate::~QRemoteObjectSourcePrivate()
+{
+ Q_FOREACH (ServerIoDevice *io, listeners) {
+ removeListener(io, true);
+ }
+}
+
+QVariantList QRemoteObjectSourcePrivate::marshalArgs(int index, void **a)
+{
+ QVariantList list;
+ const QVector<int> &argsForIndex = args[index];
+ const int N = argsForIndex.size();
+ list.reserve(N);
+ for (int i = 0; i < N; ++i) {
+ const int type = argsForIndex[i];
+ if (type == QMetaType::QVariant)
+ list << *reinterpret_cast<QVariant *>(a[i + 1]);
+ else
+ list << QVariant(type, a[i + 1]);
+ }
+ return list;
+}
+
+void QRemoteObjectSourcePrivate::invoke(QMetaObject::Call c, int index, const QVariantList &args)
+{
+ static QVariant null(QMetaType::QObjectStar, Q_NULLPTR);
+ QVarLengthArray<void*, 10> param(args.size() + 1);
+ param[0] = null.data(); //Never a return value
+ for (int i = 0; i < args.size(); ++i) {
+ param[i + 1] = const_cast<void*>(args.at(i).data());
+ }
+ if (c == QMetaObject::InvokeMetaMethod) {
+ parent()->qt_metacall(c, index + m_methodOffset, param.data());
+ } else {
+ parent()->qt_metacall(c, index + m_propertyOffset, param.data());
+ }
+}
+
+#ifdef Q_COMPILER_UNIFORM_INIT
+// QPair (like any class) can be initialized with { }
+typedef QPair<QString,QVariant> Pair;
+inline Pair make_pair(QString first, QVariant second)
+{ return { qMove(first), qMove(second) }; }
+#else
+// QPair can't be initialized with { }, need to use a POD
+struct Pair {
+ QString first;
+ QVariant second;
+};
+inline QDataStream &operator<<(QDataStream &s, const Pair &p)
+{ return s << p.first << p.second; }
+inline Pair make_pair(QString first, QVariant second)
+{ Pair p = { qMove(first), qMove(second) }; return p; }
+#endif
+
+void QRemoteObjectSourcePrivate::handleMetaCall(int index, QMetaObject::Call call, void **a)
+{
+ if (listeners.empty())
+ return;
+
+ QByteArray ba;
+
+ if (propertyFromNotifyIndex.contains(index)) {
+ const QMetaProperty mp = propertyFromNotifyIndex[index];
+ qCDebug(QT_REMOTEOBJECT) << "Invoke Property" << mp.name() << mp.read(m_object);
+ QPropertyChangePacket p(m_name, mp.name(), mp.read(m_object));
+ ba = p.serialize();
+ }
+
+ qCDebug(QT_REMOTEOBJECT) << "# Listeners" << listeners.length();
+ qCDebug(QT_REMOTEOBJECT) << "Invoke args:" << m_object << call << index << marshalArgs(index, a);
+ QInvokePacket p(m_name, call, index - m_methodOffset, marshalArgs(index, a));
+
+ ba += p.serialize();
+
+ Q_FOREACH (ServerIoDevice *io, listeners)
+ io->write(ba);
+}
+
+void QRemoteObjectSourcePrivate::addListener(ServerIoDevice *io, bool dynamic)
+{
+ listeners.append(io);
+
+ if (dynamic) {
+ QRemoteObjectPackets::QInitDynamicPacketEncoder p(m_name, m_object, m_meta);
+ io->write(p.serialize());
+ } else {
+ QRemoteObjectPackets::QInitPacketEncoder p(m_name, m_object, m_meta);
+ io->write(p.serialize());
+ }
+}
+
+int QRemoteObjectSourcePrivate::removeListener(ServerIoDevice *io, bool shouldSendRemove)
+{
+ listeners.removeAll(io);
+ if (shouldSendRemove)
+ {
+ QRemoveObjectPacket p(m_name);
+ io->write(p.serialize());
+ }
+ return listeners.length();
+}
+
+int QRemoteObjectSourcePrivate::qt_metacall(QMetaObject::Call call, int methodId, void **a)
+{
+ //We get called from the stored metaobject metacall. Thus our index won't just be the index within our type, it will include
+ //an offset for any signals/slots in the meta base class. The delta offset accounts for this.
+ const int delta = m_meta->methodCount() - m_methodOffset;
+
+ methodId = QObject::qt_metacall(call, methodId, a);
+ if (methodId < 0)
+ return methodId;
+
+ if (call == QMetaObject::InvokeMetaMethod) {
+ if (methodId >= delta) {
+ handleMetaCall(senderSignalIndex(), call, a);
+ }
+ --methodId;
+ }
+
+ return methodId;
+}
+
+
+QRemoteObjectSource::QRemoteObjectSource(QObject *parent)
+ : QObject(parent)
+ , d_ptr(Q_NULLPTR)
+{
+ emit initialized();
+}
+
+QRemoteObjectSource::~QRemoteObjectSource()
+{
+}
+
+bool QRemoteObjectSource::isReplicaValid() const
+{
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/remoteobjects/qremoteobjectsource.h b/src/remoteobjects/qremoteobjectsource.h
new file mode 100644
index 0000000..adf4a15
--- /dev/null
+++ b/src/remoteobjects/qremoteobjectsource.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTEOBJECTSOURCE_H
+#define QREMOTEOBJECTSOURCE_H
+
+#include "qtremoteobjectglobal.h"
+
+#include <QScopedPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QRemoteObjectSourcePrivate;
+
+class Q_REMOTEOBJECTS_EXPORT QRemoteObjectSource : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool isReplicaValid READ isReplicaValid NOTIFY onIsReplicaValidChanged)
+
+public:
+ explicit QRemoteObjectSource(QObject *parent = Q_NULLPTR);
+ virtual ~QRemoteObjectSource();
+
+ bool isReplicaValid() const;
+
+Q_SIGNALS:
+ void onIsReplicaValidChanged();
+ void initialized();
+
+private:
+ friend class QRemoteObjectSourceIo;
+ Q_DECLARE_PRIVATE(QRemoteObjectSource)
+
+ QScopedPointer<QRemoteObjectSourcePrivate> d_ptr;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/remoteobjects/qremoteobjectsource_p.h b/src/remoteobjects/qremoteobjectsource_p.h
new file mode 100644
index 0000000..3592034
--- /dev/null
+++ b/src/remoteobjects/qremoteobjectsource_p.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTEOBJECTSOURCE_P_H
+#define QREMOTEOBJECTSOURCE_P_H
+
+#include <QObject>
+
+#include <QVector>
+
+QT_BEGIN_NAMESPACE
+
+class ServerIoDevice;
+class QRemoteObjectSource;
+
+template <typename Container>
+class ContainerWithOffset {
+public:
+ typedef typename Container::value_type value_type;
+ typedef typename Container::reference reference;
+ typedef typename Container::const_reference const_reference;
+ typedef typename Container::difference_type difference_type;
+ typedef typename Container::pointer pointer;
+ typedef typename Container::const_pointer const_pointer;
+ typedef typename Container::iterator iterator;
+ typedef typename Container::const_iterator const_iterator;
+
+ ContainerWithOffset() :c(), offset(0) {}
+ ContainerWithOffset(off_t offset)
+ : c(), offset(offset) {}
+ ContainerWithOffset(const Container &c, off_t offset)
+ : c(c), offset(offset) {}
+#ifdef Q_COMPILER_RVALUE_REFS
+ ContainerWithOffset(Container &&c, off_t offset)
+ : c(std::move(c)), offset(offset) {}
+#endif
+
+ reference operator[](int i) { return c[i-offset]; };
+ const_reference operator[](int i) const { return c[i-offset]; }
+
+ void reserve(int size) { c.reserve(size); }
+ void push_back(const value_type &v) { c.push_back(v); }
+#ifdef Q_COMPILER_RVALUE_REFS
+ void push_back(value_type &&v) { c.push_back(std::move(v)); }
+#endif
+
+private:
+ Container c;
+ off_t offset;
+};
+
+class QRemoteObjectSourcePrivate : public QObject
+{
+public:
+ explicit QRemoteObjectSourcePrivate(QObject *object, QMetaObject const *meta, const QString &name);
+
+ ~QRemoteObjectSourcePrivate();
+
+ int qt_metacall(QMetaObject::Call call, int methodId, void **a);
+ ContainerWithOffset<QVector<QVector<int> > > args;
+ QHash<int, QMetaProperty> propertyFromNotifyIndex;
+ QList<ServerIoDevice*> listeners;
+ QString m_name;
+ QObject *m_object;
+ const QMetaObject * const m_meta;
+ const int m_methodOffset;
+ const int m_propertyOffset;
+
+ QVariantList marshalArgs(int index, void **a);
+ void handleMetaCall(int index, QMetaObject::Call call, void **a);
+ void addListener(ServerIoDevice *io, bool dynamic = false);
+ int removeListener(ServerIoDevice *io, bool shouldSendRemove = false);
+ void invoke(QMetaObject::Call, int index, const QVariantList &args);
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/remoteobjects/qremoteobjectsourceio.cpp b/src/remoteobjects/qremoteobjectsourceio.cpp
new file mode 100644
index 0000000..51bd205
--- /dev/null
+++ b/src/remoteobjects/qremoteobjectsourceio.cpp
@@ -0,0 +1,219 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qremoteobjectsourceio_p.h"
+
+#include "qremoteobjectsource.h"
+#include "qremoteobjectsource_p.h"
+#include "qtremoteobjectglobal.h"
+
+#include <QMetaClassInfo>
+#include <QStringList>
+
+QT_BEGIN_NAMESPACE
+
+QRemoteObjectSourceIo::QRemoteObjectSourceIo(const QUrl &address)
+ : m_server(m_factory.createServer(address, this))
+{
+ if (m_server->listen(address)) {
+ qCDebug(QT_REMOTEOBJECT) << "QRemoteObjectSourceIo is Listening" << address;
+ } else {
+ qCDebug(QT_REMOTEOBJECT) << "Listen failed";
+ qCDebug(QT_REMOTEOBJECT) << address;
+ qCDebug(QT_REMOTEOBJECT) << m_server->serverError();
+ }
+
+ connect(m_server.data(), SIGNAL(newConnection()), this, SLOT(handleConnection()));
+ connect(&m_serverDelete, SIGNAL(mapped(QObject*)), this, SLOT(onServerDisconnect(QObject*)));
+ connect(&m_serverRead, SIGNAL(mapped(QObject*)), this, SLOT(onServerRead(QObject*)));
+ connect(&m_remoteObjectDestroyed, SIGNAL(mapped(QString)), this, SLOT(clearRemoteObjectSource(QString)));
+}
+
+QRemoteObjectSourceIo::~QRemoteObjectSourceIo()
+{
+ Q_FOREACH (QRemoteObjectSourcePrivate *pp, m_remoteObjects) {
+ disableRemoting(pp);
+ }
+}
+
+bool QRemoteObjectSourceIo::enableRemoting(QObject *object, const QMetaObject *meta, const QString &name)
+{
+ if (m_remoteObjects.contains(name)) {
+ qCWarning(QT_REMOTEOBJECT) << "Tried to register QRemoteObjectSource twice" << name;
+ return false;
+ }
+
+ QRemoteObjectSourcePrivate *pp = new QRemoteObjectSourcePrivate(object, meta, name);
+
+ qCDebug(QT_REMOTEOBJECT) << "Registering" << name;
+
+ m_remoteObjects[name] = pp;
+ connect(pp, SIGNAL(destroyed()), &m_remoteObjectDestroyed, SLOT(map()));
+ m_remoteObjectDestroyed.setMapping(pp, name);
+ emit remoteObjectAdded(qMakePair(name, m_server->address()));
+
+ return true;
+}
+
+bool QRemoteObjectSourceIo::disableRemoting(QRemoteObjectSourcePrivate *pp)
+{
+ const QString name = pp->m_name;
+ clearRemoteObjectSource(name);
+ pp->setParent(Q_NULLPTR);
+ delete pp;
+
+ return true;
+}
+
+void QRemoteObjectSourceIo::onServerDisconnect(QObject *conn)
+{
+ ServerIoDevice *connection = qobject_cast<ServerIoDevice*>(conn);
+ m_connections.remove(connection);
+
+ qCDebug(QT_REMOTEOBJECT) << "OnServerDisconnect";
+
+ Q_FOREACH (QRemoteObjectSourcePrivate *pp, m_remoteObjects)
+ pp->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
+ ServerIoDevice *connection = qobject_cast<ServerIoDevice*>(conn);
+
+ do {
+
+ if (!connection->read())
+ return;
+
+ using namespace QRemoteObjectPackets;
+
+ const QRemoteObjectPacket* packet = connection->packet();
+ switch (packet->id) {
+ case QRemoteObjectPacket::AddObject:
+ {
+ const QAddObjectPacket *p = static_cast<const QAddObjectPacket *>(packet);
+ const QString name = p->name;
+ qCDebug(QT_REMOTEOBJECT) << "AddObject" << name << p->isDynamic;
+ if (m_remoteObjects.contains(name)) {
+ QRemoteObjectSourcePrivate *pp = m_remoteObjects[name];
+ pp->addListener(connection, p->isDynamic);
+ } else {
+ qCWarning(QT_REMOTEOBJECT) << "Request to attach to non-existent RemoteObjectSource:" << name;
+ }
+ break;
+ }
+ case QRemoteObjectPacket::RemoveObject:
+ {
+ const QRemoveObjectPacket *p = static_cast<const QRemoveObjectPacket *>(packet);
+ const QString name = p->name;
+ qCDebug(QT_REMOTEOBJECT) << "RemoveObject" << name;
+ if (m_remoteObjects.contains(name)) {
+ QRemoteObjectSourcePrivate *pp = m_remoteObjects[name];
+ const int count = pp->removeListener(connection);
+ Q_UNUSED(count);
+ //TODO - possible to have a timer that closes connections if not reopened within a timeout?
+ } else {
+ qCWarning(QT_REMOTEOBJECT) << "Request to detach from non-existent RemoteObjectSource:" << name;
+ }
+ qCDebug(QT_REMOTEOBJECT) << "RemoveObject finished" << name;
+ break;
+ }
+ case QRemoteObjectPacket::InvokePacket:
+ {
+ const QInvokePacket *p = static_cast<const QInvokePacket *>(packet);
+ const QString name = p->name;
+ if (name == QStringLiteral("Registry") && !m_registryMapping.contains(connection)) {
+ const QRemoteObjectSourceLocation loc = p->args.first().value<QRemoteObjectSourceLocation>();
+ m_registryMapping[connection] = loc.second;
+ }
+ if (m_remoteObjects.contains(name)) {
+ QRemoteObjectSourcePrivate *pp = m_remoteObjects[name];
+ if (p->call == QMetaObject::InvokeMetaMethod) {
+ qCDebug(QT_REMOTEOBJECT) << "Source (method) Invoke-->" << name << pp->m_meta->method(p->index+pp->m_methodOffset).name();
+ pp->invoke(QMetaObject::InvokeMetaMethod, p->index, p->args);
+ } else {
+ qCDebug(QT_REMOTEOBJECT) << "Source (write property) Invoke-->" << name << pp->m_meta->property(p->index+pp->m_propertyOffset).name();
+ pp->invoke(QMetaObject::WriteProperty, p->index, p->args);
+ }
+ }
+ break;
+ }
+ default:
+ qCDebug(QT_REMOTEOBJECT) << "OnReadReady invalid type" << packet->id;
+ }
+ } while (connection->bytesAvailable()); // have bytes left over, so do another iteration
+}
+
+void QRemoteObjectSourceIo::handleConnection()
+{
+ qCDebug(QT_REMOTEOBJECT) << "handleConnection" << m_connections;
+
+ ServerIoDevice *conn = m_server->nextPendingConnection();
+ m_connections.insert(conn);
+ connect(conn, SIGNAL(disconnected()), &m_serverDelete, SLOT(map()));
+ m_serverDelete.setMapping(conn, conn);
+ connect(conn, SIGNAL(readyRead()), &m_serverRead, SLOT(map()));
+ m_serverRead.setMapping(conn, conn);
+
+ QRemoteObjectPackets::QObjectListPacket p(QStringList(m_remoteObjects.keys()));
+ conn->write(p.serialize());
+ qCDebug(QT_REMOTEOBJECT) << "Wrote ObjectList packet from Server";
+}
+
+void QRemoteObjectSourceIo::clearRemoteObjectSource(const QString &name)
+{
+ m_remoteObjects.remove(name);
+ emit remoteObjectRemoved(qMakePair(name, serverAddress()));
+}
+
+QUrl QRemoteObjectSourceIo::serverAddress() const
+{
+ return m_server->address();
+}
+
+QT_END_NAMESPACE
diff --git a/src/remoteobjects/qremoteobjectsourceio_p.h b/src/remoteobjects/qremoteobjectsourceio_p.h
new file mode 100644
index 0000000..88ac68d
--- /dev/null
+++ b/src/remoteobjects/qremoteobjectsourceio_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTEOBJECTSOURCEIO_P_H
+#define QREMOTEOBJECTSOURCEIO_P_H
+
+#include "qconnectionserverfactory_p.h"
+#include "qtremoteobjectglobal.h"
+
+#include <QIODevice>
+#include <QScopedPointer>
+#include <QSignalMapper>
+
+QT_BEGIN_NAMESPACE
+
+class QRemoteObjectSource;
+class QRemoteObjectSourcePrivate;
+
+class QRemoteObjectSourceIo : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QRemoteObjectSourceIo(const QUrl &address);
+ ~QRemoteObjectSourceIo();
+
+ bool enableRemoting(QObject *object, const QMetaObject *meta, const QString &name);
+ bool disableRemoting(QRemoteObjectSourcePrivate *pp);
+
+ QUrl serverAddress() const;
+
+public Q_SLOTS:
+ void handleConnection();
+ void onServerDisconnect(QObject *obj = Q_NULLPTR);
+ void onServerRead(QObject *obj);
+ void clearRemoteObjectSource(const QString &name);
+
+Q_SIGNALS:
+ void remoteObjectAdded(const QRemoteObjectSourceLocation &);
+ void remoteObjectRemoved(const QRemoteObjectSourceLocation &);
+ void serverRemoved(const QUrl& url);
+
+private:
+ friend class QRemoteObjectNodePrivate;
+ QHash<QIODevice*, quint32> m_readSize;
+ QConnectionServerFactory m_factory;
+ QSet<ServerIoDevice*> m_connections;
+ QMap<QString, QRemoteObjectSourcePrivate*> m_remoteObjects;
+ QSignalMapper m_serverDelete;
+ QSignalMapper m_serverRead;
+ QSignalMapper m_remoteObjectDestroyed;
+ QHash<ServerIoDevice*, QUrl> m_registryMapping;
+ QScopedPointer<QConnectionAbstractServer> m_server;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/remoteobjects/qtremoteobjectglobal.cpp b/src/remoteobjects/qtremoteobjectglobal.cpp
new file mode 100644
index 0000000..ce350de
--- /dev/null
+++ b/src/remoteobjects/qtremoteobjectglobal.cpp
@@ -0,0 +1,526 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtremoteobjectglobal.h"
+
+#include <QMetaObject>
+#include <QMetaProperty>
+#include "private/qmetaobjectbuilder_p.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(QT_REMOTEOBJECT, "qt.remoteobjects")
+
+namespace QRemoteObjectPackets {
+
+QRemoteObjectPacket::~QRemoteObjectPacket(){}
+
+QRemoteObjectPacket *QRemoteObjectPacket::fromDataStream(QDataStream &in)
+{
+ QRemoteObjectPacket *packet = Q_NULLPTR;
+ quint16 type;
+ in >> type;
+ switch (type) {
+ case InitPacket:
+ packet = new QInitPacket;
+ if (packet->deserialize(in))
+ packet->id = InitPacket;
+ break;
+ case InitDynamicPacket:
+ packet = new QInitDynamicPacket;
+ if (packet->deserialize(in))
+ packet->id = InitDynamicPacket;
+ break;
+ case AddObject:
+ packet = new QAddObjectPacket;
+ if (packet->deserialize(in))
+ packet->id = AddObject;
+ break;
+ case RemoveObject:
+ packet = new QRemoveObjectPacket;
+ if (packet->deserialize(in))
+ packet->id = RemoveObject;
+ break;
+ case InvokePacket:
+ packet = new QInvokePacket;
+ if (packet->deserialize(in))
+ packet->id = InvokePacket;
+ break;
+ case PropertyChangePacket:
+ packet = new QPropertyChangePacket;
+ if (packet->deserialize(in))
+ packet->id = PropertyChangePacket;
+ break;
+ case ObjectList:
+ packet = new QObjectListPacket;
+ if (packet->deserialize(in))
+ packet->id = ObjectList;
+ break;
+ default:
+ qWarning() << "Invalid packet received" << type;
+ }
+ return packet;
+}
+
+QByteArray QInitPacketEncoder::serialize() const
+{
+ DataStreamPacket ds(id);
+ ds << name;
+ qint64 postNamePosition = ds.device()->pos();
+ ds << quint32(0);
+
+ //Now copy the property data
+ const QMetaObject *meta = object->metaObject();
+ const int propertyOffset = base && base != meta ? base->propertyCount() : meta->propertyOffset();
+ const int nParam = meta->propertyCount();
+
+ ds << quint32(nParam - propertyOffset); //Number of properties
+
+ for (int i = propertyOffset; i < nParam; ++i) {
+ const QMetaProperty mp = meta->property(i);
+ ds << mp.name();
+ ds << mp.read(object);
+ }
+
+ //Now go back and set the size of the rest of the data so we can treat is as a QByteArray
+ ds.device()->seek(postNamePosition);
+ ds << quint32(ds.array.length() - sizeof(quint32) - postNamePosition);
+ return ds.finishPacket();
+}
+
+bool QInitPacketEncoder::deserialize(QDataStream &)
+{
+ Q_ASSERT(false); //Use QInitPacket::deserialize()
+ return false;
+}
+
+QByteArray QInitPacket::serialize() const
+{
+ Q_ASSERT(false); //Use QInitPacketEncoder::serialize()
+ return QByteArray();
+}
+
+bool QInitPacket::deserialize(QDataStream& in)
+{
+ if (in.atEnd())
+ return false;
+ in >> name;
+ if (name.isEmpty() || name.isNull() || in.atEnd())
+ return false;
+ in >> packetData;
+ if (packetData.isEmpty() || packetData.isNull())
+ return false;
+
+ //Make sure the bytearray holds valid properties
+ QDataStream validate(packetData);
+ const int packetLen = packetData.size();
+ quint32 nParam, len;
+ quint8 c;
+ QVariant tmp;
+ validate >> nParam;
+ for (quint32 i = 0; i < nParam; i++)
+ {
+ const qint64 pos = validate.device()->pos();
+ qint64 bytesLeft = packetLen - pos;
+ if (bytesLeft < 4)
+ return false;
+ validate >> len;
+ bytesLeft -= 4;
+ if (bytesLeft < len)
+ return false;
+ validate.skipRawData(len-1);
+ validate >> c;
+ if (c != 0)
+ return false;
+ if (qstrlen(packetData.constData()+pos+4) != len - 1)
+ return false;
+ bytesLeft -= len;
+ if (bytesLeft <= 0)
+ return false;
+ validate >> tmp;
+ if (!tmp.isValid())
+ return false;
+ }
+ return true;
+}
+
+QByteArray QInitDynamicPacketEncoder::serialize() const
+{
+ DataStreamPacket ds(id);
+ ds << name;
+ qint64 postNamePosition = ds.device()->pos();
+ ds << quint32(0);
+
+ //Now copy the property data
+ const QMetaObject *meta = object->metaObject();
+ const int propertyOffset = base && base != meta ? base->propertyCount() : meta->propertyOffset();
+ const int nParam = meta->propertyCount();
+ const int methodOffset = base && base != meta ? base->methodCount() : meta->methodOffset();
+ const int numMethods = meta->methodCount();
+
+ ds << quint32(numMethods - methodOffset);
+ for (int i = methodOffset; i < numMethods; ++i) {
+ const QMetaMethod mm = meta->method(i);
+ ds << quint32(i - methodOffset);
+ ds << mm.name();
+ ds << mm.methodSignature();
+ ds << quint32(mm.methodType());
+ if (mm.methodType() == QMetaMethod::Method)
+ ds << mm.typeName();
+ ds << quint32(mm.parameterCount());
+ for (int i = 0; i < mm.parameterCount(); ++i)
+ ds << mm.parameterTypes()[i];
+ }
+
+ ds << quint32(nParam - propertyOffset); //Number of properties
+
+ for (int i = propertyOffset; i < nParam; ++i) {
+ const QMetaProperty mp = meta->property(i);
+ ds << mp.name();
+ ds << mp.typeName();
+ if (mp.notifySignalIndex() == -1)
+ ds << QByteArray();
+ else
+ ds << mp.notifySignal().methodSignature();
+ ds << mp.read(object);
+ }
+
+ //Now go back and set the size of the rest of the data so we can treat is as a QByteArray
+ ds.device()->seek(postNamePosition);
+ ds << quint32(ds.array.length() - sizeof(quint32) - postNamePosition);
+ return ds.finishPacket();
+}
+
+bool QInitDynamicPacketEncoder::deserialize(QDataStream &)
+{
+ Q_ASSERT(false); //Use QInitDynamicPacket::deserialize()
+ return false;
+}
+
+QByteArray QInitDynamicPacket::serialize() const
+{
+ Q_ASSERT(false); //Use QInitDynamicPacketEncoder::serialize()
+ return QByteArray();
+}
+
+bool QInitDynamicPacket::deserialize(QDataStream& in)
+{
+ if (in.atEnd())
+ return false;
+ in >> name;
+ if (name.isEmpty() || name.isNull() || in.atEnd())
+ return false;
+ in >> packetData;
+ if (packetData.isEmpty() || packetData.isNull())
+ return false;
+
+ //Make sure the bytearray holds valid properties // TODO maybe really evaluate
+ return true;
+ QDataStream validate(packetData);
+ int packetLen = packetData.size();
+ quint32 nParam, len, propLen;
+ quint8 c;
+ QVariant tmp;
+ validate >> nParam;
+ for (quint32 i = 0; i < nParam; i++)
+ {
+ qint64 pos = validate.device()->pos();
+ qint64 bytesLeft = packetLen - pos;
+ if (bytesLeft < 4)
+ return false;
+
+ //Read property name
+ validate >> len;
+ bytesLeft -= 4;
+ if (bytesLeft < len)
+ return false;
+ validate.skipRawData(len-1);
+ validate >> c;
+ if (c != 0)
+ return false;
+ if (qstrlen(packetData.constData()+pos+4) != len - 1)
+ return false;
+ bytesLeft -= len;
+ if (bytesLeft <= 0)
+ return false;
+
+ //Read notify name
+ propLen = len;
+ validate >> len;
+ bytesLeft -= 4;
+ if (bytesLeft < len)
+ return false;
+ if (len) { //notify isn't empty
+ validate.skipRawData(len-1);
+ validate >> c;
+ if (c != 0)
+ return false;
+ if (qstrlen(packetData.constData()+pos+4+propLen+4) != len - 1)
+ return false;
+ bytesLeft -= len;
+ }
+ if (bytesLeft <= 0)
+ return false;
+
+ //Read QVariant value
+ validate >> tmp;
+ if (!tmp.isValid())
+ return false;
+ }
+ return true;
+}
+
+QMetaObject *QInitDynamicPacket::createMetaObject(QMetaObjectBuilder &builder,
+ QVector<int> &methodTypes,
+ QVector<QVector<int> > &methodArgumentTypes,
+ QVector<QPair<QByteArray, QVariant> > *propertyValues) const
+{
+ quint32 numMethods = 0;
+ QDataStream ds(packetData);
+ ds >> numMethods;
+ methodTypes.clear();
+ methodTypes.resize(numMethods);
+ methodArgumentTypes.clear();
+ methodArgumentTypes.resize(numMethods);
+ for (quint32 i = 0; i < numMethods; ++i) {
+ quint32 index = 0;
+ QMetaMethod::MethodType type;
+ QByteArray name;
+ QByteArray signature;
+ QByteArray returnType;
+ quint32 typeValue;
+
+ ds >> index;
+ ds >> name;
+ ds >> signature;
+ ds >> typeValue;
+
+ type = static_cast<QMetaMethod::MethodType>(typeValue);
+ methodTypes[i] = type;
+ if (typeValue == QMetaMethod::Method)
+ ds >> returnType;
+ quint32 parameterCount = 0;
+ ds >> parameterCount;
+ QByteArray parameterType;
+ methodArgumentTypes[index].reserve(parameterCount);
+ for (unsigned int pCount = 0; pCount < parameterCount; ++pCount) {
+ ds >> parameterType;
+ methodArgumentTypes[index] << QVariant::nameToType(parameterType.constData());
+ }
+ if (type == QMetaMethod::Signal)
+ builder.addSignal(signature);
+ else if (type == QMetaMethod::Slot)
+ builder.addMethod(signature);
+ else
+ builder.addMethod(signature, returnType);
+ }
+
+ quint32 numProperties = 0;
+ ds >> numProperties; //Number of properties
+
+ QVector<QPair<QByteArray, QVariant> > &propVal = *propertyValues;
+ for (unsigned int i = 0; i < numProperties; ++i) {
+ QByteArray name;
+ QByteArray typeName;
+ QByteArray signalName;
+ ds >> name;
+ ds >> typeName;
+ ds >> signalName;
+ if (signalName.isEmpty())
+ builder.addProperty(name, typeName);
+ else
+ builder.addProperty(name, typeName, builder.indexOfSignal(signalName));
+ QVariant value;
+ ds >> value;
+ propVal.append(qMakePair(name, value));
+ }
+
+ return builder.toMetaObject();
+}
+
+
+QByteArray QAddObjectPacket::serialize() const
+{
+ DataStreamPacket ds(id);
+ ds << name;
+ ds << isDynamic;
+ return ds.finishPacket();
+}
+
+bool QAddObjectPacket::deserialize(QDataStream& in)
+{
+ in >> name;
+ in >> isDynamic;
+ return true;
+}
+
+QByteArray QRemoveObjectPacket::serialize() const
+{
+ DataStreamPacket ds(id);
+ ds << name;
+ return ds.finishPacket();
+}
+
+bool QRemoveObjectPacket::deserialize(QDataStream& in)
+{
+ in >> name;
+ return true;
+}
+
+QByteArray QInvokePacket::serialize() const
+{
+ DataStreamPacket ds(id);
+ ds << name;
+ ds << call;
+ ds << index;
+ ds << args;
+ return ds.finishPacket();
+}
+
+bool QInvokePacket::deserialize(QDataStream& in)
+{
+ in >> name;
+ in >> call;
+ in >> index;
+ in >> args;
+ return true;
+}
+
+QByteArray QPropertyChangePacket::serialize() const
+{
+ DataStreamPacket ds(id);
+ ds << name;
+ ds << propertyName;
+ ds << value;
+ return ds.finishPacket();
+}
+
+bool QPropertyChangePacket::deserialize(QDataStream& in)
+{
+ in >> name;
+ in >> propertyName;
+ in >> value;
+ return true;
+}
+
+QByteArray QObjectListPacket::serialize() const
+{
+ DataStreamPacket ds(id);
+ ds << objects;
+ return ds.finishPacket();
+}
+
+bool QObjectListPacket::deserialize(QDataStream& in)
+{
+ in >> objects;
+ return true;
+}
+
+}
+
+namespace QtRemoteObjects {
+
+void copyStoredProperties(const QObject *src, QObject *dst)
+{
+ if (!src) {
+ qCWarning(QT_REMOTEOBJECT) << Q_FUNC_INFO << ": trying to copy from a null QObject";
+ return;
+ }
+ if (!dst) {
+ qCWarning(QT_REMOTEOBJECT) << Q_FUNC_INFO << ": trying to copy to a null QObject";
+ return;
+ }
+
+ const QMetaObject * const mof = src->metaObject();
+ const QMetaObject * const mot = dst->metaObject();
+ if (mof->propertyCount() != mot->propertyCount()) {
+ qCWarning(QT_REMOTEOBJECT) << Q_FUNC_INFO << ": trying to copy from a different QObject";
+ return;
+ }
+
+ for (int i = 0, end = mof->propertyCount(); i != end; ++i) {
+ const QMetaProperty mpf = mof->property(i);
+ if (!mpf.isStored(src))
+ continue;
+ const QMetaProperty mpt = mot->property(i);
+ mpt.write(dst, mpf.read(src));
+ }
+}
+
+void copyStoredProperties(const QObject *src, QDataStream &dst)
+{
+ if (!src) {
+ qCWarning(QT_REMOTEOBJECT) << Q_FUNC_INFO << ": trying to copy from a null QObject";
+ return;
+ }
+
+ const QMetaObject * const mof = src->metaObject();
+
+ for (int i = 0, end = mof->propertyCount(); i != end; ++i) {
+ const QMetaProperty mpf = mof->property(i);
+ if (!mpf.isStored(src))
+ continue;
+ dst << mpf.read(src);
+ }
+}
+
+void copyStoredProperties(QDataStream &src, QObject *dst)
+{
+ if (!dst) {
+ qCWarning(QT_REMOTEOBJECT) << Q_FUNC_INFO << ": trying to copy to a null QObject";
+ return;
+ }
+
+ const QMetaObject * const mot = dst->metaObject();
+
+ for (int i = 0, end = mot->propertyCount(); i != end; ++i) {
+ const QMetaProperty mpt = mot->property(i);
+ if (!mpt.isStored(dst))
+ continue;
+ QVariant v;
+ src >> v;
+ mpt.write(dst, v);
+ }
+}
+
+} // namespace QtRemoteObjects
+
+QT_END_NAMESPACE
diff --git a/src/remoteobjects/qtremoteobjectglobal.h b/src/remoteobjects/qtremoteobjectglobal.h
new file mode 100644
index 0000000..53442f0
--- /dev/null
+++ b/src/remoteobjects/qtremoteobjectglobal.h
@@ -0,0 +1,261 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTREMOTEOBJECTGLOBAL_H
+#define QTREMOTEOBJECTGLOBAL_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/QHash>
+#include <QtCore/QMap>
+#include <QtCore/QPair>
+#include <QtCore/QUrl>
+#include <QtCore/QVariant>
+#include <QtCore/QLoggingCategory>
+
+QT_BEGIN_NAMESPACE
+
+typedef QPair<QString, QUrl> QRemoteObjectSourceLocation;
+typedef QHash<QString, QUrl> QRemoteObjectSourceLocations;
+
+Q_DECLARE_METATYPE(QRemoteObjectSourceLocation)
+Q_DECLARE_METATYPE(QRemoteObjectSourceLocations)
+
+#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"
+
+class QDataStream;
+class QMetaObjectBuilder;
+
+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 tcp() { return QStringLiteral("tcp"); }
+
+}
+
+namespace QRemoteObjectPackets {
+
+//Helper class for creating a QByteArray from a QRemoteObjectPacket
+class DataStreamPacket : public QDataStream
+{
+public:
+ DataStreamPacket(quint16 id) : QDataStream(&array, QIODevice::WriteOnly)
+ {
+ *this << quint32(0);
+ *this << id;
+ }
+ QByteArray finishPacket()
+ {
+ this->device()->seek(0);
+ *this << quint32(array.length() - sizeof(quint32));
+ return array;
+ }
+ QByteArray array;
+
+private:
+ Q_DISABLE_COPY(DataStreamPacket)
+};
+
+class QRemoteObjectPacket
+{
+public:
+ enum QRemoteObjectPacketTypeEnum
+ {
+ Invalid = 0,
+ InitPacket,
+ InitDynamicPacket,
+ AddObject,
+ RemoveObject,
+ InvokePacket,
+ PropertyChangePacket,
+ ObjectList
+ };
+
+ QRemoteObjectPacket() { id = AddObject; }
+ virtual ~QRemoteObjectPacket();
+ virtual QByteArray serialize() const = 0;
+ virtual bool deserialize(QDataStream&) = 0;
+ static QRemoteObjectPacket* fromDataStream(QDataStream&);
+ quint16 id;
+};
+
+class QInitPacketEncoder : public QRemoteObjectPacket
+{
+public:
+ inline QInitPacketEncoder(const QString &_name, const QObject *_object, QMetaObject const *_base = Q_NULLPTR) :
+ name(_name), object(_object), base(_base) { id = InitPacket; }
+ QByteArray serialize() const Q_DECL_OVERRIDE;
+ virtual bool deserialize(QDataStream&) Q_DECL_OVERRIDE;
+ const QString name;
+ const QObject *object;
+ const QMetaObject *base;
+private:
+ QInitPacketEncoder() {}
+};
+
+class QInitPacket : public QRemoteObjectPacket
+{
+public:
+ inline QInitPacket() : QRemoteObjectPacket() {}
+ QByteArray serialize() const Q_DECL_OVERRIDE;
+ virtual bool deserialize(QDataStream&) Q_DECL_OVERRIDE;
+ QString name;
+ QByteArray packetData;
+};
+
+class QInitDynamicPacketEncoder : public QRemoteObjectPacket
+{
+public:
+ QInitDynamicPacketEncoder(const QString &_name, const QObject *_object, QMetaObject const *_base = Q_NULLPTR) :
+ name(_name), object(_object), base(_base) { id = InitDynamicPacket; }
+ QByteArray serialize() const Q_DECL_OVERRIDE;
+ bool deserialize(QDataStream&) Q_DECL_OVERRIDE;
+ const QString name;
+ const QObject *object;
+ const QMetaObject *base;
+private:
+ QInitDynamicPacketEncoder() {}
+};
+
+class QInitDynamicPacket : public QRemoteObjectPacket
+{
+public:
+ inline QInitDynamicPacket() : QRemoteObjectPacket() {}
+ QByteArray serialize() const Q_DECL_OVERRIDE;
+ bool deserialize(QDataStream&) Q_DECL_OVERRIDE;
+ QMetaObject *createMetaObject(QMetaObjectBuilder &builder,
+ QVector<int> &methodTypes,
+ QVector<QVector<int> > &methodArgumentTypes,
+ QVector<QPair<QByteArray, QVariant> > *propertyValues = 0) const;
+ QString name;
+ QByteArray packetData;
+};
+
+class QAddObjectPacket : public QRemoteObjectPacket
+{
+public:
+ inline QAddObjectPacket() : QRemoteObjectPacket(),
+ isDynamic(false) {}
+ inline QAddObjectPacket(const QString &_name, bool _isDynamic) :
+ name(_name), isDynamic(_isDynamic) { id = AddObject; }
+ virtual QByteArray serialize() const Q_DECL_OVERRIDE;
+ virtual bool deserialize(QDataStream&) Q_DECL_OVERRIDE;
+ QString name;
+ bool isDynamic;
+};
+
+class QRemoveObjectPacket : public QRemoteObjectPacket
+{
+public:
+ inline QRemoveObjectPacket() : QRemoteObjectPacket() {}
+ inline QRemoveObjectPacket(const QString &_name) :
+ name(_name) { id = RemoveObject; }
+ virtual QByteArray serialize() const Q_DECL_OVERRIDE;
+ virtual bool deserialize(QDataStream&) Q_DECL_OVERRIDE;
+ QString name;
+};
+
+class QInvokePacket : public QRemoteObjectPacket
+{
+public:
+ inline QInvokePacket() : QRemoteObjectPacket(),
+ call(-1), index(-1) {}
+ inline QInvokePacket(const QString &_name, int _call, int _index, QVariantList _args) :
+ name(_name), call(_call), index(_index), args(_args) { id = InvokePacket; }
+ virtual QByteArray serialize() const Q_DECL_OVERRIDE;
+ virtual bool deserialize(QDataStream&) Q_DECL_OVERRIDE;
+ QString name;
+ int call;
+ int index;
+ QVariantList args;
+};
+
+class QPropertyChangePacket : public QRemoteObjectPacket
+{
+public:
+ inline QPropertyChangePacket() : QRemoteObjectPacket() {}
+ inline QPropertyChangePacket(const QString &_name, const char *_propertyNameChar, const QVariant &_value) :
+ name(_name), propertyName(_propertyNameChar), value(_value) { id = PropertyChangePacket; }
+ virtual QByteArray serialize() const Q_DECL_OVERRIDE;
+ virtual bool deserialize(QDataStream&) Q_DECL_OVERRIDE;
+ QString name;
+ QByteArray propertyName;
+ QVariant value;
+};
+
+class QObjectListPacket : public QRemoteObjectPacket
+{
+public:
+ inline QObjectListPacket() : QRemoteObjectPacket() {}
+ inline QObjectListPacket(const QStringList &_objects) :
+ objects(_objects) { id = ObjectList; }
+ virtual QByteArray serialize() const Q_DECL_OVERRIDE;
+ virtual bool deserialize(QDataStream&) Q_DECL_OVERRIDE;
+ QStringList objects;
+};
+
+} // namespace QRemoteObjectPackets
+
+namespace QtRemoteObjects {
+
+Q_REMOTEOBJECTS_EXPORT void copyStoredProperties(const QObject *src, QObject *dst);
+Q_REMOTEOBJECTS_EXPORT void copyStoredProperties(const QObject *src, QDataStream &dst);
+Q_REMOTEOBJECTS_EXPORT void copyStoredProperties(QDataStream &src, QObject *dst);
+
+}
+
+Q_DECLARE_LOGGING_CATEGORY(QT_REMOTEOBJECT)
+
+QT_END_NAMESPACE
+
+#endif // QTREMOTEOBJECTSGLOBAL_H
diff --git a/src/remoteobjects/remoteobjects.pro b/src/remoteobjects/remoteobjects.pro
new file mode 100644
index 0000000..9e967c3
--- /dev/null
+++ b/src/remoteobjects/remoteobjects.pro
@@ -0,0 +1,51 @@
+TARGET = QtRemoteObjects
+MODULE = remoteobjects
+MODULE_CONFIG = remoteobjects_repc
+QT += network core-private
+QT -= gui
+
+QMAKE_DOCS = $$PWD/doc/qtremoteobjects.qdocconf
+
+load(qt_module)
+
+DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_BYTEARRAY QT_NO_URL_CAST_FROM_STRING
+
+INCLUDEPATH += $$PWD
+
+PUBLIC_HEADERS += \
+ $$PWD/qremoteobjectdynamicreplica.h \
+ $$PWD/qremoteobjectsource.h \
+ $$PWD/qremoteobjectreplica.h \
+ $$PWD/qremoteobjectnode.h \
+ $$PWD/qtremoteobjectglobal.h \
+ $$PWD/qremoteobjectregistry.h
+
+PRIVATE_HEADERS += \
+ $$PWD/qconnectionabstractfactory_p.h \
+ $$PWD/qconnectionabstractserver_p.h \
+ $$PWD/qconnectionclientfactory_p.h \
+ $$PWD/qconnectionserverfactory_p.h \
+ $$PWD/qremoteobjectsourceio_p.h \
+ $$PWD/qremoteobjectsource_p.h \
+ $$PWD/qregistrysource_p.h \
+ $$PWD/qremoteobjectnode_p.h \
+ $$PWD/qremoteobjectreplica_p.h
+
+HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS
+
+SOURCES += \
+ $$PWD/qconnectionabstractserver.cpp \
+ $$PWD/qconnectionclientfactory.cpp \
+ $$PWD/qconnectionserverfactory.cpp \
+ $$PWD/qremoteobjectdynamicreplica.cpp \
+ $$PWD/qremoteobjectsource.cpp \
+ $$PWD/qremoteobjectsourceio.cpp \
+ $$PWD/qremoteobjectregistry.cpp \
+ $$PWD/qregistrysource.cpp \
+ $$PWD/qremoteobjectreplica.cpp \
+ $$PWD/qremoteobjectnode.cpp \
+ $$PWD/qtremoteobjectglobal.cpp
+
+DEFINES += QT_BUILD_REMOTEOBJECTS_LIB
+
+contains(QT_CONFIG, c++11): CONFIG += c++11
diff --git a/src/src.pro b/src/src.pro
new file mode 100644
index 0000000..f16d105
--- /dev/null
+++ b/src/src.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS = remoteobjects
diff --git a/sync.profile b/sync.profile
new file mode 100644
index 0000000..0f6840a
--- /dev/null
+++ b/sync.profile
@@ -0,0 +1,18 @@
+%modules = ( # path to module name map
+ "QtRemoteObjects" => "$basedir/src/remoteobjects",
+);
+#%moduleheaders = ( # restrict the module headers to those found in relative path
+#
+#);
+%deprecatedheaders = (
+);
+# Module dependencies.
+# Every module that is required to build this module should have one entry.
+# Each of the module version specifiers can take one of the following values:
+# - A specific Git revision.
+# - any git symbolic ref resolvable from the module's repository (e.g. "refs/heads/master" to track master branch)
+# - an empty string to use the same branch under test (dependencies will become "refs/heads/master" if we are in the master branch)
+#
+%dependencies = (
+ "qtbase" => "",
+);
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
new file mode 100644
index 0000000..80475ba
--- /dev/null
+++ b/tests/auto/auto.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS += repc integration cmake
diff --git a/tests/auto/cmake/CMakeLists.txt b/tests/auto/cmake/CMakeLists.txt
new file mode 100644
index 0000000..62fc89a
--- /dev/null
+++ b/tests/auto/cmake/CMakeLists.txt
@@ -0,0 +1,12 @@
+
+cmake_minimum_required(VERSION 2.8)
+
+project(qmake_cmake_files)
+
+enable_testing()
+
+find_package(Qt5Core REQUIRED)
+
+include("${_Qt5CTestMacros}")
+
+expect_pass(test_qremoteobjects_module)
diff --git a/tests/auto/cmake/cmake.pro b/tests/auto/cmake/cmake.pro
new file mode 100644
index 0000000..bf2dbcb
--- /dev/null
+++ b/tests/auto/cmake/cmake.pro
@@ -0,0 +1,5 @@
+
+# Cause make to do nothing.
+TEMPLATE = subdirs
+
+CONFIG += ctest_testcase
diff --git a/tests/auto/cmake/test_qremoteobjects_module/CMakeLists.txt b/tests/auto/cmake/test_qremoteobjects_module/CMakeLists.txt
new file mode 100644
index 0000000..e4b3b0e
--- /dev/null
+++ b/tests/auto/cmake/test_qremoteobjects_module/CMakeLists.txt
@@ -0,0 +1,32 @@
+
+cmake_minimum_required(VERSION 2.8)
+
+project(test_qremoteobjects_module)
+
+find_package(Qt5Core REQUIRED)
+find_package(Qt5Gui REQUIRED)
+find_package(Qt5Network REQUIRED)
+
+find_package(Qt5RemoteObjects REQUIRED)
+
+include_directories(
+ ${Qt5RemoteObjects_INCLUDE_DIRS}
+ ${Qt5Core_INCLUDE_DIRS}
+ ${Qt5Network_INCLUDE_DIRS}
+)
+
+add_definitions(
+ ${Qt5RemoteObjects_DEFINITIONS}
+ ${QtCore_DEFINITIONS}
+ ${Qt5Network_DEFINITIONS}
+)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Core_EXECUTABLE_COMPILE_FLAGS} ${Qt5Network_EXECUTABLE_COMPILE_FLAGS} ${Qt5Replicant_EXECUTABLE_COMPILE_FLAGS}")
+
+add_executable(mainapp main.cpp)
+
+target_link_libraries(mainapp
+ ${Qt5RemoteObjects_LIBRARIES}
+ ${Qt5Core_LIBRARIES}
+ ${Qt5Network_LIBRARIES}
+)
diff --git a/tests/auto/cmake/test_qremoteobjects_module/main.cpp b/tests/auto/cmake/test_qremoteobjects_module/main.cpp
new file mode 100644
index 0000000..0887d07
--- /dev/null
+++ b/tests/auto/cmake/test_qremoteobjects_module/main.cpp
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QRemoteObjectNode>
+
+int main(int argc, char **argv)
+{
+ QRemoteObjectNode node;
+
+ return 0;
+}
diff --git a/tests/auto/integration/.gitignore b/tests/auto/integration/.gitignore
new file mode 100644
index 0000000..151e5e1
--- /dev/null
+++ b/tests/auto/integration/.gitignore
@@ -0,0 +1 @@
+/integration
diff --git a/tests/auto/integration/Engine.cpp b/tests/auto/integration/Engine.cpp
new file mode 100644
index 0000000..5beaf5e
--- /dev/null
+++ b/tests/auto/integration/Engine.cpp
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "Engine.h"
+
+Engine::Engine(QObject *parent) :
+ EngineSource(parent)
+{
+ setRpm(0);
+}
+
+Engine::~Engine()
+{
+}
diff --git a/tests/auto/integration/Engine.h b/tests/auto/integration/Engine.h
new file mode 100644
index 0000000..5b068d1
--- /dev/null
+++ b/tests/auto/integration/Engine.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTS_ENGINE_H
+#define TESTS_ENGINE_H
+
+#include "rep_engine_source.h"
+
+class Engine : public EngineSource
+{
+ Q_OBJECT
+public:
+ Engine(QObject *parent=Q_NULLPTR);
+ virtual ~Engine();
+
+private:
+ int speed;
+};
+
+#endif
diff --git a/tests/auto/integration/RemoteObjectTest.h b/tests/auto/integration/RemoteObjectTest.h
new file mode 100644
index 0000000..f82583c
--- /dev/null
+++ b/tests/auto/integration/RemoteObjectTest.h
@@ -0,0 +1,229 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTS_REMOTEOBJECTTEST_H
+#define TESTS_REMOTEOBJECTTEST_H
+
+#include <QtTest/QtTest>
+#include <QMetaType>
+#include <qremoteobjectreplica.h>
+#include <QRemoteObjectNode>
+#include "Engine.h"
+#include "Speedometer.h"
+#include "rep_engine_replica.h"
+#include "rep_speedometer_replica.h"
+#include "rep_localdatacenter_source.h"
+#include "rep_tcpdatacenter_source.h"
+#include "rep_localdatacenter_replica.h"
+#include "rep_tcpdatacenter_replica.h"
+
+//DUMMY impl for variant comparison
+bool operator<(const QVector<int> &lhs, const QVector<int> &rhs)
+{
+ return lhs.size() < rhs.size();
+}
+
+class RemoteObjectTest: public QObject
+{
+ Q_OBJECT
+ QRemoteObjectNode m_client;
+ QRemoteObjectNode m_registryClient;
+ QRemoteObjectNode m_basicServer;
+ QRemoteObjectNode m_localCentreServer;
+ QRemoteObjectNode m_tcpCentreServer;
+ QRemoteObjectNode m_registryServer;
+private slots:
+
+ void initTestCase() {
+ QLoggingCategory::setFilterRules("*.debug=true\n"
+ "qt.remoteobjects.debug=false\n"
+ "qt.remoteobjects.warning=false");
+ //Setup registry
+ //Registry needs to be created first until we get the retry mechanism implemented
+ m_registryServer = QRemoteObjectNode::createRegistryHostNode();
+
+ m_client = QRemoteObjectNode();
+ m_registryClient = QRemoteObjectNode::createNodeConnectedToRegistry();
+ //m_client.setObjectName("DirectTestClient");
+ //m_registryClient.setObjectName("RegistryTestClient");
+
+ m_basicServer = QRemoteObjectNode::createHostNode(QUrl("tcp://localhost:9999"));
+
+ engine.reset(new Engine);
+ speedometer.reset(new Speedometer);
+ m_basicServer.enableRemoting(engine.data());
+ m_basicServer.enableRemoting(speedometer.data());
+
+ m_client.connect(QUrl("tcp://localhost:9999"));
+
+ //setup servers
+ qRegisterMetaType<QVector<int> >();
+ QMetaType::registerComparators<QVector<int> >();
+ qRegisterMetaTypeStreamOperators<QVector<int> >();
+ m_localCentreServer = QRemoteObjectNode::createHostNodeConnectedToRegistry();
+ dataCenterLocal.reset(new LocalDataCenterSource);
+ dataCenterLocal->setData1(5);
+ dataCenterLocal->setData2(5.0);
+ dataCenterLocal->setData3(QStringLiteral("local"));
+ dataCenterLocal->setData4(QVector<int>() << 1 << 2 << 3 << 4 << 5);
+ m_localCentreServer.enableRemoting(dataCenterLocal.data());
+
+ m_tcpCentreServer = QRemoteObjectNode::createHostNodeConnectedToRegistry(QUrl("tcp://localhost:19999"));
+ dataCenterTcp.reset(new TcpDataCenterSource);
+ dataCenterTcp->setData1(5);
+ dataCenterTcp->setData2(5.0);
+ dataCenterTcp->setData3(QStringLiteral("tcp"));
+ dataCenterTcp->setData4(QVector<int>() << 1 << 2 << 3 << 4 << 5);
+ m_tcpCentreServer.enableRemoting(dataCenterTcp.data());
+
+ //Setup the client
+ //QVERIFY(m_registryClient.connect( QStringLiteral("local:replica")));
+ }
+
+ void RegistryTest() {
+ QSharedPointer<TcpDataCenterReplica> tcpCentre(m_registryClient.acquire<TcpDataCenterReplica>());
+ QSharedPointer<LocalDataCenterReplica> localCentre(m_registryClient.acquire<LocalDataCenterReplica>());
+ tcpCentre->waitForSource();
+ localCentre->waitForSource();
+ QCOMPARE(m_registryClient.registry()->sourceLocations(), m_registryServer.registry()->sourceLocations());
+ QVERIFY(localCentre->isInitialized());
+ QVERIFY(tcpCentre->isInitialized());
+
+ QCOMPARE(tcpCentre->data1(), 5 );
+ QCOMPARE(tcpCentre->data2(), 5.0);
+ QCOMPARE(tcpCentre->data3(), QStringLiteral("tcp"));
+ QCOMPARE(tcpCentre->data4(), QVector<int>() << 1 << 2 << 3 << 4 << 5);
+
+ QCOMPARE(localCentre->data1(), 5);
+ QCOMPARE(localCentre->data2(), 5.0);
+ QCOMPARE(localCentre->data3(), QStringLiteral("local"));
+ QCOMPARE(localCentre->data4(), QVector<int>() << 1 << 2 << 3 << 4 << 5);
+
+ }
+
+ void basicTest() {
+ engine->setRpm(1234);
+
+ QSharedPointer<EngineReplica> engine_r(m_client.acquire<EngineReplica>());
+ engine_r->waitForSource();
+ QCOMPARE(engine_r->rpm(), 1234);
+ }
+
+ void sequentialReplicaTest() {
+ engine->setRpm(3456);
+
+ QSharedPointer<EngineReplica> engine_r(m_client.acquire<EngineReplica>());
+ engine_r->waitForSource();
+ QCOMPARE(engine_r->rpm(), 3456);
+
+ engine_r = QSharedPointer<EngineReplica>(m_client.acquire< EngineReplica >());
+ engine_r->waitForSource();
+ QCOMPARE(engine_r->rpm(), 3456);
+ }
+
+ void doubleReplicaTest() {
+ QSharedPointer<EngineReplica> engine_r1(m_client.acquire< EngineReplica >());
+ QSharedPointer<EngineReplica> engine_r2(m_client.acquire< EngineReplica >());
+ engine->setRpm(3412);
+
+ engine_r1->waitForSource();
+ engine_r2->waitForSource();
+
+ QCOMPARE(engine_r1->rpm(), 3412);
+ QCOMPARE(engine_r2->rpm(), 3412);
+ }
+
+ void twoReplicaTest() {
+ engine->setRpm(1234);
+ speedometer->setMph(70);
+
+ QSharedPointer<EngineReplica> engine_r(m_client.acquire<EngineReplica>());
+ engine_r->waitForSource();
+ QSharedPointer<SpeedometerReplica> speedometer_r(m_client.acquire<SpeedometerReplica>());
+ speedometer_r->waitForSource();
+
+ QCOMPARE(engine_r->rpm(), 1234);
+ QCOMPARE(speedometer_r->mph(), 70);
+ }
+
+ void dynamicReplicaTest() {
+ QRemoteObjectDynamicReplica *rep1 = m_registryClient.acquire("TcpDataCenter");
+ QRemoteObjectDynamicReplica *rep2 = m_registryClient.acquire("TcpDataCenter");
+ QRemoteObjectDynamicReplica *rep3 = m_registryClient.acquire("LocalDataCenter");
+ rep1->waitForSource();
+ rep2->waitForSource();
+ rep3->waitForSource();
+ const QMetaObject *metaTcpRep1 = rep1->metaObject();
+ const QMetaObject *metaLocalRep1 = rep3->metaObject();
+ const QMetaObject *metaTcpSource = dataCenterTcp->metaObject();
+ const QMetaObject *metaLocalSource = dataCenterLocal->metaObject();
+ QVERIFY(rep1->isInitialized());
+ QVERIFY(rep2->isInitialized());
+ QVERIFY(rep3->isInitialized());
+
+ for (int i = 0; i < metaTcpRep1->propertyCount(); ++i)
+ {
+ const QMetaProperty propLhs = metaTcpRep1->property(i);
+ const QMetaProperty propRhs = metaTcpSource->property(metaTcpSource->indexOfProperty(propLhs.name()));
+ QCOMPARE(propLhs.notifySignalIndex(), propRhs.notifySignalIndex());
+ QCOMPARE(propLhs.read(rep1), propRhs.read(dataCenterTcp.data()));
+ QCOMPARE(propLhs.read(rep2), propRhs.read(rep1));
+ }
+ for (int i = 0; i < metaLocalRep1->propertyCount(); ++i )
+ {
+ const QMetaProperty propLhs = metaLocalRep1->property(i);
+ const QMetaProperty propRhs = metaLocalSource->property(metaTcpSource->indexOfProperty(propLhs.name()));
+ QCOMPARE(propLhs.notifySignalIndex(), propRhs.notifySignalIndex());
+ QCOMPARE(propLhs.read(rep3), propRhs.read(dataCenterLocal.data()));
+ }
+
+ }
+
+private:
+ QScopedPointer<Engine> engine;
+ QScopedPointer<Speedometer> speedometer;
+ QScopedPointer<TcpDataCenterSource> dataCenterTcp;
+ QScopedPointer<LocalDataCenterSource> dataCenterLocal;
+};
+
+QTEST_MAIN(RemoteObjectTest)
+
+#endif
diff --git a/tests/auto/integration/Speedometer.cpp b/tests/auto/integration/Speedometer.cpp
new file mode 100644
index 0000000..50a35af
--- /dev/null
+++ b/tests/auto/integration/Speedometer.cpp
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "Speedometer.h"
+
+Speedometer::Speedometer(QObject *parent) :
+ SpeedometerSource(parent)
+{
+}
+
+Speedometer::~Speedometer()
+{
+}
diff --git a/tests/auto/integration/Speedometer.h b/tests/auto/integration/Speedometer.h
new file mode 100644
index 0000000..71c8645
--- /dev/null
+++ b/tests/auto/integration/Speedometer.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTS_SPEEDOMETER_H
+#define TESTS_SPEEDOMETER_H
+
+#include "rep_speedometer_source.h"
+
+class Speedometer : public SpeedometerSource
+{
+ Q_OBJECT
+public:
+ Speedometer(QObject *parent=Q_NULLPTR);
+ virtual ~Speedometer();
+
+private:
+ int speed;
+};
+
+#endif
diff --git a/tests/auto/integration/engine.rep b/tests/auto/integration/engine.rep
new file mode 100644
index 0000000..4bdba22
--- /dev/null
+++ b/tests/auto/integration/engine.rep
@@ -0,0 +1,5 @@
+#include <QtCore>
+class Engine
+{
+ PROP(int rpm);
+};
diff --git a/tests/auto/integration/integration.pro b/tests/auto/integration/integration.pro
new file mode 100644
index 0000000..977b3f8
--- /dev/null
+++ b/tests/auto/integration/integration.pro
@@ -0,0 +1,24 @@
+QT += network testlib
+
+QT -= gui
+
+OTHER_FILES = engine.rep \
+ speedometer.rep \
+ ../repfiles/localdatacenter.rep \
+ ../repfiles/tcpdatacenter.rep
+
+REPC_SOURCE += $$OTHER_FILES
+REPC_REPLICA += $$OTHER_FILES
+QT += remoteobjects
+
+CONFIG += testcase
+
+HEADERS += $$PWD/RemoteObjectTest.h \
+ $$PWD/Engine.h \
+ $$PWD/Speedometer.h
+
+SOURCES += $$PWD/Engine.cpp \
+ $$PWD/Speedometer.cpp
+
+contains(QT_CONFIG, c++11): CONFIG += c++11
+
diff --git a/tests/auto/integration/speedometer.rep b/tests/auto/integration/speedometer.rep
new file mode 100644
index 0000000..291adb3
--- /dev/null
+++ b/tests/auto/integration/speedometer.rep
@@ -0,0 +1,5 @@
+#include <QtCore>
+class Speedometer
+{
+ PROP(int mph);
+};
diff --git a/tests/auto/repc/pods/.gitignore b/tests/auto/repc/pods/.gitignore
new file mode 100644
index 0000000..ccb20c9
--- /dev/null
+++ b/tests/auto/repc/pods/.gitignore
@@ -0,0 +1 @@
+tst_pods
diff --git a/tests/auto/repc/pods/pods.pro b/tests/auto/repc/pods/pods.pro
new file mode 100644
index 0000000..db7188c
--- /dev/null
+++ b/tests/auto/repc/pods/pods.pro
@@ -0,0 +1,13 @@
+CONFIG += testcase parallel_test
+TARGET = tst_pods
+QT += testlib remoteobjects
+QT -= gui
+
+SOURCES += tst_pods.cpp
+
+REP_FILES = pods.rep
+
+#REPC_SOURCE = $$REP_FILES # can't have both source and replica in the same process if PODs are involved...
+REPC_REPLICA = $$REP_FILES
+
+contains(QT_CONFIG, c++11):CONFIG += c++11
diff --git a/tests/auto/repc/pods/pods.rep b/tests/auto/repc/pods/pods.rep
new file mode 100644
index 0000000..da9a0ca
--- /dev/null
+++ b/tests/auto/repc/pods/pods.rep
@@ -0,0 +1,6 @@
+#include <QString>
+
+POD PodI(int i)
+POD PodF(float f)
+POD PodS(QString s)
+POD PodIFS(int i, float f, QString s)
diff --git a/tests/auto/repc/pods/tst_pods.cpp b/tests/auto/repc/pods/tst_pods.cpp
new file mode 100644
index 0000000..fc3112a
--- /dev/null
+++ b/tests/auto/repc/pods/tst_pods.cpp
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.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 testParent();
+ void testMarshaling();
+};
+
+
+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());
+
+ PodI pi4(static_cast<QObject*>(Q_NULLPTR));
+ QCOMPARE(pi4.i(), 0);
+
+ PodI pi5(1, static_cast<QObject*>(Q_NULLPTR));
+ QCOMPARE(pi5.i(), 1);
+}
+
+void tst_Pods::testParent()
+{
+ PodI pi;
+ QVERIFY(!pi.parent());
+}
+
+void tst_Pods::testMarshaling()
+{
+ QByteArray ba;
+ QDataStream ds(&ba, QIODevice::ReadWrite);
+
+ {
+ PodI i1(1), i2(2), i3(3), iDeadBeef(0xdeadbeef);
+ Q_SET_OBJECT_NAME(i1);
+ Q_SET_OBJECT_NAME(i2);
+ Q_SET_OBJECT_NAME(i3);
+ Q_SET_OBJECT_NAME(iDeadBeef);
+ ds << i1 << i2 << i3 << iDeadBeef;
+ }
+
+ ds.device()->seek(0);
+
+ {
+ PodI i1, i2, i3, iDeadBeef;
+ ds >> i1 >> i2 >> i3 >> iDeadBeef;
+
+ QCOMPARE(i1.objectName(), QLatin1String("i1"));
+ QCOMPARE(i2.objectName(), QLatin1String("i2"));
+ QCOMPARE(i3.objectName(), QLatin1String("i3"));
+ QCOMPARE(iDeadBeef.objectName(), QLatin1String("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/repc/repc.pro b/tests/auto/repc/repc.pro
new file mode 100644
index 0000000..b0bb9e1
--- /dev/null
+++ b/tests/auto/repc/repc.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS += pods
diff --git a/tests/auto/repfiles/localdatacenter.rep b/tests/auto/repfiles/localdatacenter.rep
new file mode 100644
index 0000000..6f0f7c9
--- /dev/null
+++ b/tests/auto/repfiles/localdatacenter.rep
@@ -0,0 +1,8 @@
+#include <QtCore>
+class LocalDataCenter
+{
+ PROP(int data1);
+ PROP(float data2);
+ PROP(QString data3);
+ PROP(QVector<int> data4);
+};
diff --git a/tests/auto/repfiles/tcpdatacenter.rep b/tests/auto/repfiles/tcpdatacenter.rep
new file mode 100644
index 0000000..bfd26c2
--- /dev/null
+++ b/tests/auto/repfiles/tcpdatacenter.rep
@@ -0,0 +1,8 @@
+#include <QtCore>
+class TcpDataCenter
+{
+ PROP(int data1);
+ PROP(float data2);
+ PROP(QString data3);
+ PROP(QVector<int> data4);
+};
diff --git a/tests/tests.pro b/tests/tests.pro
new file mode 100644
index 0000000..568bdf7
--- /dev/null
+++ b/tests/tests.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+CONFIG += debug_and_release
+SUBDIRS = auto
diff --git a/tools/repc/RepCodeGenerator.cpp b/tools/repc/RepCodeGenerator.cpp
new file mode 100644
index 0000000..0dbcb44
--- /dev/null
+++ b/tools/repc/RepCodeGenerator.cpp
@@ -0,0 +1,460 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "RepCodeGenerator.h"
+
+#include "RepParser.h"
+
+#ifndef QT_BOOTSTRAPPED
+# define HAVE_QSAVEFILE
+#endif
+#ifdef HAVE_QSAVEFILE
+# include <QSaveFile>
+#else
+# include <QFile>
+#endif
+#include <QTextStream>
+
+template <typename C>
+static int accumulatedSizeOfNames(const C &c)
+{
+ int result = 0;
+ foreach (const typename C::value_type &e, c)
+ result += e.name.size();
+ return result;
+}
+
+template <typename C>
+static int accumulatedSizeOfTypes(const C &c)
+{
+ int result = 0;
+ foreach (const typename C::value_type &e, c)
+ result += e.type.size();
+ return result;
+}
+
+static QString cap(QString name)
+{
+ if (!name.isEmpty())
+ name[0] = name[0].toUpper();
+ return name;
+}
+
+RepCodeGenerator::RepCodeGenerator(const QString &fileName)
+ : m_fileName(fileName)
+{
+}
+
+bool RepCodeGenerator::generate(const AST &ast, Mode mode)
+{
+#ifdef HAVE_QSAVEFILE
+ QSaveFile file(m_fileName);
+#else
+ QFile file(m_fileName);
+#endif
+ if (!file.open(QIODevice::WriteOnly))
+ return false;
+
+ QTextStream stream(&file);
+
+ QStringList out;
+
+ generateHeader(mode, stream, ast);
+ foreach (const POD &pod, ast.pods)
+ generatePOD(stream, pod);
+ const QString podMetaTypeRegistrationCode = generateMetaTypeRegistrationForPODs(ast.pods);
+ foreach (const ASTClass &astClass, ast.classes)
+ generateClass(mode, out, astClass, podMetaTypeRegistrationCode);
+
+ stream << out.join("\n");
+#ifdef HAVE_QSAVEFILE
+ file.commit();
+#endif
+ return true;
+}
+
+void RepCodeGenerator::generateHeader(Mode mode, QTextStream &out, const AST &ast)
+{
+ out << "// 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 <QObject>\n"
+ "#include <QVariantList>\n"
+ "#include <QMetaProperty>\n"
+ "\n"
+ "#include <QRemoteObjectNode>\n"
+ ;
+ if (mode == REPLICA)
+ out << "#include <qremoteobjectreplica.h>\n";
+ else
+ out << "#include <QRemoteObjectSource>\n";
+ out << "\n";
+
+ out << ast.includes.join(QLatin1Char('\n'));
+ out << "\n";
+}
+
+static QString formatTemplateStringArgTypeNameCapitalizedName(int numberOfTypeOccurrences, int numberOfNameOccurrences,
+ QString templateString, const POD &pod)
+{
+ QString out;
+ const int LengthOfPlaceholderText = 2;
+ Q_ASSERT(templateString.count(QRegExp("%\\d")) == numberOfNameOccurrences + numberOfTypeOccurrences);
+ const int expectedOutSize
+ = numberOfNameOccurrences * accumulatedSizeOfNames(pod.attributes)
+ + numberOfTypeOccurrences * accumulatedSizeOfTypes(pod.attributes)
+ + pod.attributes.size() * (templateString.size() - (numberOfNameOccurrences + numberOfTypeOccurrences) * LengthOfPlaceholderText);
+ out.reserve(expectedOutSize);
+ foreach (const PODAttribute &a, pod.attributes)
+ out += templateString.arg(a.type, a.name, cap(a.name));
+ return out;
+}
+
+QString RepCodeGenerator::formatQPropertyDeclarations(const POD &pod)
+{
+ return formatTemplateStringArgTypeNameCapitalizedName(1, 4, QStringLiteral(" Q_PROPERTY(%1 %2 READ %2 WRITE set%3 NOTIFY on%3Changed)\n"), pod);
+}
+
+QString RepCodeGenerator::formatConstructors(const POD &pod)
+{
+ QString initializerString = QString("QObject(parent)");
+ QString defaultInitializerString = initializerString;
+ QString argString;
+ foreach (const PODAttribute &a, pod.attributes) {
+ initializerString += QString(", _%1(%1)").arg(a.name);
+ defaultInitializerString += QString(", _%1()").arg(a.name);
+ argString += QString("%1 %2, ").arg(a.type, a.name);
+ }
+ argString.chop(2);
+
+ return QString(" explicit %1(QObject *parent = Q_NULLPTR) : %2 {}\n"
+ " explicit %1(%3, QObject *parent = Q_NULLPTR) : %4 {}\n")
+ .arg(pod.name, defaultInitializerString, argString, initializerString);
+}
+
+QString RepCodeGenerator::formatCopyConstructor(const POD &pod)
+{
+ return " " + pod.name + "(const " + pod.name + "& other)\n"
+ " : QObject()\n"
+ " {\n"
+ " QtRemoteObjects::copyStoredProperties(&other, this);\n"
+ " }\n"
+ "\n"
+ ;
+}
+
+QString RepCodeGenerator::formatCopyAssignmentOperator(const POD &pod)
+{
+ return " " + pod.name + " &operator=(const " + pod.name + " &other)\n"
+ " {\n"
+ " if (this != &other)\n"
+ " QtRemoteObjects::copyStoredProperties(&other, this);\n"
+ " return *this;\n"
+ " }\n"
+ "\n"
+ ;
+}
+
+QString RepCodeGenerator::formatPropertyGettersAndSetters(const POD &pod)
+{
+ // MSVC doesn't like adjacent string literal concatenation within QStringLiteral, so keep it in one line:
+ QString templateString
+ = QStringLiteral(" %1 %2() const { return _%2; }\n void set%3(%1 %2) { if (%2 != _%2) { _%2 = %2; Q_EMIT on%3Changed(); } }\n");
+ return formatTemplateStringArgTypeNameCapitalizedName(2, 9, qMove(templateString), pod);
+}
+
+QString RepCodeGenerator::formatSignals(const POD &pod)
+{
+ QString out;
+ const QString prefix = QStringLiteral(" void on");
+ const QString suffix = QStringLiteral("Changed();\n");
+ const int expectedOutSize
+ = accumulatedSizeOfNames(pod.attributes)
+ + pod.attributes.size() * (prefix.size() + suffix.size());
+ out.reserve(expectedOutSize);
+ foreach (const PODAttribute &a, pod.attributes) {
+ out += prefix;
+ out += cap(a.name);
+ out += suffix;
+ }
+ Q_ASSERT(out.size() == expectedOutSize);
+ return out;
+}
+
+QString RepCodeGenerator::formatDataMembers(const POD &pod)
+{
+ QString out;
+ const QString prefix = QStringLiteral(" ");
+ const QString infix = QStringLiteral(" _");
+ const QString suffix = QStringLiteral(";\n");
+ const int expectedOutSize
+ = accumulatedSizeOfNames(pod.attributes)
+ + accumulatedSizeOfTypes(pod.attributes)
+ + pod.attributes.size() * (prefix.size() + infix.size() + suffix.size());
+ out.reserve(expectedOutSize);
+ foreach (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::formatMarshalingOperators(const POD &pod)
+{
+ return "inline QDataStream &operator<<(QDataStream &ds, const " + pod.name + " &obj) {\n"
+ " QtRemoteObjects::copyStoredProperties(&obj, ds);\n"
+ " return ds;\n"
+ "}\n"
+ "\n"
+ "inline QDataStream &operator>>(QDataStream &ds, " + pod.name + " &obj) {\n"
+ " QtRemoteObjects::copyStoredProperties(ds, &obj);\n"
+ " return ds;\n"
+ "}\n"
+ ;
+}
+
+void RepCodeGenerator::generatePOD(QTextStream &out, const POD &pod)
+{
+ out << "class " << pod.name << " : public QObject\n"
+ "{\n"
+ " Q_OBJECT\n"
+ << formatQPropertyDeclarations(pod)
+ << "public:\n"
+ << formatConstructors(pod)
+ << formatCopyConstructor(pod)
+ << formatCopyAssignmentOperator(pod)
+ << formatPropertyGettersAndSetters(pod)
+ << "Q_SIGNALS:\n"
+ << formatSignals(pod)
+ << "private:\n"
+ << formatDataMembers(pod)
+ << "};\n"
+ "\n"
+ << formatMarshalingOperators(pod)
+ << "\n"
+ "Q_DECLARE_METATYPE(" << pod.name << ")\n"
+ "\n"
+ ;
+}
+
+QString RepCodeGenerator::generateMetaTypeRegistrationForPODs(const QVector<POD> &pods)
+{
+ QString out;
+ const QString qRegisterMetaType = QStringLiteral(" qRegisterMetaType<");
+ const QString qRegisterMetaTypeStreamOperators = QStringLiteral(" qRegisterMetaTypeStreamOperators<");
+ const QString lineEnding = QStringLiteral(">();\n");
+ const int expectedOutSize
+ = 2 * accumulatedSizeOfNames(pods)
+ + pods.size() * (qRegisterMetaType.size() + qRegisterMetaTypeStreamOperators.size() + 2 * lineEnding.size());
+ out.reserve(expectedOutSize);
+ foreach (const POD &pod, pods) {
+ out += qRegisterMetaType;
+ out += pod.name;
+ out += lineEnding;
+
+ out += qRegisterMetaTypeStreamOperators;
+ out += pod.name;
+ out += lineEnding;
+ }
+ Q_ASSERT(expectedOutSize == out.size());
+ return out;
+}
+
+void RepCodeGenerator::generateClass(Mode mode, QStringList &out, const ASTClass &astClass, const QString &podMetaTypeRegistrationCode)
+{
+ const QString className = (astClass.name() + (mode == REPLICA ? "Replica" : "Source"));
+ if (mode == REPLICA)
+ out << QString("class %1 : public QRemoteObjectReplica").arg(className);
+ else
+ out << QString("class %1 : public QRemoteObjectSource").arg(className);
+
+ out << "{";
+ out << " Q_OBJECT";
+ out << QString(" Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_TYPE, \"%1\")").arg(astClass.name());
+ out << QString(" friend class QRemoteObjectNode;");
+ if (mode == SOURCE)
+ out <<"public:";
+ else
+ out <<"private:";
+
+ if (mode == REPLICA) {
+ out << QString(" %1() : QRemoteObjectReplica() {}").arg(className);
+ out << QString(" void initialize()");
+ } else {
+ out << QString(" %1(QObject *parent = Q_NULLPTR) : QRemoteObjectSource(parent)").arg(className);
+ }
+
+ out << " {";
+
+ if (!podMetaTypeRegistrationCode.isEmpty())
+ out << podMetaTypeRegistrationCode;
+
+ if (mode == REPLICA) {
+ out << QString(" QVariantList properties;");
+ out << QString(" properties.reserve(%1);").arg(astClass.m_properties.size());
+ foreach (const ASTProperty &property, astClass.m_properties) {
+ out << QString(" properties << QVariant::fromValue(" + property.type() + "(" + property.defaultValue() + "));");
+ }
+ out << QString(" setProperties(properties);");
+ }
+
+ out << " }";
+ out << "public:";
+
+ out << QString(" virtual ~%1() {}").arg(className);
+
+ //First output properties
+ foreach (const ASTProperty &property, astClass.m_properties) {
+ if (property.modifier() == ASTProperty::Constant)
+ out << QString(" Q_PROPERTY(%1 %2 READ %2 CONSTANT)").arg(property.type(), property.name());
+ else
+ out << QString(" Q_PROPERTY(%1 %2 READ %2 WRITE set%3 NOTIFY on%3Changed)").arg(property.type(), property.name(), cap(property.name()));
+ }
+ out << "";
+
+ //Next output getter/setter
+ if (mode == REPLICA) {
+ int i = 0;
+ foreach (const ASTProperty &property, astClass.m_properties) {
+ out << QString(" %1 %2() const").arg(property.type(), property.name());
+ out << QString(" {");
+ out << QString(" return propAsVariant(%1).value<%2>();").arg(i).arg(property.type());
+ out << QString(" }");
+ i++;
+ if (property.modifier() != ASTProperty::Constant) {
+ out << QString("");
+ out << QString(" void set%3(%1 %2)").arg(property.type(), property.name(), cap(property.name()));
+ out << QString(" {");
+ out << QString(" static int index = %1::staticMetaObject.indexOfProperty(\"%2\");").arg(className).arg( property.name());
+ out << QString(" QVariantList args;");
+ out << QString(" args << QVariant::fromValue(%1);").arg(property.name());
+ out << QString(" send(QMetaObject::WriteProperty, index, args);");
+ out << QString(" }");
+ }
+ out << QString("");
+ }
+ }
+ else
+ {
+ foreach (const ASTProperty &property, astClass.m_properties) {
+ out << QString(" %1 %2() const { return _%2;}").arg(property.type(), property.name());
+ }
+ foreach (const ASTProperty &property, astClass.m_properties) {
+ if (property.modifier() != ASTProperty::Constant) {
+ out << QString(" void set%3(%1 %2)").arg(property.type(), property.name(), cap(property.name()));
+ out << QString(" {");
+ out << QString(" if (%1 != _%1)").arg(property.name());
+ out << QString(" {");
+ out << QString(" _%1 = %1;").arg(property.name());
+ out << QString(" Q_EMIT on%1Changed();").arg(cap(property.name()));
+ out << QString(" }");
+ out << QString(" }");
+ }
+ }
+ }
+
+ //Next output property signals
+ out << "";
+ out << "Q_SIGNALS:";
+ foreach (const ASTProperty &property, astClass.m_properties) {
+ if (property.modifier() != ASTProperty::Constant)
+ out << QString(" void on%1Changed();").arg(cap(property.name()));
+ }
+
+ foreach (const QString &signalName, astClass.m_signals)
+ out << QString(" void %1;").arg(signalName);
+
+ if (!astClass.m_slots.isEmpty()) {
+ out << "";
+ out << "public Q_SLOTS:";
+ foreach (const QString &slot, astClass.m_slots) {
+ if (mode == SOURCE) {
+ out << QString(" virtual void %1 = 0;").arg(slot);
+ } else {
+ QRegExp re_slotArgs("\\s*(.*)\\s*\\(\\s*(.*)\\s*\\)");
+ if (re_slotArgs.exactMatch(slot)) {
+ QStringList types, names;
+ const QStringList cap = re_slotArgs.capturedTexts();
+
+ const QString functionString = cap[1].trimmed();
+ const QString argString = cap[2].trimmed();
+
+ if (!argString.isEmpty()) {
+ const QStringList argList = argString.split(',');
+ foreach (QString paramString, argList) {
+ paramString = paramString.trimmed();
+ const QStringList tmp = paramString.split(QRegExp("\\s+"));
+ types << tmp[0];
+ names << tmp[1];
+ }
+ }
+
+ out << QString(" void %1").arg(slot);
+ out << QString(" {");
+ out << QString(" static int index = %1::staticMetaObject.indexOfSlot(\"%2(%3)\");").arg(className).arg(functionString).arg(types.join(", "));
+ out << QString(" QVariantList args;");
+ if (names.length() > 0)
+ out << QString(" args << %1;").arg(names.join(" << "));
+ out << QString(" qDebug() << \"%1::%2\" << index;").arg(className).arg(functionString);
+ out << QString(" send(QMetaObject::InvokeMetaMethod, index, args);");
+ out << QString(" }");
+ }
+ }
+ }
+ }
+
+ //Next output data members
+ out << "";
+ out << "private:";
+ if (mode == SOURCE)
+ {
+ foreach (const ASTProperty &property, astClass.m_properties) {
+ out << QString(" %1 _%2;").arg(property.type(), property.name());
+ }
+ }
+
+ out << "};";
+ out << "";
+}
diff --git a/tools/repc/RepCodeGenerator.h b/tools/repc/RepCodeGenerator.h
new file mode 100644
index 0000000..a63ef93
--- /dev/null
+++ b/tools/repc/RepCodeGenerator.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef REPCODEGENERATOR_H
+#define REPCODEGENERATOR_H
+
+#include <QString>
+
+class AST;
+class ASTClass;
+struct POD;
+
+QT_BEGIN_NAMESPACE
+class QStringList;
+class QTextStream;
+QT_END_NAMESPACE
+
+class RepCodeGenerator
+{
+public:
+ enum Mode
+ {
+ REPLICA,
+ SOURCE
+ };
+
+ explicit RepCodeGenerator(const QString &fileName);
+
+ bool generate(const AST &ast, Mode mode);
+
+private:
+ void generateHeader(Mode mode, QTextStream &out, const AST &ast);
+ QString generateMetaTypeRegistrationForPODs(const QVector<POD> &pods);
+
+ void generatePOD(QTextStream &out, const POD &pod);
+ QString formatQPropertyDeclarations(const POD &pod);
+ QString formatConstructors(const POD &pod);
+ QString formatCopyConstructor(const POD &pod);
+ QString formatCopyAssignmentOperator(const POD &pod);
+ QString formatPropertyGettersAndSetters(const POD &pod);
+ QString formatSignals(const POD &pod);
+ QString formatDataMembers(const POD &pod);
+ QString formatMarshalingOperators(const POD &pod);
+
+ void generateClass(Mode mode, QStringList &out, const ASTClass &astClasses, const QString &podMetaTypeRegistrationCode);
+
+private:
+ QString m_fileName;
+};
+
+#endif
diff --git a/tools/repc/RepParser.cpp b/tools/repc/RepParser.cpp
new file mode 100644
index 0000000..987c133
--- /dev/null
+++ b/tools/repc/RepParser.cpp
@@ -0,0 +1,196 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "RepParser.h"
+
+#include <QFile>
+#include <QTextStream>
+
+ASTProperty::ASTProperty()
+ : m_modifier(ReadWrite)
+{
+}
+
+ASTProperty::ASTProperty(const QString &type, const QString &name, const QString &defaultValue, Modifier modifier)
+ : m_type(type), m_name(name), m_defaultValue(defaultValue), m_modifier(modifier)
+{
+}
+
+QString ASTProperty::type() const
+{
+ return m_type;
+}
+
+QString ASTProperty::name() const
+{
+ return m_name;
+}
+
+QString ASTProperty::defaultValue() const
+{
+ return m_defaultValue;
+}
+
+ASTProperty::Modifier ASTProperty::modifier() const
+{
+ return m_modifier;
+}
+
+
+ASTClass::ASTClass(const QString &name)
+ : m_name(name)
+{
+}
+
+bool ASTClass::isValid() const
+{
+ return !m_name.isEmpty();
+}
+
+QString ASTClass::name() const
+{
+ return m_name;
+}
+
+//grammar
+// R->WHITESPACE
+// WHITESPACE: newlines, whitespaces
+// R->POD
+// R->CLASS DESCR
+// DESCR->WHITESPACE IDENTIFIER CBRACKET
+// DESCR->IDENTIFIER COBRACKET
+// COBRACKET->WHITESPACE CLASSBODY
+// COBRACKET->CLASSBODY
+// CLASSBODY->WHITESPACE PROPERTY SEMICOLON
+// CLASSBODY->PROPERTY SEMICOLON
+// CLASSBODY->WHITESPACE SIGNAL SEMICOLON
+// CLASSBODY->SIGNAL SEMICOLON
+// CLASSBODY->WHITESPACE SLOT SEMICOLON
+// CLASSBODY->SLOT SEMICOLON
+// SEMICOLON->WHITESPACE CLASSBODY
+// SEMICOLON->CLASSBODY
+// SEMICOLON->WHITESPACE CCLOSEBRACKET
+// SEMICOLON->CCLOSEBRACKET
+// CCLOSEBRACKET->; WHITESPACE R
+// CCLOSEBRACKET->; R
+// SLOT->WHITESPACE SLOT
+// SLOT->IDENTIFIER ROPENBRACKET
+// ROPENBRACKET
+
+QRegExp re_class("class\\s*(\\S+)\\s*");
+QRegExp re_pod("POD\\s*(\\S+)\\s*\\(\\s*(.*)\\s*\\);?\\s*");
+QRegExp re_prop("\\s*PROP\\((.+)\\s+([^\\)=]+)(=(.*))?\\);?.*");
+QRegExp re_fixed("\\s*FIXED\\((.+)\\s+([^\\)=]+)(=(.*))?\\);?.*");
+QRegExp re_signal("\\s*SIGNAL\\(\\s*(.*)\\s*\\);?\\s*");
+QRegExp re_slot("\\s*SLOT\\(\\s*(.*)\\s*\\);?\\s*");
+QRegExp re_start("^\\{\\s*");
+QRegExp re_end("^\\};?\\s*");
+
+RepParser::RepParser(const QString &fileName)
+ : m_fileName(fileName)
+{
+}
+
+bool RepParser::parse()
+{
+ // clean up from previous run
+ m_ast.classes.clear();
+ m_ast.pods.clear();
+ m_ast.includes.clear();
+
+ QFile file(m_fileName);
+ if (!file.open(QIODevice::ReadOnly))
+ return false;
+
+ ASTClass astClass;
+
+ QTextStream stream(&file);
+ while (!stream.atEnd()) {
+ const QString line = stream.readLine();
+
+ if (re_class.exactMatch(line)) {
+ // new Class declaration
+ astClass = ASTClass(re_class.capturedTexts()[1]);
+ } else if (re_pod.exactMatch(line)) {
+ POD pod;
+ pod.name = re_pod.capturedTexts()[1];
+
+ const QString argString = re_pod.capturedTexts()[2].trimmed();
+ const QStringList argList = argString.split(",");
+ if (argList.length() == 0)
+ continue;
+
+ foreach (const QString &paramString, argList) {
+ const QStringList tmp = paramString.trimmed().split(QRegExp("\\s+"));
+ PODAttribute attr = { tmp[0], tmp[1] };
+ pod.attributes.append(qMove(attr));
+ }
+
+ m_ast.pods.append(pod);
+ } else if (re_prop.exactMatch(line)) {
+ const QStringList params = re_prop.capturedTexts();
+
+ ASTProperty property(params[1], params[2], (params.length() == 5 ? params[4] : QString()), ASTProperty::ReadWrite);
+ astClass.m_properties << property;
+ } else if (re_fixed.exactMatch(line)) {
+ const QStringList params = re_prop.capturedTexts();
+
+ ASTProperty property(params[1], params[2], (params.length() == 5 ? params[4] : QString()), ASTProperty::Constant);
+ astClass.m_properties << property;
+ } else if (re_signal.exactMatch(line)) {
+ astClass.m_signals << re_signal.capturedTexts()[1];
+ } else if (re_slot.exactMatch(line)) {
+ astClass.m_slots << re_slot.capturedTexts()[1];
+ } else if (re_end.exactMatch(line)) {
+ m_ast.classes.append(astClass);
+ } else if (re_start.exactMatch(line)) {
+ } else {
+ m_ast.includes.append(line);
+ }
+ }
+
+ return true;
+}
+
+AST RepParser::ast() const
+{
+ return m_ast;
+}
diff --git a/tools/repc/RepParser.h b/tools/repc/RepParser.h
new file mode 100644
index 0000000..cf95713
--- /dev/null
+++ b/tools/repc/RepParser.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef REPPARSER_H
+#define REPPARSER_H
+
+#include <QStringList>
+#include <QVector>
+
+// A property of a Class declaration
+class ASTProperty
+{
+public:
+ enum Modifier
+ {
+ Constant,
+ Read,
+ ReadWrite
+ };
+
+ ASTProperty();
+ ASTProperty(const QString &type, const QString &name, const QString &defaultValue, Modifier modifier);
+
+ QString type() const;
+ QString name() const;
+ QString defaultValue() const;
+ Modifier modifier() const;
+
+private:
+ QString m_type;
+ QString m_name;
+ QString m_defaultValue;
+ Modifier m_modifier;
+};
+
+// A Class declaration
+class ASTClass
+{
+public:
+ explicit ASTClass(const QString& name = QString());
+ bool isValid() const;
+ QString name() const;
+
+private:
+ friend class RepParser;
+ friend class RepCodeGenerator;
+
+ QString m_name;
+ QVector<ASTProperty> m_properties;
+ QStringList m_signals;
+ QStringList m_slots;
+
+};
+
+// The attribute of a POD
+struct PODAttribute
+{
+ QString type;
+ QString name;
+};
+Q_DECLARE_TYPEINFO(PODAttribute, Q_MOVABLE_TYPE);
+
+// A POD declaration
+struct POD
+{
+ QString name;
+ QVector<PODAttribute> attributes;
+};
+
+// The AST representation of a .rep file
+class AST
+{
+public:
+ QVector<ASTClass> classes;
+ QVector<POD> pods;
+ QStringList includes;
+};
+
+class RepParser
+{
+public:
+ explicit RepParser(const QString &fileName);
+
+ bool parse();
+
+ AST ast() const;
+
+private:
+ QString m_fileName;
+ AST m_ast;
+};
+
+#endif
diff --git a/tools/repc/main.cpp b/tools/repc/main.cpp
new file mode 100644
index 0000000..9088103
--- /dev/null
+++ b/tools/repc/main.cpp
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+
+#include "RepCodeGenerator.h"
+#include "RepParser.h"
+
+#include <cstdio>
+
+void usage()
+{
+ printf("repc [-s/-r] -i input-file -o output-file\n");
+ printf(" -s outputs the source version from the template\n");
+ printf(" -r outputs the replica version from the template\n");
+ exit(-1);
+}
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+
+ if (app.arguments().size() < 3 || app.arguments().contains("--help"))
+ usage();
+
+ const int idxOfInput = app.arguments().indexOf("-i")+1;
+ const int idxOfOutput = app.arguments().indexOf("-o")+1;
+ if (idxOfInput <= 1 && idxOfOutput <= 1)
+ usage();
+
+ RepCodeGenerator::Mode mode;
+ if (app.arguments().contains("-s"))
+ mode = RepCodeGenerator::SOURCE;
+ else if (app.arguments().contains("-r"))
+ mode = RepCodeGenerator::REPLICA;
+ else
+ usage();
+
+ const QString input = app.arguments().at(idxOfInput);
+ const QString output = app.arguments().at(idxOfOutput);
+
+ RepParser parser(input);
+ if (!parser.parse())
+ return 1;
+
+ RepCodeGenerator generator(output);
+ if (!generator.generate(parser.ast(), mode))
+ return 2;
+
+ return 0;
+}
diff --git a/tools/repc/repc.pro b/tools/repc/repc.pro
new file mode 100644
index 0000000..f290bda
--- /dev/null
+++ b/tools/repc/repc.pro
@@ -0,0 +1,6 @@
+option(host_build)
+
+load(qt_tool)
+
+SOURCES += main.cpp RepParser.cpp RepCodeGenerator.cpp
+HEADERS += RepParser.h RepCodeGenerator.h
diff --git a/tools/tools.pro b/tools/tools.pro
new file mode 100644
index 0000000..509502d
--- /dev/null
+++ b/tools/tools.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS += repc