1 | // Copyright (C) 2017 Ford Motor Company |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qremoteobjectpendingcall.h" |
5 | #include "qremoteobjectpendingcall_p.h" |
6 | |
7 | #include "qremoteobjectreplica_p.h" |
8 | |
9 | #include <QtCore/qcoreapplication.h> |
10 | |
11 | #include <private/qobject_p.h> |
12 | |
13 | QT_BEGIN_NAMESPACE |
14 | |
15 | QT_IMPL_METATYPE_EXTERN(QRemoteObjectPendingCall) |
16 | |
17 | QRemoteObjectPendingCallData::QRemoteObjectPendingCallData(int serialId, QRemoteObjectReplicaImplementation *replica) |
18 | : replica(replica) |
19 | , serialId(serialId) |
20 | , error(QRemoteObjectPendingCall::InvalidMessage) |
21 | , watcherHelper(nullptr) |
22 | { |
23 | } |
24 | |
25 | QRemoteObjectPendingCallData::~QRemoteObjectPendingCallData() |
26 | { |
27 | } |
28 | |
29 | void QRemoteObjectPendingCallWatcherHelper::add(QRemoteObjectPendingCallWatcher *watcher) |
30 | { |
31 | connect(sender: this, signal: &QRemoteObjectPendingCallWatcherHelper::finished, context: watcher, slot: [watcher]() { |
32 | emit watcher->finished(self: watcher); |
33 | }, type: Qt::QueuedConnection); |
34 | } |
35 | |
36 | void QRemoteObjectPendingCallWatcherHelper::emitSignals() |
37 | { |
38 | emit finished(); |
39 | } |
40 | |
41 | /*! |
42 | \class QRemoteObjectPendingCall |
43 | \inmodule QtRemoteObjects |
44 | \brief Encapsulates the result of an asynchronous method call. |
45 | */ |
46 | |
47 | QRemoteObjectPendingCall::QRemoteObjectPendingCall() |
48 | : d(new QRemoteObjectPendingCallData) |
49 | { |
50 | } |
51 | |
52 | QRemoteObjectPendingCall::~QRemoteObjectPendingCall() |
53 | { |
54 | } |
55 | |
56 | QRemoteObjectPendingCall::QRemoteObjectPendingCall(const QRemoteObjectPendingCall& other) |
57 | : d(other.d) |
58 | { |
59 | } |
60 | |
61 | QRemoteObjectPendingCall::QRemoteObjectPendingCall(QRemoteObjectPendingCallData *dd) |
62 | : d(dd) |
63 | { |
64 | } |
65 | |
66 | QRemoteObjectPendingCall &QRemoteObjectPendingCall::operator=(const QRemoteObjectPendingCall &other) |
67 | { |
68 | d = other.d; |
69 | return *this; |
70 | } |
71 | |
72 | /*! |
73 | Returns the return value of the remote call. |
74 | |
75 | returnValue will only be valid when the remote call has finished and there |
76 | are no \l {error}s. |
77 | */ |
78 | QVariant QRemoteObjectPendingCall::returnValue() const |
79 | { |
80 | if (!d) |
81 | return QVariant(); |
82 | |
83 | QMutexLocker locker(&d->mutex); |
84 | return d->returnValue; |
85 | } |
86 | |
87 | /*! |
88 | \enum QRemoteObjectPendingCall::Error |
89 | |
90 | This enum type specifies the possible error values for a remote call: |
91 | |
92 | \value NoError |
93 | No error occurred. |
94 | \value InvalidMessage |
95 | The default error state prior to the remote call finishing. |
96 | */ |
97 | |
98 | /*! |
99 | Returns the error, if any, from the remote call. |
100 | */ |
101 | QRemoteObjectPendingCall::Error QRemoteObjectPendingCall::error() const |
102 | { |
103 | if (!d) |
104 | return QRemoteObjectPendingCall::InvalidMessage; |
105 | |
106 | QMutexLocker locker(&d->mutex); |
107 | return d->error; |
108 | } |
109 | |
110 | /*! |
111 | Returns true if the remote call has finished, false otherwise. |
112 | |
113 | A finished call will include a returnValue or \l error. |
114 | */ |
115 | bool QRemoteObjectPendingCall::isFinished() const |
116 | { |
117 | if (!d) |
118 | return true; // considered finished |
119 | |
120 | QMutexLocker locker(&d->mutex); |
121 | return d->error != InvalidMessage; |
122 | } |
123 | |
124 | /*! |
125 | Blocks for up to \a timeout milliseconds, until the remote call has finished. |
126 | |
127 | Returns \c true on success, \c false otherwise. |
128 | */ |
129 | bool QRemoteObjectPendingCall::waitForFinished(int timeout) |
130 | { |
131 | if (!d) |
132 | return false; |
133 | |
134 | if (d->error != QRemoteObjectPendingCall::InvalidMessage) |
135 | return true; // already finished |
136 | |
137 | QMutexLocker locker(&d->mutex); |
138 | if (!d->replica) |
139 | return false; |
140 | |
141 | return d->replica->waitForFinished(*this, timeout); |
142 | } |
143 | |
144 | QRemoteObjectPendingCall QRemoteObjectPendingCall::fromCompletedCall(const QVariant &returnValue) |
145 | { |
146 | QRemoteObjectPendingCallData *data = new QRemoteObjectPendingCallData; |
147 | data->returnValue = returnValue; |
148 | data->error = NoError; |
149 | return QRemoteObjectPendingCall(data); |
150 | } |
151 | |
152 | class QRemoteObjectPendingCallWatcherPrivate: public QObjectPrivate |
153 | { |
154 | public: |
155 | Q_DECLARE_PUBLIC(QRemoteObjectPendingCallWatcher) |
156 | }; |
157 | |
158 | /*! |
159 | \class QRemoteObjectPendingCallWatcher |
160 | \inmodule QtRemoteObjects |
161 | \brief Provides a QObject-based API for watching a QRemoteObjectPendingCall. |
162 | |
163 | QRemoteObjectPendingCallWatcher provides a signal indicating when a QRemoteObjectPendingCall |
164 | has finished, allowing for convenient, non-blocking handling of the call. |
165 | */ |
166 | |
167 | QRemoteObjectPendingCallWatcher::QRemoteObjectPendingCallWatcher(const QRemoteObjectPendingCall &call, QObject *parent) |
168 | : QObject(*new QRemoteObjectPendingCallWatcherPrivate, parent) |
169 | , QRemoteObjectPendingCall(call) |
170 | { |
171 | if (d) { |
172 | QMutexLocker locker(&d->mutex); |
173 | if (!d->watcherHelper) { |
174 | d->watcherHelper.reset(other: new QRemoteObjectPendingCallWatcherHelper); |
175 | if (d->error != QRemoteObjectPendingCall::InvalidMessage) { |
176 | // cause a signal emission anyways |
177 | QMetaObject::invokeMethod(obj: d->watcherHelper.data(), member: "finished" , c: Qt::QueuedConnection); |
178 | } |
179 | } |
180 | d->watcherHelper->add(watcher: this); |
181 | } |
182 | } |
183 | |
184 | QRemoteObjectPendingCallWatcher::~QRemoteObjectPendingCallWatcher() |
185 | { |
186 | } |
187 | |
188 | /*! |
189 | Returns true if the remote call has finished, false otherwise. |
190 | |
191 | A finished call will include a returnValue or error. |
192 | */ |
193 | bool QRemoteObjectPendingCallWatcher::isFinished() const |
194 | { |
195 | if (!d) |
196 | return true; // considered finished |
197 | |
198 | QMutexLocker locker(&d->mutex); |
199 | return d->error != QRemoteObjectPendingCall::InvalidMessage; |
200 | } |
201 | |
202 | /*! |
203 | Blocks until the remote call has finished. |
204 | */ |
205 | void QRemoteObjectPendingCallWatcher::waitForFinished() |
206 | { |
207 | if (d) { |
208 | QRemoteObjectPendingCall::waitForFinished(); |
209 | |
210 | // our signals were queued, so deliver them |
211 | QCoreApplication::sendPostedEvents(receiver: d->watcherHelper.data(), event_type: QEvent::MetaCall); |
212 | QCoreApplication::sendPostedEvents(receiver: this, event_type: QEvent::MetaCall); |
213 | } |
214 | } |
215 | |
216 | /*! |
217 | \fn QRemoteObjectPendingCallWatcher::finished(QRemoteObjectPendingCallWatcher *self) |
218 | |
219 | This signal is emitted when the remote call has finished. \a self is the pointer to |
220 | the watcher object that emitted the signal. A finished call will include a |
221 | returnValue or error. |
222 | */ |
223 | |
224 | /*! |
225 | \class QRemoteObjectPendingReply |
226 | \inmodule QtRemoteObjects |
227 | \brief A templated version of QRemoteObjectPendingCall. |
228 | */ |
229 | |
230 | /*! \fn template <typename T> T QRemoteObjectPendingReply<T>::returnValue() const |
231 | |
232 | Returns a strongly typed version of the return value of the remote call. |
233 | */ |
234 | |
235 | QT_END_NAMESPACE |
236 | |
237 | #include "moc_qremoteobjectpendingcall.cpp" |
238 | |