summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/contacts/contacts.pro8
-rw-r--r--src/contacts/filters/filters.pri3
-rw-r--r--src/contacts/filters/qcontactcollectionfilter.cpp101
-rw-r--r--src/contacts/filters/qcontactcollectionfilter.h73
-rw-r--r--src/contacts/filters/qcontactcollectionfilter_p.h120
-rw-r--r--src/contacts/filters/qcontactfilters.h1
-rw-r--r--src/contacts/qcontact.cpp10
-rw-r--r--src/contacts/qcontact.h4
-rw-r--r--src/contacts/qcontact_p.h3
-rw-r--r--src/contacts/qcontactabstractrequest.h5
-rw-r--r--src/contacts/qcontactcollection.cpp307
-rw-r--r--src/contacts/qcontactcollection.h116
-rw-r--r--src/contacts/qcontactcollection_p.h89
-rw-r--r--src/contacts/qcontactcollectionchangeset.cpp279
-rw-r--r--src/contacts/qcontactcollectionchangeset.h98
-rw-r--r--src/contacts/qcontactcollectionchangeset_p.h96
-rw-r--r--src/contacts/qcontactcollectionid.cpp259
-rw-r--r--src/contacts/qcontactcollectionid.h108
-rw-r--r--src/contacts/qcontactfilter.h3
-rw-r--r--src/contacts/qcontactmanager.cpp68
-rw-r--r--src/contacts/qcontactmanager.h18
-rw-r--r--src/contacts/qcontactmanagerengine.cpp192
-rw-r--r--src/contacts/qcontactmanagerengine.h21
-rw-r--r--src/contacts/requests/qcontactcollectionfetchrequest.cpp86
-rw-r--r--src/contacts/requests/qcontactcollectionfetchrequest.h75
-rw-r--r--src/contacts/requests/qcontactcollectionremoverequest.cpp115
-rw-r--r--src/contacts/requests/qcontactcollectionremoverequest.h80
-rw-r--r--src/contacts/requests/qcontactcollectionsaverequest.cpp116
-rw-r--r--src/contacts/requests/qcontactcollectionsaverequest.h80
-rw-r--r--src/contacts/requests/qcontactrequests.h5
-rw-r--r--src/contacts/requests/qcontactrequests_p.h86
-rw-r--r--src/contacts/requests/requests.pri6
-rw-r--r--src/imports/contacts/contacts.pro2
-rw-r--r--src/imports/contacts/filters/filters.pri1
-rw-r--r--src/imports/contacts/filters/qdeclarativecontactcollectionfilter_p.h116
-rw-r--r--src/imports/contacts/filters/qdeclarativecontactfiltermoc.cpp1
-rw-r--r--src/imports/contacts/filters/qdeclarativecontactfilters_p.h1
-rw-r--r--src/imports/contacts/plugin.cpp4
-rw-r--r--src/imports/contacts/qdeclarativecontact.cpp25
-rw-r--r--src/imports/contacts/qdeclarativecontact_p.h6
-rw-r--r--src/imports/contacts/qdeclarativecontactcollection.cpp237
-rw-r--r--src/imports/contacts/qdeclarativecontactcollection_p.h120
-rw-r--r--src/imports/contacts/qdeclarativecontactmodel.cpp281
-rw-r--r--src/imports/contacts/qdeclarativecontactmodel_p.h18
-rw-r--r--src/plugins/contacts/memory/qcontactmemorybackend.cpp186
-rw-r--r--src/plugins/contacts/memory/qcontactmemorybackend_p.h19
-rw-r--r--tests/auto/contacts/contacts.pro1
-rw-r--r--tests/auto/contacts/qcontactasync/unittest/tst_qcontactasync.cpp472
-rw-r--r--tests/auto/contacts/qcontactcollection/qcontactcollection.pro5
-rw-r--r--tests/auto/contacts/qcontactcollection/tst_qcontactcollection.cpp397
-rw-r--r--tests/auto/contacts/qcontactfilter/tst_qcontactfilter.cpp94
-rw-r--r--tests/auto/contacts/qcontactmanager/tst_qcontactmanager.cpp166
-rw-r--r--tests/auto/contacts/qmlcontacts/qmlcontacts.pro2
-rw-r--r--tests/auto/contacts/qmlcontacts/testcases/ContactsSavingTestCase.qml17
-rw-r--r--tests/auto/contacts/qmlcontacts/testcases/tst_contact_collection_filter.qml161
55 files changed, 4940 insertions, 23 deletions
diff --git a/src/contacts/contacts.pro b/src/contacts/contacts.pro
index d4100f8a4..55226af73 100644
--- a/src/contacts/contacts.pro
+++ b/src/contacts/contacts.pro
@@ -19,6 +19,9 @@ PUBLIC_HEADERS += \
qcontactactionfactory.h \
qcontactactiontarget.h \
qcontactchangeset.h \
+ qcontactcollection.h \
+ qcontactcollectionchangeset.h \
+ qcontactcollectionid.h \
qcontactdetail.h \
qcontactfetchhint.h \
qcontactfilter.h \
@@ -39,6 +42,8 @@ PRIVATE_HEADERS += \
qcontactactionmanager_p.h \
qcontactactiontarget_p.h \
qcontactchangeset_p.h \
+ qcontactcollection_p.h \
+ qcontactcollectionchangeset_p.h \
qcontactdetail_p.h \
qcontactfetchhint_p.h \
qcontactfilter_p.h \
@@ -56,6 +61,9 @@ SOURCES += \
qcontactactionmanager_p.cpp \
qcontactactiontarget.cpp \
qcontactchangeset.cpp \
+ qcontactcollection.cpp \
+ qcontactcollectionchangeset.cpp \
+ qcontactcollectionid.cpp \
qcontactdetail.cpp \
qcontactfetchhint.cpp \
qcontactfilter.cpp \
diff --git a/src/contacts/filters/filters.pri b/src/contacts/filters/filters.pri
index 0c017cab0..19a8e8d75 100644
--- a/src/contacts/filters/filters.pri
+++ b/src/contacts/filters/filters.pri
@@ -3,6 +3,7 @@ INCLUDEPATH += filters
PUBLIC_HEADERS += \
filters/qcontactactionfilter.h \
filters/qcontactchangelogfilter.h \
+ filters/qcontactcollectionfilter.h \
filters/qcontactdetailfilter.h \
filters/qcontactdetailrangefilter.h \
filters/qcontactfilters.h \
@@ -15,6 +16,7 @@ PUBLIC_HEADERS += \
PRIVATE_HEADERS += \
filters/qcontactactionfilter_p.h \
filters/qcontactchangelogfilter_p.h \
+ filters/qcontactcollectionfilter_p.h \
filters/qcontactdetailfilter_p.h \
filters/qcontactdetailrangefilter_p.h \
filters/qcontactidfilter_p.h \
@@ -25,6 +27,7 @@ PRIVATE_HEADERS += \
SOURCES += \
filters/qcontactactionfilter.cpp \
filters/qcontactchangelogfilter.cpp \
+ filters/qcontactcollectionfilter.cpp \
filters/qcontactdetailfilter.cpp \
filters/qcontactdetailrangefilter.cpp \
filters/qcontactidfilter.cpp \
diff --git a/src/contacts/filters/qcontactcollectionfilter.cpp b/src/contacts/filters/qcontactcollectionfilter.cpp
new file mode 100644
index 000000000..56bb9de21
--- /dev/null
+++ b/src/contacts/filters/qcontactcollectionfilter.cpp
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtContacts module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcontactcollectionfilter.h"
+#include "qcontactcollectionfilter_p.h"
+
+QT_BEGIN_NAMESPACE_CONTACTS
+
+/*!
+ \class QContactCollectionFilter
+ \brief The QContactCollectionFilter class provides a filter based around the collection one
+ contact belongs to.
+ \inmodule QtContacts
+ \ingroup contacts-filters
+
+ It may be used to select contacts belonging to certain collections.
+ */
+
+Q_IMPLEMENT_CONTACTFILTER_PRIVATE(QContactCollectionFilter)
+
+/*!
+ \fn QContactCollectionFilter::QContactCollectionFilter(const QContactCollectionFilter &other)
+
+ Constructs a copy of \a other if possible, otherwise constructs a new contact collection filter.
+ */
+
+/*!
+ Constructs a new contact collection filter.
+ */
+QContactCollectionFilter::QContactCollectionFilter()
+ : QContactFilter(new QContactCollectionFilterPrivate)
+{
+}
+
+/*!
+ Sets the \a id of the collection, which the contacts should belong to.
+ */
+void QContactCollectionFilter::setCollectionId(const QContactCollectionId &id)
+{
+ Q_D(QContactCollectionFilter);
+ d->m_ids.clear();
+ d->m_ids.insert(id);
+}
+
+/*!
+ Sets the list of collection \a ids, which the contacts should belong to.
+ */
+void QContactCollectionFilter::setCollectionIds(const QSet<QContactCollectionId> &ids)
+{
+ Q_D(QContactCollectionFilter);
+ d->m_ids = ids;
+}
+
+/*!
+ Returns the list of collection IDs of contacts should belong to.
+ */
+QSet<QContactCollectionId> QContactCollectionFilter::collectionIds() const
+{
+ Q_D(const QContactCollectionFilter);
+ return d->m_ids;
+}
+
+QT_END_NAMESPACE_CONTACTS
diff --git a/src/contacts/filters/qcontactcollectionfilter.h b/src/contacts/filters/qcontactcollectionfilter.h
new file mode 100644
index 000000000..da6cdede4
--- /dev/null
+++ b/src/contacts/filters/qcontactcollectionfilter.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2015 Canonical Ltd
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtOrganizer module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCONTACTCOLLECTIONFILTER_H
+#define QCONTACTCOLLECTIONFILTER_H
+
+#include <QtCore/qset.h>
+
+#include <QtContacts/qcontactcollectionid.h>
+#include <QtContacts/qcontactfilter.h>
+
+QT_BEGIN_NAMESPACE_CONTACTS
+
+class QContactCollectionFilterPrivate;
+
+/* Leaf class */
+
+class Q_CONTACTS_EXPORT QContactCollectionFilter : public QContactFilter
+{
+public:
+ QContactCollectionFilter();
+ QContactCollectionFilter(const QContactFilter &other);
+
+ void setCollectionId(const QContactCollectionId &id);
+ void setCollectionIds(const QSet<QContactCollectionId> &ids);
+ QSet<QContactCollectionId> collectionIds() const;
+
+private:
+ Q_DECLARE_CONTACTFILTER_PRIVATE(QContactCollectionFilter)
+};
+
+QT_END_NAMESPACE_CONTACTS
+
+#endif // QCONTACTCOLLECTIONFILTER_H
diff --git a/src/contacts/filters/qcontactcollectionfilter_p.h b/src/contacts/filters/qcontactcollectionfilter_p.h
new file mode 100644
index 000000000..db06be826
--- /dev/null
+++ b/src/contacts/filters/qcontactcollectionfilter_p.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2015 Canonical Ltd
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtOrganizer module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCONTACTCOLLECTIONFILTER_P_H
+#define QCONTACTCOLLECTIONFILTER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtContacts/qcontactcollectionfilter.h>
+#include <QtContacts/private/qcontactfilter_p.h>
+
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE_CONTACTS
+
+class QContactCollectionFilterPrivate : public QContactFilterPrivate
+{
+public:
+ QContactCollectionFilterPrivate()
+ : QContactFilterPrivate()
+ {
+ }
+
+ QContactCollectionFilterPrivate(const QContactCollectionFilterPrivate &other)
+ : QContactFilterPrivate(other), m_ids(other.m_ids)
+ {
+ }
+
+ virtual bool compare(const QContactFilterPrivate *other) const
+ {
+ const QContactCollectionFilterPrivate *od = static_cast<const QContactCollectionFilterPrivate *>(other);
+ if (od)
+ return m_ids == od->m_ids;
+ return false;
+ }
+
+#ifndef QT_NO_DATASTREAM
+ QDataStream &outputToStream(QDataStream &stream, quint8 formatVersion) const
+ {
+ if (formatVersion == 1)
+ stream << m_ids;
+ return stream;
+ }
+
+ QDataStream &inputFromStream(QDataStream &stream, quint8 formatVersion)
+ {
+ if (formatVersion == 1)
+ stream >> m_ids;
+ return stream;
+ }
+#endif // QT_NO_DATASTREAM
+
+#ifndef QT_NO_DEBUG_STREAM
+ QDebug &debugStreamOut(QDebug &dbg) const
+ {
+ dbg.nospace() << "QContactCollectionFilter(collectionIds=";
+ QList<QContactCollectionId> ids(m_ids.toList());
+ std::sort(ids.begin(), ids.end());
+ dbg.nospace() << ids;
+ dbg.nospace() << ")";
+ return dbg.maybeSpace();
+ }
+#endif // QT_NO_DEBUG_STREAM
+
+ Q_IMPLEMENT_CONTACTFILTER_VIRTUALCTORS(QContactCollectionFilter, QContactFilter::CollectionFilter)
+
+ QSet<QContactCollectionId> m_ids;
+};
+
+QT_END_NAMESPACE_CONTACTS
+
+#endif // QCONTACTCOLLECTIONFILTER_P_H
diff --git a/src/contacts/filters/qcontactfilters.h b/src/contacts/filters/qcontactfilters.h
index ccae29276..8d8618a7b 100644
--- a/src/contacts/filters/qcontactfilters.h
+++ b/src/contacts/filters/qcontactfilters.h
@@ -47,6 +47,7 @@
#include <QtContacts/qcontactactionfilter.h>
#include <QtContacts/qcontactchangelogfilter.h>
+#include <QtContacts/qcontactcollectionfilter.h>
#include <QtContacts/qcontactdetailfilter.h>
#include <QtContacts/qcontactdetailrangefilter.h>
#include <QtContacts/qcontactidfilter.h>
diff --git a/src/contacts/qcontact.cpp b/src/contacts/qcontact.cpp
index 931fbd6ae..d2ebadf33 100644
--- a/src/contacts/qcontact.cpp
+++ b/src/contacts/qcontact.cpp
@@ -670,6 +670,16 @@ QList<QContactId> QContact::relatedContacts(const QString& relationshipType, QCo
return retn;
}
+QContactCollectionId QContact::collectionId() const
+{
+ return d->m_collectionId;
+}
+
+void QContact::setCollectionId(const QContactCollectionId &collectionId)
+{
+ d->m_collectionId = collectionId;
+}
+
/*!
* Return a list of descriptors for the actions available to be performed on this contact.
*
diff --git a/src/contacts/qcontact.h b/src/contacts/qcontact.h
index ef895dd39..05da340ed 100644
--- a/src/contacts/qcontact.h
+++ b/src/contacts/qcontact.h
@@ -56,6 +56,7 @@ QT_BEGIN_NAMESPACE_CONTACTS
class QContactActionDescriptor;
class QContactId;
class QContactManager;
+class QContactCollectionId;
class QContactData;
class Q_CONTACTS_EXPORT QContact
@@ -115,6 +116,9 @@ public:
QList<QContactRelationship> relationships(const QString& relationshipType = QString()) const;
QList<QContactId> relatedContacts(const QString& relationshipType = QString(), QContactRelationship::Role role = QContactRelationship::Either) const;
+ QContactCollectionId collectionId() const;
+ void setCollectionId(const QContactCollectionId &collectionId);
+
/* Actions available to be performed on this contact */
QList<QContactActionDescriptor> availableActions(const QString& serviceName = QString()) const;
diff --git a/src/contacts/qcontact_p.h b/src/contacts/qcontact_p.h
index eba3dfe93..460c0bcef 100644
--- a/src/contacts/qcontact_p.h
+++ b/src/contacts/qcontact_p.h
@@ -61,6 +61,7 @@
#include <QtContacts/qcontactdetail.h>
#include <QtContacts/qcontactid.h>
#include <QtContacts/qcontactrelationship.h>
+#include <QtContacts/qcontactcollectionid.h>
QT_BEGIN_NAMESPACE_CONTACTS
@@ -75,6 +76,7 @@ public:
QContactData(const QContactData& other)
: QSharedData(other),
m_id(other.m_id),
+ m_collectionId(other.m_collectionId),
m_details(other.m_details),
m_relationshipsCache(other.m_relationshipsCache),
m_preferences(other.m_preferences)
@@ -84,6 +86,7 @@ public:
~QContactData() {}
QContactId m_id;
+ QContactCollectionId m_collectionId;
QList<QContactDetail> m_details;
QList<QContactRelationship> m_relationshipsCache;
QMap<QString, int> m_preferences;
diff --git a/src/contacts/qcontactabstractrequest.h b/src/contacts/qcontactabstractrequest.h
index e8dec9316..0e2ea3b95 100644
--- a/src/contacts/qcontactabstractrequest.h
+++ b/src/contacts/qcontactabstractrequest.h
@@ -84,7 +84,10 @@ public:
RelationshipFetchRequest,
RelationshipRemoveRequest,
RelationshipSaveRequest,
- ContactFetchByIdRequest
+ ContactFetchByIdRequest,
+ CollectionFetchRequest,
+ CollectionRemoveRequest,
+ CollectionSaveRequest,
};
RequestType type() const;
diff --git a/src/contacts/qcontactcollection.cpp b/src/contacts/qcontactcollection.cpp
new file mode 100644
index 000000000..3d7affe56
--- /dev/null
+++ b/src/contacts/qcontactcollection.cpp
@@ -0,0 +1,307 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2015 Canonical Ltd
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtOrganizer module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcontactcollection.h"
+#include "qcontactcollection_p.h"
+
+#ifndef QT_NO_DATASTREAM
+#include <QtCore/qdatastream.h>
+#endif
+#ifndef QT_NO_DEBUG_STREAM
+#include <QtCore/qdebug.h>
+#endif
+
+QT_BEGIN_NAMESPACE_CONTACTS
+
+/*!
+ \class QContactCollection
+ \brief The QContactCollection class represents a collection of contacts in a manager.
+ \inmodule QtContacts
+ \ingroup contacts-main
+
+ A collection has an ID and optionally some metadata, and contains zero or more contacts.
+ Each different manager will have different requirements before a collection may be saved
+ in it. Some managers do not allow collections to be saved at all, while others may require
+ a collection to have some minimal amount of metadata defined in it prior to save.
+ For example, most managers require a valid value for the QContactCollection::KeyName
+ meta data key to be set prior to save.
+
+ Every QContact is contained within a collection when stored in a manager.
+ To save an contact in a collection, the client should call QContact::setCollectionId()
+ on the contact, passing in the ID of the destination collection as the argument, and then
+ save the contact in the manager. To move an contact from one collection to another, the client
+ must fetch the contact from the manager, set the collection ID in the contact to the ID of the
+ collection to which the client wishes the contact to be moved, and then resave the contact in the
+ manager. That is, the collection which a contact is part of is treated as a property of the
+ contact.
+ */
+
+/*!
+ \enum QContactCollection::MetaDataKey
+
+ This enumeration describes the key of the contact collection metadata.
+
+ \value KeyName This metadata describes the name of the collection.
+ \value KeyDescription This metadata gives a description of the collection.
+ \value KeyColor This metadata describes the color of the collection.
+ \value KeySecondaryColor This metadata describes the secondary color of the collection.
+ \value KeyImage This metadata describes the image of the collection.
+ \value KeyExtended This is an extened metadata, which is stored as a QVariantMap.
+ */
+
+/*!
+ Constructs a new collection.
+ */
+QContactCollection::QContactCollection()
+ : d(new QContactCollectionData)
+{
+}
+
+/*!
+ Cleans up any memory in use by the collection.
+ */
+QContactCollection::~QContactCollection()
+{
+}
+
+/*!
+ Constructs a new copy of the \a other collection.
+ */
+QContactCollection::QContactCollection(const QContactCollection &other)
+ : d(other.d)
+{
+}
+
+/*!
+ Assigns this collection to be equal to the \a other collection.
+ */
+QContactCollection &QContactCollection::operator=(const QContactCollection &other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+ Returns true if the collection is the same as that of the \a other collection, false if either
+ the ID or any of the stored metadata are not the same.
+ */
+bool QContactCollection::operator==(const QContactCollection &other) const
+{
+ if (d == other.d)
+ return true;
+
+ if (d->m_id != other.d->m_id
+ || d->m_metaData.size() != other.d->m_metaData.size()) {
+ return false;
+ }
+
+ QMap<QContactCollection::MetaDataKey, QVariant>::const_iterator i = d->m_metaData.constBegin();
+ while (i != d->m_metaData.constEnd()) {
+ if (i.value() != other.d->m_metaData.value(i.key()))
+ return false;
+ ++i;
+ }
+
+ return true;
+}
+
+/*!
+ \fn QContactCollection::operator!=(const QContactCollection &other) const
+
+ Returns true if the collection is not the same as the \a other collection.
+ */
+
+/*!
+ Returns the ID of the collection.
+ */
+QContactCollectionId QContactCollection::id() const
+{
+ return d->m_id;
+}
+
+/*!
+ Sets the ID of the collection to \a id.
+
+ If the ID is set to a null (default-constructed) ID, saving the collection will cause the manager
+ to save the collection as a new collection.
+ */
+void QContactCollection::setId(const QContactCollectionId &id)
+{
+ d->m_id = id;
+}
+
+/*!
+ Sets the metadata of the collection to be \a metaData.
+ */
+void QContactCollection::setMetaData(const QMap<QContactCollection::MetaDataKey, QVariant> &metaData)
+{
+ d->m_metaData = metaData;
+}
+
+/*!
+ Returns the meta data of the collection.
+ */
+QMap<QContactCollection::MetaDataKey, QVariant> QContactCollection::metaData() const
+{
+ return d->m_metaData;
+}
+
+/*!
+ Sets the meta data of the collection for the given \a key to the given \a value.
+ */
+void QContactCollection::setMetaData(MetaDataKey key, const QVariant &value)
+{
+ d->m_metaData.insert(key, value);
+}
+
+/*!
+ Sets the value of the extended metadata with the given \a key to \a value.
+ */
+void QContactCollection::setExtendedMetaData(const QString &key, const QVariant &value)
+{
+ QVariantMap variantMap = d->m_metaData.value(QContactCollection::KeyExtended).toMap();
+ variantMap.insert(key, value);
+ d->m_metaData.insert(QContactCollection::KeyExtended, variantMap);
+}
+
+/*!
+ Returns the value of extended metadata with the given \a key.
+ */
+QVariant QContactCollection::extendedMetaData(const QString &key) const
+{
+ return d->m_metaData.value(QContactCollection::KeyExtended).toMap().value(key);
+}
+
+/*!
+ Returns the meta data of the collection for the given \a key.
+ */
+QVariant QContactCollection::metaData(MetaDataKey key) const
+{
+ return d->m_metaData.value(key);
+}
+
+/*!
+ \relates QContactCollection
+ Returns the hash value for \a key.
+ */
+Q_CONTACTS_EXPORT uint qHash(const QContactCollection &key)
+{
+ uint hash = qHash(key.id());
+ QMap<QContactCollection::MetaDataKey, QVariant>::const_iterator i = key.d->m_metaData.constBegin();
+ while (i != key.d->m_metaData.constEnd()) {
+ if (i.key() == QContactCollection::KeyExtended) {
+ QVariantMap variantMap = i.value().toMap();
+ QVariantMap::const_iterator j = variantMap.constBegin();
+ while (j != variantMap.constEnd()) {
+ hash += QT_PREPEND_NAMESPACE(qHash)(j.key()) + QT_PREPEND_NAMESPACE(qHash)(j.value().toString());
+ ++j;
+ }
+ } else {
+ hash += QT_PREPEND_NAMESPACE(qHash)(i.key()) + QT_PREPEND_NAMESPACE(qHash)(i.value().toString());
+ }
+ ++i;
+ }
+ return hash;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+/*!
+ \relates QContactCollection
+ Streams the \a collection to the given debug stream \a dbg, and returns the stream.
+ */
+QDebug operator<<(QDebug dbg, const QContactCollection& collection)
+{
+ dbg.nospace() << "QContactCollection(id=" << collection.id();
+
+ QMap<QContactCollection::MetaDataKey, QVariant> metaData = collection.metaData();
+ QMap<QContactCollection::MetaDataKey, QVariant>::const_iterator i = metaData.constBegin();
+ while (i != metaData.constEnd()) {
+ dbg.nospace() << ", " << i.key() << '=' << i.value();
+ ++i;
+ }
+ dbg.nospace() << ')';
+ return dbg.maybeSpace();
+}
+#endif // QT_NO_DEBUG_STREAM
+
+#ifndef QT_NO_DATASTREAM
+/*!
+ \relates QContactCollection
+ Writes \a collection to the stream \a out.
+ */
+QDataStream &operator<<(QDataStream &out, const QContactCollection &collection)
+{
+ quint8 formatVersion = 1;
+ return out << formatVersion
+ << collection.id().toString()
+ << collection.metaData();
+}
+
+/*!
+ \relates QContactCollection
+ Reads an organizer collection from stream \a in into \a collection.
+ */
+QDataStream &operator>>(QDataStream &in, QContactCollection &collection)
+{
+ quint8 formatVersion;
+ in >> formatVersion;
+ if (formatVersion == 1) {
+ QString idString;
+ QMap<int, QVariant> values;
+ in >> idString >> values;
+
+ collection = QContactCollection();
+ collection.setId(QContactCollectionId::fromString(idString));
+
+ QMap<int, QVariant>::const_iterator i = values.constBegin();
+ while (i != values.constEnd()) {
+ collection.setMetaData(static_cast<QContactCollection::MetaDataKey>(i.key()), i.value());
+ ++i;
+ }
+ } else {
+ in.setStatus(QDataStream::ReadCorruptData);
+ }
+ return in;
+}
+#endif // QT_NO_DATASTREAM
+
+QT_END_NAMESPACE_CONTACTS
diff --git a/src/contacts/qcontactcollection.h b/src/contacts/qcontactcollection.h
new file mode 100644
index 000000000..2278db565
--- /dev/null
+++ b/src/contacts/qcontactcollection.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2015 Canonical Ltd
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtOrganizer module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCONTACTCOLLECTION_H
+#define QCONTACTCOLLECTION_H
+
+#include <QtCore/qmap.h>
+#include <QtCore/qshareddata.h>
+#include <QtCore/qvariant.h>
+
+#include <QtContacts/qcontactcollectionid.h>
+#include <QtContacts/qcontactid.h>
+#include <QtContacts/qcontactdetail.h>
+#include <QtContacts/qcontacttype.h>
+
+QT_BEGIN_NAMESPACE_CONTACTS
+
+class QContactManagerEngine;
+
+class QContactCollectionData;
+class Q_CONTACTS_EXPORT QContactCollection
+{
+public:
+ enum MetaDataKey {
+ KeyName = 0,
+ KeyDescription,
+ KeyColor,
+ KeySecondaryColor,
+ KeyImage,
+ KeyExtended
+ };
+
+ QContactCollection();
+ ~QContactCollection();
+
+ QContactCollection(const QContactCollection &other);
+ QContactCollection &operator=(const QContactCollection &other);
+
+ bool operator==(const QContactCollection &other) const;
+ bool operator!=(const QContactCollection &other) const {return !(other == *this);}
+
+ QContactCollectionId id() const;
+ void setId(const QContactCollectionId &id);
+
+ void setMetaData(MetaDataKey key, const QVariant &value);
+ QVariant metaData(MetaDataKey key) const;
+
+ void setMetaData(const QMap<QContactCollection::MetaDataKey, QVariant> &metaData);
+ QMap<QContactCollection::MetaDataKey, QVariant> metaData() const;
+
+ void setExtendedMetaData(const QString &key, const QVariant &value);
+ QVariant extendedMetaData(const QString &key) const;
+
+private:
+ friend Q_CONTACTS_EXPORT uint qHash(const QContactCollection &key);
+ friend class QContactManagerEngine;
+ QSharedDataPointer<QContactCollectionData> d;
+};
+
+Q_CONTACTS_EXPORT uint qHash(const QContactCollection &key);
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_CONTACTS_EXPORT QDebug operator<<(QDebug dbg, const QContactCollection &collection);
+#endif // QT_NO_DEBUG_STREAM
+
+#ifndef QT_NO_DATASTREAM
+Q_CONTACTS_EXPORT QDataStream &operator<<(QDataStream &out, const QContactCollection &collection);
+Q_CONTACTS_EXPORT QDataStream &operator>>(QDataStream &in, QContactCollection &collection);
+#endif // QT_NO_DATASTREAM
+
+QT_END_NAMESPACE_CONTACTS
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_TYPEINFO(QTCONTACTS_PREPEND_NAMESPACE(QContactCollection), Q_MOVABLE_TYPE);
+QT_END_NAMESPACE
+
+#endif // QCONTACTCOLLECTION_H
diff --git a/src/contacts/qcontactcollection_p.h b/src/contacts/qcontactcollection_p.h
new file mode 100644
index 000000000..eaf5da748
--- /dev/null
+++ b/src/contacts/qcontactcollection_p.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2015 Canonical Ltd
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtOrganizer module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCONTACTCOLLECTION_P_H
+#define QCONTACTCOLLECTION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qmap.h>
+#include <QtCore/qshareddata.h>
+#include <QtCore/qvariant.h>
+
+#include <QtContacts/qcontactcollection.h>
+#include <QtContacts/qcontactcollectionid.h>
+
+QT_BEGIN_NAMESPACE_CONTACTS
+
+class QContactCollectionData : public QSharedData
+{
+public:
+ QContactCollectionData()
+ : QSharedData()
+ {
+ }
+
+ QContactCollectionData(const QContactCollectionData &other)
+ : QSharedData(other), m_metaData(other.m_metaData), m_id(other.m_id)
+ {
+ }
+
+ ~QContactCollectionData()
+ {
+ }
+
+ QMap<QContactCollection::MetaDataKey, QVariant> m_metaData;
+ QContactCollectionId m_id;
+};
+
+QT_END_NAMESPACE_CONTACTS
+
+#endif // QCONTACTCOLLECTION_P_H
diff --git a/src/contacts/qcontactcollectionchangeset.cpp b/src/contacts/qcontactcollectionchangeset.cpp
new file mode 100644
index 000000000..8f9af6805
--- /dev/null
+++ b/src/contacts/qcontactcollectionchangeset.cpp
@@ -0,0 +1,279 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2015 Canonical Ltd
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtOrganizer module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcontactcollectionchangeset.h"
+#include "qcontactcollectionchangeset_p.h"
+
+#include "qcontactmanagerengine.h"
+
+QT_BEGIN_NAMESPACE_CONTACTS
+
+/*!
+ \class QContactCollectionChangeSet
+ \brief The QContactCollectionChangeSet class provides a simple API to simplify the emission
+ of state-change signals for collections from QContactManagerEngine implementations.
+ \inmodule QtContacts
+ \ingroup contacts-main
+
+ This class should only be used by backend developers.
+ */
+
+/*!
+ Constructs a new change set.
+ */
+QContactCollectionChangeSet::QContactCollectionChangeSet()
+ : d(new QContactCollectionChangeSetData)
+{
+}
+
+/*!
+ Constructs a copy of the \a other change set.
+ */
+QContactCollectionChangeSet::QContactCollectionChangeSet(const QContactCollectionChangeSet &other)
+ : d(other.d)
+{
+}
+
+/*!
+ Frees the memory used by this change set.
+ */
+QContactCollectionChangeSet::~QContactCollectionChangeSet()
+{
+}
+
+/*!
+ Assigns this change set to be equal to \a other.
+ */
+QContactCollectionChangeSet &QContactCollectionChangeSet::operator=(const QContactCollectionChangeSet &other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+ Sets the data changed flag to \a dataChanged.
+
+ If this is set to true prior to calling emitSignals(), only the QContactManagerEngine::dataChanged()
+ signal will be emitted; otherwise, the appropriate finer-grained signals will be emitted.
+ */
+void QContactCollectionChangeSet::setDataChanged(bool dataChanged)
+{
+ d->m_dataChanged = dataChanged;
+}
+
+/*!
+ Returns the value of the data changed flag.
+ */
+bool QContactCollectionChangeSet::dataChanged() const
+{
+ return d->m_dataChanged;
+}
+
+/*!
+ Returns the set of IDs of collections which have been added to the database.
+ */
+QSet<QContactCollectionId> QContactCollectionChangeSet::addedCollections() const
+{
+ return d->m_addedCollections;
+}
+
+/*!
+ Inserts the given \a collectionId into the set of IDs of collections which have been added to
+ the database.
+ */
+void QContactCollectionChangeSet::insertAddedCollection(const QContactCollectionId &collectionId)
+{
+ d->m_addedCollections.insert(collectionId);
+ d->m_modifiedCollections.append(QPair<QContactCollectionId, QContactManager::Operation>(collectionId, QContactManager::Add));
+}
+
+/*!
+ Inserts each of the given \a collectionIds into the set of IDs of collections which have been
+ added to the database.
+ */
+void QContactCollectionChangeSet::insertAddedCollections(const QList<QContactCollectionId> &collectionIds)
+{
+ foreach (const QContactCollectionId &id, collectionIds) {
+ d->m_addedCollections.insert(id);
+ d->m_modifiedCollections.append(QPair<QContactCollectionId, QContactManager::Operation>(id, QContactManager::Add));
+ }
+}
+
+/*!
+ Clears the set of IDs of collections which have been added to the database.
+ */
+void QContactCollectionChangeSet::clearAddedCollections()
+{
+ d->m_addedCollections.clear();
+}
+
+/*!
+ Returns the set of IDs of collections which have been changed in the database.
+ */
+QSet<QContactCollectionId> QContactCollectionChangeSet::changedCollections() const
+{
+ return d->m_changedCollections;
+}
+
+/*!
+ Inserts the given \a collectionId into the set of IDs of collections which have been changed in
+ the database.
+ */
+void QContactCollectionChangeSet::insertChangedCollection(const QContactCollectionId &collectionId)
+{
+ d->m_changedCollections.insert(collectionId);
+ d->m_modifiedCollections.append(QPair<QContactCollectionId, QContactManager::Operation>(collectionId, QContactManager::Change));
+}
+
+/*!
+ Inserts each of the given \a collectionIds into the set of IDs of collections which have been
+ changed in the database.
+ */
+void QContactCollectionChangeSet::insertChangedCollections(const QList<QContactCollectionId> &collectionIds)
+{
+ foreach (const QContactCollectionId &id, collectionIds) {
+ d->m_changedCollections.insert(id);
+ d->m_modifiedCollections.append(QPair<QContactCollectionId, QContactManager::Operation>(id, QContactManager::Change));
+ }
+}
+
+/*!
+ Clears the set of IDs of collections which have been changed in the database.
+ */
+void QContactCollectionChangeSet::clearChangedCollections()
+{
+ d->m_changedCollections.clear();
+}
+
+/*!
+ Returns the set of IDs of collections which have been removed from the database.
+ */
+QSet<QContactCollectionId> QContactCollectionChangeSet::removedCollections() const
+{
+ return d->m_removedCollections;
+}
+
+/*!
+ Inserts the given \a collectionId into the set of IDs of collections which have been removed from
+ the database.
+ */
+void QContactCollectionChangeSet::insertRemovedCollection(const QContactCollectionId &collectionId)
+{
+ d->m_removedCollections.insert(collectionId);
+ d->m_modifiedCollections.append(QPair<QContactCollectionId, QContactManager::Operation>(collectionId, QContactManager::Remove));
+}
+
+/*!
+ Inserts each of the given \a collectionIds into the set of IDs of collections which have been
+ removed from the database.
+ */
+void QContactCollectionChangeSet::insertRemovedCollections(const QList<QContactCollectionId> &collectionIds)
+{
+ foreach (const QContactCollectionId &id, collectionIds) {
+ d->m_removedCollections.insert(id);
+ d->m_modifiedCollections.append(QPair<QContactCollectionId, QContactManager::Operation>(id, QContactManager::Remove));
+ }
+}
+
+/*!
+ Clears the set of ids of collections which have been removed from the database.
+ */
+void QContactCollectionChangeSet::clearRemovedCollections()
+{
+ d->m_removedCollections.clear();
+}
+
+/*!
+ Returns the list of ids of organizer collections which have been added, changed or removed from
+ the database. The list includes information about which database operation was done. The ids and
+ operations are ordered so that the first operation is first in the list.
+ */
+QList<QPair<QContactCollectionId, QContactManager::Operation> > QContactCollectionChangeSet::modifiedCollections() const
+{
+ return d->m_modifiedCollections;
+}
+
+/*!
+ Clears the list of ids of organizer collections which have been added, changed or removed from the database
+ */
+void QContactCollectionChangeSet::clearModifiedCollections()
+{
+ d->m_modifiedCollections.clear();
+}
+
+/*!
+ Clears all flags and sets of IDs in this change set.
+ */
+void QContactCollectionChangeSet::clearAll()
+{
+ d->m_dataChanged = false;
+ d->m_addedCollections.clear();
+ d->m_changedCollections.clear();
+ d->m_removedCollections.clear();
+ d->m_modifiedCollections.clear();
+}
+
+/*!
+ Emits the appropriate signals from the given \a engine given the state of the change set. Note
+ that the flags and sets of IDs are not cleared after signals are emitted.
+ */
+void QContactCollectionChangeSet::emitSignals(QContactManagerEngine *engine) const
+{
+ if (!engine)
+ return;
+
+ if (d->m_dataChanged) {
+ emit engine->dataChanged();
+ } else {
+ if (!d->m_addedCollections.isEmpty())
+ emit engine->collectionsAdded(d->m_addedCollections.toList());
+ if (!d->m_changedCollections.isEmpty())
+ emit engine->collectionsChanged(d->m_changedCollections.toList());
+ if (!d->m_removedCollections.isEmpty())
+ emit engine->collectionsRemoved(d->m_removedCollections.toList());
+ if (!d->m_modifiedCollections.isEmpty())
+ emit engine->collectionsModified(d->m_modifiedCollections);
+
+ }
+}
+
+QT_END_NAMESPACE_CONTACTS
diff --git a/src/contacts/qcontactcollectionchangeset.h b/src/contacts/qcontactcollectionchangeset.h
new file mode 100644
index 000000000..8cb392cd8
--- /dev/null
+++ b/src/contacts/qcontactcollectionchangeset.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2015 Canonical Ltd
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtOrganizer module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCONTACTCOLLECTIONCHANGESET_H
+#define QCONTACTCOLLECTIONCHANGESET_H
+
+#include <QtCore/qlist.h>
+#include <QtCore/qset.h>
+#include <QtCore/qshareddata.h>
+
+#include <QtContacts/qcontactcollectionid.h>
+#include <QtContacts/qcontactmanager.h>
+
+QT_BEGIN_NAMESPACE_CONTACTS
+
+class QContactManagerEngine;
+
+class QContactCollectionChangeSetData;
+class Q_CONTACTS_EXPORT QContactCollectionChangeSet
+{
+public:
+ QContactCollectionChangeSet();
+ QContactCollectionChangeSet(const QContactCollectionChangeSet &other);
+ ~QContactCollectionChangeSet();
+
+ QContactCollectionChangeSet &operator=(const QContactCollectionChangeSet &other);
+
+ void setDataChanged(bool dataChanged);
+ bool dataChanged() const;
+
+ QSet<QContactCollectionId> addedCollections() const;
+ void insertAddedCollection(const QContactCollectionId &collectionId);
+ void insertAddedCollections(const QList<QContactCollectionId> &collectionIds);
+ void clearAddedCollections();
+
+ QSet<QContactCollectionId> changedCollections() const;
+ void insertChangedCollection(const QContactCollectionId &collectionId);
+ void insertChangedCollections(const QList<QContactCollectionId> &collectionIds);
+ void clearChangedCollections();
+
+ QSet<QContactCollectionId> removedCollections() const;
+ void insertRemovedCollection(const QContactCollectionId &collectionId);
+ void insertRemovedCollections(const QList<QContactCollectionId> &collectionIds);
+ void clearRemovedCollections();
+
+ QList<QPair<QContactCollectionId, QContactManager::Operation> > modifiedCollections() const;
+ void clearModifiedCollections();
+
+ void clearAll();
+
+ void emitSignals(QContactManagerEngine *engine) const;
+
+private:
+ QSharedDataPointer<QContactCollectionChangeSetData> d;
+};
+
+QT_END_NAMESPACE_CONTACTS
+
+#endif // QCONTACTCOLLECTIONCHANGESET_H
diff --git a/src/contacts/qcontactcollectionchangeset_p.h b/src/contacts/qcontactcollectionchangeset_p.h
new file mode 100644
index 000000000..b8e372f37
--- /dev/null
+++ b/src/contacts/qcontactcollectionchangeset_p.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2015 Canonical Ltd
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtOrganizer module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCONTACTCOLLECTIONCHANGESET_P_H
+#define QCONTACTCOLLECTIONCHANGESET_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qlist.h>
+#include <QtCore/qset.h>
+#include <QtCore/qshareddata.h>
+
+#include <QtContacts/qcontactcollectionid.h>
+
+QT_BEGIN_NAMESPACE_CONTACTS
+
+class QContactCollectionChangeSetData : public QSharedData
+{
+public:
+ QContactCollectionChangeSetData()
+ : QSharedData(), m_dataChanged(false)
+ {
+ }
+
+ QContactCollectionChangeSetData(const QContactCollectionChangeSetData& other)
+ : QSharedData(other),
+ m_dataChanged(other.m_dataChanged),
+ m_addedCollections(other.m_addedCollections),
+ m_changedCollections(other.m_changedCollections),
+ m_removedCollections(other.m_removedCollections),
+ m_modifiedCollections(other.m_modifiedCollections)
+ {
+ }
+
+ ~QContactCollectionChangeSetData()
+ {
+ }
+
+ bool m_dataChanged;
+ QSet<QContactCollectionId> m_addedCollections;
+ QSet<QContactCollectionId> m_changedCollections;
+ QSet<QContactCollectionId> m_removedCollections;
+ QList<QPair<QContactCollectionId, QContactManager::Operation> > m_modifiedCollections;
+};
+
+QT_END_NAMESPACE_CONTACTS
+
+#endif // QCONTACTCOLLECTIONCHANGESET_P_H
diff --git a/src/contacts/qcontactcollectionid.cpp b/src/contacts/qcontactcollectionid.cpp
new file mode 100644
index 000000000..82b4f9243
--- /dev/null
+++ b/src/contacts/qcontactcollectionid.cpp
@@ -0,0 +1,259 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2015 Canonical Ltd
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtOrganizer module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcontactcollectionid.h"
+
+#ifndef QT_NO_DATASTREAM
+#include <QtCore/qdatastream.h>
+#endif
+#ifndef QT_NO_DEBUG_STREAM
+#include <QtCore/qdebug.h>
+#endif
+
+#include "qcontactmanager_p.h"
+
+QT_BEGIN_NAMESPACE_CONTACTS
+
+/*!
+ \class QContactCollectionId
+ \brief The QContactCollectionId class provides information that uniquely identifies a collection
+ in a particular manager.
+ \inmodule QtContact
+ \ingroup contact-main
+
+ It consists of a manager URI which identifies the manager which contains the collection,
+ and the engine specific ID of the collection in that manager.
+
+ An invalid QContactCollectionId has an empty manager URI.
+*/
+
+/*!
+ \fn QContactCollectionId::QContactCollectionId()
+
+ Constructs a new, invalid collection ID.
+*/
+
+// TODO: Document and remove internal once the correct signature has been determined
+/*!
+ \fn QContactCollectionId::QContactCollectionId(const QString &managerUri, const QByteArray &localId)
+ \internal
+
+ Constructs an ID from the supplied manager URI \a managerUri and the engine
+ specific \a localId string.
+*/
+
+/*!
+ \fn bool QContactCollectionId::operator==(const QContactCollectionId &other) const
+
+ Returns true if this collection ID has the same manager URI and
+ engine specific ID as \a other. Returns true also, if both IDs are null.
+*/
+
+/*!
+ \fn bool QContactCollectionId::operator!=(const QContactCollectionId &other) const
+
+ Returns true if either the manager URI or engine specific ID of this
+ collection ID is different to that of \a other.
+*/
+
+/*!
+ \fn bool operator<(const QContactCollectionId &id1, const QContactCollectionId &id2)
+ \relates QContactCollectionId
+
+ Returns true if the collection ID \a id1 will be considered less than
+ the collection ID \a id2 if the manager URI of ID \a id1 is alphabetically
+ less than the manager URI of the \a id2 ID. If both IDs have the same
+ manager URI, ID \a id1 will be considered less than the ID \a id2
+ if the the engine specific ID of \a id1 is less than the engine specific ID of \a id2.
+
+ The invalid, null collection ID consists of an empty manager URI and a null engine ID,
+ and hence will be less than any valid, non-null collection ID.
+
+ This operator is provided primarily to allow use of a QContactCollectionId as a key in a QMap.
+*/
+
+/*!
+ \fn uint qHash(const QContactCollectionId &id)
+ \relates QContactCollectionId
+
+ Returns the hash value for \a id.
+*/
+
+/*!
+ \fn bool QContactCollectionId::isValid() const
+
+ Returns true if the manager URI part is not null; returns false otherwise.
+
+ Note that valid ID may be null at the same time, which means new collection.
+
+ \sa isNull()
+*/
+
+/*!
+ \fn bool QContactCollectionId::isNull() const
+
+ Returns true if the engine specific ID part is a null (default constructed);
+ returns false otherwise.
+
+ \sa isValid()
+*/
+
+/*!
+ \fn QString QContactCollectionId::managerUri() const
+
+ Returns the URI of the manager which contains the collection identified by this ID.
+
+ \sa localId()
+*/
+
+/*!
+ \fn QByteArray QContactCollectionId::localId() const
+
+ Returns the collection's engine specific ID part.
+
+ \sa managerUri()
+*/
+
+/*!
+ Serializes the collection ID to a string. The format of the string will be:
+ "qtorganizer:managerName:params:localId", where localId is encoded binary data
+ formatted as hexadecimal to ensure it is in a printable form.
+
+ \sa fromString(), toByteArray()
+*/
+QString QContactCollectionId::toString() const
+{
+ if (!isNull()) {
+ // Ensure the localId component has a valid string representation by hex encoding
+ const QByteArray encodedLocalId(m_localId.toHex());
+ return QString::fromUtf8(QContactManagerData::buildIdData(m_managerUri, encodedLocalId));
+ }
+
+ return QString();
+}
+
+/*!
+ Deserializes the given \a idString. Returns a default-constructed (null)
+ collection ID if the given \a idString is not a valid, serialized collection ID.
+
+ \sa toString(), fromByteArray()
+*/
+QContactCollectionId QContactCollectionId::fromString(const QString &idString)
+{
+ QString managerUri;
+ QByteArray localId;
+
+ if (QContactManagerData::parseIdData(idString.toUtf8(), 0, 0, &managerUri, &localId)) {
+ // The localId component must be decoded from hex
+ return QContactCollectionId(managerUri, QByteArray::fromHex(localId));
+ }
+
+ return QContactCollectionId();
+}
+
+/*!
+ Serializes the collection ID to a byte array.
+
+ \sa fromByteArray(), toString()
+*/
+QByteArray QContactCollectionId::toByteArray() const
+{
+ if (!isNull())
+ return QContactManagerData::buildIdData(m_managerUri, m_localId);
+
+ return QByteArray();
+}
+
+/*!
+ Deserializes the given \a idData. Returns a default-constructed (null)
+ collection ID if the given \a idData does not contain a valid, serialized collection ID.
+
+ \sa toByteArray(), fromString()
+*/
+QContactCollectionId QContactCollectionId::fromByteArray(const QByteArray &idData)
+{
+ QString managerUri;
+ QByteArray localId;
+
+ if (QContactManagerData::parseIdData(idData, 0, 0, &managerUri, &localId))
+ return QContactCollectionId(managerUri, localId);
+
+ return QContactCollectionId();
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+/*!
+ \relates QContactCollectionId
+ Outputs \a id to the debug stream \a dbg.
+*/
+QDebug operator<<(QDebug dbg, const QContactCollectionId &id)
+{
+ dbg.nospace() << "QContactCollectionId(" << id.toString().toUtf8().constData() << ")";
+ return dbg.maybeSpace();
+}
+#endif // QT_NO_DEBUG_STREAM
+
+#ifndef QT_NO_DATASTREAM
+/*!
+ \relates QContactCollectionId
+ Streams \a id to the data stream \a out.
+*/
+QDataStream &operator<<(QDataStream &out, const QContactCollectionId &id)
+{
+ out << id.toByteArray();
+ return out;
+}
+
+/*!
+ \relates QContactCollectionId
+ Streams \a id in from the data stream \a in.
+*/
+QDataStream &operator>>(QDataStream &in, QContactCollectionId &id)
+{
+ QByteArray idData;
+ in >> idData;
+ id = QContactCollectionId::fromByteArray(idData);
+ return in;
+}
+#endif // QT_NO_DATASTREAM
+
+QT_END_NAMESPACE_CONTACTS
diff --git a/src/contacts/qcontactcollectionid.h b/src/contacts/qcontactcollectionid.h
new file mode 100644
index 000000000..8df821091
--- /dev/null
+++ b/src/contacts/qcontactcollectionid.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2015 Canonical Ltd
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtOrganizer module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCONTACTCOLLECTIONID_H
+#define QCONTACTCOLLECTIONID_H
+
+#include <QtCore/qvariant.h>
+
+#include <QtContacts/qcontactsglobal.h>
+
+QT_BEGIN_NAMESPACE_CONTACTS
+
+class QContactManagerEngine;
+
+class Q_CONTACTS_EXPORT QContactCollectionId
+{
+public:
+ inline QContactCollectionId() {}
+ inline QContactCollectionId(const QString &managerUri, const QByteArray &localId)
+ : m_managerUri(localId.isEmpty() ? QString() : managerUri),
+ m_localId(m_managerUri.isEmpty() ? QByteArray() : localId)
+ {}
+ // compiler-generated dtor and copy/move ctors/assignment operators are fine!
+
+ inline bool operator==(const QContactCollectionId &other) const
+ { return localId() == other.localId() && managerUri() == other.managerUri(); }
+ inline bool operator!=(const QContactCollectionId &other) const
+ { return !operator==(other); }
+
+ inline bool isNull() const { return m_localId.isEmpty(); }
+
+ inline QString managerUri() const { return m_managerUri; }
+ inline QByteArray localId() const { return m_localId; }
+
+ QString toString() const;
+ static QContactCollectionId fromString(const QString &idString);
+
+ QByteArray toByteArray() const;
+ static QContactCollectionId fromByteArray(const QByteArray &idData);
+
+private:
+ QString m_managerUri;
+ QByteArray m_localId;
+};
+
+inline bool operator<(const QContactCollectionId &id1, const QContactCollectionId &id2)
+{ return id1.managerUri() != id2.managerUri() ? id1.managerUri() < id2.managerUri() : id1.localId() < id2.localId(); }
+
+inline uint qHash(const QContactCollectionId &id)
+{ return qHash(id.localId()); }
+
+#ifndef QT_NO_DATASTREAM
+Q_CONTACTS_EXPORT QDataStream &operator<<(QDataStream &out, const QContactCollectionId &id);
+Q_CONTACTS_EXPORT QDataStream &operator>>(QDataStream &in, QContactCollectionId &id);
+#endif
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_CONTACTS_EXPORT QDebug operator<<(QDebug dbg, const QContactCollectionId &id);
+#endif
+
+QT_END_NAMESPACE_CONTACTS
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_TYPEINFO(QTCONTACTS_PREPEND_NAMESPACE(QContactCollectionId), Q_MOVABLE_TYPE);
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QTCONTACTS_PREPEND_NAMESPACE(QContactCollectionId))
+
+#endif // QCONTACTCOLLECTIONID_H
diff --git a/src/contacts/qcontactfilter.h b/src/contacts/qcontactfilter.h
index fdcddf77f..50fb81c9c 100644
--- a/src/contacts/qcontactfilter.h
+++ b/src/contacts/qcontactfilter.h
@@ -74,7 +74,8 @@ public:
IntersectionFilter,
UnionFilter,
IdFilter,
- DefaultFilter
+ DefaultFilter,
+ CollectionFilter
};
FilterType type() const;
diff --git a/src/contacts/qcontactmanager.cpp b/src/contacts/qcontactmanager.cpp
index 805d4203f..2730d29e3 100644
--- a/src/contacts/qcontactmanager.cpp
+++ b/src/contacts/qcontactmanager.cpp
@@ -812,6 +812,74 @@ QList<QContactDetail::DetailType> QContactManager::supportedContactDetailTypes()
}
/*!
+ Returns the default collection managed by this manager. There is always only one default collection
+ for each backend.
+ */
+QContactCollection QContactManager::defaultCollection()
+{
+ QContactManagerSyncOpErrorHolder h(this);
+ return d->m_engine->defaultCollection(&h.error);
+}
+
+/*!
+ Returns the collection identified by the given \a collectionId which is managed by this manager.
+ */
+QContactCollection QContactManager::collection(const QContactCollectionId& collectionId)
+{
+ QContactManagerSyncOpErrorHolder h(this);
+ return d->m_engine->collection(collectionId, &h.error);
+}
+
+/*!
+ Returns a list of all of the collections managed by this manager.
+ */
+QList<QContactCollection> QContactManager::collections()
+{
+ QContactManagerSyncOpErrorHolder h(this);
+ return d->m_engine->collections(&h.error);
+}
+
+/*!
+ Saves the given \a collection to the backend, and returns true on success or false otherwise.
+
+ Note that certain backends may not allow modification nor adding new collections, in such cases
+ the operation will fail and result a QContactManager::PermissionsError error.
+
+ A new collection will be created in the backend store if the collection ID of it is null.
+ Otherwise, an existing collection with the same ID will be updated. If the given collection ID
+ does not exist in the backend, it will result a QContactManager::DoesNotExistError error.
+
+ Note that upon successful saving, the backend may update the collection, e.g. collection ID for
+ newly saved collections.
+ */
+bool QContactManager::saveCollection(QContactCollection* collection)
+{
+ QContactManagerSyncOpErrorHolder h(this);
+ if (collection) {
+ return d->m_engine->saveCollection(collection, &h.error);
+ } else {
+ h.error = QContactManager::BadArgumentError;
+ return false;
+ }
+}
+
+/*!
+ Removes the collection identified by the given \a collectionId (and all items in the collection)
+ from the manager. Returns true on success, false on failure.
+
+ If the given \a collectionId does not exist, the operation will fail and QContactManager::DoesNotExistError
+ will be returned when calling error().
+
+ If the given \a collectionId refers to the default collection, the operation will fail and
+ QContactManager::PermissionsError will be returned when calling error().
+ */
+bool QContactManager::removeCollection(const QContactCollectionId &collectionId)
+{
+ QContactManagerSyncOpErrorHolder h(this);
+ return d->m_engine->removeCollection(collectionId, &h.error);
+}
+
+/*!
Returns the engine backend implementation version number
*/
int QContactManager::managerVersion() const
diff --git a/src/contacts/qcontactmanager.h b/src/contacts/qcontactmanager.h
index 9ccf3e6ca..c50288ed1 100644
--- a/src/contacts/qcontactmanager.h
+++ b/src/contacts/qcontactmanager.h
@@ -47,6 +47,7 @@
#include <QtCore/qstringlist.h>
#include <QtContacts/qcontact.h>
+#include <QtContacts/qcontactcollection.h>
#include <QtContacts/qcontactid.h>
#include <QtContacts/qcontactfetchhint.h>
#include <QtContacts/qcontactrelationship.h>
@@ -110,6 +111,12 @@ public:
MissingPlatformRequirementsError
};
+ enum Operation {
+ Add,
+ Change,
+ Remove
+ };
+
/* Error reporting */
QContactManager::Error error() const;
QMap<int, QContactManager::Error> errorMap() const;
@@ -150,6 +157,13 @@ public:
QList<QContactType::TypeValues> supportedContactTypes() const;
QList<QContactDetail::DetailType> supportedContactDetailTypes() const;
+ // collections
+ QContactCollection defaultCollection();
+ QContactCollection collection(const QContactCollectionId& collectionId);
+ QList<QContactCollection> collections();
+ bool saveCollection(QContactCollection* collection);
+ bool removeCollection(const QContactCollectionId& collectionId);
+
/* return a list of available backends for which a QContactManager can be constructed. */
static QStringList availableManagers();
@@ -161,6 +175,10 @@ Q_SIGNALS:
void relationshipsAdded(const QList<QContactId>& affectedContactIds);
void relationshipsRemoved(const QList<QContactId>& affectedContactIds);
void selfContactIdChanged(const QContactId& oldId, const QContactId& newId); // need both? or just new?
+ void collectionsAdded(const QList<QContactCollectionId> &collectionIds);
+ void collectionsChanged(const QList<QContactCollectionId> &collectionIds);
+ void collectionsRemoved(const QList<QContactCollectionId> &collectionIds);
+ void collectionsModified(const QList<QPair<QContactCollectionId, QContactManager::Operation> > &collectionIds);
protected:
void connectNotify(const QMetaMethod &signal);
diff --git a/src/contacts/qcontactmanagerengine.cpp b/src/contacts/qcontactmanagerengine.cpp
index 5c41a499c..ba2919d5f 100644
--- a/src/contacts/qcontactmanagerengine.cpp
+++ b/src/contacts/qcontactmanagerengine.cpp
@@ -451,6 +451,79 @@ bool QContactManagerEngine::removeRelationships(const QList<QContactRelationship
return false;
}
+/*!
+ This function should be reimplemented to support synchronous calls to fetch the default collection.
+ Any errors encountered during this operation should be stored to \a error.
+*/
+QContactCollection QContactManagerEngine::defaultCollection(QContactManager::Error* error)
+{
+ *error = QContactManager::NotSupportedError;
+ return QContactCollection();
+}
+
+/*!
+ This function should be reimplemented to support synchronous calls to fetch a collection based
+ on its ID. Any errors encountered during this operation should be stored to \a error. If the
+ given \a collectionId does not specify a valid collection, \a error will be set to
+ \c QContactManager::DoesNotExistError.
+
+*/
+QContactCollection QContactManagerEngine::collection(const QContactCollectionId& collectionId, QContactManager::Error* error)
+{
+ Q_UNUSED(collectionId);
+ *error = QContactManager::NotSupportedError;
+ return QContactCollection();
+}
+
+/*!
+ This function should be reimplemented to support synchronous calls to fetch all the collections
+ managed by this backend. Any errors encountered during this operation should be stored to \a error.
+ */
+QList<QContactCollection> QContactManagerEngine::collections(QContactManager::Error* error)
+{
+ *error = QContactManager::NotSupportedError;
+ return QList<QContactCollection>();
+}
+
+/*!
+ This function should be reimplemented to support synchronous calls to save a collection.
+
+ This function is supposed to save the given \a collection to the backend, and returns true on
+ success or false otherwise. Any errors encountered during this operation should be stored to
+ \a error.
+
+ A new collection will be created in the backend store if the collection ID of it is null.
+ Otherwise, an existing collection with the same ID will be updated. If the given collection ID
+ does not exist in the backend, it will result a QContactManager::DoesNotExistError error.
+
+ Note that upon successful saving, the backend may update the collection, e.g. collection ID for
+ newly saved collections.
+*/
+bool QContactManagerEngine::saveCollection(QContactCollection* collection, QContactManager::Error* error)
+{
+ Q_UNUSED(collection);
+
+ *error = QContactManager::NotSupportedError;
+ return false;
+}
+
+/*!
+ This function should be reimplemented to support synchronous calls to remove a collection.
+
+ This function is supposed to remove the collection identified by the given \a collectionId, and
+ all items in the collection. Returns true on success, or false otherwise. Any errors encountered
+ during this operation should be stored to \a error.
+
+ Note that removing the default collection should not be allowed and should result a
+ QContactManager::PermissionsError error.
+*/
+bool QContactManagerEngine::removeCollection(const QContactCollectionId& collectionId, QContactManager::Error* error)
+{
+ Q_UNUSED(collectionId);
+
+ *error = QContactManager::NotSupportedError;
+ return false;
+}
/*!
Given an input \a filter, returns the canonical version of the filter.
@@ -1416,6 +1489,15 @@ bool QContactManagerEngine::testFilter(const QContactFilter &filter, const QCont
// Fall through to end
}
break;
+
+ case QContactFilter::CollectionFilter:
+ {
+ const QContactCollectionFilter cf(filter);
+ const QSet<QContactCollectionId>& ids = cf.collectionIds();
+ if (ids.contains(contact.collectionId()))
+ return true;
+ return false;
+ }
}
return false;
}
@@ -1922,6 +2004,116 @@ void QContactManagerEngine::updateRelationshipFetchRequest(QContactRelationshipF
}
/*!
+ Updates the given QContactCollectionFetchRequest \a req with the latest results \a result and an operation error \a error.
+ In addition, the state of the request will be changed to \a newState.
+
+ It then causes the request to emit its resultsAvailable() signal to notify clients of the request progress.
+ If the new request state is different from the previous state, the stateChanged() signal will also be emitted from the request.
+ */
+void QContactManagerEngine::updateCollectionFetchRequest(QContactCollectionFetchRequest* req, const QList<QContactCollection>& result, QContactManager::Error error, QContactAbstractRequest::State newState)
+{
+ Q_ASSERT(req);
+ QContactCollectionFetchRequestPrivate* rd = static_cast<QContactCollectionFetchRequestPrivate*>(req->d_ptr);
+ QMutexLocker ml(&rd->m_mutex);
+ bool emitState = rd->m_state != newState;
+ rd->m_collections = result;
+ rd->m_error = error;
+ rd->m_state = newState;
+ ml.unlock();
+#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
+ QPointer<QContactAbstractRequest> guard(req);
+#endif
+ Qt::ConnectionType connectionType = Qt::DirectConnection;
+#ifdef QT_NO_THREAD
+ if (req->thread() != QThread::currentThread())
+ connectionType = Qt::BlockingQueuedConnection;
+#endif
+ QMetaObject::invokeMethod(req, "resultsAvailable", connectionType);
+#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
+ Q_ASSERT(guard);
+#endif
+ if (emitState)
+ QMetaObject::invokeMethod(req, "stateChanged", connectionType, Q_ARG(QContactAbstractRequest::State, newState));
+#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
+ Q_ASSERT(guard);
+#endif
+}
+
+/*!
+ Updates the given QContactCollectionRemoveRequest \a req with the operation error \a error, and map of input index to individual error \a errorMap.
+ In addition, the state of the request will be changed to \a newState.
+
+ It then causes the request to emit its resultsAvailable() signal to notify clients of the request progress.
+ If the new request state is different from the previous state, the stateChanged() signal will also be emitted from the request.
+ */
+void QContactManagerEngine::updateCollectionRemoveRequest(QContactCollectionRemoveRequest* req, QContactManager::Error error, const QMap<int, QContactManager::Error>& errorMap, QContactAbstractRequest::State newState)
+{
+ Q_ASSERT(req);
+ QContactCollectionRemoveRequestPrivate* rd = static_cast<QContactCollectionRemoveRequestPrivate*>(req->d_ptr);
+ QMutexLocker ml(&rd->m_mutex);
+ bool emitState = rd->m_state != newState;
+ rd->m_errors = errorMap;
+ rd->m_error = error;
+ rd->m_state = newState;
+ ml.unlock();
+#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
+ QPointer<QContactAbstractRequest> guard(req);
+#endif
+ Qt::ConnectionType connectionType = Qt::DirectConnection;
+#ifdef QT_NO_THREAD
+ if (req->thread() != QThread::currentThread())
+ connectionType = Qt::BlockingQueuedConnection;
+#endif
+ QMetaObject::invokeMethod(req, "resultsAvailable", connectionType);
+#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
+ Q_ASSERT(guard);
+#endif
+ if (emitState)
+ QMetaObject::invokeMethod(req, "stateChanged", connectionType, Q_ARG(QContactAbstractRequest::State, newState));
+#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
+ Q_ASSERT(guard);
+#endif
+}
+
+/*!
+ Updates the given QContactCollectionSaveRequest \a req with the latest results \a result, operation error \a error, and map of input index to individual error \a errorMap.
+ In addition, the state of the request will be changed to \a newState.
+
+ It then causes the request to emit its resultsAvailable() signal to notify clients of the request progress.
+ If the new request state is different from the previous state, the stateChanged() signal will also be emitted from the request.
+ */
+void QContactManagerEngine::updateCollectionSaveRequest(QContactCollectionSaveRequest* req, const QList<QContactCollection>& result, QContactManager::Error error, const QMap<int, QContactManager::Error>& errorMap, QContactAbstractRequest::State newState)
+{
+ Q_ASSERT(req);
+ QContactCollectionSaveRequestPrivate* rd = static_cast<QContactCollectionSaveRequestPrivate*>(req->d_ptr);
+ QMutexLocker ml(&rd->m_mutex);
+ bool emitState = rd->m_state != newState;
+ rd->m_collections = result;
+ rd->m_errors = errorMap;
+ rd->m_error = error;
+ rd->m_state = newState;
+ ml.unlock();
+#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
+ QPointer<QContactAbstractRequest> guard(req);
+#endif
+ Qt::ConnectionType connectionType = Qt::DirectConnection;
+#ifdef QT_NO_THREAD
+ if (req->thread() != QThread::currentThread())
+ connectionType = Qt::BlockingQueuedConnection;
+#endif
+ QMetaObject::invokeMethod(req, "resultsAvailable", connectionType);
+#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
+ Q_ASSERT(guard);
+#endif
+ if (emitState)
+ QMetaObject::invokeMethod(req, "stateChanged", connectionType, Q_ARG(QContactAbstractRequest::State, newState));
+#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
+ Q_ASSERT(guard);
+#endif
+}
+
+
+/*!
For each contact in \a contacts, either add it to the database or update an existing one.
This function accepts a \a typeMask, which specifies which details of the contacts should be
diff --git a/src/contacts/qcontactmanagerengine.h b/src/contacts/qcontactmanagerengine.h
index c438772d7..146b4a48d 100644
--- a/src/contacts/qcontactmanagerengine.h
+++ b/src/contacts/qcontactmanagerengine.h
@@ -56,6 +56,9 @@
#include <QtContacts/qcontactmanager.h>
#include <QtContacts/qcontactrequests.h>
#include <QtContacts/qcontactsortorder.h>
+#include <QtContacts/qcontactcollectionfetchrequest.h>
+#include <QtContacts/qcontactcollectionsaverequest.h>
+#include <QtContacts/qcontactcollectionremoverequest.h>
QT_BEGIN_NAMESPACE_CONTACTS
@@ -77,6 +80,8 @@ public:
inline QContactId contactId(const QByteArray &localId) const
{ return QContactId(managerUri(), localId); }
+ inline QContactCollectionId collectionId(const QByteArray &localId) const
+ { return QContactCollectionId(managerUri(), localId); }
/* Filtering */
virtual QList<QContactId> contactIds(const QContactFilter &filter, const QList<QContactSortOrder> &sortOrders, QContactManager::Error *error) const;
@@ -102,6 +107,13 @@ public:
virtual bool saveRelationships(QList<QContactRelationship> *relationships, QMap<int, QContactManager::Error>* errorMap, QContactManager::Error *error);
virtual bool removeRelationships(const QList<QContactRelationship> &relationships, QMap<int, QContactManager::Error> *errorMap, QContactManager::Error *error);
+ // collections
+ virtual QContactCollection defaultCollection(QContactManager::Error *error);
+ virtual QContactCollection collection(const QContactCollectionId &collectionId, QContactManager::Error *error);
+ virtual QList<QContactCollection> collections(QContactManager::Error *error);
+ virtual bool saveCollection(QContactCollection *collection, QContactManager::Error *error);
+ virtual bool removeCollection(const QContactCollectionId &collectionId, QContactManager::Error *error);
+
/* Validation for saving */
virtual bool validateContact(const QContact &contact, QContactManager::Error *error) const;
@@ -126,6 +138,10 @@ Q_SIGNALS:
void relationshipsAdded(const QList<QContactId> &affectedContactIds);
void relationshipsRemoved(const QList<QContactId> &affectedContactIds);
void selfContactIdChanged(const QContactId &oldId, const QContactId &newId);
+ void collectionsAdded(const QList<QContactCollectionId> &collectionIds);
+ void collectionsChanged(const QList<QContactCollectionId> &collectionIds);
+ void collectionsRemoved(const QList<QContactCollectionId> &collectionIds);
+ void collectionsModified(const QList<QPair<QContactCollectionId, QContactManager::Operation> > &collectionIds);
public:
// Async update functions
@@ -140,6 +156,11 @@ public:
static void updateRelationshipRemoveRequest(QContactRelationshipRemoveRequest *req, QContactManager::Error error, const QMap<int, QContactManager::Error> &errorMap, QContactAbstractRequest::State);
static void updateRelationshipFetchRequest(QContactRelationshipFetchRequest *req, const QList<QContactRelationship> &result, QContactManager::Error error, QContactAbstractRequest::State);
+ // collections
+ static void updateCollectionFetchRequest(QContactCollectionFetchRequest *request, const QList<QContactCollection> &result, QContactManager::Error error, QContactAbstractRequest::State newState);
+ static void updateCollectionRemoveRequest(QContactCollectionRemoveRequest *request, QContactManager::Error error, const QMap<int, QContactManager::Error> &errorMap, QContactAbstractRequest::State newState);
+ static void updateCollectionSaveRequest(QContactCollectionSaveRequest *request, const QList<QContactCollection> &result, QContactManager::Error error, const QMap<int, QContactManager::Error> &errorMap, QContactAbstractRequest::State newState);
+
// Other protected area update functions
static void setDetailAccessConstraints(QContactDetail *detail, QContactDetail::AccessConstraints constraints);
static void setContactRelationships(QContact *contact, const QList<QContactRelationship> &relationships);
diff --git a/src/contacts/requests/qcontactcollectionfetchrequest.cpp b/src/contacts/requests/qcontactcollectionfetchrequest.cpp
new file mode 100644
index 000000000..adf09a6a3
--- /dev/null
+++ b/src/contacts/requests/qcontactcollectionfetchrequest.cpp
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2015 Canonical Ltd
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtOrganizer module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcontactcollectionfetchrequest.h"
+
+#include "qcontactrequests_p.h"
+
+QT_BEGIN_NAMESPACE_CONTACTS
+
+/*!
+ \class QContactCollectionFetchRequest
+ \brief The QContactCollectionFetchRequest class allows a client to asynchronously fetch collections
+ from a backend.
+ \inmodule QtContacts
+ \ingroup contacts-requests
+
+ This request will fetch all the collections stored in the given backend.
+ */
+
+/*!
+ Constructs a new contact fetch request whose parent is the specified \a parent.
+*/
+QContactCollectionFetchRequest::QContactCollectionFetchRequest(QObject *parent)
+ : QContactAbstractRequest(new QContactCollectionFetchRequestPrivate, parent)
+{
+}
+
+/*!
+ Frees memory in use by this request.
+*/
+QContactCollectionFetchRequest::~QContactCollectionFetchRequest()
+{
+}
+
+/*!
+ Returns the collections retrieved by this request.
+*/
+QList<QContactCollection> QContactCollectionFetchRequest::collections() const
+{
+ Q_D(const QContactCollectionFetchRequest);
+ QMutexLocker ml(&d->m_mutex);
+ return d->m_collections;
+}
+
+#include "moc_qcontactcollectionfetchrequest.cpp"
+
+QT_END_NAMESPACE_CONTACTS
diff --git a/src/contacts/requests/qcontactcollectionfetchrequest.h b/src/contacts/requests/qcontactcollectionfetchrequest.h
new file mode 100644
index 000000000..db08499f5
--- /dev/null
+++ b/src/contacts/requests/qcontactcollectionfetchrequest.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2015 Canonical Ltd
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtOrganizer module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCONTACTCOLLECTIONFETCHREQUEST_H
+#define QCONTACTCOLLECTIONFETCHREQUEST_H
+
+#include <QtCore/qlist.h>
+
+#include <QtContacts/qcontactabstractrequest.h>
+#include <QtContacts/qcontactcollection.h>
+
+QT_BEGIN_NAMESPACE_CONTACTS
+
+class QContactCollectionFetchRequestPrivate;
+
+/* Leaf class */
+
+class Q_CONTACTS_EXPORT QContactCollectionFetchRequest : public QContactAbstractRequest
+{
+ Q_OBJECT
+
+public:
+ QContactCollectionFetchRequest(QObject *parent = 0);
+ ~QContactCollectionFetchRequest();
+
+ QList<QContactCollection> collections() const;
+
+private:
+ Q_DISABLE_COPY(QContactCollectionFetchRequest)
+ friend class QContactManagerEngine;
+ Q_DECLARE_PRIVATE_D(d_ptr, QContactCollectionFetchRequest)
+};
+
+QT_END_NAMESPACE_CONTACTS
+
+#endif // QCONTACTCOLLECTIONFETCHREQUEST_H
diff --git a/src/contacts/requests/qcontactcollectionremoverequest.cpp b/src/contacts/requests/qcontactcollectionremoverequest.cpp
new file mode 100644
index 000000000..9bd3a03ad
--- /dev/null
+++ b/src/contacts/requests/qcontactcollectionremoverequest.cpp
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2015 Canonical Ltd
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtOrganizer module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcontactcollectionremoverequest.h"
+
+#include "qcontactrequests_p.h"
+
+QT_BEGIN_NAMESPACE_CONTACTS
+
+/*!
+ \class QContactCollectionRemoveRequest
+ \brief The QContactCollectionRemoveRequest class allows a client to asynchronously remove
+ collections from a backend.
+ \inmodule QtContacts
+ \ingroup contact-requests
+ */
+
+/*!
+ Constructs a new collection remove request whose parent is the specified \a parent.
+*/
+QContactCollectionRemoveRequest::QContactCollectionRemoveRequest(QObject *parent)
+ : QContactAbstractRequest(new QContactCollectionRemoveRequestPrivate, parent)
+{
+}
+
+/*!
+ Frees memory in use by this request.
+*/
+QContactCollectionRemoveRequest::~QContactCollectionRemoveRequest()
+{
+}
+
+/*!
+ Sets the ID of collection which will be removed by this request to \a collectionId.
+*/
+void QContactCollectionRemoveRequest::setCollectionId(const QContactCollectionId &collectionId)
+{
+ Q_D(QContactCollectionRemoveRequest);
+ QMutexLocker ml(&d->m_mutex);
+ d->m_collectionIds.clear();
+ d->m_collectionIds.append(collectionId);
+}
+
+/*!
+ Sets the list of IDs of collections which will be removed by this request to \a collectionIds.
+*/
+void QContactCollectionRemoveRequest::setCollectionIds(const QList<QContactCollectionId> &collectionIds)
+{
+ Q_D(QContactCollectionRemoveRequest);
+ QMutexLocker ml(&d->m_mutex);
+ d->m_collectionIds = collectionIds;
+}
+
+/*!
+ Returns the list of IDs of collections which will be removed by this request.
+*/
+QList<QContactCollectionId> QContactCollectionRemoveRequest::collectionIds() const
+{
+ Q_D(const QContactCollectionRemoveRequest);
+ QMutexLocker ml(&d->m_mutex);
+ return d->m_collectionIds;
+}
+
+/*!
+ Returns any errors which occurred during the request.
+*/
+QMap<int, QContactManager::Error> QContactCollectionRemoveRequest::errorMap() const
+{
+ Q_D(const QContactCollectionRemoveRequest);
+ QMutexLocker ml(&d->m_mutex);
+ return d->m_errors;
+}
+
+#include "moc_qcontactcollectionremoverequest.cpp"
+
+QT_END_NAMESPACE_CONTACTS
diff --git a/src/contacts/requests/qcontactcollectionremoverequest.h b/src/contacts/requests/qcontactcollectionremoverequest.h
new file mode 100644
index 000000000..54b2e7538
--- /dev/null
+++ b/src/contacts/requests/qcontactcollectionremoverequest.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2015 Canonical Ltd
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtOrganizer module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCONTACTCOLLECTIONREMOVEREQUEST_H
+#define QCONTACTCOLLECTIONREMOVEREQUEST_H
+
+#include <QtCore/qlist.h>
+#include <QtCore/qmap.h>
+
+#include <QtContacts/qcontactabstractrequest.h>
+#include <QtContacts/qcontactcollectionid.h>
+
+QT_BEGIN_NAMESPACE_CONTACTS
+
+class QContactCollectionRemoveRequestPrivate;
+
+/* Leaf class */
+
+class Q_CONTACTS_EXPORT QContactCollectionRemoveRequest : public QContactAbstractRequest
+{
+ Q_OBJECT
+
+public:
+ QContactCollectionRemoveRequest(QObject *parent = 0);
+ ~QContactCollectionRemoveRequest();
+
+ void setCollectionId(const QContactCollectionId &collectionId);
+ void setCollectionIds(const QList<QContactCollectionId> &collectionIds);
+ QList<QContactCollectionId> collectionIds() const;
+
+ QMap<int, QContactManager::Error> errorMap() const;
+
+private:
+ Q_DISABLE_COPY(QContactCollectionRemoveRequest)
+ friend class QOrganizerManagerEngine;
+ Q_DECLARE_PRIVATE_D(d_ptr, QContactCollectionRemoveRequest)
+};
+
+QT_END_NAMESPACE_CONTACTS
+
+#endif // QCONTACTCOLLECTIONREMOVEREQUEST_H
diff --git a/src/contacts/requests/qcontactcollectionsaverequest.cpp b/src/contacts/requests/qcontactcollectionsaverequest.cpp
new file mode 100644
index 000000000..39877f7c9
--- /dev/null
+++ b/src/contacts/requests/qcontactcollectionsaverequest.cpp
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2015 Canonical Ltd
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtOrganizer module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcontactcollectionsaverequest.h"
+
+#include "qcontactrequests_p.h"
+
+QT_BEGIN_NAMESPACE_CONTACTS
+
+/*!
+ \class QContactCollectionSaveRequest
+ \brief The QContactCollectionSaveRequest class allows a client to asynchronously save collections
+ to a backend.
+ \inmodule QtContacts
+ \ingroup contact-requests
+ */
+
+/*!
+ Constructs a new collection save request whose parent is the specified \a parent.
+*/
+QContactCollectionSaveRequest::QContactCollectionSaveRequest(QObject *parent)
+ : QContactAbstractRequest(new QContactCollectionSaveRequestPrivate, parent)
+{
+}
+
+/*!
+ Frees memory in use by this request.
+*/
+QContactCollectionSaveRequest::~QContactCollectionSaveRequest()
+{
+}
+
+/*!
+ Sets the collection which will be saved to \a collection.
+*/
+void QContactCollectionSaveRequest::setCollection(const QContactCollection &collection)
+{
+ Q_D(QContactCollectionSaveRequest);
+ QMutexLocker ml(&d->m_mutex);
+ d->m_collections.clear();
+ d->m_collections.append(collection);
+}
+
+/*!
+ Sets the list of collections which will be saved to \a collections.
+*/
+void QContactCollectionSaveRequest::setCollections(const QList<QContactCollection> &collections)
+{
+ Q_D(QContactCollectionSaveRequest);
+ QMutexLocker ml(&d->m_mutex);
+ d->m_collections = collections;
+}
+
+/*!
+ Returns the collections which will be saved by this request if called prior to calling start(),
+ otherwise returns the (possibly updated) collections which have been saved.
+*/
+QList<QContactCollection> QContactCollectionSaveRequest::collections() const
+{
+ Q_D(const QContactCollectionSaveRequest);
+ QMutexLocker ml(&d->m_mutex);
+ return d->m_collections;
+}
+
+/*!
+ Returns the map of input definition list indices to errors which occurred.
+*/
+QMap<int, QContactManager::Error> QContactCollectionSaveRequest::errorMap() const
+{
+ Q_D(const QContactCollectionSaveRequest);
+ QMutexLocker ml(&d->m_mutex);
+ return d->m_errors;
+}
+
+#include "moc_qcontactcollectionsaverequest.cpp"
+
+QT_END_NAMESPACE_CONTACTS
diff --git a/src/contacts/requests/qcontactcollectionsaverequest.h b/src/contacts/requests/qcontactcollectionsaverequest.h
new file mode 100644
index 000000000..287157c5e
--- /dev/null
+++ b/src/contacts/requests/qcontactcollectionsaverequest.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2015 Canonical Ltd
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtOrganizer module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCONTACTCOLLECTIONSAVEREQUEST_H
+#define QCONTACTCOLLECTIONSAVEREQUEST_H
+
+#include <QtCore/qlist.h>
+#include <QtCore/qmap.h>
+
+#include <QtContacts/qcontactabstractrequest.h>
+#include <QtContacts/qcontactcollection.h>
+
+QT_BEGIN_NAMESPACE_CONTACTS
+
+class QContactCollectionSaveRequestPrivate;
+
+/* Leaf class */
+
+class Q_CONTACTS_EXPORT QContactCollectionSaveRequest : public QContactAbstractRequest
+{
+ Q_OBJECT
+
+public:
+ QContactCollectionSaveRequest(QObject *parent = 0);
+ ~QContactCollectionSaveRequest();
+
+ void setCollection(const QContactCollection &collection);
+ void setCollections(const QList<QContactCollection> &collections);
+ QList<QContactCollection> collections() const;
+
+ QMap<int, QContactManager::Error> errorMap() const;
+
+private:
+ Q_DISABLE_COPY(QContactCollectionSaveRequest)
+ friend class QContactManagerEngine;
+ Q_DECLARE_PRIVATE_D(d_ptr, QContactCollectionSaveRequest)
+};
+
+QT_END_NAMESPACE_CONTACTS
+
+#endif // QCONTACTCOLLECTIONSAVEREQUEST_H
diff --git a/src/contacts/requests/qcontactrequests.h b/src/contacts/requests/qcontactrequests.h
index d976eecfd..778942c1e 100644
--- a/src/contacts/requests/qcontactrequests.h
+++ b/src/contacts/requests/qcontactrequests.h
@@ -55,6 +55,11 @@
#include <QtContacts/qcontactremoverequest.h>
#include <QtContacts/qcontactsaverequest.h>
+#include <QtContacts/qcontactcollectionchangeset.h>
+#include <QtContacts/qcontactcollectionfetchrequest.h>
+#include <QtContacts/qcontactcollectionremoverequest.h>
+#include <QtContacts/qcontactcollectionsaverequest.h>
+
QT_BEGIN_NAMESPACE_CONTACTS
QT_END_NAMESPACE_CONTACTS
diff --git a/src/contacts/requests/qcontactrequests_p.h b/src/contacts/requests/qcontactrequests_p.h
index f2aae7c5f..6ea90fdd5 100644
--- a/src/contacts/requests/qcontactrequests_p.h
+++ b/src/contacts/requests/qcontactrequests_p.h
@@ -306,6 +306,92 @@ public:
QMap<int, QContactManager::Error> m_errors;
};
+class QContactCollectionFetchRequestPrivate : public QContactAbstractRequestPrivate
+{
+public:
+ QContactCollectionFetchRequestPrivate()
+ : QContactAbstractRequestPrivate(QContactAbstractRequest::CollectionFetchRequest)
+ {
+ }
+
+ ~QContactCollectionFetchRequestPrivate()
+ {
+ }
+
+#ifndef QT_NO_DEBUG_STREAM
+ QDebug& debugStreamOut(QDebug &dbg) const
+ {
+ dbg.nospace() << "QContactCollectionFetchRequestPrivate(";
+ dbg.nospace() << "collections=";
+ dbg.nospace() << m_collections;
+ dbg.nospace() << ")";
+ return dbg.maybeSpace();
+ }
+#endif
+
+ QList<QContactCollection> m_collections;
+};
+
+class QContactCollectionRemoveRequestPrivate : public QContactAbstractRequestPrivate
+{
+public:
+ QContactCollectionRemoveRequestPrivate()
+ : QContactAbstractRequestPrivate(QContactAbstractRequest::CollectionRemoveRequest)
+ {
+ }
+
+ ~QContactCollectionRemoveRequestPrivate()
+ {
+ }
+
+#ifndef QT_NO_DEBUG_STREAM
+ QDebug& debugStreamOut(QDebug &dbg) const
+ {
+ dbg.nospace() << "QContactCollectionRemoveRequestPrivate(";
+ dbg.nospace() << "collectionIds=";
+ dbg.nospace() << m_collectionIds;
+ dbg.nospace() << ",";
+ dbg.nospace() << "errorMap=";
+ dbg.nospace() << m_errors;
+ dbg.nospace() << ")";
+ return dbg.maybeSpace();
+ }
+#endif
+
+ QList<QContactCollectionId> m_collectionIds;
+ QMap<int, QContactManager::Error> m_errors;
+};
+
+class QContactCollectionSaveRequestPrivate : public QContactAbstractRequestPrivate
+{
+public:
+ QContactCollectionSaveRequestPrivate()
+ : QContactAbstractRequestPrivate(QContactAbstractRequest::CollectionSaveRequest)
+ {
+ }
+
+ ~QContactCollectionSaveRequestPrivate()
+ {
+ }
+
+#ifndef QT_NO_DEBUG_STREAM
+ QDebug& debugStreamOut(QDebug &dbg) const
+ {
+ dbg.nospace() << "QContactCollectionSaveRequestPrivate(";
+ dbg.nospace() << "collections=";
+ dbg.nospace() << m_collections;
+ dbg.nospace() << ",";
+ dbg.nospace() << "errorMap=";
+ dbg.nospace() << m_errors;
+ dbg.nospace() << ")";
+ return dbg.maybeSpace();
+ }
+#endif
+
+ QList<QContactCollection> m_collections;
+ QMap<int, QContactManager::Error> m_errors;
+};
+
QT_END_NAMESPACE_CONTACTS
#endif // QCONTACTREQUESTS_P_H
diff --git a/src/contacts/requests/requests.pri b/src/contacts/requests/requests.pri
index a8efb65b1..d5c9dff03 100644
--- a/src/contacts/requests/requests.pri
+++ b/src/contacts/requests/requests.pri
@@ -1,6 +1,9 @@
INCLUDEPATH += requests
PUBLIC_HEADERS += \
+ requests/qcontactcollectionfetchrequest.h \
+ requests/qcontactcollectionremoverequest.h \
+ requests/qcontactcollectionsaverequest.h \
requests/qcontactfetchrequest.h \
requests/qcontactfetchbyidrequest.h \
requests/qcontactidfetchrequest.h \
@@ -15,6 +18,9 @@ PRIVATE_HEADERS += \
requests/qcontactrequests_p.h
SOURCES += \
+ requests/qcontactcollectionfetchrequest.cpp \
+ requests/qcontactcollectionremoverequest.cpp \
+ requests/qcontactcollectionsaverequest.cpp \
requests/qcontactfetchrequest.cpp \
requests/qcontactfetchbyidrequest.cpp \
requests/qcontactidfetchrequest.cpp \
diff --git a/src/imports/contacts/contacts.pro b/src/imports/contacts/contacts.pro
index b9b3c6a29..a26bb8265 100644
--- a/src/imports/contacts/contacts.pro
+++ b/src/imports/contacts/contacts.pro
@@ -5,6 +5,7 @@ include(filters/filters.pri)
HEADERS += qdeclarativecontactmodel_p.h \
qdeclarativecontact_p.h \
+ qdeclarativecontactcollection_p.h \
qdeclarativecontactdetail_p.h \
qdeclarativecontactfilter_p.h \
qdeclarativecontactsortorder_p.h \
@@ -15,6 +16,7 @@ HEADERS += qdeclarativecontactmodel_p.h \
SOURCES += plugin.cpp \
qdeclarativecontactmodel.cpp \
qdeclarativecontact.cpp \
+ qdeclarativecontactcollection.cpp \
qdeclarativecontactdetail.cpp \
qdeclarativecontactfilter.cpp \
qdeclarativecontactsortorder.cpp \
diff --git a/src/imports/contacts/filters/filters.pri b/src/imports/contacts/filters/filters.pri
index 63bf1e468..2bb4738e9 100644
--- a/src/imports/contacts/filters/filters.pri
+++ b/src/imports/contacts/filters/filters.pri
@@ -3,6 +3,7 @@ INCLUDEPATH += filters
HEADERS += \
filters/qdeclarativecontactactionfilter_p.h \
filters/qdeclarativecontactchangelogfilter_p.h \
+ filters/qdeclarativecontactcollectionfilter_p.h \
filters/qdeclarativecontactdetailfilter_p.h \
filters/qdeclarativecontactdetailrangefilter_p.h \
filters/qdeclarativecontactidfilter_p.h \
diff --git a/src/imports/contacts/filters/qdeclarativecontactcollectionfilter_p.h b/src/imports/contacts/filters/qdeclarativecontactcollectionfilter_p.h
new file mode 100644
index 000000000..3f523db16
--- /dev/null
+++ b/src/imports/contacts/filters/qdeclarativecontactcollectionfilter_p.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtContacts module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVECONTACTCOLLECTIONFILTER_H
+#define QDECLARATIVECONTACTCOLLECTIONFILTER_H
+
+#include <QtContacts/qcontactcollectionfilter.h>
+
+#include "qdeclarativecontactfilter_p.h"
+
+QTCONTACTS_USE_NAMESPACE
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeContactCollectionFilter : public QDeclarativeContactFilter
+{
+ Q_OBJECT
+ Q_PROPERTY(QStringList ids READ ids WRITE setIds NOTIFY valueChanged)
+
+public:
+ QDeclarativeContactCollectionFilter(QObject *parent = 0)
+ : QDeclarativeContactFilter(parent)
+ {
+ connect(this, SIGNAL(valueChanged()), SIGNAL(filterChanged()));
+ }
+
+ QStringList ids() const
+ {
+ return m_ids;
+ }
+
+ void setIds(const QStringList &ids)
+ {
+ foreach (const QString &id, ids) {
+ if (!m_ids.contains(id)) {
+ m_ids = ids;
+ emit valueChanged();
+ return;
+ }
+ }
+
+ foreach (const QString &id, m_ids) {
+ if (!ids.contains(id)) {
+ m_ids = ids;
+ emit valueChanged();
+ return;
+ }
+ }
+ }
+
+ // used by model
+ QContactFilter filter() const
+ {
+ QContactCollectionFilter f;
+ QSet<QContactCollectionId> ids;
+
+ foreach (const QVariant &id, m_ids) {
+ QContactCollectionId cId = QContactCollectionId::fromString(id.toString());
+ if (!cId.isNull())
+ ids << cId;
+ }
+
+ f.setCollectionIds(ids);
+ return f;
+ }
+
+Q_SIGNALS:
+ void valueChanged();
+
+private:
+ QStringList m_ids;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeContactCollectionFilter)
+
+#endif // QDECLARATIVECONTACTCOLLECTIONFILTER_H
diff --git a/src/imports/contacts/filters/qdeclarativecontactfiltermoc.cpp b/src/imports/contacts/filters/qdeclarativecontactfiltermoc.cpp
index 9a83d1d03..c7db6f83c 100644
--- a/src/imports/contacts/filters/qdeclarativecontactfiltermoc.cpp
+++ b/src/imports/contacts/filters/qdeclarativecontactfiltermoc.cpp
@@ -45,6 +45,7 @@ QT_BEGIN_NAMESPACE
#include "moc_qdeclarativecontactactionfilter_p.cpp"
#include "moc_qdeclarativecontactchangelogfilter_p.cpp"
+#include "moc_qdeclarativecontactcollectionfilter_p.cpp"
#include "moc_qdeclarativecontactdetailfilter_p.cpp"
#include "moc_qdeclarativecontactdetailrangefilter_p.cpp"
#include "moc_qdeclarativecontactintersectionfilter_p.cpp"
diff --git a/src/imports/contacts/filters/qdeclarativecontactfilters_p.h b/src/imports/contacts/filters/qdeclarativecontactfilters_p.h
index c80393965..a073715b9 100644
--- a/src/imports/contacts/filters/qdeclarativecontactfilters_p.h
+++ b/src/imports/contacts/filters/qdeclarativecontactfilters_p.h
@@ -47,6 +47,7 @@
#include "qdeclarativecontactactionfilter_p.h"
#include "qdeclarativecontactchangelogfilter_p.h"
+#include "qdeclarativecontactcollectionfilter_p.h"
#include "qdeclarativecontactdetailfilter_p.h"
#include "qdeclarativecontactdetailrangefilter_p.h"
#include "qdeclarativecontactidfilter_p.h"
diff --git a/src/imports/contacts/plugin.cpp b/src/imports/contacts/plugin.cpp
index 0b3902e80..1060eae34 100644
--- a/src/imports/contacts/plugin.cpp
+++ b/src/imports/contacts/plugin.cpp
@@ -46,6 +46,7 @@
#include <QtContacts/qcontactabstractrequest.h>
#include "qdeclarativecontact_p.h"
+#include "qdeclarativecontactcollection_p.h"
#include "qdeclarativecontactdetail_p.h"
#include "qdeclarativecontactfetchhint_p.h"
#include "qdeclarativecontactfilter_p.h"
@@ -73,8 +74,10 @@ public:
qRegisterMetaType<QContactAbstractRequest::State>("QContactAbstractRequest::State");
qRegisterMetaType<QContactId>("QContactId");
qRegisterMetaType<QList<QContactId> >("QList<QContactId>");
+ qRegisterMetaType<QList<QContactCollectionId> >("QList<QContactCollectionId>");
qmlRegisterType<QDeclarativeContactModel>(uri, major, minor, "ContactModel");
qmlRegisterType<QDeclarativeContact>(uri, major, minor, "Contact");
+ qmlRegisterType<QDeclarativeContactCollection>(uri, major, minor, "Collection");
qmlRegisterType<QDeclarativeContactFetchHint>(uri, major, minor, "FetchHint");
qmlRegisterType<QDeclarativeContactRelationshipModel>(uri, major, minor, "RelationshipModel");
qmlRegisterType<QDeclarativeContactRelationship>(uri, major, minor, "Relationship");
@@ -115,6 +118,7 @@ public:
qmlRegisterType<QDeclarativeContactFilter>(uri, major, minor, "Filter");
qmlRegisterType<QDeclarativeContactActionFilter>(uri, major, minor, "ActionFilter");
qmlRegisterType<QDeclarativeContactChangeLogFilter>(uri, major, minor, "ChangeLogFilter");
+ qmlRegisterType<QDeclarativeContactCollectionFilter>(uri, major, minor, "CollectionFilter");
qmlRegisterType<QDeclarativeContactDetailFilter>(uri, major, minor, "DetailFilter");
qmlRegisterType<QDeclarativeContactDetailRangeFilter>(uri, major, minor, "DetailRangeFilter");
qmlRegisterType<QDeclarativeContactIdFilter>(uri, major, minor, "IdFilter");
diff --git a/src/imports/contacts/qdeclarativecontact.cpp b/src/imports/contacts/qdeclarativecontact.cpp
index 19b5abedd..dc05ae690 100644
--- a/src/imports/contacts/qdeclarativecontact.cpp
+++ b/src/imports/contacts/qdeclarativecontact.cpp
@@ -125,6 +125,7 @@ QDeclarativeContact::~QDeclarativeContact()
void QDeclarativeContact::setContact(const QContact& contact)
{
m_id = contact.id();
+ m_collectionId = contact.collectionId();
foreach (QDeclarativeContactDetail *detail, m_details)
delete detail;
m_details.clear();
@@ -154,6 +155,7 @@ QContact QDeclarativeContact::contact() const
{
QContact contact;
contact.setId(m_id);
+ contact.setCollectionId(m_collectionId);
foreach (QDeclarativeContactDetail *detail, m_details)
contact.saveDetail(&detail->detail());
@@ -354,6 +356,29 @@ QVariantMap QDeclarativeContact::preferredDetails() const
}
/*!
+ \qmlproperty string OContact::collectionId
+
+ This property holds the id of collection where the contact belongs to.
+*/
+QString QDeclarativeContact::collectionId() const
+{
+ return m_collectionId.toString();
+}
+
+void QDeclarativeContact::setCollectionId(const QString &collectionId)
+{
+ QContactCollectionId newCollectionId(QContactCollectionId::fromString(collectionId));
+
+ // in case invalid collectionId-string, fromString() will return default collectionId-string
+ // instead of the intended collectionId-string
+ if (newCollectionId.toString() == collectionId && m_collectionId.toString() != collectionId) {
+ m_collectionId = newCollectionId;
+ m_modified = true;
+ emit contactChanged();
+ }
+}
+
+/*!
\qmlproperty list<ContactDetail> Contact::contactDetails
This property holds the list of all the details that the contact has.
diff --git a/src/imports/contacts/qdeclarativecontact_p.h b/src/imports/contacts/qdeclarativecontact_p.h
index 35937fdbb..f788e4842 100644
--- a/src/imports/contacts/qdeclarativecontact_p.h
+++ b/src/imports/contacts/qdeclarativecontact_p.h
@@ -46,6 +46,7 @@
#include <QtContacts/qcontact.h>
#include <QtContacts/qcontactid.h>
+#include <QtContacts/qcontactcollectionid.h>
#include "qdeclarativecontactdetails_p.h"
@@ -98,6 +99,7 @@ class QDeclarativeContact : public QObject
Q_PROPERTY (QQmlListProperty<QDeclarativeContactUrl> urls READ urls NOTIFY contactChanged)
Q_PROPERTY (QDeclarativeContactVersion* version READ version NOTIFY contactChanged)
Q_PROPERTY (QVariantMap preferredDetails READ preferredDetails NOTIFY contactChanged)
+ Q_PROPERTY (QString collectionId READ collectionId WRITE setCollectionId NOTIFY contactChanged)
Q_CLASSINFO("DefaultProperty", "contactDetails")
public:
@@ -127,6 +129,9 @@ public:
Q_INVOKABLE QDeclarativeContactDetail* preferredDetail(const QString& actionName) const;
QVariantMap preferredDetails() const;
+ QString collectionId() const;
+ void setCollectionId(const QString& collectionId);
+
QDeclarativeContactAddress* address();
QQmlListProperty<QDeclarativeContactAddress> addresses();
QDeclarativeContactAnniversary* anniversary();
@@ -164,6 +169,7 @@ public:
protected:
bool m_modified;
QContactId m_id;
+ QContactCollectionId m_collectionId;
// always create a copy of the detail for QML
// however, seems the garbage collection can't delete all of them (QTBUG-20377)
diff --git a/src/imports/contacts/qdeclarativecontactcollection.cpp b/src/imports/contacts/qdeclarativecontactcollection.cpp
new file mode 100644
index 000000000..6505f3820
--- /dev/null
+++ b/src/imports/contacts/qdeclarativecontactcollection.cpp
@@ -0,0 +1,237 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtContacts module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdeclarativecontactcollection_p.h"
+
+QTCONTACTS_USE_NAMESPACE
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Collection
+ \instantiates QDeclarativeContactCollection
+ \brief The Collection element represents a collection of items in an organizer manager.
+ \ingroup qml-contacts-main
+ \inqmlmodule QtContacts
+ */
+
+/*!
+ \internal
+ */
+QDeclarativeContactCollection::QDeclarativeContactCollection(QObject *parent)
+ : QObject(parent)
+{
+}
+
+/*!
+ \qmlproperty string Collection::collectionId
+
+ This property holds the ID of the collection.
+ */
+QString QDeclarativeContactCollection::id() const
+{
+ return d.id().toString();
+}
+
+void QDeclarativeContactCollection::setId(const QString &id)
+{
+ if (d.id().toString() != id) {
+ d.setId(QContactCollectionId::fromString(id));
+ emit valueChanged();
+ }
+}
+
+/*!
+ \qmlproperty string Collection::name
+
+ This property holds the name meta data of a collection.
+ */
+QString QDeclarativeContactCollection::name() const
+{
+ return metaData(QContactCollection::KeyName).toString();
+}
+
+void QDeclarativeContactCollection::setName(const QString &name)
+{
+ setMetaData(QContactCollection::KeyName, name);
+}
+
+/*!
+ \qmlproperty string Collection::description
+
+ This property holds the description meta data of a collection.
+ */
+QString QDeclarativeContactCollection::description() const
+{
+ return metaData(QContactCollection::KeyDescription).toString();
+}
+
+void QDeclarativeContactCollection::setDescription(const QString &description)
+{
+ setMetaData(QContactCollection::KeyDescription, description);
+}
+
+/*!
+ \qmlproperty color Collection::secondaryColor
+
+ This property holds the secondary color meta data of a collection.
+ */
+QColor QDeclarativeContactCollection::secondaryColor() const
+{
+ return metaData(QContactCollection::KeySecondaryColor).value<QColor>();
+}
+
+void QDeclarativeContactCollection::setSecondaryColor(const QColor &secondaryColor)
+{
+ setMetaData(QContactCollection::KeySecondaryColor, secondaryColor);
+}
+
+/*!
+ \qmlproperty color Collection::color
+
+ This property holds the color meta data of a collection.
+ */
+QColor QDeclarativeContactCollection::color() const
+{
+ return metaData(QContactCollection::KeyColor).value<QColor>();
+}
+
+void QDeclarativeContactCollection::setColor(const QColor &color)
+{
+ setMetaData(QContactCollection::KeyColor, color);
+}
+
+/*!
+ \qmlproperty url Collection::image
+
+ This property holds the image url meta data of a collection.
+ */
+QUrl QDeclarativeContactCollection::image() const
+{
+ return QUrl(metaData(QContactCollection::KeyImage).toString());
+}
+
+void QDeclarativeContactCollection::setImage(const QUrl &url)
+{
+ setMetaData(QContactCollection::KeyImage, url);
+}
+
+/*!
+ \qmlmethod Collection::setMetaData(key, value)
+
+ Sets the meta data of the collection for the given \a key to the given \a value. Possible keys
+ include:
+ \list
+ \li Collection.KeyName
+ \li Collection.KeyDescription
+ \li Collection.KeyColor
+ \li Collection.KeySecondaryColor
+ \li Collection.KeyImage
+ \li Collection.KeyExtended
+ \endlist
+ */
+void QDeclarativeContactCollection::setMetaData(QContactCollection::MetaDataKey key, const QVariant &value)
+{
+ if (metaData(key) != value) {
+ d.setMetaData(key, value);
+ emit valueChanged();
+ }
+}
+
+/*!
+ \qmlmethod var Collection::metaData(key)
+
+ Returns the meta data stored in this collection for the given \a key. Possible keys include:
+ \list
+ \li Collection.KeyName
+ \li Collection.KeyDescription
+ \li Collection.KeyColor
+ \li Collection.KeyImage
+ \li Collection.KeyExtended
+ \endlist
+ */
+QVariant QDeclarativeContactCollection::metaData(QContactCollection::MetaDataKey key) const
+{
+ return d.metaData(key);
+}
+
+/*!
+ \qmlmethod Collection::setExtendedMetaData(key, value)
+
+ Sets the value of the extended metadata with the given \a key to \a value.
+ */
+void QDeclarativeContactCollection::setExtendedMetaData(const QString &key, const QVariant &value)
+{
+ if (extendedMetaData(key) != value) {
+ d.setExtendedMetaData(key, value);
+ emit valueChanged();
+ }
+}
+
+/*!
+ \qmlmethod var Collection::extendedMetaData(key)
+
+ Returns the value of extended metadata with the given \a key.
+ */
+QVariant QDeclarativeContactCollection::extendedMetaData(const QString &key) const
+{
+ return d.extendedMetaData(key);
+}
+
+/*!
+ \internal
+ */
+QContactCollection QDeclarativeContactCollection::collection() const
+{
+ return d;
+}
+
+/*!
+ \internal
+ */
+void QDeclarativeContactCollection::setCollection(const QContactCollection &collection)
+{
+ d = collection;
+}
+
+#include "moc_qdeclarativecontactcollection_p.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/imports/contacts/qdeclarativecontactcollection_p.h b/src/imports/contacts/qdeclarativecontactcollection_p.h
new file mode 100644
index 000000000..1fe9a7ff7
--- /dev/null
+++ b/src/imports/contacts/qdeclarativecontactcollection_p.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtContacts module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVECONTACTCOLLECTION_H
+#define QDECLARATIVECONTACTCOLLECTION_H
+
+#include <QtCore/qurl.h>
+
+#include <QtGui/qcolor.h>
+
+#include <QtQml/qqml.h>
+
+#include <QtContacts/qcontactcollection.h>
+
+QTCONTACTS_USE_NAMESPACE
+
+QT_BEGIN_NAMESPACE
+
+class QDeclarativeContactCollection : public QObject
+{
+ Q_OBJECT
+
+ Q_ENUMS(MetaDataKey)
+ Q_PROPERTY(QString collectionId READ id WRITE setId NOTIFY valueChanged)
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY valueChanged)
+ Q_PROPERTY(QString description READ description WRITE setDescription NOTIFY valueChanged)
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY valueChanged)
+ Q_PROPERTY(QColor secondaryColor READ secondaryColor WRITE setSecondaryColor NOTIFY valueChanged)
+ Q_PROPERTY(QUrl image READ image WRITE setImage NOTIFY valueChanged)
+
+public:
+ enum MetaDataKey {
+ KeyName = QContactCollection::KeyName,
+ KeyDescription = QContactCollection::KeyDescription,
+ KeyColor = QContactCollection::KeyColor,
+ KeySecondaryColor = QContactCollection::KeySecondaryColor,
+ KeyImage = QContactCollection::KeyImage,
+ KeyExtended = QContactCollection::KeyExtended
+ };
+
+ QDeclarativeContactCollection(QObject *parent = 0);
+
+ QString id() const;
+ void setId(const QString &id);
+
+ QString name() const;
+ void setName(const QString &name);
+
+ QString description() const;
+ void setDescription(const QString &description);
+
+ QColor color() const;
+ void setColor(const QColor &color);
+
+ QColor secondaryColor() const;
+ void setSecondaryColor(const QColor &secondaryColor);
+
+ QUrl image() const;
+ void setImage(const QUrl &url);
+
+ Q_INVOKABLE void setMetaData(QContactCollection::MetaDataKey key, const QVariant &value);
+ Q_INVOKABLE QVariant metaData(QContactCollection::MetaDataKey key) const;
+
+ Q_INVOKABLE void setExtendedMetaData(const QString &key, const QVariant &value);
+ Q_INVOKABLE QVariant extendedMetaData(const QString &key) const;
+
+ // used by model
+ QContactCollection collection() const;
+ void setCollection(const QContactCollection & collection);
+
+Q_SIGNALS:
+ void valueChanged();
+
+private:
+ QContactCollection d;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QDeclarativeContactCollection)
+
+#endif // QDECLARATIVECONTACTCOLLECTION_H
diff --git a/src/imports/contacts/qdeclarativecontactmodel.cpp b/src/imports/contacts/qdeclarativecontactmodel.cpp
index d640116b0..9bf213673 100644
--- a/src/imports/contacts/qdeclarativecontactmodel.cpp
+++ b/src/imports/contacts/qdeclarativecontactmodel.cpp
@@ -179,7 +179,8 @@ public:
m_error(QContactManager::NoError),
m_autoUpdate(true),
m_componentCompleted(false),
- m_progressiveLoading(true)
+ m_progressiveLoading(true),
+ m_updatePendingFlag(QDeclarativeContactModelPrivate::NonePending)
{
}
~QDeclarativeContactModelPrivate()
@@ -188,6 +189,12 @@ public:
delete m_manager;
}
+ enum UpdateTypePending {
+ NonePending = 0x0,
+ UpdatingContactsPending = 0x1,
+ UpdatingCollectionsPending = 0x2
+ };
+
QList<QDeclarativeContact*> m_contacts;
QMap<QContactId, QDeclarativeContact*> m_contactMap;
QMap<QContactId, QDeclarativeContact*> m_contactFetchedMap;
@@ -211,7 +218,9 @@ public:
QHash<QContactAbstractRequest *, int> m_requestIdHash;
QList<QContactFetchRequest*> m_pendingRequests;
QList<QContact> m_pendingContacts;
+ QList<QDeclarativeContactCollection*> m_collections;
bool m_progressiveLoading;
+ int m_updatePendingFlag;
};
QDeclarativeContactModel::QDeclarativeContactModel(QObject *parent) :
@@ -224,9 +233,9 @@ QDeclarativeContactModel::QDeclarativeContactModel(QObject *parent) :
setRoleNames(roleNames);
connect(this, SIGNAL(managerChanged()), SLOT(doUpdate()));
- connect(this, SIGNAL(filterChanged()), SLOT(doUpdate()));
- connect(this, SIGNAL(fetchHintChanged()), SLOT(doUpdate()));
- connect(this, SIGNAL(sortOrdersChanged()), SLOT(doUpdate()));
+ connect(this, SIGNAL(filterChanged()), SLOT(doContactUpdate()));
+ connect(this, SIGNAL(fetchHintChanged()), SLOT(doContactUpdate()));
+ connect(this, SIGNAL(sortOrdersChanged()), SLOT(doContactUpdate()));
//import vcard
connect(&d->m_reader, SIGNAL(stateChanged(QVersitReader::State)), this, SLOT(startImport(QVersitReader::State)));
@@ -253,14 +262,21 @@ void QDeclarativeContactModel::setManager(const QString& managerName)
if (d->m_manager && (managerName == d->m_manager->managerName() || managerName == d->m_manager->managerUri()))
return;
- if (d->m_manager)
+ if (d->m_manager) {
+ cancelUpdate();
delete d->m_manager;
+ }
+
d->m_manager = new QContactManager(managerName);
connect(d->m_manager, SIGNAL(dataChanged()), this, SLOT(doUpdate()));
connect(d->m_manager, SIGNAL(contactsAdded(QList<QContactId>)), this, SLOT(onContactsAdded(QList<QContactId>)));
connect(d->m_manager, SIGNAL(contactsRemoved(QList<QContactId>)), this, SLOT(onContactsRemoved(QList<QContactId>)));
connect(d->m_manager, SIGNAL(contactsChanged(QList<QContactId>,QList<QContactDetail::DetailType>)), this, SLOT(onContactsChanged(QList<QContactId>)));
+ connect(d->m_manager, SIGNAL(collectionsAdded(QList<QContactCollectionId>)), this, SLOT(fetchCollections()));
+ connect(d->m_manager, SIGNAL(collectionsChanged(QList<QContactCollectionId>)), this, SLOT(fetchCollections()));
+ connect(d->m_manager, SIGNAL(collectionsRemoved(QList<QContactCollectionId>)), this, SLOT(fetchCollections()));
+
if (d->m_error != QContactManager::NoError) {
d->m_error = QContactManager::NoError;
@@ -300,15 +316,71 @@ bool QDeclarativeContactModel::autoUpdate() const
void QDeclarativeContactModel::update()
{
- if (!d->m_componentCompleted)
+ if (!d->m_componentCompleted || d->m_updatePendingFlag)
return;
+ // Disallow possible duplicate request triggering
+ d->m_updatePendingFlag = (QDeclarativeContactModelPrivate::UpdatingContactsPending | QDeclarativeContactModelPrivate::UpdatingCollectionsPending);
+ QMetaObject::invokeMethod(this, "fetchCollections", Qt::QueuedConnection);
+}
+
+/*!
+ \qmlmethod ContactModel::updateContacts()
+
+ Manually update the contact model contacts.
+
+ \sa ContactModel::update
+ \sa ContactModel::updateCollections
+ \sa ContactModel::autoUpdate
+ */
+void QDeclarativeContactModel::updateContacts()
+{
+ if (!d->m_componentCompleted || d->m_updatePendingFlag)
+ return;
+ // Disallow possible duplicate request triggering
+ d->m_updatePendingFlag = QDeclarativeContactModelPrivate::UpdatingContactsPending;
QMetaObject::invokeMethod(this, "fetchAgain", Qt::QueuedConnection);
}
-void QDeclarativeContactModel::doUpdate()
+/*!
+ \qmlmethod ContactModel::updateCollections()
+
+ Manually update the contact model collections.
+
+ \sa ContactModel::update
+ \sa ContactModel::updateContacts
+ \sa ContactModel::autoUpdate
+ */
+void QDeclarativeContactModel::updateCollections()
+{
+ if (!d->m_componentCompleted || d->m_updatePendingFlag)
+ return;
+ // Disallow possible duplicate request triggering
+ d->m_updatePendingFlag = QDeclarativeContactModelPrivate::UpdatingCollectionsPending;
+ QMetaObject::invokeMethod(this, "fetchCollections", Qt::QueuedConnection);
+}
+
+/*!
+ \qmlmethod ContactModel::cancelUpdate()
+
+ Cancel the running contact model content update request.
+
+ \sa ContactModel::autoUpdate
+ \sa ContactModel::update
+ */
+void QDeclarativeContactModel::cancelUpdate()
+{
+ foreach (QContactFetchRequest *req, d->m_pendingRequests) {
+ req->cancel();
+ req->deleteLater();
+ }
+ d->m_pendingRequests.clear();;
+ d->m_updatePendingFlag = QDeclarativeContactModelPrivate::NonePending;
+}
+
+void QDeclarativeContactModel::doContactUpdate()
{
if (d->m_autoUpdate)
- update();
+ updateContacts();
}
/*!
@@ -720,6 +792,66 @@ int QDeclarativeContactModel::fetchContacts(const QStringList &contactIds)
}
/*!
+ \qmlmethod ContactModel::removeCollection(string collectionId)
+ Removes asynchronously the contact collection with the given \a collectionId from the backend.
+ */
+void QDeclarativeContactModel::removeCollection(const QString &collectionId)
+{
+ QContactCollectionRemoveRequest* req = new QContactCollectionRemoveRequest(this);
+ req->setManager(d->m_manager);
+ req->setCollectionId(QContactCollectionId::fromString(collectionId));
+
+ connect(req, SIGNAL(stateChanged(QContactAbstractRequest::State)), this, SLOT(onRequestStateChanged(QContactAbstractRequest::State)));
+
+ req->start();
+}
+
+/*!
+ \qmlmethod OContactModel::saveCollection(Collection collection)
+
+ Saves asynchronously the given \a collection into the contact backend.
+ */
+void QDeclarativeContactModel::saveCollection(QDeclarativeContactCollection *declColl)
+{
+ if (declColl) {
+ QContactCollection collection = declColl->collection();
+ QContactCollectionSaveRequest* req = new QContactCollectionSaveRequest(this);
+ req->setManager(d->m_manager);
+ req->setCollection(collection);
+
+ if (declColl->collection().id().isNull()) {
+ // if the collection id is empty this means that this is a new collection
+ // we need to keep trace of this declarative collection to update with the
+ // new Id as soon as this request finish
+ QPointer<QDeclarativeContactCollection> pCollection = declColl;
+ req->setProperty("DeclarativeCollection", QVariant::fromValue(pCollection));
+ }
+
+ connect(req, SIGNAL(stateChanged(QContactAbstractRequest::State)), this, SLOT(onRequestStateChanged(QContactAbstractRequest::State)));
+ req->start();
+ }
+}
+
+/*!
+ \qmlmethod OContactModel::fetchCollections()
+ Fetch asynchronously a list of contact collections from the contact backend.
+*/
+void QDeclarativeContactModel::fetchCollections()
+{
+ // fetchCollections() is used for both direct calls and
+ // signals from model. For signal from model, check also the
+ // autoupdate-flag.
+ if (sender() == d->m_manager && !d->m_autoUpdate) {
+ return;
+ }
+
+ QContactCollectionFetchRequest* req = new QContactCollectionFetchRequest(this);
+ connect(req,SIGNAL(stateChanged(QContactAbstractRequest::State)), this, SLOT(collectionsFetched()));
+ req->setManager(d->m_manager);
+ req->start();
+}
+
+/*!
\internal
*/
void QDeclarativeContactModel::onFetchContactsRequestStateChanged(QContactAbstractRequest::State state)
@@ -764,6 +896,56 @@ void QDeclarativeContactModel::onFetchContactsRequestStateChanged(QContactAbstra
request->deleteLater();
}
+/*!
+ \internal
+ */
+void QDeclarativeContactModel::collectionsFetched()
+{
+ QContactCollectionFetchRequest* req = qobject_cast<QContactCollectionFetchRequest*>(QObject::sender());
+ Q_ASSERT(req);
+ if (req->isFinished() && QContactManager::NoError == req->error()) {
+ d->m_updatePendingFlag &= ~QDeclarativeContactModelPrivate::UpdatingCollectionsPending;
+ // prepare tables
+ QHash<QString, const QContactCollection*> collections;
+ foreach (const QContactCollection& collection, req->collections()) {
+ collections.insert(collection.id().toString(), &collection);
+ }
+ QHash<QString, QDeclarativeContactCollection*> declCollections;
+ foreach (QDeclarativeContactCollection* declCollection, d->m_collections) {
+ declCollections.insert(declCollection->collection().id().toString(), declCollection);
+ }
+ // go tables through
+ QHashIterator<QString, const QContactCollection*> collIterator(collections);
+ while (collIterator.hasNext()) {
+ collIterator.next();
+ if (declCollections.contains(collIterator.key())) {
+ // collection on both sides, update the declarative collection
+ declCollections.value(collIterator.key())->setCollection(*collections.value(collIterator.key()));
+ } else {
+ // new collection, add it to declarative collection list
+ QDeclarativeContactCollection* declCollection = new QDeclarativeContactCollection(this);
+ declCollection->setCollection(*collections.value(collIterator.key()));
+ d->m_collections.append(declCollection);
+ }
+ }
+ QHashIterator<QString, QDeclarativeContactCollection*> declCollIterator(declCollections);
+ while (declCollIterator.hasNext()) {
+ declCollIterator.next();
+ if (!collections.contains(declCollIterator.key())) {
+ // collection deleted on the backend side, delete from declarative collection list
+ QDeclarativeContactCollection* toBeDeletedColl = declCollections.value(declCollIterator.key());
+ d->m_collections.removeOne(toBeDeletedColl);
+ toBeDeletedColl->deleteLater();
+ }
+ }
+ emit collectionsChanged();
+ if (d->m_updatePendingFlag & QDeclarativeContactModelPrivate::UpdatingContactsPending)
+ QMetaObject::invokeMethod(this, "fetchAgain", Qt::QueuedConnection);
+ req->deleteLater();
+ }
+ checkError(req);
+}
+
void QDeclarativeContactModel::clearContacts()
{
qDeleteAll(d->m_contacts);
@@ -860,6 +1042,7 @@ void QDeclarativeContactModel::fetchRequestStateChanged(QContactAbstractRequest:
if (newState != QContactAbstractRequest::FinishedState)
return;
+ d->m_updatePendingFlag &= ~QDeclarativeContactModelPrivate::UpdatingContactsPending;
QContactFetchRequest* req = qobject_cast<QContactFetchRequest*>(QObject::sender());
Q_ASSERT(req);
if (req) {
@@ -909,6 +1092,15 @@ void QDeclarativeContactModel::fetchRequestStateChanged(QContactAbstractRequest:
}
/*!
+ \internal
+ */
+void QDeclarativeContactModel::doUpdate()
+{
+ if (d->m_autoUpdate)
+ update();
+}
+
+/*!
\qmlmethod ContactModel::saveContact(Contact contact)
Save the given \a contact into the contacts backend.
@@ -944,18 +1136,40 @@ void QDeclarativeContactModel::onRequestStateChanged(QContactAbstractRequest::St
QContactAbstractRequest *request = qobject_cast<QContactAbstractRequest *>(sender());
Q_ASSERT(request);
- if ((request->type() == QContactSaveRequest::ContactSaveRequest) &&
- (request->error() == QContactManager::NoError)) {
- QVariant vContact = request->property("DeclarativeContact");
- if (vContact.isValid()) {
- QPointer<QDeclarativeContact> pContact = vContact.value<QPointer<QDeclarativeContact> >();
- // Update contact info.
- // this is necessary to make sure that the declarative contact get the new contact ID otherwise
- // the contact Id will be empty
- QList<QContact> contacts = qobject_cast<QContactSaveRequest*>(request)->contacts();
- if (pContact && contacts.length() == 1) {
- pContact->setContact(contacts[0]);
+ if (request->error() == QContactManager::NoError) {
+ switch (request->type()) {
+ case QContactAbstractRequest::ContactSaveRequest:
+ {
+ QVariant vContact = request->property("DeclarativeContact");
+ if (vContact.isValid()) {
+ QPointer<QDeclarativeContact> pContact = vContact.value<QPointer<QDeclarativeContact> >();
+ // Update contact info.
+ // this is necessary to make sure that the declarative contact get the new contact ID otherwise
+ // the contact Id will be empty
+ QList<QContact> contacts = qobject_cast<QContactSaveRequest*>(request)->contacts();
+ if (pContact && contacts.length() == 1) {
+ pContact->setContact(contacts[0]);
+ }
}
+ break;
+ }
+ case QContactAbstractRequest::CollectionSaveRequest:
+ {
+ QVariant vCollection = request->property("DeclarativeCollection");
+ if (vCollection.isValid()) {
+ QPointer<QDeclarativeContactCollection> pCollection = vCollection.value<QPointer<QDeclarativeContactCollection> >();
+ // Update collection info.
+ // this is necessary to make sure that the declarative collection get the new collection ID otherwise
+ // the collection Id will be empty
+ QList<QContactCollection> collections = qobject_cast<QContactCollectionSaveRequest*>(request)->collections();
+ if (pCollection && collections.length() == 1) {
+ pCollection->setCollection(collections[0]);
+ }
+ }
+ break;
+ }
+ default:
+ break;
}
}
checkError(request);
@@ -1169,6 +1383,35 @@ void QDeclarativeContactModel::sortOrder_clear(QQmlListProperty<QDeclarativeCon
emit model->sortOrdersChanged();
}
}
+
+/*!
+ \qmlproperty list<Collection> OContactModel::collections
+
+ This property holds a list of collections in the contact model.
+
+ \sa Collection
+ */
+QQmlListProperty<QDeclarativeContactCollection> QDeclarativeContactModel::collections()
+{
+ return QQmlListProperty<QDeclarativeContactCollection>(this, 0, collection_count, collection_at);
+}
+
+int QDeclarativeContactModel::collection_count(QQmlListProperty<QDeclarativeContactCollection> *p)
+{
+ QDeclarativeContactModel* model = qobject_cast<QDeclarativeContactModel*>(p->object);
+ return model ? model->d->m_collections.count() : 0;
+}
+
+QDeclarativeContactCollection *QDeclarativeContactModel::collection_at(QQmlListProperty<QDeclarativeContactCollection> *p, int idx)
+{
+ QDeclarativeContactModel* model = qobject_cast<QDeclarativeContactModel*>(p->object);
+ QDeclarativeContactCollection* collection = 0;
+ if (model) {
+ if (!model->d->m_collections.isEmpty() && idx >= 0 && idx < model->d->m_collections.count())
+ collection = model->d->m_collections.at(idx);
+ }
+ return collection;
+}
/*!
\internal
diff --git a/src/imports/contacts/qdeclarativecontactmodel_p.h b/src/imports/contacts/qdeclarativecontactmodel_p.h
index a3acdf884..bfdf27ce7 100644
--- a/src/imports/contacts/qdeclarativecontactmodel_p.h
+++ b/src/imports/contacts/qdeclarativecontactmodel_p.h
@@ -53,6 +53,7 @@
#include <QtVersit/qversitwriter.h>
#include "qdeclarativecontact_p.h"
+#include "qdeclarativecontactcollection_p.h"
#include "qdeclarativecontactfetchhint_p.h"
#include "qdeclarativecontactfilter_p.h"
#include "qdeclarativecontactsortorder_p.h"
@@ -73,6 +74,7 @@ class QDeclarativeContactModel : public QAbstractListModel, public QQmlParserSta
Q_PROPERTY(QDeclarativeContactFilter* filter READ filter WRITE setFilter NOTIFY filterChanged)
Q_PROPERTY(QDeclarativeContactFetchHint* fetchHint READ fetchHint WRITE setFetchHint NOTIFY fetchHintChanged)
Q_PROPERTY(QQmlListProperty<QDeclarativeContact> contacts READ contacts NOTIFY contactsChanged)
+ Q_PROPERTY(QQmlListProperty<QDeclarativeContactCollection> collections READ collections NOTIFY collectionsChanged)
Q_PROPERTY(QQmlListProperty<QDeclarativeContactSortOrder> sortOrders READ sortOrders NOTIFY sortOrdersChanged)
Q_ENUMS(ExportError)
Q_ENUMS(ImportError)
@@ -133,17 +135,24 @@ public:
static QDeclarativeContact* contacts_at(QQmlListProperty<QDeclarativeContact>* prop, int index);
static void contacts_clear(QQmlListProperty<QDeclarativeContact>* prop);
+ QQmlListProperty<QDeclarativeContactSortOrder> sortOrders();
static void sortOrder_append(QQmlListProperty<QDeclarativeContactSortOrder> *p, QDeclarativeContactSortOrder *sortOrder);
static int sortOrder_count(QQmlListProperty<QDeclarativeContactSortOrder> *p);
static QDeclarativeContactSortOrder * sortOrder_at(QQmlListProperty<QDeclarativeContactSortOrder> *p, int idx);
static void sortOrder_clear(QQmlListProperty<QDeclarativeContactSortOrder> *p);
- QQmlListProperty<QDeclarativeContactSortOrder> sortOrders() ;
+ QQmlListProperty<QDeclarativeContactCollection> collections();
+ static int collection_count(QQmlListProperty<QDeclarativeContactCollection> *p);
+ static QDeclarativeContactCollection* collection_at(QQmlListProperty<QDeclarativeContactCollection> *p, int idx);
Q_INVOKABLE void removeContact(QString id);
Q_INVOKABLE void removeContacts(const QStringList& ids);
Q_INVOKABLE void saveContact(QDeclarativeContact* dc);
Q_INVOKABLE int fetchContacts(const QStringList& contactIds);
+ Q_INVOKABLE void removeCollection(const QString& collectionId);
+ Q_INVOKABLE void saveCollection(QDeclarativeContactCollection* collection);
+ // FIXME : Naming indicates fetch from database
+ Q_INVOKABLE void fetchCollections();
Q_INVOKABLE void importContacts(const QUrl& url, const QStringList& profiles = QStringList());
Q_INVOKABLE void exportContacts(const QUrl& url, const QStringList& profiles = QStringList(), const QVariantList &declarativeContacts = QVariantList());
@@ -153,6 +162,7 @@ signals:
void errorChanged();
void fetchHintChanged();
void contactsChanged();
+ void collectionsChanged();
void sortOrdersChanged();
void autoUpdateChanged();
void exportCompleted(ExportError error, QUrl url);
@@ -161,6 +171,9 @@ signals:
public slots:
void update();
+ void updateContacts();
+ void updateCollections();
+ void cancelUpdate();
private slots:
void clearContacts();
@@ -168,6 +181,7 @@ private slots:
void requestUpdated();
void fetchRequestStateChanged(QContactAbstractRequest::State newState);
void doUpdate();
+ void doContactUpdate();
void onRequestStateChanged(QContactAbstractRequest::State newState);
void onContactsAdded(const QList<QContactId>& ids);
void onContactsRemoved(const QList<QContactId>& ids);
@@ -185,6 +199,8 @@ private slots:
// handle fetch request from fetchContacts()
void onFetchContactsRequestStateChanged(QContactAbstractRequest::State state);
+ void collectionsFetched();
+
private:
QContactFetchRequest *createContactFetchRequest(const QList<QContactId> &ids);
void checkError(const QContactAbstractRequest *request);
diff --git a/src/plugins/contacts/memory/qcontactmemorybackend.cpp b/src/plugins/contacts/memory/qcontactmemorybackend.cpp
index d8e698c1d..6476ae485 100644
--- a/src/plugins/contacts/memory/qcontactmemorybackend.cpp
+++ b/src/plugins/contacts/memory/qcontactmemorybackend.cpp
@@ -134,6 +134,16 @@ QContactMemoryEngine::QContactMemoryEngine(QContactMemoryEngineData *data)
qRegisterMetaType<QContactId>("QContactId");
d->m_managerUri = managerUri();
d->m_sharedEngines.append(this);
+
+ // the default collection always exists.
+ if (d->m_idToCollectionHash.isEmpty()) {
+ d->m_managerUri = managerUri();
+ const QContactCollectionId defaultId = defaultCollectionId();
+ QContactCollection defaultCollection;
+ defaultCollection.setId(defaultId);
+ defaultCollection.setMetaData(QContactCollection::KeyName, QString(QStringLiteral("Default Collection")));
+ d->m_idToCollectionHash.insert(defaultId, defaultCollection);
+ }
}
/*! Frees any memory used by this engine */
@@ -511,6 +521,102 @@ bool QContactMemoryEngine::removeRelationships(const QList<QContactRelationship>
return (*error == QContactManager::NoError);
}
+QContactCollection QContactMemoryEngine::defaultCollection(QContactManager::Error *error)
+{
+ const QContactCollectionId defaultCollectionId = this->defaultCollectionId();
+ Q_ASSERT(d->m_idToCollectionHash.contains(defaultCollectionId));
+ *error = QContactManager::NoError;
+ return d->m_idToCollectionHash.value(defaultCollectionId);
+}
+
+QContactCollection QContactMemoryEngine::collection(const QContactCollectionId &collectionId, QContactManager::Error *error)
+{
+ if (d->m_idToCollectionHash.contains(collectionId)) {
+ *error = QContactManager::NoError;
+ return d->m_idToCollectionHash.value(collectionId);
+ }
+
+ *error = QContactManager::DoesNotExistError;
+ return QContactCollection();
+}
+
+QList<QContactCollection> QContactMemoryEngine::collections(QContactManager::Error *error)
+{
+ Q_ASSERT(!d->m_idToCollectionHash.isEmpty());
+ *error = QContactManager::NoError;
+ return d->m_idToCollectionHash.values();
+}
+
+bool QContactMemoryEngine::saveCollection(QContactCollection *collection, QContactManager::Error *error)
+{
+ QContactCollectionId collectionId = collection->id();
+
+ QContactCollectionChangeSet cs;
+ if (d->m_idToCollectionHash.contains(collectionId)) {
+ // this collection already exists. update our internal list
+ // if the collection has been modified.
+ if (d->m_idToCollectionHash.value(collectionId) == *collection) {
+ *error = QContactManager::NoError;
+ return true;
+ }
+
+ cs.insertChangedCollection(collectionId);
+ } else {
+ // this must be a new collection. check that the id is null.
+ if (!collectionId.isNull() && collectionId.managerUri() != d->m_managerUri) {
+ // nope, this collection belongs in another manager, or has been deleted.
+ *error = QContactManager::DoesNotExistError;
+ return false;
+ }
+
+ // this is a new collection with a null id; create a new id, add it to our list.
+ QUuid id = QUuid::createUuid();
+ collectionId = this->collectionId(id.toByteArray());
+ collection->setId(collectionId);
+ cs.insertAddedCollection(collectionId);
+ }
+
+ d->m_idToCollectionHash.insert(collectionId, *collection);
+ d->emitSharedSignals(&cs);
+ *error = QContactManager::NoError;
+ return true;
+}
+
+bool QContactMemoryEngine::removeCollection(const QContactCollectionId &collectionId, QContactManager::Error *error)
+{
+ if (collectionId == defaultCollectionId()) {
+ // attempting to remove the default collection. this is not allowed in the memory engine.
+ *error = QContactManager::PermissionsError;
+ return false;
+ }
+
+ // try to find the collection to remove it (and the items it contains)
+ if (d->m_idToCollectionHash.contains(collectionId)) {
+ // found the collection to remove. remove the items in the collection.
+ const QList<QContactId> contactsToRemove = d->m_contactsInCollections.values(collectionId);
+ if (!contactsToRemove.isEmpty()) {
+ QMap<int, QContactManager::Error> errorMap;
+ if (!removeContacts(contactsToRemove, &errorMap, error)) {
+ // without transaction support, we can't back out. but the operation should fail.
+ return false;
+ }
+ }
+
+ // now remove the collection from our lists.
+ d->m_idToCollectionHash.remove(collectionId);
+ d->m_contactsInCollections.remove(collectionId);
+ QContactCollectionChangeSet cs;
+ cs.insertRemovedCollection(collectionId);
+ d->emitSharedSignals(&cs);
+ *error = QContactManager::NoError;
+ return true;
+ }
+
+ // the collection doesn't exist...
+ *error = QContactManager::DoesNotExistError;
+ return false;
+}
+
/*! \reimp */
void QContactMemoryEngine::requestDestroyed(QContactAbstractRequest *req)
{
@@ -728,6 +834,65 @@ void QContactMemoryEngine::performAsynchronousOperation(QContactAbstractRequest
}
break;
+ case QContactAbstractRequest::CollectionFetchRequest:
+ {
+ QContactCollectionFetchRequest* r = static_cast<QContactCollectionFetchRequest*>(currentRequest);
+ QContactManager::Error operationError = QContactManager::NoError;
+ QList<QContactCollection> requestedContactCollections = collections(&operationError);
+
+ // update the request with the results.
+ updateCollectionFetchRequest(r, requestedContactCollections, operationError, QContactAbstractRequest::FinishedState);
+ }
+ break;
+
+ case QContactAbstractRequest::CollectionSaveRequest:
+ {
+ QContactCollectionSaveRequest* r = static_cast<QContactCollectionSaveRequest*>(currentRequest);
+ QList<QContactCollection> collections = r->collections();
+ QList<QContactCollection> retn;
+
+ QContactManager::Error operationError = QContactManager::NoError;
+ QMap<int, QContactManager::Error> errorMap;
+ for (int i = 0; i < collections.size(); ++i) {
+ QContactManager::Error tempError = QContactManager::NoError;
+ QContactCollection curr = collections.at(i);
+ if (!saveCollection(&curr, &tempError)) {
+ errorMap.insert(i, tempError);
+ operationError = tempError;
+ }
+ retn.append(curr);
+ }
+
+ updateCollectionSaveRequest(r, retn, operationError, errorMap, QContactAbstractRequest::FinishedState);
+ }
+ break;
+
+ case QContactAbstractRequest::CollectionRemoveRequest:
+ {
+ // removes the collections identified in the list of ids.
+ QContactCollectionRemoveRequest* r = static_cast<QContactCollectionRemoveRequest*>(currentRequest);
+ QContactManager::Error operationError = QContactManager::NoError;
+ QList<QContactCollectionId> collectionsToRemove = r->collectionIds();
+ QMap<int, QContactManager::Error> errorMap;
+
+ for (int i = 0; i < collectionsToRemove.size(); i++) {
+ QContactManager::Error tempError = QContactManager::NoError;
+ removeCollection(collectionsToRemove.at(i), &tempError);
+
+ if (tempError != QContactManager::NoError) {
+ errorMap.insert(i, tempError);
+ operationError = tempError;
+ }
+ }
+
+ if (!errorMap.isEmpty() || operationError != QContactManager::NoError)
+ updateCollectionRemoveRequest(r, operationError, errorMap, QContactAbstractRequest::FinishedState);
+ else
+ updateRequestState(currentRequest, QContactAbstractRequest::FinishedState);
+ }
+ break;
+
+
default: // unknown request type.
break;
}
@@ -736,6 +901,12 @@ void QContactMemoryEngine::performAsynchronousOperation(QContactAbstractRequest
d->emitSharedSignals(&changeSet);
}
+QContactCollectionId QContactMemoryEngine::defaultCollectionId() const
+{
+ static const QByteArray id("Personal");
+ return collectionId(id);
+}
+
void QContactMemoryEngine::partiallySyncDetails(QContact *to, const QContact &from, const QList<QContactDetail::DetailType> &mask)
{
// these details in old contact
@@ -893,6 +1064,20 @@ bool QContactMemoryEngine::saveContact(QContact *theContact, QContactChangeSet &
return false;
}
+ // check the contact collection
+ QContactCollectionId collectionId = theContact->collectionId();
+ // if is null use default collection
+ if (collectionId.isNull()) {
+ collectionId = this->defaultCollectionId();
+ theContact->setCollectionId(collectionId);
+ } else {
+ // check if the collection exists
+ QContactCollection collection = this->collection(collectionId, error);
+ if (collection.id().isNull()) {
+ return false;
+ }
+ }
+
// check if this is partial save
if (!mask.isEmpty()) {
QContact tempContact;
@@ -915,6 +1100,7 @@ bool QContactMemoryEngine::saveContact(QContact *theContact, QContactChangeSet &
// finally, add the contact to our internal lists and return
d->m_contacts.append(*theContact); // add contact to list
d->m_contactIds.append(theContact->id()); // track the contact id.
+ d->m_contactsInCollections.insert(collectionId, newContactId); // link contact to collection
changeSet.insertAddedContact(theContact->id());
}
diff --git a/src/plugins/contacts/memory/qcontactmemorybackend_p.h b/src/plugins/contacts/memory/qcontactmemorybackend_p.h
index 7c44d7d3f..adeff03a7 100644
--- a/src/plugins/contacts/memory/qcontactmemorybackend_p.h
+++ b/src/plugins/contacts/memory/qcontactmemorybackend_p.h
@@ -104,7 +104,9 @@ public:
QString m_id; // the id parameter value
QContactId m_selfContactId; // the "MyCard" contact id
- QList<QContact> m_contacts; // list of contacts
+ QList<QContact> m_contacts; // list of contacts
+ QHash<QContactCollectionId, QContactId> m_contactsInCollections; // hash of contacts for each collection
+ QHash<QContactCollectionId, QContactCollection> m_idToCollectionHash; // hash of id to the collection identified by that id
QList<QContactId> m_contactIds; // list of contact Id's
QList<QContactRelationship> m_relationships; // list of contact relationships
QMap<QContactId, QList<QContactRelationship> > m_orderedRelationships; // map of ordered lists of contact relationships
@@ -120,6 +122,12 @@ public:
cs->emitSignals(engine);
}
+ void emitSharedSignals(QContactCollectionChangeSet *cs)
+ {
+ foreach (QContactManagerEngine *engine, m_sharedEngines)
+ cs->emitSignals(engine);
+ }
+
QList<QContactManagerEngine*> m_sharedEngines; // The list of engines that share this data
};
@@ -157,6 +165,13 @@ public:
virtual bool saveRelationships(QList<QContactRelationship> *relationships, QMap<int, QContactManager::Error> *errorMap, QContactManager::Error *error);
virtual bool removeRelationships(const QList<QContactRelationship> &relationships, QMap<int, QContactManager::Error> *errorMap, QContactManager::Error *error);
+ // collections
+ QContactCollection defaultCollection(QContactManager::Error* error);
+ QContactCollection collection(const QContactCollectionId &collectionId, QContactManager::Error *error);
+ QList<QContactCollection> collections(QContactManager::Error* error);
+ bool saveCollection(QContactCollection* collection, QContactManager::Error* error);
+ bool removeCollection(const QContactCollectionId& collectionId, QContactManager::Error* error);
+
/*! \reimp */
virtual bool validateContact(const QContact &contact, QContactManager::Error *error) const
{
@@ -202,6 +217,8 @@ private:
void performAsynchronousOperation(QContactAbstractRequest *request);
+ QContactCollectionId defaultCollectionId() const;
+
QContactMemoryEngineData *d;
static QMap<QString, QContactMemoryEngineData*> engineDatas;
diff --git a/tests/auto/contacts/contacts.pro b/tests/auto/contacts/contacts.pro
index fe4cb4865..408b57e44 100644
--- a/tests/auto/contacts/contacts.pro
+++ b/tests/auto/contacts/contacts.pro
@@ -4,6 +4,7 @@ TEMPLATE = subdirs
SUBDIRS += \
qcontact \
qcontactasync \
+ qcontactcollection \
qcontactdetail \
qcontactdetails \
qcontactfilter \
diff --git a/tests/auto/contacts/qcontactasync/unittest/tst_qcontactasync.cpp b/tests/auto/contacts/qcontactasync/unittest/tst_qcontactasync.cpp
index 59a584f83..885606b27 100644
--- a/tests/auto/contacts/qcontactasync/unittest/tst_qcontactasync.cpp
+++ b/tests/auto/contacts/qcontactasync/unittest/tst_qcontactasync.cpp
@@ -56,6 +56,13 @@ QTCONTACTS_USE_NAMESPACE
fqcfr2.start(); \
fqcfr3.start();
+/* Define an innocuous request (fetch ie doesn't mutate) to "fill up" any queues */
+#define FILL_QUEUE_WITH_FETCH_REQUESTS_WITH_MANAGER(manager) QContactFetchRequest fqifr1, fqifr2, fqifr3; \
+ fqifr1.setManager(manager); fqifr1.start(); \
+ fqifr2.setManager(manager); fqifr2.start(); \
+ fqifr3.setManager(manager); fqifr3.start();
+
+
//TESTED_COMPONENT=src/contacts
// Unfortunately the plumbing isn't in place to allow cancelling requests at arbitrary points
@@ -230,6 +237,13 @@ private slots:
void relationshipSave();
void relationshipSave_data() { addManagers(); }
+ void collectionFetch();
+ void collectionFetch_data() { addManagers(); }
+ void collectionRemove();
+ void collectionRemove_data() { addManagers(); }
+ void collectionSave();
+ void collectionSave_data() { addManagers(); }
+
void maliciousManager(); // uses it's own custom data (manager)
void testQuickDestruction();
@@ -245,6 +259,7 @@ private:
bool compareContacts(QContact ca, QContact cb);
bool containsIgnoringTimestamps(const QList<QContact>& list, const QContact& c);
bool compareIgnoringTimestamps(const QContact& ca, const QContact& cb);
+ bool containsAllCollectionIds(const QList<QContactCollectionId>& target, const QList<QContactCollectionId>& ids);
QContactManager* prepareModel(const QString& uri);
Qt::HANDLE m_mainThreadId;
@@ -376,6 +391,18 @@ bool tst_QContactAsync::compareIgnoringTimestamps(const QContact& ca, const QCon
return false;
}
+bool tst_QContactAsync::containsAllCollectionIds(const QList<QContactCollectionId> &target, const QList<QContactCollectionId> &ids)
+{
+ bool containsAllIds = true;
+ foreach (QContactCollectionId id, ids) {
+ if (!target.contains(id)) {
+ containsAllIds = false;
+ break;
+ }
+ }
+ return containsAllIds;
+}
+
void tst_QContactAsync::testDestructor()
{
QFETCH(QString, uri);
@@ -1316,6 +1343,9 @@ void tst_QContactAsync::contactSave()
//QCOMPARE(result, expected);
// XXX: really, we should use isSuperset() from tst_QContactManager, but this will do for now:
QVERIFY(result.first().detail<QContactName>() == nameDetail);
+
+ // check if the contact was saved on default collection
+ QCOMPARE(result.first().collectionId().toString(), cm->defaultCollection().id().toString());
QCOMPARE(cm->contactIds().size(), originalCount + 1);
// update a previously saved contact
@@ -2413,6 +2443,443 @@ void tst_QContactAsync::relationshipSave()
}
}
+void tst_QContactAsync::collectionFetch()
+{
+ QFETCH(QString, uri);
+ QScopedPointer<QContactManager> cm(prepareModel(uri));
+
+ QContactCollectionFetchRequest cfr;
+ QVERIFY(cfr.type() == QContactAbstractRequest::CollectionFetchRequest);
+
+ // initial state - not started, no manager.
+ QVERIFY(!cfr.isActive());
+ QVERIFY(!cfr.isFinished());
+ QVERIFY(!cfr.start());
+ QVERIFY(!cfr.cancel());
+ QVERIFY(!cfr.waitForFinished());
+
+ // retrieve all collections.
+ cfr.setManager(cm.data());
+ QCOMPARE(cfr.manager(), cm.data());
+ QVERIFY(!cfr.isActive());
+ QVERIFY(!cfr.isFinished());
+ QVERIFY(!cfr.cancel());
+ QVERIFY(!cfr.waitForFinished());
+ qRegisterMetaType<QContactCollectionFetchRequest*>("QContactCollectionFetchRequest*");
+ QThreadSignalSpy spy(&cfr, SIGNAL(stateChanged(QContactAbstractRequest::State)));
+ QVERIFY(!cfr.cancel()); // not started
+
+ QVERIFY(cfr.start());
+ //QVERIFY(cfr.isFinished() || !cfr.start()); // already started. // thread scheduling means this is untestable
+ QVERIFY((cfr.isActive() && cfr.state() == QContactAbstractRequest::ActiveState) || cfr.isFinished());
+ QVERIFY(cfr.waitForFinished());
+ QVERIFY(cfr.isFinished());
+
+ QVERIFY(spy.count() >= 1); // active + finished progress signals
+ spy.clear();
+
+ QList<QContactCollection> syncCols = cm->collections();
+ QList<QContactCollection> cols = cfr.collections();
+ QCOMPARE(cols.size(), syncCols.size());
+ for (int i = 0; i < cols.size(); i++) {
+ QContactCollection curr = cols.at(i);
+ QVERIFY(syncCols.contains(curr));
+ }
+
+ // cancelling
+ int bailoutCount = MAX_OPTIMISTIC_SCHEDULING_LIMIT; // attempt to cancel 40 times. If it doesn't work due to threading, bail out.
+ while (true) {
+ QVERIFY(!cfr.cancel()); // not started
+ FILL_QUEUE_WITH_FETCH_REQUESTS_WITH_MANAGER(cm.data());
+ QVERIFY(cfr.start());
+ if (!cfr.cancel()) {
+ // due to thread scheduling, async cancel might be attempted
+ // after the request has already finished.. so loop and try again.
+ spy.clear();
+ cfr.waitForFinished();
+ bailoutCount -= 1;
+ if (!bailoutCount) {
+// qWarning("Unable to test cancelling due to thread scheduling!");
+ bailoutCount = MAX_OPTIMISTIC_SCHEDULING_LIMIT;
+ break;
+ }
+ continue;
+ }
+
+ // if we get here, then we are cancelling the request.
+ QVERIFY(cfr.waitForFinished());
+ QVERIFY(cfr.isCanceled());
+
+ QVERIFY(spy.count() >= 1); // active + cancelled progress signals
+ spy.clear();
+ break;
+ }
+
+ // restart, and wait for progress after cancel.
+ while (true) {
+ QVERIFY(!cfr.cancel()); // not started
+ FILL_QUEUE_WITH_FETCH_REQUESTS_WITH_MANAGER(cm.data());
+ QVERIFY(cfr.start());
+ if (!cfr.cancel()) {
+ // due to thread scheduling, async cancel might be attempted
+ // after the request has already finished.. so loop and try again.
+ cfr.waitForFinished();
+ bailoutCount -= 1;
+ spy.clear();
+ if (!bailoutCount) {
+ //qWarning("Unable to test cancelling due to thread scheduling!");
+ bailoutCount = MAX_OPTIMISTIC_SCHEDULING_LIMIT;
+ break;
+ }
+ continue;
+ }
+ cfr.waitForFinished();
+ QVERIFY(spy.count() >= 1); // active + cancelled progress signals
+ spy.clear();
+ QVERIFY(!cfr.isActive());
+ QVERIFY(cfr.state() == QContactAbstractRequest::CanceledState);
+ break;
+ }
+}
+
+void tst_QContactAsync::collectionRemove()
+{
+ QFETCH(QString, uri);
+ QScopedPointer<QContactManager> cm(prepareModel(uri));
+ QContactCollectionRemoveRequest crr;
+ QVERIFY(crr.type() == QContactAbstractRequest::CollectionRemoveRequest);
+
+ // initial state - not started, no manager.
+ QVERIFY(!crr.isActive());
+ QVERIFY(!crr.isFinished());
+ QVERIFY(!crr.start());
+ QVERIFY(!crr.cancel());
+ QVERIFY(!crr.waitForFinished());
+
+ // specific collection set
+ QContactCollectionId removeId = cm->collections().last().id();
+ if (cm->defaultCollection().id() == removeId)
+ removeId = cm->collections().first().id();
+ crr.setCollectionId(removeId);
+ QVERIFY(crr.collectionIds() == QList<QContactCollectionId>() << removeId);
+ int originalCount = cm->collections().size();
+ crr.setManager(cm.data());
+ QCOMPARE(crr.manager(), cm.data());
+ QVERIFY(!crr.isActive());
+ QVERIFY(!crr.isFinished());
+ QVERIFY(!crr.cancel());
+ QVERIFY(!crr.waitForFinished());
+ qRegisterMetaType<QContactCollectionRemoveRequest*>("QContactCollectionRemoveRequest*");
+ QThreadSignalSpy spy(&crr, SIGNAL(stateChanged(QContactAbstractRequest::State)));
+ QVERIFY(!crr.cancel()); // not started
+ QVERIFY(crr.start());
+ QVERIFY((crr.isActive() &&crr.state() == QContactAbstractRequest::ActiveState) || crr.isFinished());
+ //QVERIFY(crr.isFinished() || !crr.start()); // already started. // thread scheduling means this is untestable
+ QVERIFY(crr.waitForFinished());
+ QVERIFY(crr.isFinished());
+
+ QVERIFY(spy.count() >= 1); // active + finished progress signals
+ spy.clear();
+
+ QCOMPARE(cm->collections().size(), originalCount - 1); // should have removed that particular collection.
+ QVERIFY(crr.error() == QContactManager::NoError);
+ QVERIFY(crr.errorMap().isEmpty());
+
+ // remove all collections
+ QList<QContactCollectionId> allCollectionIds;
+ QList<QContactCollection> allCollections = cm->collections();
+ for (int i = 0; i < allCollections.size(); ++i)
+ allCollectionIds << allCollections.at(i).id();
+ crr.setCollectionIds(allCollectionIds);
+
+ QVERIFY(!crr.cancel()); // not started
+ QVERIFY(crr.start());
+
+ QVERIFY((crr.isActive() && crr.state() == QContactAbstractRequest::ActiveState) || crr.isFinished());
+ //QVERIFY(crr.isFinished() || !crr.start()); // already started. // thread scheduling means this is untestable
+ QVERIFY(crr.waitForFinished());
+ QVERIFY(crr.isFinished());
+
+ QVERIFY(cm->collections().size() >= 1); // at least one collection must be left, since default collection cannot be removed.
+ QVERIFY(spy.count() >= 1); // active + finished progress signals
+ spy.clear();
+
+ // remove empty list
+ QList<QContactCollectionId> collectionIdList;
+ QContactCollectionRemoveRequest crr1;
+ crr1.setManager(cm.data());
+ crr1.setCollectionIds(collectionIdList);
+ crr1.start();
+ crr1.waitForFinished();
+ QVERIFY(crr1.isFinished());
+ QVERIFY(crr1.error() == QContactManager::NoError);
+
+ // cancelling
+ QContactCollection temp;
+ temp.setMetaData(QContactCollection::KeyDescription, "Should not be removed!");
+ cm->saveCollection(&temp);
+ crr.setCollectionId(temp.id());
+
+ int collectionCount = cm->collections().size();
+ int bailoutCount = MAX_OPTIMISTIC_SCHEDULING_LIMIT; // attempt to cancel 40 times. If it doesn't work due to threading, bail out.
+ while (true) {
+ QVERIFY(!crr.cancel()); // not started
+ FILL_QUEUE_WITH_FETCH_REQUESTS_WITH_MANAGER(cm.data());
+ QVERIFY(spy.count() == 0);
+ QVERIFY(crr.start());
+ if (!crr.cancel()) {
+ // due to thread scheduling, async cancel might be attempted
+ // after the request has already finished.. so loop and try again.
+ crr.waitForFinished();
+ temp.setId(QContactCollectionId());
+ if (!cm->saveCollection(&temp)) {
+ QSKIP("Unable to save temporary item for remove request cancellation test!");
+ }
+ crr.setCollectionId(temp.id());
+ bailoutCount -= 1;
+ if (!bailoutCount) {
+// qWarning("Unable to test cancelling due to thread scheduling!");
+ bailoutCount = MAX_OPTIMISTIC_SCHEDULING_LIMIT;
+ break;
+ }
+ spy.clear();
+ continue;
+ }
+
+ // if we get here, then we are cancelling the request.
+ QVERIFY(crr.waitForFinished());
+ QVERIFY(crr.isCanceled());
+ QCOMPARE(cm->collections().size(), collectionCount); // temp collection should not have been removed
+ QList<QContactCollectionId> removeCollectionIds;
+ QList<QContactCollection> removeCollections = cm->collections();
+ for (int i = 0; i < removeCollections.size(); ++i)
+ removeCollectionIds << removeCollections.at(i).id();
+ QVERIFY(containsAllCollectionIds(removeCollectionIds, crr.collectionIds()));
+ QVERIFY(spy.count() >= 1); // active + cancelled progress signals
+ spy.clear();
+ break;
+ }
+
+ // restart, and wait for progress after cancel.
+ while (true) {
+ QVERIFY(!crr.cancel()); // not started
+ FILL_QUEUE_WITH_FETCH_REQUESTS_WITH_MANAGER(cm.data());
+ QVERIFY(crr.start());
+ if (!crr.cancel()) {
+ // due to thread scheduling, async cancel might be attempted
+ // after the request has already finished.. so loop and try again.
+ crr.waitForFinished();
+ temp.setId(QContactCollectionId());
+ if (!cm->saveCollection(&temp)) {
+ QSKIP("Unable to save temporary item for remove request cancellation test!");
+ }
+ crr.setCollectionId(temp.id());
+ bailoutCount -= 1;
+ if (!bailoutCount) {
+// qWarning("Unable to test cancelling due to thread scheduling!");
+ bailoutCount = MAX_OPTIMISTIC_SCHEDULING_LIMIT;
+ break;
+ }
+ spy.clear();
+ continue;
+ }
+ crr.waitForFinished();
+ QVERIFY(crr.isCanceled());
+ QCOMPARE(cm->collections().size(), collectionCount); // temp collection should not have been removed
+ QList<QContactCollectionId> removeCollectionIds;
+ QList<QContactCollection> removeCollections = cm->collections();
+ for (int i = 0; i < removeCollections.size(); ++i)
+ removeCollectionIds << removeCollections.at(i).id();
+ QVERIFY(containsAllCollectionIds(removeCollectionIds, crr.collectionIds()));
+ QVERIFY(spy.count() >= 1); // active + cancelled progress signals
+ spy.clear();
+ break;
+ }
+
+ // now clean up our temp collection.
+ cm->removeCollection(temp.id());
+
+}
+
+void tst_QContactAsync::collectionSave()
+{
+ QFETCH(QString, uri);
+ QScopedPointer<QContactManager> cm(prepareModel(uri));
+ QContactCollectionSaveRequest csr;
+ QVERIFY(csr.type() == QContactAbstractRequest::CollectionSaveRequest);
+
+ // initial state - not started, no manager.
+ QVERIFY(!csr.isActive());
+ QVERIFY(!csr.isFinished());
+ QVERIFY(!csr.start());
+ QVERIFY(!csr.cancel());
+ QVERIFY(!csr.waitForFinished());
+
+ // save a new item
+ int originalCount = cm->collections().size();
+ QContactCollection testCollection;
+ testCollection.setMetaData(QContactCollection::KeyDescription, "test description");
+ testCollection.setMetaData(QContactCollection::KeyName, "New collection");
+ QList<QContactCollection> saveList;
+ saveList << testCollection;
+ csr.setManager(cm.data());
+ QCOMPARE(csr.manager(), cm.data());
+ QVERIFY(!csr.isActive());
+ QVERIFY(!csr.isFinished());
+ QVERIFY(!csr.cancel());
+ QVERIFY(!csr.waitForFinished());
+ qRegisterMetaType<QContactCollectionSaveRequest*>("QContactCollectionSaveRequest*");
+ QThreadSignalSpy spy(&csr, SIGNAL(stateChanged(QContactAbstractRequest::State)));
+ csr.setCollection(testCollection);
+ QCOMPARE(csr.collections(), saveList);
+ QVERIFY(!csr.cancel()); // not started
+ QVERIFY(csr.start());
+
+ QVERIFY((csr.isActive() && csr.state() == QContactAbstractRequest::ActiveState) || csr.isFinished());
+ //QVERIFY(csr.isFinished() || !csr.start()); // already started. // thread scheduling means this is untestable
+ QVERIFY(csr.waitForFinished());
+ QVERIFY(csr.isFinished());
+ QVERIFY(spy.count() >= 1); // active + finished progress signals
+ spy.clear();
+
+ QList<QContactCollection> expected = csr.collections();
+ QCOMPARE(expected.size(), 1);
+ QList<QContactCollection> result;
+ result << cm->collection(csr.collections().at(0).id());
+
+ // find the saved one, compare.
+ foreach (const QContactCollection &col, result)
+ QVERIFY(col.id() == expected.at(0).id());
+
+ // update a previously saved collection
+ QVERIFY(!result.isEmpty()); // make sure that we were able to retrieve the required collection.
+ testCollection = result.first();
+ testCollection.setMetaData(QContactCollection::KeyName, "test name");
+ saveList.clear();
+ saveList << testCollection;
+ csr.setCollections(saveList);
+ QCOMPARE(csr.collections(), saveList);
+ QVERIFY(!csr.cancel()); // not started
+ QVERIFY(csr.start());
+
+ QVERIFY((csr.isActive() && csr.state() == QContactAbstractRequest::ActiveState) || csr.isFinished());
+ //QVERIFY(csr.isFinished() || !csr.start()); // already started. // thread scheduling means this is untestable
+ QVERIFY(csr.waitForFinished());
+
+ QVERIFY(csr.isFinished());
+ QVERIFY(spy.count() >= 1); // active + finished progress signals
+ spy.clear();
+
+ expected = csr.collections();
+ result.clear();
+ result = cm->collections();
+ // find the saved one, compare.
+ foreach (const QContactCollection& col, result) {
+ if (col.id() == expected.at(0).id()) {
+ QVERIFY(col == expected.at(0)); // XXX TODO: if we change the semantic so that save merely updates the id...?
+ }
+ }
+ QCOMPARE(cm->collections().size(), originalCount + 1); // ie shouldn't have added an extra one (would be +2)
+ QVERIFY(csr.error() == QContactManager::NoError);
+ QVERIFY(csr.errorMap().isEmpty());
+
+ // save empty list
+ QList<QContactCollection> collectionList;
+ QContactCollectionSaveRequest csr1;
+ csr1.setManager(cm.data());
+ csr1.setCollections(collectionList);
+ csr1.start();
+ csr1.waitForFinished();
+ QVERIFY(csr1.isFinished());
+ QVERIFY(csr1.error() == QContactManager::NoError);
+
+ // cancelling
+ QContactCollection temp;
+ temp.setMetaData(testCollection.metaData());
+ temp.setExtendedMetaData("test", "shouldn't be saved");
+ saveList.clear();
+ saveList << temp;
+ csr.setCollections(saveList);
+
+ int bailoutCount = MAX_OPTIMISTIC_SCHEDULING_LIMIT; // attempt to cancel 40 times. If it doesn't work due to threading, bail out.
+ while (true) {
+ QVERIFY(!csr.cancel()); // not started
+ FILL_QUEUE_WITH_FETCH_REQUESTS_WITH_MANAGER(cm.data());
+ QVERIFY(csr.start());
+ if (!csr.cancel()) {
+ // due to thread scheduling, async cancel might be attempted
+ // after the request has already finished.. so loop and try again.
+ csr.waitForFinished();
+ saveList = csr.collections();
+ if (cm->collections().size() > (originalCount + 1) && !cm->removeCollection(saveList.at(0).id())) {
+ QSKIP("Unable to remove saved collection to test cancellation of collection save request");
+ }
+ saveList.clear();
+ saveList << temp;
+ csr.setCollections(saveList);
+ bailoutCount -= 1;
+ if (!bailoutCount) {
+// qWarning("Unable to test cancelling due to thread scheduling!");
+ bailoutCount = MAX_OPTIMISTIC_SCHEDULING_LIMIT;
+ break;
+ }
+ spy.clear();
+ continue;
+ }
+
+ // if we get here, then we are cancelling the request.
+ QVERIFY(csr.waitForFinished());
+ QVERIFY(csr.isCanceled());
+ QVERIFY(spy.count() >= 1); // active + cancelled progress signals
+ spy.clear();
+
+ // verify that the changes were not saved
+ expected.clear();
+ QList<QContactCollection> allCollections = cm->collections();
+ QVERIFY(!allCollections.contains(temp)); // should NOT contain it since it was cancelled.
+ QCOMPARE(allCollections.size(), originalCount + 1);
+ break;
+ }
+ // restart, and wait for progress after cancel.
+
+ while (true) {
+ QVERIFY(!csr.cancel()); // not started
+ FILL_QUEUE_WITH_FETCH_REQUESTS_WITH_MANAGER(cm.data());
+ QVERIFY(csr.start());
+ if (!csr.cancel()) {
+ // due to thread scheduling, async cancel might be attempted
+ // after the request has already finished.. so loop and try again.
+ csr.waitForFinished();
+ saveList = csr.collections();
+ if (cm->collections().size() > (originalCount + 1) && !cm->removeCollection(saveList.at(0).id())) {
+ QSKIP("Unable to remove saved item to test cancellation of item save request");
+ }
+ saveList.clear();
+ saveList << temp;
+ csr.setCollections(saveList);
+ bailoutCount -= 1;
+ if (!bailoutCount) {
+// qWarning("Unable to test cancelling due to thread scheduling!");
+ bailoutCount = MAX_OPTIMISTIC_SCHEDULING_LIMIT;
+ break;
+ }
+ spy.clear();
+ continue;
+ }
+ csr.waitForFinished(); // now wait until finished (if it hasn't already).
+ QVERIFY(csr.isCanceled());
+ QVERIFY(spy.count() >= 1); // active + cancelled progress signals
+ spy.clear();
+
+ // verify that the changes were not saved
+ expected.clear();
+ QList<QContactCollection> allCollections = cm->collections();
+ QVERIFY(!allCollections.contains(temp));
+ QCOMPARE(cm->collections().size(), originalCount + 1);
+ break;
+ }
+}
+
void tst_QContactAsync::maliciousManager()
{
// use the invalid manager: passes all requests through to base class
@@ -2655,6 +3122,11 @@ QContactManager* tst_QContactAsync::prepareModel(const QString& managerUri)
crb.setRelationshipType(QContactRelationship::IsSameAs());
cm->saveRelationship(&crb);
+ QContactCollection testCollection;
+ testCollection.setMetaData(QContactCollection::KeyName, "Test Collection");
+ testCollection.setMetaData(QContactCollection::KeyDescription, "test collection");
+ cm->saveCollection(&testCollection);
+
return cm;
// TODO: cleanup once test is complete
diff --git a/tests/auto/contacts/qcontactcollection/qcontactcollection.pro b/tests/auto/contacts/qcontactcollection/qcontactcollection.pro
new file mode 100644
index 000000000..bb6599776
--- /dev/null
+++ b/tests/auto/contacts/qcontactcollection/qcontactcollection.pro
@@ -0,0 +1,5 @@
+include(../../auto.pri)
+
+QT += contacts
+
+SOURCES += tst_qcontactcollection.cpp
diff --git a/tests/auto/contacts/qcontactcollection/tst_qcontactcollection.cpp b/tests/auto/contacts/qcontactcollection/tst_qcontactcollection.cpp
new file mode 100644
index 000000000..d36f36c48
--- /dev/null
+++ b/tests/auto/contacts/qcontactcollection/tst_qcontactcollection.cpp
@@ -0,0 +1,397 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2015 Canonical Ltd
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+
+#include <QtCore/qset.h>
+
+#include <QtContacts/qcontacts.h>
+
+
+QTCONTACTS_USE_NAMESPACE
+
+static inline QContactCollectionId makeId(const QString &managerName, uint id)
+{
+ return QContactCollectionId(QStringLiteral("qtcontacts:%1:").arg(managerName), QByteArray(reinterpret_cast<const char *>(&id), sizeof(uint)));
+}
+
+class tst_QContactCollection: public QObject
+{
+Q_OBJECT
+
+public:
+ tst_QContactCollection();
+ virtual ~tst_QContactCollection();
+
+private slots:
+ void metaData();
+ void compare();
+ void idComparison();
+ void idHash();
+ void idStringFunctions();
+ void hash();
+ void datastream();
+ void traits();
+ void idTraits();
+};
+
+tst_QContactCollection::tst_QContactCollection()
+{
+}
+
+tst_QContactCollection::~tst_QContactCollection()
+{
+}
+
+void tst_QContactCollection::metaData()
+{
+ QContactCollection c;
+ QVERIFY(c.metaData().isEmpty());
+ c.setExtendedMetaData(QString(QStringLiteral("test")), 5);
+ QCOMPARE(c.extendedMetaData(QString(QStringLiteral("test"))).toInt(), 5);
+
+ QMap<QContactCollection::MetaDataKey, QVariant> mdm;
+ mdm.insert(QContactCollection::KeyName, QString(QStringLiteral("test2")));
+ c.setMetaData(mdm);
+ QCOMPARE(c.metaData(), mdm);
+ QCOMPARE(c.metaData(QContactCollection::KeyName).toString(), QString(QStringLiteral("test2")));
+}
+
+void tst_QContactCollection::compare()
+{
+ QContactCollection c, c2;
+ QVERIFY(c == c2);
+ c.setExtendedMetaData(QStringLiteral("test"), 5);
+ QVERIFY(c != c2);
+ c2.setExtendedMetaData(QStringLiteral("test"), 5);
+ QVERIFY(c == c2);
+
+ QMap<QContactCollection::MetaDataKey, QVariant> mdm;
+ mdm.insert(QContactCollection::KeyName, QStringLiteral("test2"));
+ c.setMetaData(mdm);
+ QVERIFY(c != c2);
+ c2.setMetaData(mdm);
+ QVERIFY(c == c2);
+
+ c2 = QContactCollection();
+ QVERIFY(c != c2);
+ c2 = c;
+ QVERIFY(c == c2);
+
+ c.setId(makeId(QStringLiteral("a"), 1));
+ QVERIFY(c != c2);
+ c2.setId(makeId(QStringLiteral("a"), 1));
+ QVERIFY(c == c2);
+ c.setId(makeId(QStringLiteral("b"), 1));
+ QVERIFY(c != c2);
+ c2.setId(c.id());
+ QVERIFY(c == c2);
+ c.setId(makeId(QStringLiteral("b"), 2));
+}
+
+void tst_QContactCollection::idComparison()
+{
+ QContactCollectionId id1(makeId("a", 1));
+ QContactCollectionId id2(makeId("a", 1));
+ QVERIFY(!(id1 < id2));
+ QVERIFY(!(id2 < id1));
+ QVERIFY(id1 == id2);
+
+ QContactCollectionId id3(makeId("a", 2));
+ QContactCollectionId id4(makeId("b", 1));
+ QContactCollectionId id5(makeId("b", 2));
+ QVERIFY((((id1 < id3) && !(id3 < id1)) || ((id3 < id1) && !(id1 < id3))) && (id1 != id3));
+ QVERIFY((((id1 < id4) && !(id4 < id1)) || ((id4 < id1) && !(id1 < id4))) && (id1 != id4));
+ QVERIFY((((id3 < id4) && !(id4 < id3)) || ((id4 < id3) && !(id3 < id4))) && (id3 != id4));
+ QVERIFY((((id1 < id5) && !(id5 < id1)) || ((id5 < id1) && !(id1 < id5))) && (id3 != id4));
+
+ QContactCollectionId id6;
+ QContactCollectionId id7(QString(), "1");
+ QContactCollectionId id8(QString(), "2");
+ QContactCollectionId id9(QStringLiteral("qtcontacts:basic:"), QByteArray());
+ QVERIFY(id6.isNull());
+ QVERIFY(id7.isNull());
+ QVERIFY(id8.isNull());
+ QVERIFY(id9.isNull());
+ QVERIFY(id6 == id7);
+ QVERIFY(!(id6 < id7));
+ QVERIFY(id7 == id6);
+ QVERIFY(!(id7 < id6));
+ QVERIFY(id7 == id8);
+ QVERIFY(!(id7 < id8));
+ QVERIFY(id8 == id7);
+ QVERIFY(!(id9 < id8));
+ QVERIFY(id8 == id9);
+ QVERIFY(!(id8 < id9));
+ QVERIFY(id9 == id8);
+ QVERIFY(!(id9 < id8));
+
+ QVERIFY(!(id1 == id6));
+ QVERIFY(!(id1 < id6));
+ QVERIFY(id6 < id1);
+ QVERIFY(!(id1 == id7));
+ QVERIFY(!(id1 < id7));
+ QVERIFY(id7 < id1);
+ QVERIFY(!(id1 == id8));
+ QVERIFY(!(id1 < id8));
+ QVERIFY(id8 < id1);
+ QVERIFY(!(id1 == id9));
+ QVERIFY(!(id1 < id9));
+ QVERIFY(id9 < id1);
+}
+
+void tst_QContactCollection::idHash()
+{
+ QContactCollectionId id1(makeId("a", 1));
+ QContactCollectionId id2(makeId("a", 1));
+ QContactCollectionId id3(makeId("b", 1));
+ QContactCollectionId id4(makeId("a", 2));
+ // note that the hash function ignores the managerUri
+ QCOMPARE(qHash(id1), qHash(id2));
+ QCOMPARE(qHash(id1), qHash(id3));
+ QVERIFY(qHash(id1) != qHash(id4));
+
+ QSet<QContactCollectionId> set;
+ set.insert(id1);
+ set.insert(id2);
+ set.insert(id3);
+ set.insert(id4);
+ QCOMPARE(set.size(), 3);
+}
+
+void tst_QContactCollection::idStringFunctions()
+{
+ // TODO: review test
+ QContactCollectionId id1(makeId("a", 1));
+ QContactCollectionId id2(makeId("a", 1));
+ QContactCollectionId id3(makeId("b", 1));
+ QContactCollectionId id4(makeId("a", 2));
+ QVERIFY(qHash(id1) == qHash(id2));
+ QVERIFY(qHash(id1) != qHash(id4));
+
+ // note that the toString and fromString functions are
+ // engine and id specific. This test merely checks that
+ // the API is hooked up correctly.
+
+ QVERIFY(id1.toString() == id2.toString());
+ QVERIFY(id1.toString() != id3.toString());
+ QVERIFY(id1.toString() != id4.toString());
+ QVERIFY(id3.toString() != id4.toString());
+
+ // this should "work" -- string of the correct format
+ const uint numericId2 = 2u;
+ const QByteArray localId2 = QByteArray(reinterpret_cast<const char *>(&numericId2), sizeof(uint));
+ QString prebuiltidstring = QString("qtcontacts") + QString(":") + QString("a") + QString("::") + localId2.toHex();
+ QContactCollectionId rebuiltid = QContactCollectionId::fromString(prebuiltidstring);
+ QVERIFY(rebuiltid == id4);
+ QVERIFY(rebuiltid.localId() == id4.localId());
+
+ // this string has the right format and one parameter, but requires a working backend
+ prebuiltidstring = QString("qtcontacts") + QString(":") + QString("a") + QString(":") + QString("key=value") + QString(":") + localId2.toHex();
+ rebuiltid = QContactCollectionId::fromString(prebuiltidstring);
+ QVERIFY(rebuiltid != id4);
+ QVERIFY(rebuiltid.localId() == id4.localId());
+
+ // this string has the right format and some parameters, but requires a working backend
+ prebuiltidstring = QString("qtcontacts") + QString(":") + QString("a") + QString(":") + QString("key=value&key2=value2") + QString(":") + localId2.toHex();
+ rebuiltid = QContactCollectionId::fromString(prebuiltidstring);
+ QVERIFY(rebuiltid != id4);
+ QVERIFY(rebuiltid.localId() == id4.localId());
+
+ // this string has the right format but misses the value for a parameter
+ prebuiltidstring = QString("qtcontacts") + QString(":") + QString("a") + QString(":") + QString("key=value&key2=") + QString(":") + localId2.toHex();
+ rebuiltid = QContactCollectionId::fromString(prebuiltidstring);
+ QVERIFY(rebuiltid != id4);
+ QVERIFY(rebuiltid.localId() == id4.localId());
+
+ // this string misses a field (the parameters)
+ prebuiltidstring = QString("qtcontacts") + QString(":") + QString("a") + QString(":") + localId2.toHex();
+ rebuiltid = QContactCollectionId::fromString(prebuiltidstring);
+ QVERIFY(rebuiltid == QContactCollectionId()); // invalid so should be null.
+
+ // this string misses two fields (params plus manager uri)
+ prebuiltidstring = QString("qtcontacts") + QString(":") + QString::number(2);
+ rebuiltid = QContactCollectionId::fromString(prebuiltidstring);
+ QVERIFY(rebuiltid == QContactCollectionId()); // invalid so should be null.
+
+ // this string misses the prefix (qtorganizer)
+ prebuiltidstring = QString("notorganizer") + QString(":") + QString("a") + QString("::") + localId2.toHex();
+ rebuiltid = QContactCollectionId::fromString(prebuiltidstring);
+ QVERIFY(rebuiltid == QContactCollectionId()); // invalid so should be null.
+
+ // this string misses the manager uri
+ prebuiltidstring = QString("notorganizer") + QString(":::") + localId2.toHex();
+ rebuiltid = QContactCollectionId::fromString(prebuiltidstring);
+ QVERIFY(rebuiltid == QContactCollectionId()); // invalid so should be null.
+}
+
+void tst_QContactCollection::hash()
+{
+ // TODO: review tests
+ QContactCollectionId id(makeId("a", 1));
+ QContactCollection c1;
+ c1.setId(id);
+ c1.setExtendedMetaData("key", "value");
+ QContactCollection c2;
+ c2.setId(id);
+ c2.setExtendedMetaData("key", "value");
+ QContactCollection c3;
+ c3.setId(id);
+ c3.setExtendedMetaData("key", "another value");
+ QContactCollection c4; // no details
+ c4.setId(id);
+ QContactCollection c5;
+ c5.setId(id);
+ c5.setExtendedMetaData("key", "value");
+ QVERIFY(qHash(c1) == qHash(c2));
+ QVERIFY(qHash(c1) != qHash(c3));
+ QVERIFY(qHash(c1) != qHash(c4));
+ QVERIFY(qHash(c1) == qHash(c5));
+}
+
+void tst_QContactCollection::datastream()
+{
+ // collection datastreaming
+ QByteArray buffer;
+ QContactCollection collectionIn;
+ collectionIn.setExtendedMetaData("key", "value");
+ QContactCollection collectionOut;
+ QContactCollectionId originalId;
+
+ // first, stream an item with a complete id
+ {
+ QDataStream stream1(&buffer, QIODevice::WriteOnly);
+ QContactManager om("memory");
+ QVERIFY(om.saveCollection(&collectionIn)); // fill in its ID
+ originalId = collectionIn.id();
+ stream1 << collectionIn;
+ QVERIFY(buffer.size() > 0);
+ QDataStream stream2(buffer);
+ stream2 >> collectionOut;
+ QCOMPARE(collectionOut, collectionIn); // can use QCOMPARE for collections, since no detail keys.
+ }
+
+ // second, stream an item with an id with the mgr uri set, local id null
+ {
+ QDataStream stream1(&buffer, QIODevice::WriteOnly);
+ collectionIn.setId(QContactCollectionId());
+ stream1 << collectionIn;
+ QVERIFY(buffer.size() > 0);
+ QDataStream stream2(buffer);
+ stream2 >> collectionOut;
+ QCOMPARE(collectionOut, collectionIn); // can use QCOMPARE for collections, since no detail keys.
+ }
+
+ // third, stream an item with a null id
+ {
+ QDataStream stream1(&buffer, QIODevice::WriteOnly);
+ collectionIn.setId(QContactCollectionId());
+ stream1 << collectionIn;
+ QVERIFY(buffer.size() > 0);
+ QDataStream stream2(buffer);
+ stream2 >> collectionOut;
+ QVERIFY(collectionOut.metaData() == collectionIn.metaData());
+ QVERIFY(collectionOut.id() == collectionIn.id()); // should both be null ids.
+ }
+
+ // id datastreaming
+ buffer.clear();
+ QContactCollectionId inputId;
+ QContactCollectionId outputId;
+
+ // first, stream the whole id (mgr uri set, local id set)
+ {
+ inputId = originalId;
+ QString serializedId = inputId.toString();
+ outputId = QContactCollectionId::fromString(serializedId);
+ QCOMPARE(inputId, outputId);
+
+ inputId = originalId;
+ buffer.clear();
+ QDataStream stream1(&buffer, QIODevice::WriteOnly);
+ stream1 << inputId;
+ QVERIFY(buffer.size() > 0);
+ QDataStream stream2(buffer);
+ stream2 >> outputId;
+ QCOMPARE(inputId, outputId);
+ }
+
+ // second, stream a null id
+ {
+ inputId = QContactCollectionId();
+ QString serializedId = inputId.toString();
+ outputId = QContactCollectionId::fromString(serializedId);
+ QCOMPARE(inputId, outputId);
+
+ inputId = QContactCollectionId();
+ buffer.clear();
+ QDataStream stream1(&buffer, QIODevice::WriteOnly);
+ stream1 << inputId;
+ QVERIFY(buffer.size() > 0);
+ QDataStream stream2(buffer);
+ stream2 >> outputId;
+ QCOMPARE(inputId, outputId);
+ }
+}
+
+void tst_QContactCollection::traits()
+{
+ QCOMPARE(sizeof(QContactCollection), sizeof(void *));
+ QVERIFY(QTypeInfo<QContactCollection>::isComplex);
+ QVERIFY(!QTypeInfo<QContactCollection>::isStatic);
+ QVERIFY(!QTypeInfo<QContactCollection>::isLarge);
+ QVERIFY(!QTypeInfo<QContactCollection>::isPointer);
+ QVERIFY(!QTypeInfo<QContactCollection>::isDummy);
+}
+
+void tst_QContactCollection::idTraits()
+{
+ QCOMPARE(sizeof(QContactCollectionId), 2*sizeof(void *));
+ QVERIFY(QTypeInfo<QContactCollectionId>::isComplex);
+ QVERIFY(!QTypeInfo<QContactCollectionId>::isStatic);
+ QVERIFY(QTypeInfo<QContactCollectionId>::isLarge);
+ QVERIFY(!QTypeInfo<QContactCollectionId>::isPointer);
+ QVERIFY(!QTypeInfo<QContactCollectionId>::isDummy);
+}
+
+QTEST_MAIN(tst_QContactCollection)
+#include "tst_qcontactcollection.moc"
diff --git a/tests/auto/contacts/qcontactfilter/tst_qcontactfilter.cpp b/tests/auto/contacts/qcontactfilter/tst_qcontactfilter.cpp
index e347c3fdd..4df9a25f3 100644
--- a/tests/auto/contacts/qcontactfilter/tst_qcontactfilter.cpp
+++ b/tests/auto/contacts/qcontactfilter/tst_qcontactfilter.cpp
@@ -55,6 +55,11 @@ static inline QContactId makeId(const QString &managerName, uint id)
return QContactId(QStringLiteral("qtcontacts:basic%1:").arg(managerName), QByteArray(reinterpret_cast<const char *>(&id), sizeof(uint)));
}
+static inline QContactCollectionId makeCollectionId(uint id)
+{
+ return QContactCollectionId(QStringLiteral("qtcontacts:basic:"), QByteArray(reinterpret_cast<const char *>(&id), sizeof(uint)));
+}
+
class tst_QContactFilter : public QObject
{
Q_OBJECT
@@ -81,9 +86,12 @@ private slots:
void canonicalizedFilter_data();
void testFilter();
void testFilter_data();
+ void collectionFilter();
void datastream();
void datastream_data();
+ void testDebugStreamOut();
+ void testDebugStreamOut_data();
void traits();
};
@@ -1210,6 +1218,40 @@ void tst_QContactFilter::testFilter_data()
}
}
+void tst_QContactFilter::collectionFilter()
+{
+ QContactCollectionFilter icf;
+
+ QVERIFY(icf.collectionIds().isEmpty());
+
+ QContactCollectionId id1 = makeCollectionId(5);
+ QContactCollectionId id2 = makeCollectionId(6);
+ QContactCollectionId id3 = makeCollectionId(7);
+ QContactCollectionId id4 = makeCollectionId(12);
+ QSet<QContactCollectionId> ids;
+ ids << id1 << id2 << id3;
+
+ icf.setCollectionIds(ids);
+ QVERIFY(icf.collectionIds() == ids);
+
+ icf.setCollectionId(id4);
+ ids.clear();
+ ids << id4;
+ QVERIFY(icf.collectionIds() == ids);
+
+ QContactCollectionFilter icf2;
+ icf2 = icf;
+ QVERIFY(icf2.collectionIds() == ids);
+
+ QContactFilter fil;
+ fil = icf;
+ QVERIFY(fil.type() == QContactFilter::CollectionFilter);
+
+ QContactCollectionFilter icf3(fil);
+ QVERIFY(fil.type() == QContactFilter::CollectionFilter);
+ QVERIFY(icf3.collectionIds() == ids);
+}
+
void tst_QContactFilter::datastream()
{
QFETCH(QContactFilter, filterIn);
@@ -1286,6 +1328,58 @@ void tst_QContactFilter::datastream_data()
}
}
+void tst_QContactFilter::testDebugStreamOut()
+{
+ QFETCH(QContactFilter, filterIn);
+ QFETCH(QString, messageExpected);
+
+ QTest::ignoreMessage(QtDebugMsg, messageExpected.toUtf8());
+ qDebug() << filterIn;
+}
+
+void tst_QContactFilter::testDebugStreamOut_data()
+{
+ QTest::addColumn<QContactFilter>("filterIn");
+ QTest::addColumn<QString>("messageExpected");
+
+ {
+ QContactCollectionFilter filter;
+ QContactCollectionId id1 = makeCollectionId(5);
+ QContactCollectionId id2 = makeCollectionId(6);
+ QContactCollectionId id3 = makeCollectionId(7);
+ QContactCollectionId id4 = makeCollectionId(12);
+ QSet<QContactCollectionId> ids;
+ ids << id1 << id2 << id3;
+ filter.setCollectionIds(ids);
+ // Testing method setCollectionIds
+ QTest::newRow("collection") << (QContactFilter)filter << "QContactFilter(QContactCollectionFilter(collectionIds=(QContactCollectionId(qtcontacts:basic::05000000), QContactCollectionId(qtcontacts:basic::06000000), QContactCollectionId(qtcontacts:basic::07000000))))";
+
+ filter.setCollectionId(id2);
+ // Testing method setCollectionId (and the related clearing of the collection)
+ QTest::newRow("collection") << (QContactFilter)filter << "QContactFilter(QContactCollectionFilter(collectionIds=(QContactCollectionId(qtcontacts:basic::06000000))))";
+ filter.setCollectionId(id4);
+ // Testing again method setCollectionId (and the related clearing of the collection)
+ QTest::newRow("collection") << (QContactFilter)filter << "QContactFilter(QContactCollectionFilter(collectionIds=(QContactCollectionId(qtcontacts:basic::0c000000))))";
+ ids.clear();
+ ids << id4;
+ // Testing again method setCollectionIds
+ QTest::newRow("collection") << (QContactFilter)filter << "QContactFilter(QContactCollectionFilter(collectionIds=(QContactCollectionId(qtcontacts:basic::0c000000))))";
+
+ QContactCollectionFilter filter2;
+ filter2 = filter;
+ // Testing again method setCollectionIds on the copied filter
+ QTest::newRow("collection") << (QContactFilter)filter2 << "QContactFilter(QContactCollectionFilter(collectionIds=(QContactCollectionId(qtcontacts:basic::0c000000))))";
+
+ QContactFilter fil;
+ fil = filter;
+ // Testing that the assignment/conversion went fine
+ QTest::newRow("collection") << (QContactFilter)fil << "QContactFilter(QContactCollectionFilter(collectionIds=(QContactCollectionId(qtcontacts:basic::0c000000))))";
+
+ QContactCollectionFilter filter3(fil);
+ QTest::newRow("collection") << (QContactFilter)filter3 << "QContactFilter(QContactCollectionFilter(collectionIds=(QContactCollectionId(qtcontacts:basic::0c000000))))";
+ }
+}
+
void tst_QContactFilter::traits()
{
QCOMPARE(sizeof(QContactFilter), sizeof(void *));
diff --git a/tests/auto/contacts/qcontactmanager/tst_qcontactmanager.cpp b/tests/auto/contacts/qcontactmanager/tst_qcontactmanager.cpp
index 7e7f8d0a0..94395c859 100644
--- a/tests/auto/contacts/qcontactmanager/tst_qcontactmanager.cpp
+++ b/tests/auto/contacts/qcontactmanager/tst_qcontactmanager.cpp
@@ -150,6 +150,10 @@ private slots:
void contactType();
void lateDeletion();
void compareVariant();
+ void createCollection();
+ void modifyCollection();
+ void removeCollection();
+ void saveContactIntoCollections();
#if defined(USE_VERSIT_PLZ)
void partialSave();
@@ -190,6 +194,10 @@ private slots:
void lateDeletion_data() {addManagers();}
void testInterSectionOfIdFilters_data() {addManagers();}
void testInterSectionOfIdAndDetailFilters_data() {addManagers();}
+ void createCollection_data() {addManagers();}
+ void modifyCollection_data() {addManagers();}
+ void removeCollection_data() {addManagers();}
+ void saveContactIntoCollections_data() {addManagers();}
};
// Helper class that connects to a signal on ctor, and disconnects on dtor
@@ -1474,15 +1482,23 @@ void tst_QContactManager::memoryManager()
nc.setLastName("Civilian");
c.saveDetail(&nc);
m1.saveContact(&c);
+
+ // reset ids
c.setId(QContactId());
+ c.setCollectionId(QContactCollectionId());
+
QContact c2;
QContactName nc2 = c2.detail(QContactName::Type);
c2 = c;
nc2.setMiddleName("Public");
c2.saveDetail(&nc2);
+
m2.saveContact(&c2); // save c2 first; c will be given a higher id
m2.saveContact(&c); // save c to m2
+
+ // reset ids
c.setId(QContactId());
+ c.setCollectionId(QContactCollectionId());
nc.setSuffix("MD");
c.saveDetail(&nc);
m3.saveContact(&c);
@@ -1871,6 +1887,7 @@ void tst_QContactManager::signalEmission()
qRegisterMetaType<QContactId>("QContactId");
qRegisterMetaType<QList<QContactId> >("QList<QContactId>");
qRegisterMetaType<QList<QContactDetail::DetailType> >("QList<QContactDetail::DetailType>");
+
QSignalSpy spyCA(m1.data(), SIGNAL(contactsAdded(QList<QContactId>)));
QSignalSpy spyCM(m1.data(), SIGNAL(contactsChanged(QList<QContactId>, QList<QContactDetail::DetailType>)));
QSignalSpy spyCR(m1.data(), SIGNAL(contactsRemoved(QList<QContactId>)));
@@ -1879,8 +1896,10 @@ void tst_QContactManager::signalEmission()
QTestSignalSink cmsink(m1.data(), SIGNAL(contactsChanged(QList<QContactId>, QList<QContactDetail::DetailType>)));
QTestSignalSink crsink(m1.data(), SIGNAL(contactsRemoved(QList<QContactId>)));
+
QList<QVariant> args;
QList<QContactId> arg;
+ QList<QContactCollectionId> collectionIdList;
QContact c;
QList<QContact> batchAdd;
QList<QContactId> batchRemove;
@@ -3209,6 +3228,153 @@ void tst_QContactManager::compareVariant()
QVERIFY((comparison + expected) == 0);
}
+void tst_QContactManager::createCollection()
+{
+ QFETCH(QString, uri);
+ QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
+
+ qRegisterMetaType<QList<QContactCollectionId> >("QList<QContactCollectionId>");
+ QSignalSpy collectionsAddedSpy(cm.data(), SIGNAL(collectionsAdded(QList<QContactCollectionId>)));
+ QByteArray collectionName = QUuid::createUuid().toByteArray();
+
+ // create collection
+ {
+ QContactCollection col;
+ col.setMetaData(QContactCollection::KeyName, collectionName);
+ QVERIFY(cm->saveCollection(&col));
+ }
+
+ // check "collectionsAdded" signal
+ QCOMPARE(collectionsAddedSpy.count(), 1);
+ QList<QContactCollectionId> ids = collectionsAddedSpy.takeFirst().at(0).value<QList<QContactCollectionId> >();
+ QCOMPARE(ids.count(), 1);
+
+ // query for new collection
+ {
+ QContactCollection col = cm->collection(ids.at(0));
+ QVERIFY(!col.id().isNull());
+ QCOMPARE(col.id().toString(), ids.at(0).toString());
+ QCOMPARE(col.metaData(QContactCollection::KeyName).toByteArray(), collectionName);
+ }
+}
+
+void tst_QContactManager::modifyCollection()
+{
+ QFETCH(QString, uri);
+ QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
+
+ qRegisterMetaType<QList<QContactCollectionId> >("QList<QContactCollectionId>");
+ QSignalSpy collectionsAddedSpy(cm.data(), SIGNAL(collectionsAdded(QList<QContactCollectionId>)));
+ QSignalSpy collectionsChangedSpy(cm.data(), SIGNAL(collectionsChanged(QList<QContactCollectionId>)));
+
+ QContactCollectionId colId;
+ QByteArray collectionName = QUuid::createUuid().toByteArray();
+
+ // save a new collection
+ {
+ QContactCollection col;
+ col.setMetaData(QContactCollection::KeyName, collectionName);
+ QVERIFY(cm->saveCollection(&col));
+ QTRY_COMPARE(collectionsAddedSpy.count(), 1);
+ colId = col.id();
+ QVERIFY(!colId.isNull());
+ }
+
+ // edit collection
+ {
+ QCOMPARE(collectionsChangedSpy.count(), 0);
+ QContactCollection col = cm->collection(colId);
+ QByteArray newCollectionName = QUuid::createUuid().toByteArray();
+ col.setMetaData(QContactCollection::KeyName, newCollectionName);
+ QVERIFY(cm->saveCollection(&col));
+
+ // check signal "collectionsChanged" fired contains the collection id
+ QTRY_COMPARE(collectionsChangedSpy.count(), 1);
+ QList<QContactCollectionId> ids = collectionsChangedSpy.takeFirst().at(0).value<QList<QContactCollectionId> >();
+ QCOMPARE(ids.at(0).toString(), colId.toString());
+
+ // check if the collection name was updated
+ QContactCollection col2 = cm->collection(colId);
+ QCOMPARE(col2.metaData(QContactCollection::KeyName).toByteArray(), newCollectionName);
+ }
+}
+
+void tst_QContactManager::removeCollection()
+{
+ QFETCH(QString, uri);
+ QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
+
+ qRegisterMetaType<QList<QContactCollectionId> >("QList<QContactCollectionId>");
+ QSignalSpy collectionsAddedSpy(cm.data(), SIGNAL(collectionsAdded(QList<QContactCollectionId>)));
+ QSignalSpy collectionsRemovedSpy(cm.data(), SIGNAL(collectionsRemoved(QList<QContactCollectionId>)));
+
+ QContactCollectionId colId;
+
+ // save a new collection
+ {
+ QContactCollection col;
+ QByteArray collectionName = QUuid::createUuid().toByteArray();
+ col.setMetaData(QContactCollection::KeyName, collectionName);
+ QVERIFY(cm->saveCollection(&col));
+ QTRY_COMPARE(collectionsAddedSpy.count(), 1);
+ colId = col.id();
+ }
+ QList<QContactCollection> collections = cm->collections();
+
+ // remove collection
+ cm->removeCollection(colId);
+
+ // check "collectionsRemoved" signal
+ QTRY_COMPARE(collectionsRemovedSpy.count(), 1);
+ QList<QContactCollectionId> ids = collectionsRemovedSpy.takeFirst().at(0).value<QList<QContactCollectionId> >();
+ QCOMPARE(ids.at(0).toString(), colId.toString());
+
+
+ // check if the correct collection was removed
+ QList<QContactCollection> collectionsAfterRemoval = cm->collections();
+ QCOMPARE(collections.count() - 1, collectionsAfterRemoval.count());
+ Q_FOREACH (const QContactCollection &col, collectionsAfterRemoval) {
+ collections.removeAll(col);
+ }
+ QCOMPARE(collections.count(), 1);
+ QCOMPARE(collections.at(0).id().toString(), colId.toString());
+}
+
+void tst_QContactManager::saveContactIntoCollections()
+{
+ QFETCH(QString, uri);
+ QScopedPointer<QContactManager> cm(QContactManager::fromUri(uri));
+
+ qRegisterMetaType<QList<QContactCollectionId> >("QList<QContactCollectionId>");
+ QSignalSpy collectionsAddedSpy(cm.data(), SIGNAL(collectionsAdded(QList<QContactCollectionId>)));
+ QByteArray collectionName = QUuid::createUuid().toByteArray();
+ QContactCollectionId colId;
+ QContactId cId;
+
+ // create collection
+ {
+ QContactCollection col;
+ col.setMetaData(QContactCollection::KeyName, collectionName);
+ QVERIFY(cm->saveCollection(&col));
+ QTRY_COMPARE(collectionsAddedSpy.count(), 1);
+ colId = col.id();
+ }
+
+ // create contact
+ {
+ QContact c = createContact("Alice", "Last", "12345");
+ c.setCollectionId(colId);
+ cm->saveContact(&c);
+ cId = c.id();
+ }
+
+ // query new contact and check for collection
+ {
+ QContact c = cm->contact(cId);
+ QCOMPARE(c.collectionId().toString(), colId.toString());
+ }
+}
+
void tst_QContactManager::compareVariant_data()
{
QTest::addColumn<QVariant>("a");
diff --git a/tests/auto/contacts/qmlcontacts/qmlcontacts.pro b/tests/auto/contacts/qmlcontacts/qmlcontacts.pro
index 540543d76..0a9187726 100644
--- a/tests/auto/contacts/qmlcontacts/qmlcontacts.pro
+++ b/tests/auto/contacts/qmlcontacts/qmlcontacts.pro
@@ -12,8 +12,10 @@ OTHER_FILES += \
testcases/ContactsSavingTestCase.qml \
testcases/ContactsSignalingTestCase.qml \
testcases/ContactsTestHelper.qml \
+ testcases/tst_collection.qml \
testcases/tst_contact_add_detail.qml \
testcases/tst_contact_addresses.qml \
+ testcases/tst_contact_collection_filter.qml \
testcases/tst_contact_detail_access.qml \
testcases/tst_contactdetail.qml \
testcases/tst_contact_emails.qml \
diff --git a/tests/auto/contacts/qmlcontacts/testcases/ContactsSavingTestCase.qml b/tests/auto/contacts/qmlcontacts/testcases/ContactsSavingTestCase.qml
index bc2911178..b5e2ded90 100644
--- a/tests/auto/contacts/qmlcontacts/testcases/ContactsSavingTestCase.qml
+++ b/tests/auto/contacts/qmlcontacts/testcases/ContactsSavingTestCase.qml
@@ -48,6 +48,7 @@ TestCase {
id: contactsSavingTestCase
property SignalSpy spy
+ property SignalSpy collectionSpy
property bool debug: false
ContactsTestConfiguration {
@@ -69,6 +70,15 @@ TestCase {
contactsSavingTestCase);
spy.target = model;
spy.signalName = "contactsChanged";
+
+ collectionSpy = Qt.createQmlObject(
+ "import QtTest 1.0;" +
+ "SignalSpy {" +
+ "}",
+ contactsSavingTestCase);
+ collectionSpy.target = model
+ collectionSpy.signalName = "collectionsChanged"
+
return spy;
}
@@ -83,6 +93,13 @@ TestCase {
spy.wait();
}
+ // Verify that the collectionsChanged signal is emitted
+ function waitForCollectionsChanged() {
+ logDebug("waitForCollectionsChanged");
+ collectionSpy.wait();
+ }
+
+
// Wait until duration has elapsed, or the contactsChanged signal is emitted
function waitUntilContactsChanged(duration) {
logDebug("waitUntilContactsChanged");
diff --git a/tests/auto/contacts/qmlcontacts/testcases/tst_contact_collection_filter.qml b/tests/auto/contacts/qmlcontacts/testcases/tst_contact_collection_filter.qml
new file mode 100644
index 000000000..074adb52a
--- /dev/null
+++ b/tests/auto/contacts/qmlcontacts/testcases/tst_contact_collection_filter.qml
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2015 Canonical Ltd
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtTest 1.0
+import QtContacts 5.0
+
+ContactsSavingTestCase {
+ id: testcase
+ name: "Contacts collection filter test"
+
+ property string defaultCollectionId: ""
+
+ ContactModel {
+ id: model
+ manager: getManagerUnderTest()
+ autoUpdate: true
+ }
+
+ Collection {
+ id: testCollection
+ name: 'My collection filter test'
+ description: 'collection filter test'
+ }
+
+ Contact {
+ id: contact1;
+ Name {
+ firstName: "A"
+ }
+ PhoneNumber {
+ number: "1111111111"
+ }
+ }
+
+ Contact {
+ id: contact2;
+ Name {
+ firstName: "B"
+ }
+ PhoneNumber {
+ number: "2222222222"
+ }
+ }
+
+ Contact {
+ id: contact3;
+ Name {
+ firstName: "John Joe"
+ }
+ PhoneNumber {
+ number: "3333333333"
+ }
+ }
+
+ function createCollectionFilter(ids)
+ {
+ var filter = Qt.createQmlObject(
+ "import QtContacts 5.0;" +
+ "CollectionFilter {}",
+ testcase);
+
+ filter.ids = ids
+ return filter;
+ }
+
+ function initTestCase() {
+ initTestForModel(model);
+ waitUntilContactsChanged();
+ compare(model.collections.length, 1);
+ defaultCollectionId = model.collections[0].collectionId
+ // The wait is needed so the model is populated
+ // (e.g. with garbage left from previous test runs)
+ // before cleanup() is called.
+ emptyContacts(model);
+ model.saveCollection(testCollection)
+ waitForCollectionsChanged();
+ compare(model.collections.length, 2);
+ model.saveContact(contact1);
+ waitForContactsChanged();
+ compare(contact1.collectionId, defaultCollectionId);
+ contact2.collectionId = testCollection.collectionId
+ model.saveContact(contact2);
+ waitForContactsChanged();
+ contact3.collectionId = testCollection.collectionId
+ model.saveContact(contact3);
+ waitForContactsChanged();
+ compare(model.contacts.length, 3);
+ }
+
+ function test_collectionFilter(data) {
+ var filterDefaultCollection = createCollectionFilter([defaultCollectionId]);
+ model.filter = filterDefaultCollection;
+ waitForContactsChanged();
+ compare(model.contacts.length, 1);
+
+ var filterOnlyNewCollection = createCollectionFilter([testCollection.collectionId]);
+ model.filter = filterOnlyNewCollection;
+ waitForContactsChanged();
+ compare(model.contacts.length, 2);
+
+ var filterNewCollectionAndDefaultCollection = createCollectionFilter([defaultCollectionId, testCollection.collectionId])
+ model.filter = filterNewCollectionAndDefaultCollection;
+ waitForContactsChanged();
+ compare(model.contacts.length, 3);
+
+ var filterEmpty = createCollectionFilter([])
+ model.filter = filterEmpty;
+ waitForContactsChanged();
+ compare(model.contacts.length, 0);
+
+ var filterValidAndInvalidIds = createCollectionFilter([defaultCollectionId, "12345678", testCollection.collectionId])
+ model.filter = filterValidAndInvalidIds;
+ waitForContactsChanged();
+ compare(model.contacts.length, 3);
+
+ var filterWithInvalidId = createCollectionFilter(["12345678"])
+ model.filter = filterWithInvalidId;
+ waitForContactsChanged();
+ compare(model.contacts.length, 0);
+ }
+}