summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
32 files changed, 4908 insertions, 0 deletions
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