qtmobility/src/contacts/qcontactabstractrequest.cpp
changeset 14 6fbed849b4f4
parent 11 06b8e2af4411
child 15 1f895d8a5b2b
--- a/qtmobility/src/contacts/qcontactabstractrequest.cpp	Fri Jun 11 14:26:25 2010 +0300
+++ b/qtmobility/src/contacts/qcontactabstractrequest.cpp	Wed Jun 23 19:08:38 2010 +0300
@@ -45,6 +45,8 @@
 #include "qcontactmanager_p.h"
 #include "qcontactmanagerengine.h"
 
+#include <QMutex>
+#include <QMutexLocker>
 
 QTM_BEGIN_NAMESPACE
 /*!
@@ -64,11 +66,60 @@
   but should instead use the use-case-specific classes derived from this
   class.
 
-  After creating any sort of request, the client retains ownership and
-  must delete the request to avoid leaking memory.  The client may either
-  do this directly (if not within a slot connected to a signal emitted
-  by the request) or by using the deleteLater() slot to schedule the
-  request for deletion when control returns to the event loop.
+  All such request classes have a similar interface: clients set the
+  parameters of the asynchronous call, including which manager the
+  request will be made of, and then call the start() slot of the request.
+  The manager will then enqueue or begin to process the request, at which
+  point the request's state will transition from \c InactiveState to
+  \c ActiveState.  After any state transition, the request will emit the
+  stateChanged() signal.  The manager may periodically update the request
+  with results, at which point the request will emit the resultsAvailable()
+  signal.  These results are not guaranteed to have a stable ordering.
+  Error information is considered a result, so some requests will emit the
+  resultsAvailable() signal even if no results are possible from the request
+  (for example, a contact remove request) when the manager updates the request
+  with information about any errors which may have occurred.
+
+  Please see the class documentation of each of the use-case-specific
+  classes derived from this class for information about how to retrieve
+  the results of a request (including error information).  In all cases,
+  those functions are synchronous, and will return the cached result set with
+  which the manager has updated the request instance if the resultsAvailable()
+  signal has been emitted.
+
+  Clients can choose which signals they wish to handle from a request.
+  If the client is not interested in interim results, they can choose to
+  handle only the stateChanged() signal, and in the slot to which that
+  signal is connected, check whether the state has changed to either
+  \c FinishedState or \c CanceledState (both of which signify that the
+  manager has finished handling the request, and that the request will not
+  be updated with any more results).  If the client is not interested in
+  any results (including error information), they may choose to delete
+  the request after calling \l start(), or simply not connect the
+  request's signals to any slots.
+
+  If the request is allocated via operator new, the client must
+  delete the request when they are no longer using it in order to avoid
+  leaking memory.  That is, the client retains ownership of the request.
+
+  The client may delete a heap-allocated request in various ways:
+  by deleting it directly (but not within a slot connected to a signal
+  emitted by the request), or by using the deleteLater() slot to schedule
+  the request for deletion when control returns to the event loop (from
+  within a slot connected to a signal emitted by the request, for example
+  \l stateChanged()).
+
+  An active request may be deleted by the client, but the client will not
+  receive any notifications about whether the request succeeded or not,
+  nor any results of the request.
+
+  Because clients retain ownership of any request object, and may delete
+  a request object at any time, manager engine implementors must be careful
+  to ensure that they do not assume that a request has not been deleted
+  at some point during processing of a request, particularly if the engine
+  has a multithreaded implementation.  It is suggested that engine
+  implementors read the \l{Qt Contacts Manager Engines} documentation for
+  more information on this topic.
  */
 
 /*!
@@ -131,7 +182,9 @@
 QContactAbstractRequest::~QContactAbstractRequest()
 {
     if (d_ptr) {
+        QMutexLocker ml(&d_ptr->m_mutex);
         QContactManagerEngine *engine = QContactManagerData::engine(d_ptr->m_manager);
+        ml.unlock();
         if (engine) {
             engine->requestDestroyed(this);
         }
@@ -147,6 +200,7 @@
  */
 bool QContactAbstractRequest::isInactive() const
 {
+    QMutexLocker ml(&d_ptr->m_mutex);
     return (d_ptr->m_state == QContactAbstractRequest::InactiveState);
 }
 
@@ -157,6 +211,7 @@
  */
 bool QContactAbstractRequest::isActive() const
 {
+    QMutexLocker ml(&d_ptr->m_mutex);
     return (d_ptr->m_state == QContactAbstractRequest::ActiveState);
 }
 
@@ -167,6 +222,7 @@
  */
 bool QContactAbstractRequest::isFinished() const
 {
+    QMutexLocker ml(&d_ptr->m_mutex);
     return (d_ptr->m_state == QContactAbstractRequest::FinishedState);
 }
 
@@ -177,12 +233,14 @@
  */
 bool QContactAbstractRequest::isCanceled() const
 {
+    QMutexLocker ml(&d_ptr->m_mutex);
     return (d_ptr->m_state == QContactAbstractRequest::CanceledState);
 }
 
 /*! Returns the overall error of the most recent asynchronous operation */
 QContactManager::Error QContactAbstractRequest::error() const
 {
+    QMutexLocker ml(&d_ptr->m_mutex);
     return d_ptr->m_error;
 }
 
@@ -191,6 +249,7 @@
  */
 QContactAbstractRequest::RequestType QContactAbstractRequest::type() const
 {
+    QMutexLocker ml(&d_ptr->m_mutex);
     return d_ptr->type();
 }
 
@@ -199,18 +258,28 @@
  */
 QContactAbstractRequest::State QContactAbstractRequest::state() const
 {
+    QMutexLocker ml(&d_ptr->m_mutex);
     return d_ptr->m_state;
 }
 
 /*! Returns a pointer to the manager of which this request instance requests operations */
 QContactManager* QContactAbstractRequest::manager() const
 {
+    QMutexLocker ml(&d_ptr->m_mutex);
     return d_ptr->m_manager;
 }
 
-/*! Sets the manager of which this request instance requests operations to \a manager */
+/*!
+    Sets the manager of which this request instance requests operations to \a manager
+
+    If the request is currently active, this function will return without updating the \a manager object.
+*/
 void QContactAbstractRequest::setManager(QContactManager* manager)
 {
+    QMutexLocker ml(&d_ptr->m_mutex);
+    // In theory we might have been active and the manager didn't cancel/finish us
+    if (d_ptr->m_state == QContactAbstractRequest::ActiveState && d_ptr->m_manager)
+        return;
     d_ptr->m_manager = manager;
 }
 
@@ -218,10 +287,12 @@
     or if the request was unable to be performed by the manager engine; otherwise returns true. */
 bool QContactAbstractRequest::start()
 {
+    QMutexLocker ml(&d_ptr->m_mutex);
     QContactManagerEngine *engine = QContactManagerData::engine(d_ptr->m_manager);
     if (engine && (d_ptr->m_state == QContactAbstractRequest::CanceledState
                    || d_ptr->m_state == QContactAbstractRequest::FinishedState
                    || d_ptr->m_state == QContactAbstractRequest::InactiveState)) {
+        ml.unlock();
         return engine->startRequest(this);
     }
 
@@ -232,8 +303,10 @@
     or if the request is unable to be cancelled by the manager engine; otherwise returns true. */
 bool QContactAbstractRequest::cancel()
 {
+    QMutexLocker ml(&d_ptr->m_mutex);
     QContactManagerEngine *engine = QContactManagerData::engine(d_ptr->m_manager);
-    if (engine && state() == QContactAbstractRequest::ActiveState) {
+    if (engine && d_ptr->m_state == QContactAbstractRequest::ActiveState) {
+        ml.unlock();
         return engine->cancelRequest(this);
     }
 
@@ -247,10 +320,12 @@
  */
 bool QContactAbstractRequest::waitForFinished(int msecs)
 {
+    QMutexLocker ml(&d_ptr->m_mutex);
     QContactManagerEngine *engine = QContactManagerData::engine(d_ptr->m_manager);
     if (engine) {
         switch (d_ptr->m_state) {
         case QContactAbstractRequest::ActiveState:
+            ml.unlock();
             return engine->waitForRequestFinished(this, msecs);
         case QContactAbstractRequest::CanceledState:
         case QContactAbstractRequest::FinishedState: