// Copyright (C) 2017 Ford Motor Company // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qremoteobjectpendingcall.h" #include "qremoteobjectpendingcall_p.h" #include "qremoteobjectreplica_p.h" #include #include QT_BEGIN_NAMESPACE QT_IMPL_METATYPE_EXTERN(QRemoteObjectPendingCall) QRemoteObjectPendingCallData::QRemoteObjectPendingCallData(int serialId, QRemoteObjectReplicaImplementation *replica) : replica(replica) , serialId(serialId) , error(QRemoteObjectPendingCall::InvalidMessage) , watcherHelper(nullptr) { } QRemoteObjectPendingCallData::~QRemoteObjectPendingCallData() { } void QRemoteObjectPendingCallWatcherHelper::add(QRemoteObjectPendingCallWatcher *watcher) { connect(this, &QRemoteObjectPendingCallWatcherHelper::finished, watcher, [watcher]() { emit watcher->finished(watcher); }, Qt::QueuedConnection); } void QRemoteObjectPendingCallWatcherHelper::emitSignals() { emit finished(); } /*! \class QRemoteObjectPendingCall \inmodule QtRemoteObjects \brief Encapsulates the result of an asynchronous method call. */ QRemoteObjectPendingCall::QRemoteObjectPendingCall() : d(new QRemoteObjectPendingCallData) { } QRemoteObjectPendingCall::~QRemoteObjectPendingCall() { } QRemoteObjectPendingCall::QRemoteObjectPendingCall(const QRemoteObjectPendingCall& other) : d(other.d) { } QRemoteObjectPendingCall::QRemoteObjectPendingCall(QRemoteObjectPendingCallData *dd) : d(dd) { } QRemoteObjectPendingCall &QRemoteObjectPendingCall::operator=(const QRemoteObjectPendingCall &other) { d = other.d; return *this; } /*! Returns the return value of the remote call. returnValue will only be valid when the remote call has finished and there are no \l {error}s. */ QVariant QRemoteObjectPendingCall::returnValue() const { if (!d) return QVariant(); QMutexLocker locker(&d->mutex); return d->returnValue; } /*! \enum QRemoteObjectPendingCall::Error This enum type specifies the possible error values for a remote call: \value NoError No error occurred. \value InvalidMessage The default error state prior to the remote call finishing. */ /*! Returns the error, if any, from the remote call. */ QRemoteObjectPendingCall::Error QRemoteObjectPendingCall::error() const { if (!d) return QRemoteObjectPendingCall::InvalidMessage; QMutexLocker locker(&d->mutex); return d->error; } /*! Returns true if the remote call has finished, false otherwise. A finished call will include a returnValue or \l error. */ bool QRemoteObjectPendingCall::isFinished() const { if (!d) return true; // considered finished QMutexLocker locker(&d->mutex); return d->error != InvalidMessage; } /*! Blocks for up to \a timeout milliseconds, until the remote call has finished. Returns \c true on success, \c false otherwise. */ bool QRemoteObjectPendingCall::waitForFinished(int timeout) { if (!d) return false; if (d->error != QRemoteObjectPendingCall::InvalidMessage) return true; // already finished QMutexLocker locker(&d->mutex); if (!d->replica) return false; return d->replica->waitForFinished(*this, timeout); } QRemoteObjectPendingCall QRemoteObjectPendingCall::fromCompletedCall(const QVariant &returnValue) { QRemoteObjectPendingCallData *data = new QRemoteObjectPendingCallData; data->returnValue = returnValue; data->error = NoError; return QRemoteObjectPendingCall(data); } class QRemoteObjectPendingCallWatcherPrivate: public QObjectPrivate { public: Q_DECLARE_PUBLIC(QRemoteObjectPendingCallWatcher) }; /*! \class QRemoteObjectPendingCallWatcher \inmodule QtRemoteObjects \brief Provides a QObject-based API for watching a QRemoteObjectPendingCall. QRemoteObjectPendingCallWatcher provides a signal indicating when a QRemoteObjectPendingCall has finished, allowing for convenient, non-blocking handling of the call. */ QRemoteObjectPendingCallWatcher::QRemoteObjectPendingCallWatcher(const QRemoteObjectPendingCall &call, QObject *parent) : QObject(*new QRemoteObjectPendingCallWatcherPrivate, parent) , QRemoteObjectPendingCall(call) { if (d) { QMutexLocker locker(&d->mutex); if (!d->watcherHelper) { d->watcherHelper.reset(new QRemoteObjectPendingCallWatcherHelper); if (d->error != QRemoteObjectPendingCall::InvalidMessage) { // cause a signal emission anyways QMetaObject::invokeMethod(d->watcherHelper.data(), "finished", Qt::QueuedConnection); } } d->watcherHelper->add(this); } } QRemoteObjectPendingCallWatcher::~QRemoteObjectPendingCallWatcher() { } /*! Returns true if the remote call has finished, false otherwise. A finished call will include a returnValue or error. */ bool QRemoteObjectPendingCallWatcher::isFinished() const { if (!d) return true; // considered finished QMutexLocker locker(&d->mutex); return d->error != QRemoteObjectPendingCall::InvalidMessage; } /*! Blocks until the remote call has finished. */ void QRemoteObjectPendingCallWatcher::waitForFinished() { if (d) { QRemoteObjectPendingCall::waitForFinished(); // our signals were queued, so deliver them QCoreApplication::sendPostedEvents(d->watcherHelper.data(), QEvent::MetaCall); QCoreApplication::sendPostedEvents(this, QEvent::MetaCall); } } /*! \fn QRemoteObjectPendingCallWatcher::finished(QRemoteObjectPendingCallWatcher *self) This signal is emitted when the remote call has finished. \a self is the pointer to the watcher object that emitted the signal. A finished call will include a returnValue or error. */ /*! \class QRemoteObjectPendingReply \inmodule QtRemoteObjects \brief A templated version of QRemoteObjectPendingCall. */ /*! \fn template T QRemoteObjectPendingReply::returnValue() const Returns a strongly typed version of the return value of the remote call. */ QT_END_NAMESPACE #include "moc_qremoteobjectpendingcall.cpp"