1
/****************************************************************************
3
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4
** All rights reserved.
5
** Contact: Nokia Corporation (qt-info@nokia.com)
7
** This file is part of the QtDeclarative module of the Qt Toolkit.
9
** $QT_BEGIN_LICENSE:LGPL$
11
** Licensees holding valid Qt Commercial licenses may use this file in
12
** accordance with the Qt Commercial License Agreement provided with
13
** the Software or, alternatively, in accordance with the terms
14
** contained in a written agreement between you and Nokia.
16
** GNU Lesser General Public License Usage
17
** Alternatively, this file may be used under the terms of the GNU Lesser
18
** General Public License version 2.1 as published by the Free Software
19
** Foundation and appearing in the file LICENSE.LGPL included in the
20
** packaging of this file. Please review the following information to
21
** ensure the GNU Lesser General Public License version 2.1 requirements
22
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24
** In addition, as a special exception, Nokia gives you certain additional
25
** rights. These rights are described in the Nokia Qt LGPL Exception
26
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28
** GNU General Public License Usage
29
** Alternatively, this file may be used under the terms of the GNU
30
** General Public License version 3.0 as published by the Free Software
31
** Foundation and appearing in the file LICENSE.GPL included in the
32
** packaging of this file. Please review the following information to
33
** ensure the GNU General Public License version 3.0 requirements will be
34
** met: http://www.gnu.org/copyleft/gpl.html.
36
** If you are unsure which license is appropriate for your use, please
37
** contact the sales department at qt-sales@nokia.com.
40
****************************************************************************/
41
#include <qcontactdetails.h>
43
#include "qdeclarativecontactmodel_p.h"
44
#include "qcontactmanager.h"
45
#include "qcontactdetailfilter.h"
46
#include "qcontactlocalidfilter.h"
47
#include "qversitreader.h"
48
#include "qversitwriter.h"
49
#include "qversitcontactimporter.h"
50
#include "qversitcontactexporter.h"
58
#include "qcontactrequests.h"
61
\qmlclass ContactModel QDeclarativeContactModel
62
\brief The ContactModel element provides access to contacts from the contacts store.
65
This element is part of the \bold{QtMobility.contacts 1.1} module.
67
ContactModel provides a model of contacts from the contacts store.
68
The contents of the model can be specified with \l filter, \l sortOrders and \l fetchHint properties.
69
Whether the model is automatically updated when the store or \l contacts changes, can be
70
controlled with \l ContactModel::autoUpdate property.
72
There are two ways of accessing the contact data: via model by using views and delegates,
73
or alternatively via \l contacts list property. Of the two, the model access is preferred.
74
Direct list access (i.e. non-model) is not guaranteed to be in order set by \l sortOrder.
76
At the moment the model roles provided by ContactModel are display, decoration and \c contact.
77
Through the \c contact role can access any data provided by the Contact element.
79
\sa RelationshipModel, Contact, {QContactManager}
86
class QDeclarativeContactModelPrivate
89
QDeclarativeContactModelPrivate()
94
m_updatePending(false),
95
m_componentCompleted(false)
98
~QDeclarativeContactModelPrivate()
104
QList<QDeclarativeContact*> m_contacts;
105
QMap<QContactLocalId, QDeclarativeContact*> m_contactMap;
106
QContactManager* m_manager;
107
QDeclarativeContactFetchHint* m_fetchHint;
108
QList<QDeclarativeContactSortOrder*> m_sortOrders;
109
QDeclarativeContactFilter* m_filter;
111
QVersitReader m_reader;
112
QVersitWriter m_writer;
113
QStringList m_importProfiles;
116
bool m_updatePending;
117
bool m_componentCompleted;
120
QDeclarativeContactModel::QDeclarativeContactModel(QObject *parent) :
121
QAbstractListModel(parent),
122
d(new QDeclarativeContactModelPrivate)
124
QHash<int, QByteArray> roleNames;
125
roleNames = QAbstractItemModel::roleNames();
126
roleNames.insert(ContactRole, "contact");
127
setRoleNames(roleNames);
129
connect(this, SIGNAL(managerChanged()), SLOT(fetchAgain()));
130
connect(this, SIGNAL(filterChanged()), SLOT(fetchAgain()));
131
connect(this, SIGNAL(fetchHintChanged()), SLOT(fetchAgain()));
132
connect(this, SIGNAL(sortOrdersChanged()), SLOT(fetchAgain()));
134
d->m_manager = new QContactManager();
136
connect(&d->m_reader, SIGNAL(stateChanged(QVersitReader::State)), this, SLOT(startImport(QVersitReader::State)));
140
\qmlproperty string ContactModel::manager
142
This property holds the manager uri of the contact backend engine.
144
QString QDeclarativeContactModel::manager() const
147
return d->m_manager->managerName();
150
void QDeclarativeContactModel::setManager(const QString& managerName)
156
d->m_manager = new QContactManager(managerName);
158
connect(d->m_manager, SIGNAL(dataChanged()), this, SLOT(fetchAgain()));
159
connect(d->m_manager, SIGNAL(contactsAdded(QList<QContactLocalId>)), this, SLOT(fetchAgain()));
160
connect(d->m_manager, SIGNAL(contactsRemoved(QList<QContactLocalId>)), this, SLOT(contactsRemoved(QList<QContactLocalId>)));
161
connect(d->m_manager, SIGNAL(contactsChanged(QList<QContactLocalId>)), this, SLOT(contactsChanged(QList<QContactLocalId>)));
162
emit managerChanged();
164
void QDeclarativeContactModel::componentComplete()
166
d->m_componentCompleted = true;
168
d->m_manager = new QContactManager();
171
if (d->m_autoUpdate) {
177
\qmlproperty bool ContactModel::autoUpdate
179
This property indicates whether or not the contact model should be updated automatically, default value is true.
181
void QDeclarativeContactModel::setAutoUpdate(bool autoUpdate)
183
if (autoUpdate == d->m_autoUpdate)
185
d->m_autoUpdate = autoUpdate;
186
emit autoUpdateChanged();
189
bool QDeclarativeContactModel::autoUpdate() const
191
return d->m_autoUpdate;
194
void QDeclarativeContactModel::update()
200
\qmlproperty string ContactModel::error
202
This property holds the latest error code returned by the contact manager.
204
This property is read only.
206
QString QDeclarativeContactModel::error() const
208
switch (d->m_manager->error()) {
209
case QContactManager::DoesNotExistError:
210
return QLatin1String("DoesNotExist");
211
case QContactManager::AlreadyExistsError:
212
return QLatin1String("AlreadyExists");
213
case QContactManager::InvalidDetailError:
214
return QLatin1String("InvalidDetail");
215
case QContactManager::InvalidRelationshipError:
216
return QLatin1String("InvalidRelationship");
217
case QContactManager::LockedError:
218
return QLatin1String("LockedError");
219
case QContactManager::DetailAccessError:
220
return QLatin1String("DetailAccessError");
221
case QContactManager::PermissionsError:
222
return QLatin1String("PermissionsError");
223
case QContactManager::OutOfMemoryError:
224
return QLatin1String("OutOfMemory");
225
case QContactManager::NotSupportedError:
226
return QLatin1String("NotSupported");
227
case QContactManager::BadArgumentError:
228
return QLatin1String("BadArgument");
229
case QContactManager::UnspecifiedError:
230
return QLatin1String("UnspecifiedError");
231
case QContactManager::VersionMismatchError:
232
return QLatin1String("VersionMismatch");
233
case QContactManager::LimitReachedError:
234
return QLatin1String("LimitReached");
235
case QContactManager::InvalidContactTypeError:
236
return QLatin1String("InvalidContactType");
240
return QLatin1String("NoError");
245
\qmlproperty list<string> ContactModel::availableManagers
247
This property holds the list of available manager names.
248
This property is read only.
250
QStringList QDeclarativeContactModel::availableManagers() const
252
return QContactManager::availableManagers();
254
static QString urlToLocalFileName(const QUrl& url)
256
if (!url.isValid()) {
257
return url.toString();
258
} else if (url.scheme() == "qrc") {
259
return url.toString().remove(0, 5).prepend(':');
261
return url.toLocalFile();
267
\qmlmethod ContactModel::importContacts(url url, list<string> profiles)
269
Import contacts from a vcard by the given \a url and optional \a profiles.
271
void QDeclarativeContactModel::importContacts(const QUrl& url, const QStringList& profiles)
273
//qWarning() << "importing contacts from:" << url;
274
d->m_importProfiles = profiles;
276
//TODO: need to allow download vcard from network
277
QFile* file = new QFile(urlToLocalFileName(url));
278
bool ok = file->open(QIODevice::ReadOnly);
280
d->m_reader.setDevice(file);
281
d->m_reader.startReading();
286
\qmlmethod ContactModel::exportContacts(url url, list<string> profiles)
288
Export contacts into a vcard file to the given \a url by optional \a profiles.
289
At the moment only the local file url is supported in export method.
291
void QDeclarativeContactModel::exportContacts(const QUrl& url, const QStringList& profiles)
293
//qWarning() << "exporting contacts into:" << url;
295
QString profile = profiles.isEmpty()? QString() : profiles.at(0);
296
//only one profile string supported now
297
QVersitContactExporter exporter(profile);
299
QList<QContact> contacts;
300
foreach (QDeclarativeContact* dc, d->m_contacts) {
301
contacts.append(dc->contact());
304
exporter.exportContacts(contacts, QVersitDocument::VCard30Type);
305
QList<QVersitDocument> documents = exporter.documents();
306
QFile* file = new QFile(urlToLocalFileName(url));
307
bool ok = file->open(QIODevice::ReadWrite);
309
d->m_writer.setDevice(file);
310
d->m_writer.startWriting(documents);
314
void QDeclarativeContactModel::contactsExported(QVersitWriter::State state)
316
if (state == QVersitWriter::FinishedState || state == QVersitWriter::CanceledState) {
317
delete d->m_writer.device();
318
d->m_writer.setDevice(0);
322
int QDeclarativeContactModel::rowCount(const QModelIndex &parent) const
325
return d->m_contacts.count();
331
\qmlproperty Filter ContactModel::filter
333
This property holds the filter instance used by the contact model.
337
QDeclarativeContactFilter* QDeclarativeContactModel::filter() const
342
void QDeclarativeContactModel::setFilter(QDeclarativeContactFilter* filter)
344
d->m_filter = filter;
346
connect(d->m_filter, SIGNAL(valueChanged()), SLOT(fetchAgain()));
347
emit filterChanged();
352
\qmlproperty FetchHint ContactModel::fetchHint
354
This property holds the fetch hint instance used by the contact model.
358
QDeclarativeContactFetchHint* QDeclarativeContactModel::fetchHint() const
360
return d->m_fetchHint;
362
void QDeclarativeContactModel::setFetchHint(QDeclarativeContactFetchHint* fetchHint)
364
if (fetchHint && fetchHint != d->m_fetchHint) {
366
delete d->m_fetchHint;
367
d->m_fetchHint = fetchHint;
368
emit fetchHintChanged();
373
\qmlproperty QDeclarativeListProperty ContactModel::contacts
375
This property holds a list of contacts.
379
QDeclarativeListProperty<QDeclarativeContact> QDeclarativeContactModel::contacts()
381
return QDeclarativeListProperty<QDeclarativeContact>(this, d->m_contacts);
385
\qmlproperty QDeclarativeListProperty ContactModel::sortOrders
387
This property holds a list of sort orders used by the organizer model.
391
QDeclarativeListProperty<QDeclarativeContactSortOrder> QDeclarativeContactModel::sortOrders()
393
return QDeclarativeListProperty<QDeclarativeContactSortOrder>(this, d->m_sortOrders);
396
void QDeclarativeContactModel::startImport(QVersitReader::State state)
398
if (state == QVersitReader::FinishedState || state == QVersitReader::CanceledState) {
399
QVersitContactImporter importer(d->m_importProfiles);
400
importer.importDocuments(d->m_reader.results());
401
QList<QContact> contacts = importer.contacts();
403
delete d->m_reader.device();
404
d->m_reader.setDevice(0);
407
if (d->m_manager->saveContacts(&contacts))
408
qWarning() << "contacts imported.";
415
\qmlmethod ContactModel::fetchContacts(list<int> contactIds)
416
Fetch a list of contacts from the contacts store by given \a contactIds.
418
void QDeclarativeContactModel::fetchContacts(const QList<QContactLocalId>& contactIds)
420
QList<QContactSortOrder> sortOrders;
421
foreach (QDeclarativeContactSortOrder* so, d->m_sortOrders) {
422
sortOrders.append(so->sortOrder());
424
QContactFetchRequest* req = new QContactFetchRequest(this);
425
req->setManager(d->m_manager);
426
req->setSorting(sortOrders);
428
QContactLocalIdFilter filter;
429
filter.setIds(contactIds);
430
req->setFilter(filter);
432
req->setFetchHint(d->m_fetchHint ? d->m_fetchHint->fetchHint() : QContactFetchHint());
434
connect(req,SIGNAL(stateChanged(QContactAbstractRequest::State)), this, SLOT(requestUpdated()));
439
void QDeclarativeContactModel::fetchAgain()
441
d->m_contacts.clear();
442
d->m_contactMap.clear();
444
QList<QContactSortOrder> sortOrders;
445
foreach (QDeclarativeContactSortOrder* so, d->m_sortOrders) {
446
sortOrders.append(so->sortOrder());
448
QContactFetchRequest* req = new QContactFetchRequest(this);
449
req->setManager(d->m_manager);
450
req->setSorting(sortOrders);
452
req->setFilter(d->m_filter? d->m_filter->filter() : QContactFilter());
453
req->setFetchHint(d->m_fetchHint ? d->m_fetchHint->fetchHint() : QContactFetchHint());
455
connect(req,SIGNAL(stateChanged(QContactAbstractRequest::State)), this, SLOT(requestUpdated()));
460
void QDeclarativeContactModel::requestUpdated()
462
QContactFetchRequest* req = qobject_cast<QContactFetchRequest*>(QObject::sender());
463
if (req && req->isFinished()) {
464
QList<QContact> contacts = req->contacts();
466
QList<QDeclarativeContact*> dcs;
467
foreach(QContact c, contacts) {
468
QDeclarativeContact* dc = new QDeclarativeContact(c, d->m_manager->detailDefinitions(c.type()), this);
470
d->m_contactMap.insert(c.localId(), dc);
474
beginInsertRows(QModelIndex(), 0, req->contacts().count());
477
emit contactsChanged();
483
\qmlmethod ContactModel::saveContact(Contact contact)
484
Save the given \a contact into the contacts store. Once saved successfully, the dirty flags of this contact will be reset.
486
\sa Contact::modified
488
void QDeclarativeContactModel::saveContact(QDeclarativeContact* dc)
491
QContact c = dc->contact();
492
QContactSaveRequest* req = new QContactSaveRequest(this);
493
req->setManager(d->m_manager);
496
connect(req,SIGNAL(stateChanged(QContactAbstractRequest::State)), this, SLOT(contactsSaved()));
503
void QDeclarativeContactModel::contactsSaved()
505
QContactSaveRequest* req = qobject_cast<QContactSaveRequest*>(QObject::sender());
506
if (req->isFinished()) {
507
if (req->error() == QContactManager::NoError) {
508
QList<QContact> cs = req->contacts();
509
foreach (const QContact& c, cs) {
510
if (d->m_contactMap.contains(c.localId())) {
511
d->m_contactMap.value(c.localId())->setContact(c);
514
QDeclarativeContact* dc = new QDeclarativeContact(c, d->m_manager->detailDefinitions(c.type()) , this);
515
d->m_contactMap.insert(c.localId(), dc);
516
beginInsertRows(QModelIndex(), d->m_contacts.count(), d->m_contacts.count());
517
d->m_contacts.append(dc);
527
\qmlmethod ContactModel::removeContact(int contactId)
528
Remove the contact from the contacts store by given \a contactId.
530
void QDeclarativeContactModel::removeContact(QContactLocalId id)
532
removeContacts(QList<QContactLocalId>() << id);
536
\qmlmethod ContactModel::removeContacts(list<int> contactIds)
537
Remove the list of contacts from the contacts store by given \a contactIds.
540
void QDeclarativeContactModel::removeContacts(const QList<QContactLocalId>& ids)
542
QContactRemoveRequest* req = new QContactRemoveRequest(this);
543
req->setManager(d->m_manager);
544
req->setContactIds(ids);
546
connect(req,SIGNAL(stateChanged(QContactAbstractRequest::State)), this, SLOT(contactRemoved()));
551
void QDeclarativeContactModel::contactsRemoved(const QList<QContactLocalId>& ids)
553
bool emitSignal = false;
554
foreach (const QContactLocalId& id, ids) {
555
if (d->m_contactMap.contains(id)) {
557
//TODO:need a fast lookup
558
for (; row < d->m_contacts.count(); row++) {
559
if (d->m_contacts.at(row)->contactId() == id)
563
if (row < d->m_contacts.count()) {
564
beginRemoveRows(QModelIndex(), row, row);
565
d->m_contacts.removeAt(row);
566
d->m_contactMap.remove(id);
573
emit contactsChanged();
576
void QDeclarativeContactModel::contactsChanged(const QList<QContactLocalId>& ids)
578
QList<QContactLocalId> updatedIds;
579
foreach (const QContactLocalId& id, ids) {
580
if (d->m_contactMap.contains(id)) {
585
if (updatedIds.count() > 0)
586
fetchContacts(updatedIds);
589
void QDeclarativeContactModel::contactsRemoved()
591
QContactRemoveRequest* req = qobject_cast<QContactRemoveRequest*>(QObject::sender());
594
if (req->isFinished()) {
595
QList<QContactLocalId> ids = req->contactIds();
596
QList<int> errorIds = req->errorMap().keys();
597
QList<QContactLocalId> removedIds;
598
for( int i = 0; i < ids.count(); i++) {
599
if (!errorIds.contains(i))
600
removedIds << ids.at(i);
602
if (!removedIds.isEmpty())
603
contactsRemoved(removedIds);
609
QVariant QDeclarativeContactModel::data(const QModelIndex &index, int role) const
611
QDeclarativeContact* dc = d->m_contacts.value(index.row());
612
QContact c = dc->contact();
615
case Qt::DisplayRole:
616
return c.displayLabel();
617
case Qt::DecorationRole:
619
QContactThumbnail t = c.detail<QContactThumbnail>();
620
if (!t.thumbnail().isNull())
621
return QPixmap::fromImage(t.thumbnail());
625
return QVariant::fromValue(dc);