1/****************************************************************************
2**
3** Copyright (C) 2015 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the QtContacts module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL21$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 or version 3 as published by the Free
20** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22** following information to ensure the GNU Lesser General Public License
23** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25**
26** As a special exception, The Qt Company gives you certain additional
27** rights. These rights are described in The Qt Company LGPL Exception
28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29**
30** $QT_END_LICENSE$
31**
32****************************************************************************/
33
34#include "qcontactabstractrequest.h"
35#include "qcontactabstractrequest_p.h"
36
37#ifndef QT_NO_DEBUG_STREAM
38#include <QtCore/qdebug.h>
39#endif
40
41#include "qcontactmanager_p.h"
42#include "qcontactmanagerengine.h"
43
44QT_BEGIN_NAMESPACE_CONTACTS
45/*!
46 \class QContactAbstractRequest
47
48 \brief The QContactAbstractRequest class provides a mechanism for
49 asynchronous requests to be made of a manager if it supports them.
50
51 \inmodule QtContacts
52
53 \ingroup contacts-main
54
55 It allows a client to asynchronously request some functionality of a
56 particular QContactManager. Instances of the class will emit signals
57 when the state of the request changes, or when more results become
58 available.
59
60 Clients should not attempt to create instances of this class directly,
61 but should instead use the use-case-specific classes derived from this
62 class.
63
64 All such request classes have a similar interface: clients set the
65 parameters of the asynchronous call, including which manager the
66 request will be made of, and then call the start() slot of the request.
67 The manager will then enqueue or begin to process the request, at which
68 point the request's state will transition from \c InactiveState to
69 \c ActiveState. After any state transition, the request will emit the
70 stateChanged() signal. The manager may periodically update the request
71 with results, at which point the request will emit the resultsAvailable()
72 signal. These results are not guaranteed to have a stable ordering.
73 Error information is considered a result, so some requests will emit the
74 resultsAvailable() signal even if no results are possible from the request
75 (for example, a contact remove request) when the manager updates the request
76 with information about any errors which may have occurred.
77
78 Please see the class documentation of each of the use-case-specific
79 classes derived from this class for information about how to retrieve
80 the results of a request (including error information). In all cases,
81 those functions are synchronous, and will return the cached result set with
82 which the manager has updated the request instance if the resultsAvailable()
83 signal has been emitted.
84
85 Clients can choose which signals they wish to handle from a request.
86 If the client is not interested in interim results, they can choose to
87 handle only the stateChanged() signal, and in the slot to which that
88 signal is connected, check whether the state has changed to either
89 \c FinishedState or \c CanceledState (both of which signify that the
90 manager has finished handling the request, and that the request will not
91 be updated with any more results). If the client is not interested in
92 any results (including error information), they may choose to delete
93 the request after calling \l start(), or simply not connect the
94 request's signals to any slots.
95
96 If the request is allocated via operator new, the client must
97 delete the request when they are no longer using it in order to avoid
98 leaking memory. That is, the client retains ownership of the request.
99
100 The client may delete a heap-allocated request in various ways:
101 by deleting it directly (but not within a slot connected to a signal
102 emitted by the request), or by using the deleteLater() slot to schedule
103 the request for deletion when control returns to the event loop (from
104 within a slot connected to a signal emitted by the request, for example
105 \l stateChanged()).
106
107 An active request may be deleted by the client, but the client will not
108 receive any notifications about whether the request succeeded or not,
109 nor any results of the request.
110
111 Because clients retain ownership of any request object, and may delete
112 a request object at any time, manager engine implementors must be careful
113 to ensure that they do not assume that a request has not been deleted
114 at some point during processing of a request, particularly if the engine
115 has a multithreaded implementation. It is suggested that engine
116 implementors read the \l{Qt Contacts Manager Engines} documentation for
117 more information on this topic.
118 */
119
120/*!
121 \fn QContactAbstractRequest::stateChanged(QContactAbstractRequest::State newState)
122 This signal is emitted when the state of the request is changed. The new state of
123 the request will be contained in \a newState.
124 */
125
126
127/*!
128 \fn QContactAbstractRequest::resultsAvailable()
129 This signal is emitted when new results are available. Results can include
130 the operation error which may be accessed via error(), or derived-class-specific
131 results which are accessible through the derived class API.
132
133
134 \sa error()
135 */
136
137/*!
138 \enum QContactAbstractRequest::RequestType
139 Enumerates the various possible types of asynchronous requests
140 \value InvalidRequest An invalid request
141 \value ContactFetchRequest A request to fetch a list of contacts
142 \value ContactIdFetchRequest A request to fetch a list of contact ids
143 \value ContactRemoveRequest A request to remove a list of contacts
144 \value ContactSaveRequest A request to save a list of contacts
145 \value RelationshipFetchRequest A request to fetch relationships between contacts
146 \value RelationshipRemoveRequest A request to remove any relationships which match the request criteria
147 \value RelationshipSaveRequest A request to save a list of relationships
148 \value ContactFetchByIdRequest A request to fetch a list of contacts given a list of ids
149 */
150
151/*!
152 \enum QContactAbstractRequest::State
153 Enumerates the various states that a request may be in at any given time
154 \value InactiveState Operation not yet started
155 \value ActiveState Operation started, not yet finished
156 \value CanceledState Operation is finished due to cancellation
157 \value FinishedState Operation successfully completed
158 */
159
160/*!
161 \fn QContactAbstractRequest::QContactAbstractRequest(QObject* parent)
162 Constructs a new, invalid asynchronous request with the specified \a parent
163 */
164
165/*!
166 \internal
167 Constructs a new request from the given request data \a otherd with
168 the given parent \a parent
169*/
170QContactAbstractRequest::QContactAbstractRequest(QContactAbstractRequestPrivate* otherd, QObject* parent)
171 : QObject(parent), d_ptr(otherd)
172{
173}
174
175/*! Cleans up the memory used by this request */
176QContactAbstractRequest::~QContactAbstractRequest()
177{
178 d_ptr->m_mutex.lock();
179 QContactManagerEngine *engine = QContactManagerData::engine(manager: d_ptr->m_manager);
180 d_ptr->m_mutex.unlock();
181 if (engine)
182 engine->requestDestroyed(req: this);
183
184 delete d_ptr;
185 d_ptr = 0;
186}
187
188/*!
189 \fn bool QContactAbstractRequest::isInactive() const
190
191 Returns true if the request is in the \l QContactAbstractRequest::InactiveState state;
192 returns false otherwise.
193
194 \sa state(), isActive(), isCanceled(), isFinished()
195*/
196
197/*!
198 \fn bool QContactAbstractRequest::isActive() const
199
200 Returns true if the request is in the \l QContactAbstractRequest::ActiveState state;
201 returns false otherwise.
202
203 \sa state(), isInactive(), isCanceled(), isFinished()
204*/
205
206/*!
207 \fn bool QContactAbstractRequest::isFinished() const
208
209 Returns true if the request is in the \l QContactAbstractRequest::FinishedState;
210 returns false otherwise.
211
212 \sa state(), isActive(), isInactive(), isCanceled()
213*/
214
215/*!
216 \fn bool QContactAbstractRequest::isCanceled() const
217
218 Returns true if the request is in the \l QContactAbstractRequest::CanceledState;
219 returns false otherwise.
220
221 \sa state(), isActive(), isInactive(), isFinished()
222*/
223
224/*! Returns the overall error of the most recent asynchronous operation
225*/
226QContactManager::Error QContactAbstractRequest::error() const
227{
228 QMutexLocker ml(&d_ptr->m_mutex);
229 return d_ptr->m_error;
230}
231
232/*!
233 Returns the type of this asynchronous request
234 */
235QContactAbstractRequest::RequestType QContactAbstractRequest::type() const
236{
237 return d_ptr->m_type;
238}
239
240/*!
241 Returns the current state of the request.
242 */
243QContactAbstractRequest::State QContactAbstractRequest::state() const
244{
245 QMutexLocker ml(&d_ptr->m_mutex);
246 return d_ptr->m_state;
247}
248
249/*! Returns a pointer to the manager of which this request instance requests operations
250*/
251QContactManager* QContactAbstractRequest::manager() const
252{
253 QMutexLocker ml(&d_ptr->m_mutex);
254 return d_ptr->m_manager;
255}
256
257/*!
258 Sets the manager of which this request instance requests operations to \a manager
259
260 If the request is currently active, this function will return without updating the \a manager object.
261*/
262void QContactAbstractRequest::setManager(QContactManager* manager)
263{
264 QMutexLocker ml(&d_ptr->m_mutex);
265 // In theory we might have been active and the manager didn't cancel/finish us
266 if (d_ptr->m_state == QContactAbstractRequest::ActiveState && d_ptr->m_manager)
267 return;
268 d_ptr->m_manager = manager;
269}
270
271/*! Attempts to start the request. Returns false if the request is not in the \c QContactAbstractRequest::Inactive, \c QContactAbstractRequest::Finished or \c QContactAbstractRequest::Cancelled states,
272 or if the request was unable to be performed by the manager engine; otherwise returns true.
273*/
274bool QContactAbstractRequest::start()
275{
276 QMutexLocker ml(&d_ptr->m_mutex);
277 QContactManagerEngine* engine = QContactManagerData::engine(manager: d_ptr->m_manager);
278 if (engine && (d_ptr->m_state == QContactAbstractRequest::CanceledState
279 || d_ptr->m_state == QContactAbstractRequest::FinishedState
280 || d_ptr->m_state == QContactAbstractRequest::InactiveState)) {
281 ml.unlock();
282 return engine->startRequest(req: this);
283 }
284
285 return false; // unable to start operation; another operation already in progress or no engine.
286}
287
288/*! Attempts to cancel the request. Returns false if the request is not in the \c QContactAbstractRequest::Active state,
289 or if the request is unable to be cancelled by the manager engine; otherwise returns true.
290*/
291bool QContactAbstractRequest::cancel()
292{
293 QMutexLocker ml(&d_ptr->m_mutex);
294 QContactManagerEngine* engine = QContactManagerData::engine(manager: d_ptr->m_manager);
295 if (engine && d_ptr->m_state == QContactAbstractRequest::ActiveState) {
296 ml.unlock();
297 return engine->cancelRequest(req: this);
298 }
299
300 return false; // unable to cancel operation; not in progress or no engine.
301}
302
303/*! Blocks until the request has been completed by the manager engine, or until \a msecs milliseconds has elapsed.
304 If \a msecs is zero or negative, this function will block until the request is complete, regardless of how long it takes.
305 Returns true if the request was cancelled or completed successfully within the given period, otherwise false.
306 Some backends are unable to support this operation safely, and will return false immediately.
307
308 Note that any signals generated while waiting for the request to complete may be queued and delivered
309 some time after this function has returned, when the calling thread's event loop is dispatched. If your code
310 depends on your slots being invoked, you may need to process events after calling this function.
311 */
312bool QContactAbstractRequest::waitForFinished(int msecs)
313{
314 QMutexLocker ml(&d_ptr->m_mutex);
315 QContactManagerEngine* engine = QContactManagerData::engine(manager: d_ptr->m_manager);
316 if (engine) {
317 switch (d_ptr->m_state) {
318 case QContactAbstractRequest::ActiveState:
319 ml.unlock();
320 return engine->waitForRequestFinished(req: this, msecs);
321 case QContactAbstractRequest::CanceledState:
322 case QContactAbstractRequest::FinishedState:
323 return true;
324 default:
325 return false;
326 }
327 }
328
329 return false; // unable to wait for operation; not in progress or no engine.
330}
331
332#ifndef QT_NO_DEBUG_STREAM
333/*!
334 Outputs \a request to the debug stream \a dbg
335 */
336QDebug operator<<(QDebug dbg, const QContactAbstractRequest& request)
337{
338 dbg.nospace() << "QContactAbstractRequest(";
339 Q_ASSERT(request.d_ptr);
340 if (request.d_ptr->m_type != QContactAbstractRequest::InvalidRequest) {
341 QMutexLocker locker(&request.d_ptr->m_mutex);
342 request.d_ptr->debugStreamOut(dbg);
343 } else {
344 dbg.nospace() << "(null)";
345 }
346 dbg.nospace() << ")";
347 return dbg.maybeSpace();
348}
349#endif
350
351#include "moc_qcontactabstractrequest.cpp"
352
353QT_END_NAMESPACE_CONTACTS
354

source code of qtpim/src/contacts/qcontactabstractrequest.cpp