diff options
author | Kevin Funk <kevin.funk.ford@kdab.com> | 2014-11-12 14:16:21 +0100 |
---|---|---|
committer | Kevin Funk <kevin.funk@kdab.com> | 2014-11-20 17:59:55 +0100 |
commit | f4b78bd7dc409ecdf6b4e7014bb376e60eb958a7 (patch) | |
tree | f85af0a28847d7130277a9cdd46efd5a14f25f67 /src/remoteobjects/qremoteobjectpendingcall.cpp | |
parent | ad4612ff9885dc5a790fc31b6f6f5bd0ab958e15 (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.cpp | 208 |
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" |