--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qtmobility/plugins/contacts/wince/qcontactrequestworker.cpp Fri Apr 16 15:51:22 2010 +0300
@@ -0,0 +1,655 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QDebug>
+#include <QTimer>
+
+#include "qcontactrequests.h"
+#include "qcontactmanagerengine.h"
+#include "qcontactrequestworker_p.h"
+
+
+/*!
+ * \class QContactRequestWorker
+ *
+ * \brief The QContactRequestWorker class provides a common thread worker queue for QContact asynchronous requests.
+ *
+ * A QContactRequestWorker consists of a QContactAbstractRequest request queue.
+ *
+ * An instance of the QContactRequestWorker class is a thread object which is dedicated for processing asynchronous contact requests.
+ * All of these requests are instances of derived classes from QContactAbstractRequest. These request instances can be added to, removed/cancelled from the
+ * worker thread's internal request queue. Once these requests are processed by the worker thread, the related signals will be emitted
+ * and all these requests' waiting clients will also wake up.
+ *
+ * \sa QContactAbstractRequest
+ */
+
+/*! Construct an worker thread. */
+QContactRequestWorker::QContactRequestWorker()
+ :QThread(), d(new QContactRequestWorkerData)
+{
+}
+
+/*! Initializes this QContactRequestWorker from \a other */
+QContactRequestWorker::QContactRequestWorker(const QContactRequestWorker& other)
+ : QThread(), d(other.d)
+{
+}
+
+/*! Replace the contents of this QContactRequestWorker with \a other */
+QContactRequestWorker& QContactRequestWorker::operator=(const QContactRequestWorker& other)
+{
+ // assign
+ d = other.d;
+ return *this;
+}
+
+/*! Frees the memory used by this QContactRequestWorker, stops the thread and clean up all request elements in the working queue */
+QContactRequestWorker::~QContactRequestWorker()
+{
+ stop();
+ quit();
+ while (isRunning() && !wait(1))
+ d->m_newRequestAdded.wakeAll();
+}
+
+/*!
+ * Stops the worker thread. The worker thread may still run a while until it tries to process next request.
+ * If the worker thread was waiting on an empty queue, wakes it up.
+ * \sa run()
+ */
+void QContactRequestWorker::stop()
+{
+ QMutexLocker locker(&d->m_mutex);
+ d->m_stop = true;
+ d->m_newRequestAdded.wakeAll();
+}
+
+/*!
+ * Worker thread's main working loop. Runs forever until the \l stop() function called.
+ * The worker thread initionally waits on the empty request queue, once the request queue is not empty, takes the first element of
+ * the queue, then calls related request processing functions based on the request type. Once the request was processed, update the request's
+ * status and wakes up any threads which waiting for this request.
+ *
+ * \sa stop()
+ * \sa processContactFetchRequest()
+ * \sa processContactLocalIdFetchRequest()
+ * \sa processContactSaveRequest()
+ * \sa processContactRemoveRequest()
+ * \sa processContactRelationshipFetchRequest()
+ * \sa processContactRelationshipSaveRequest()
+ * \sa processContactRelationshipRemoveRequest()
+ * \sa processContactDetailDefinitionFetchRequest()
+ * \sa processContactDetailDefinitionSaveRequest()
+ * \sa processContactDetailDefinitionRemoveRequest()
+ */
+void QContactRequestWorker::run()
+{
+ QContactRequestElement *re;
+
+ for(;;) {
+
+ d->cleanUpFinishedRequests();
+ re = d->takeFirstRequestElement();
+ if (d->m_stop)
+ break;
+
+ Q_ASSERT(re && re->request);
+
+ if (re->request->isFinished() || !re->request->manager()) {
+ removeRequest(re->request);
+ continue;
+ }
+
+ // Now perform the active request and emit required signals.
+ Q_ASSERT(re->request->state() == QContactAbstractRequest::ActiveState);
+ switch (re->request->type()) {
+ case QContactAbstractRequest::ContactFetchRequest:
+ processContactFetchRequest(static_cast<QContactFetchRequest*>(re->request));
+ break;
+ case QContactAbstractRequest::ContactLocalIdFetchRequest:
+ processContactLocalIdFetchRequest(static_cast<QContactLocalIdFetchRequest*>(re->request));
+ break;
+ case QContactAbstractRequest::ContactSaveRequest:
+ processContactSaveRequest(static_cast<QContactSaveRequest*>(re->request));
+ break;
+ case QContactAbstractRequest::ContactRemoveRequest:
+ processContactRemoveRequest(static_cast<QContactRemoveRequest*>(re->request));
+ break;
+ case QContactAbstractRequest::RelationshipFetchRequest:
+ processContactRelationshipFetchRequest(static_cast<QContactRelationshipFetchRequest*>(re->request));
+ break;
+ case QContactAbstractRequest::RelationshipSaveRequest:
+ processContactRelationshipSaveRequest(static_cast<QContactRelationshipSaveRequest*>(re->request));
+ break;
+ case QContactAbstractRequest::RelationshipRemoveRequest:
+ processContactRelationshipRemoveRequest(static_cast<QContactRelationshipRemoveRequest*>(re->request));
+ break;
+ case QContactAbstractRequest::DetailDefinitionFetchRequest:
+ processContactDetailDefinitionFetchRequest(static_cast<QContactDetailDefinitionFetchRequest*>(re->request));
+ break;
+ case QContactAbstractRequest::DetailDefinitionSaveRequest:
+ processContactDetailDefinitionSaveRequest(static_cast<QContactDetailDefinitionSaveRequest*>(re->request));
+ break;
+ case QContactAbstractRequest::DetailDefinitionRemoveRequest:
+ processContactDetailDefinitionRemoveRequest(static_cast<QContactDetailDefinitionRemoveRequest*>(re->request));
+ break;
+ default:
+ break;
+ }//switch
+ re->condition.wakeAll();
+ removeRequest(re->request);
+ }//for
+
+ {
+ QMutexLocker locker(&d->m_mutex);
+ foreach (QContactRequestElement* re, d->m_requestQueue) {
+ if (re)
+ removeRequest(re->request);
+ }
+ d->m_requestQueue.clear();
+ d->m_requestMap.clear();
+ d->cleanUpFinishedRequests(true);
+ }
+}
+
+
+/*!
+ * Returns true if the given \a req successfully added into the working queue, false if not.
+ * \sa removeRequest()
+ * \sa cancelRequest()
+ */
+bool QContactRequestWorker::addRequest(QContactAbstractRequest* req)
+{
+ if (req) {
+ QMutexLocker locker(&d->m_mutex);
+
+ if (!d->m_requestMap.contains(req)) {
+ QContactRequestElement* re = new QContactRequestElement;
+ if (re) {
+ re->request = req;
+ re->waiting = false;
+ d->m_requestQueue.enqueue(re);
+ d->m_requestMap.insert(req, re);
+ QContactManagerEngine::updateRequestState(req, QContactAbstractRequest::ActiveState);
+ d->m_newRequestAdded.wakeAll();
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/*!
+ * Returns true if the given \a req successfully removed from the working queue, false if not.
+ * \sa addRequest()
+ */
+bool QContactRequestWorker::removeRequest(QContactAbstractRequest* req)
+{
+ if (req) {
+ QMutexLocker locker(&d->m_mutex);
+ QContactRequestElement * re = d->m_requestMap.value(req);
+ if (re) {
+ d->m_requestQueue.removeOne(re);
+ d->m_requestMap.remove(req);
+ d->m_removedRequests.append(re);
+ return true;
+ }
+ }
+ return false;
+}
+
+/*!
+ * Update the status of the given request \a req to QContactAbstractRequest::Cancelling, returns true if sucessful, false if not.
+ * \sa addRequest()
+ */
+bool QContactRequestWorker::cancelRequest(QContactAbstractRequest* req)
+{
+ if (req) {
+ QMutexLocker locker(&d->m_mutex);
+ QContactManagerEngine::updateRequestState(req, QContactAbstractRequest::CanceledState);
+ return true;
+ }
+ return false;
+}
+
+/*!
+ * Blocks the caller until the given request \a req has been completed by the worker thread or worker thread signals that more partial results
+ * are available for the request, or until \a msecs milliseconds has elapsed.
+ * If \a msecs is zero, this function will block indefinitely.
+ * Returns true if the request was cancelled or completed successfully within the given period, otherwise false.
+ *
+ * \sa QContactAbstractRequest::waitForFinished(), QContactAbstractRequest::waitForProgress()
+ */
+bool QContactRequestWorker::waitRequest(QContactAbstractRequest* req, int msecs)
+{
+ bool ret = false;
+ if (req) {
+ QContactRequestElement* re = d->m_requestMap.value(req);
+ if (re) {
+ QMutexLocker locker(&re->mutex);
+ re->waiting = true;
+ if (msecs) {
+ ret = re->condition.wait(&re->mutex, msecs);
+ }
+ ret = re->condition.wait(&re->mutex);
+ re->waiting = false;
+ }
+ }
+ return ret;
+}
+
+/*!
+ * Processes the QContactFetchRequest \a req
+ * \sa QContactFetchRequest
+ */
+void QContactRequestWorker::processContactFetchRequest(QContactFetchRequest* req)
+{
+ if (req->manager()) {
+ QContactFilter filter = req->filter();
+ QList<QContactSortOrder> sorting = req->sorting();
+ QStringList defs = req->definitionRestrictions();
+
+ QContactManager::Error operationError;
+ QList<QContact> requestedContacts;
+
+ QList<QContactLocalId> requestedContactIds = req->manager()->contactIds(filter, sorting);
+ operationError = req->manager()->error();
+
+ QContactManager::Error tempError;
+ for (int i = 0; i < requestedContactIds.size(); i++) {
+ QContact current = req->manager()->contact(requestedContactIds.at(i));
+ tempError = req->manager()->error();
+
+ // check for single error; update total operation error if required
+ if (tempError != QContactManager::NoError)
+ operationError = tempError;
+
+ // apply the required detail definition restrictions
+ if (!defs.isEmpty()) {
+ QList<QContactDetail> allDetails = current.details();
+ for (int j = 0; j < allDetails.size(); j++) {
+ QContactDetail d = allDetails.at(j);
+ if (!defs.contains(d.definitionName())) {
+ // this detail is not required.
+ current.removeDetail(&d);
+ }
+ }
+ }
+
+ // add the contact to the result list.
+ requestedContacts.append(current);
+ }
+
+ // update the request with the results.
+ QContactManagerEngine::updateContactFetchRequest(req, requestedContacts, operationError);
+ }
+}
+
+/*!
+ * Processes the QContactLocalIdFetchRequest \a req
+ * \sa QContactLocalIdFetchRequest
+ */
+void QContactRequestWorker::processContactLocalIdFetchRequest(QContactLocalIdFetchRequest* req)
+{
+ if (req->manager()) {
+ QContactFilter filter = req->filter();
+ QList<QContactSortOrder> sorting = req->sorting();
+
+ QContactManager::Error operationError = QContactManager::NoError;
+ QList<QContactLocalId> requestedContactIds = req->manager()->contactIds(filter, sorting);
+ operationError = req->manager()->error();
+
+ QContactManagerEngine::updateContactLocalIdFetchRequest(req, requestedContactIds, operationError);
+ }
+}
+
+/*!
+ * Processes the QContactSaveRequest \a req
+ * \sa QContactSaveRequest
+ */
+void QContactRequestWorker::processContactSaveRequest(QContactSaveRequest* req)
+{
+ if (req->manager()) {
+ QList<QContact> contacts = req->contacts();
+
+ QContactManager::Error operationError = QContactManager::NoError;
+ QMap<int, QContactManager::Error> errorMap;
+ req->manager()->saveContacts(&contacts, &errorMap);
+ operationError = req->manager()->error();
+
+ QContactManagerEngine::updateContactSaveRequest(req, contacts, operationError, errorMap);
+ }
+}
+
+/*!
+ * Processes the QContactRemoveRequest \a req
+ * \sa QContactRemoveRequest
+ */
+void QContactRequestWorker::processContactRemoveRequest(QContactRemoveRequest* req )
+{
+ if (req->manager()) {
+ // this implementation provides scant information to the user
+ // the operation either succeeds (all contacts matching the filter were removed)
+ // or it fails (one or more contacts matching the filter could not be removed)
+ // if a failure occurred, the request error will be set to the most recent
+ // error that occurred during the remove operation.
+
+ QContactManager::Error operationError = QContactManager::NoError;
+ QList<QContactLocalId> contactsToRemove = req->contactIds();
+ operationError = req->manager()->error();
+
+ QMap<int, QContactManager::Error> errorMap;
+ for (int i = 0; i < contactsToRemove.size(); i++) {
+ QContactManager::Error tempError;
+
+ req->manager()->removeContact(contactsToRemove.at(i));
+ tempError = req->manager()->error();
+
+ if (tempError != QContactManager::NoError) {
+ errorMap.insert(i, tempError);
+ operationError = tempError;
+ }
+ }
+
+ // there are no results, so just update the status with the error.
+ QContactManagerEngine::updateContactRemoveRequest(req, operationError, errorMap);
+ }
+}
+
+
+/*!
+ * Processes the QContactDetailDefinitionFetchRequest \a req
+ * \sa QContactDetailDefinitionFetchRequest
+ */
+void QContactRequestWorker::processContactDetailDefinitionFetchRequest(QContactDetailDefinitionFetchRequest* req)
+{
+ if (req->manager()) {
+ QContactManager::Error operationError = QContactManager::NoError;
+ QMap<int, QContactManager::Error> errorMap;
+ QMap<QString, QContactDetailDefinition> requestedDefinitions;
+ QStringList names = req->definitionNames();
+ if (names.isEmpty()) {
+ names = req->manager()->detailDefinitions().keys(); // all definitions.
+ operationError = req->manager()->error();
+ }
+
+ QContactManager::Error tempError;
+ for (int i = 0; i < names.size(); i++) {
+ QContactDetailDefinition current = req->manager()->detailDefinition(names.at(i));
+ tempError = req->manager()->error();
+ requestedDefinitions.insert(names.at(i), current);
+
+ if (tempError != QContactManager::NoError) {
+ errorMap.insert(i, tempError);
+ operationError = tempError;
+ }
+ }
+
+ // update the request with the results.
+ QContactManagerEngine::updateDefinitionFetchRequest(req, requestedDefinitions, operationError, errorMap);
+ }
+}
+/*!
+ * Processes the QContactDetailDefinitionSaveRequest \a req
+ * \sa QContactDetailDefinitionSaveRequest
+ */
+void QContactRequestWorker::processContactDetailDefinitionSaveRequest(QContactDetailDefinitionSaveRequest* req)
+{
+ if (req->manager()) {
+ QContactManager::Error operationError = QContactManager::NoError;
+ QMap<int, QContactManager::Error> errorMap;
+ QList<QContactDetailDefinition> definitions = req->definitions();
+ QList<QContactDetailDefinition> savedDefinitions;
+
+ QContactManager::Error tempError;
+ for (int i = 0; i < definitions.size(); i++) {
+ QContactDetailDefinition current = definitions.at(i);
+ req->manager()->saveDetailDefinition(current);
+ tempError = req->manager()->error();
+ savedDefinitions.append(current);
+
+ if (tempError != QContactManager::NoError) {
+ errorMap.insert(i, tempError);
+ operationError = tempError;
+ }
+ }
+
+ // update the request with the results.
+ QContactManagerEngine::updateDefinitionSaveRequest(req, savedDefinitions, operationError, errorMap);
+ }
+}
+/*!
+ * Processes the QContactDetailDefinitionRemoveRequest \a req
+ * \sa QContactDetailDefinitionRemoveRequest
+ */
+void QContactRequestWorker::processContactDetailDefinitionRemoveRequest(QContactDetailDefinitionRemoveRequest* req)
+{
+ if (req->manager()) {
+ QStringList names = req->definitionNames();
+
+ QContactManager::Error operationError = QContactManager::NoError;
+ QMap<int, QContactManager::Error> errorMap;
+
+ for (int i = 0; i < names.size(); i++) {
+ QContactManager::Error tempError;
+ req->manager()->removeDetailDefinition(names.at(i));
+ tempError = req->manager()->error();
+
+ if (tempError != QContactManager::NoError) {
+ errorMap.insert(i, tempError);
+ operationError = tempError;
+ }
+ }
+
+ // there are no results, so just update the status with the error.
+ QContactManagerEngine::updateDefinitionRemoveRequest(req, operationError, errorMap);
+ }
+}
+
+/*!
+ * Processes the QContactRelationshipFetchRequest \a req
+ * \sa QContactRelationshipFetchRequest
+ */
+void QContactRequestWorker::processContactRelationshipFetchRequest(QContactRelationshipFetchRequest* req)
+{
+ if (req->manager()) {
+ QList<QContactRelationship> allRelationships = req->manager()->relationships(QString(), QContactId(), QContactRelationshipFilter::Either);
+ QContactManager::Error operationError = req->manager()->error();
+ QList<QContactRelationship> requestedRelationships;
+
+ // first criteria: source contact id must be empty or must match
+ if (req->first() == QContactId()) {
+ // all relationships match this criteria (zero id denotes "any")
+ requestedRelationships = allRelationships;
+ } else {
+ for (int i = 0; i < allRelationships.size(); i++) {
+ QContactRelationship currRelationship = allRelationships.at(i);
+ if (req->first() == currRelationship.first()) {
+ requestedRelationships.append(currRelationship);
+ }
+ }
+ }
+
+ // second criteria: relationship type must be empty or must match
+ if (!req->relationshipType().isEmpty()) {
+ allRelationships = requestedRelationships;
+ requestedRelationships.clear();
+ for (int i = 0; i < allRelationships.size(); i++) {
+ QContactRelationship currRelationship = allRelationships.at(i);
+ if (req->relationshipType() == currRelationship.relationshipType()) {
+ requestedRelationships.append(currRelationship);
+ }
+ }
+ }
+
+ // third criteria: participant must be empty or must match (including role in relationship)
+ QString myUri = req->manager()->managerUri();
+ QContactId anonymousParticipant;
+ anonymousParticipant.setLocalId(QContactLocalId(0));
+ anonymousParticipant.setManagerUri(QString());
+ if (req->second() != anonymousParticipant) {
+ allRelationships = requestedRelationships;
+ requestedRelationships.clear();
+ for (int i = 0; i < allRelationships.size(); i++) {
+ QContactRelationship currRelationship = allRelationships.at(i);
+ if ((req->participantRole() == QContactRelationshipFilter::Either || req->participantRole() == QContactRelationshipFilter::Second)
+ && currRelationship.second() == req->second()) {
+ requestedRelationships.append(currRelationship);
+ } else if ((req->participantRole() == QContactRelationshipFilter::Either || req->participantRole() == QContactRelationshipFilter::First)
+ && currRelationship.first() == req->second()) {
+ requestedRelationships.append(currRelationship);
+ }
+ }
+ }
+
+ // update the request with the results.
+ QContactManagerEngine::updateRelationshipFetchRequest(req, requestedRelationships, operationError);
+ }
+}
+
+/*!
+ * Processes the QContactRelationshipRemoveRequest \a req
+ * \sa QContactRelationshipRemoveRequest
+ */
+void QContactRequestWorker::processContactRelationshipRemoveRequest(QContactRelationshipRemoveRequest* req)
+{
+ if (req->manager()) {
+ QMap<int, QContactManager::Error> errorMap;
+ QContactManager::Error operationError = req->manager()->error();
+ foreach (const QContactRelationship& relationship, req->relationships()) {
+ QList<QContactRelationship> matchingRelationships = req->manager()->relationships(relationship.relationshipType(), relationship.first(), QContactRelationshipFilter::First);
+
+ for (int i = 0; i < matchingRelationships.size(); i++) {
+ QContactManager::Error tempError;
+ QContactRelationship possibleMatch = matchingRelationships.at(i);
+
+ // if the second criteria matches, or is default constructed id, then we have a match and should remove it.
+ if (relationship.second() == QContactId() || possibleMatch.second() == relationship.second()) {
+ req->manager()->removeRelationship(matchingRelationships.at(i));
+ tempError = req->manager()->error();
+
+ if (tempError != QContactManager::NoError) {
+ errorMap.insert(i, tempError);
+ operationError = tempError;
+ }
+ }
+ }
+ }
+
+ // there are no results, so just update the status with the error.
+ QContactManagerEngine::updateRelationshipRemoveRequest(req, operationError, errorMap);
+ }
+}
+
+/*!
+ * Processes the QContactRelationshipSaveRequest \a req
+ * \sa QContactRelationshipSaveRequest
+ */
+void QContactRequestWorker::processContactRelationshipSaveRequest(QContactRelationshipSaveRequest* req)
+{
+ if (req->manager()) {
+ QContactManager::Error operationError = QContactManager::NoError;
+ QMap<int, QContactManager::Error> errorMap;
+ QList<QContactRelationship> requestRelationships = req->relationships();
+ QList<QContactRelationship> savedRelationships;
+
+ QContactManager::Error tempError;
+ for (int i = 0; i < requestRelationships.size(); i++) {
+ QContactRelationship current = requestRelationships.at(i);
+ req->manager()->saveRelationship(¤t);
+ tempError = req->manager()->error();
+ savedRelationships.append(current);
+
+ if (tempError != QContactManager::NoError) {
+ errorMap.insert(i, tempError);
+ operationError = tempError;
+ }
+ }
+
+ // update the request with the results.
+ QContactManagerEngine::updateRelationshipSaveRequest(req, savedRelationships, operationError, errorMap);
+ }
+}
+
+QContactRequestElement* QContactRequestWorkerData::takeFirstRequestElement()
+{
+ QMutexLocker locker(&m_mutex);
+
+ // take the first pending request and finish it
+ if (m_requestQueue.isEmpty())
+ m_newRequestAdded.wait(&m_mutex);
+ if (!m_requestQueue.isEmpty())
+ return m_requestQueue.head();
+ return 0;
+}
+
+void QContactRequestWorkerData::cleanUpFinishedRequests(bool waitForAll)
+{
+ QList<QContactRequestElement*> deleteAll;
+ QMutex mtx;
+ QWaitCondition wc;
+ for (;;) {
+ foreach (QContactRequestElement* re, m_removedRequests) {
+ if (re->waiting) {
+ re->condition.wakeAll();
+ } else {
+ deleteAll.append(re);
+ m_removedRequests.removeOne(re);
+ }
+ }
+
+ foreach (QContactRequestElement* re, deleteAll) {
+ if (re)
+ delete re;
+ }
+ deleteAll.clear();
+ if (!waitForAll || m_removedRequests.isEmpty()) {
+ break;
+ } else {
+ QMutexLocker locker(&mtx);
+ wc.wait(&mtx, 10);
+ }
+ }
+}
+
+#include "moc_qcontactrequestworker.cpp"
+