summaryrefslogtreecommitdiffstats
path: root/src/remoteobjects/qremoteobjectpendingcall.cpp
diff options
context:
space:
mode:
authorKevin Funk <kevin.funk.ford@kdab.com>2014-11-12 14:16:21 +0100
committerKevin Funk <kevin.funk@kdab.com>2014-11-20 17:59:55 +0100
commitf4b78bd7dc409ecdf6b4e7014bb376e60eb958a7 (patch)
treef85af0a28847d7130277a9cdd46efd5a14f25f67 /src/remoteobjects/qremoteobjectpendingcall.cpp
parentad4612ff9885dc5a790fc31b6f6f5bd0ab958e15 (diff)
Implement QRemoteObjectPending{Call, Reply}
This patch introduces the following classes in QTRO: * QRemoteObjectPendingCall (let's call it ROPC) * template<typename T> QRemoteObjectPendingReply (based on ROPC) * QRemoteObjectPendingCallWatcher (QObject, based on ROPC) This works for both in-process and connected versions replicas. Also works with dynamic replicas. Note that these classes' design is loosely copied from QtDBus's API. (They also have a 'pending call', and watchers.) Usage: QRemoteObjectPendingReply<bool> reply = engine_r->start(); QCOMPARE(reply.error(), QRemoteObjectPendingCall::InvalidMessage); reply.waitForFinished(); QVERIFY(reply.isFinished()); QCOMPARE(reply.returnValue(), true); TODO: * Error handling (i.e. what to do with invocations where we never get a reply for?) Change-Id: I9d2556b3fcd47a3804c1ada5db526b78c311c0a1 Reviewed-by: Brett Stottlemyer <bstottle@ford.com> Reviewed-by: Björn Breitmeyer <bjoern.breitmeyer@kdab.com>
Diffstat (limited to 'src/remoteobjects/qremoteobjectpendingcall.cpp')
-rw-r--r--src/remoteobjects/qremoteobjectpendingcall.cpp208
1 files changed, 208 insertions, 0 deletions
diff --git a/src/remoteobjects/qremoteobjectpendingcall.cpp b/src/remoteobjects/qremoteobjectpendingcall.cpp
new file mode 100644
index 0000000..1676d08
--- /dev/null
+++ b/src/remoteobjects/qremoteobjectpendingcall.cpp
@@ -0,0 +1,208 @@
+/****************************************************************************
+**
+** 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 "qremoteobjectpendingcall.h"
+#include "qremoteobjectpendingcall_p.h"
+
+#include "qremoteobjectreplica_p.h"
+
+#include <QCoreApplication>
+#include <QDebug>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QRemoteObjectPendingCallData::QRemoteObjectPendingCallData(int serialId, QRemoteObjectReplicaPrivate *replica)
+ : replica(replica)
+ , serialId(serialId)
+ , error(QRemoteObjectPendingCall::InvalidMessage)
+ , watcherHelper(Q_NULLPTR)
+{
+}
+
+QRemoteObjectPendingCallData::~QRemoteObjectPendingCallData()
+{
+}
+
+void QRemoteObjectPendingCallWatcherHelper::add(QRemoteObjectPendingCallWatcher *watcher)
+{
+ connect(this, SIGNAL(finished()), watcher, SLOT(_q_finished()), Qt::QueuedConnection);
+}
+
+void QRemoteObjectPendingCallWatcherHelper::emitSignals()
+{
+ emit finished();
+}
+
+QRemoteObjectPendingCall::QRemoteObjectPendingCall()
+ : d(new QRemoteObjectPendingCallData)
+{
+}
+
+QRemoteObjectPendingCall::~QRemoteObjectPendingCall()
+{
+}
+
+QRemoteObjectPendingCall::QRemoteObjectPendingCall(const QRemoteObjectPendingCall& other)
+ : d(other.d)
+{
+}
+
+QRemoteObjectPendingCall::QRemoteObjectPendingCall(QRemoteObjectPendingCallData *dd)
+ : d(dd)
+{
+}
+
+QRemoteObjectPendingCall &QRemoteObjectPendingCall::operator=(const QRemoteObjectPendingCall &other)
+{
+ d = other.d;
+ return *this;
+}
+
+QVariant QRemoteObjectPendingCall::returnValue() const
+{
+ if (!d)
+ return QVariant();
+
+ QMutexLocker locker(&d->mutex);
+ return d->returnValue;
+}
+
+QRemoteObjectPendingCall::Error QRemoteObjectPendingCall::error() const
+{
+ if (!d)
+ return QRemoteObjectPendingCall::InvalidMessage;
+
+ QMutexLocker locker(&d->mutex);
+ return d->error;
+}
+
+bool QRemoteObjectPendingCall::isFinished() const
+{
+ if (!d)
+ return true; // considered finished
+
+ QMutexLocker locker(&d->mutex);
+ return d->error != InvalidMessage;
+}
+
+bool QRemoteObjectPendingCall::waitForFinished(int timeout)
+{
+ if (!d)
+ return false;
+
+ if (d->error != QRemoteObjectPendingCall::InvalidMessage)
+ return true; // already finished
+
+ QMutexLocker locker(&d->mutex);
+ if (!d->replica)
+ return false;
+
+ return d->replica->waitForFinished(*this, timeout);
+}
+
+QRemoteObjectPendingCall QRemoteObjectPendingCall::fromCompletedCall(const QVariant &returnValue)
+{
+ QRemoteObjectPendingCallData *data = new QRemoteObjectPendingCallData;
+ data->returnValue = returnValue;
+ data->error = NoError;
+ return QRemoteObjectPendingCall(data);
+}
+
+class QRemoteObjectPendingCallWatcherPrivate: public QObjectPrivate
+{
+public:
+ void _q_finished();
+
+ Q_DECLARE_PUBLIC(QRemoteObjectPendingCallWatcher)
+};
+
+inline void QRemoteObjectPendingCallWatcherPrivate::_q_finished()
+{
+ Q_Q(QRemoteObjectPendingCallWatcher);
+ emit q->finished(q);
+}
+
+QRemoteObjectPendingCallWatcher::QRemoteObjectPendingCallWatcher(const QRemoteObjectPendingCall &call, QObject *parent)
+ : QObject(*new QRemoteObjectPendingCallWatcherPrivate, parent)
+ , QRemoteObjectPendingCall(call)
+{
+ if (d) {
+ QMutexLocker locker(&d->mutex);
+ if (!d->watcherHelper) {
+ d->watcherHelper.reset(new QRemoteObjectPendingCallWatcherHelper);
+ if (d->error != QRemoteObjectPendingCall::InvalidMessage) {
+ // cause a signal emission anyways
+ QMetaObject::invokeMethod(d->watcherHelper.data(), "finished", Qt::QueuedConnection);
+ }
+ }
+ d->watcherHelper->add(this);
+ }
+}
+
+QRemoteObjectPendingCallWatcher::~QRemoteObjectPendingCallWatcher()
+{
+}
+
+bool QRemoteObjectPendingCallWatcher::isFinished() const
+{
+ if (!d)
+ return true; // considered finished
+
+ QMutexLocker locker(&d->mutex);
+ return d->error != QRemoteObjectPendingCall::InvalidMessage;
+}
+
+void QRemoteObjectPendingCallWatcher::waitForFinished()
+{
+ if (d) {
+ QRemoteObjectPendingCall::waitForFinished();
+
+ // our signals were queued, so deliver them
+ QCoreApplication::sendPostedEvents(d->watcherHelper.data(), QEvent::MetaCall);
+ QCoreApplication::sendPostedEvents(this, QEvent::MetaCall);
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qremoteobjectpendingcall.cpp"