~chris.gagnon/+junk/qtpim-coverage

« back to all changes in this revision

Viewing changes to .pc/0001-Update-QDeclarativeContact-contactId-field-after-cre.patch/src/imports/contacts/qdeclarativecontactmodel.cpp

  • Committer: chris.gagnon
  • Date: 2013-12-10 23:09:37 UTC
  • Revision ID: chris.gagnon@canonical.com-20131210230937-2akf1ft1edcttk87
first post

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
 
4
** Contact: http://www.qt-project.org/legal
 
5
**
 
6
** This file is part of the QtQml module of the Qt Toolkit.
 
7
**
 
8
** $QT_BEGIN_LICENSE:LGPL$
 
9
** Commercial License Usage
 
10
** Licensees holding valid commercial Qt licenses may use this file in
 
11
** accordance with the commercial license agreement provided with the
 
12
** Software or, alternatively, in accordance with the terms contained in
 
13
** a written agreement between you and Digia.  For licensing terms and
 
14
** conditions see http://qt.digia.com/licensing.  For further information
 
15
** use the contact form at http://qt.digia.com/contact-us.
 
16
**
 
17
** GNU Lesser General Public License Usage
 
18
** Alternatively, this file may be used under the terms of the GNU Lesser
 
19
** General Public License version 2.1 as published by the Free Software
 
20
** Foundation and appearing in the file LICENSE.LGPL included in the
 
21
** packaging of this file.  Please review the following information to
 
22
** ensure the GNU Lesser General Public License version 2.1 requirements
 
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 
24
**
 
25
** In addition, as a special exception, Digia gives you certain additional
 
26
** rights.  These rights are described in the Digia Qt LGPL Exception
 
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 
28
**
 
29
** GNU General Public License Usage
 
30
** Alternatively, this file may be used under the terms of the GNU
 
31
** General Public License version 3.0 as published by the Free Software
 
32
** Foundation and appearing in the file LICENSE.GPL included in the
 
33
** packaging of this file.  Please review the following information to
 
34
** ensure the GNU General Public License version 3.0 requirements will be
 
35
** met: http://www.gnu.org/copyleft/gpl.html.
 
36
**
 
37
**
 
38
** $QT_END_LICENSE$
 
39
**
 
40
****************************************************************************/
 
41
#include <qcontactdetails.h>
 
42
#include <QtQml/qqmlinfo.h>
 
43
 
 
44
#include "qdeclarativecontactmodel_p.h"
 
45
#include "qcontactmanager.h"
 
46
#include "qcontactmanagerengine.h"
 
47
#include "qcontactengineid.h"
 
48
#include "qcontactdetailfilter.h"
 
49
#include "qcontactidfilter.h"
 
50
#include "qcontactintersectionfilter.h"
 
51
#include "qversitreader.h"
 
52
#include "qversitwriter.h"
 
53
#include "qversitcontactimporter.h"
 
54
#include "qversitcontactexporter.h"
 
55
#include <QColor>
 
56
#include <QHash>
 
57
#include <QPixmap>
 
58
#include <QFile>
 
59
#include <QMap>
 
60
#include <QUrl>
 
61
 
 
62
#include "qcontactrequests.h"
 
63
 
 
64
/*!
 
65
    \qmltype ContactModel
 
66
    \instantiates QDeclarativeContactModel
 
67
    \brief The ContactModel element provides access to contacts from the contacts store.
 
68
    \ingroup qml-contacts-main
 
69
    \inqmlmodule QtContacts 5.0
 
70
 
 
71
    This element is part of the \b{QtContacts} module.
 
72
 
 
73
    ContactModel provides a model of contacts from the contacts store.
 
74
    The contents of the model can be specified with \l filter, \l sortOrders and \l fetchHint properties.
 
75
    Whether the model is automatically updated when the store or \l contacts changes, can be
 
76
    controlled with \l ContactModel::autoUpdate property.
 
77
 
 
78
    There are two ways of accessing the contact data: via model by using views and delegates,
 
79
    or alternatively via \l contacts list property. Of the two, the model access is preferred.
 
80
    Direct list access (i.e. non-model) is not guaranteed to be in order set by \l sortOrder.
 
81
 
 
82
    At the moment the model roles provided by ContactModel are display, decoration and \c contact.
 
83
    Through the \c contact role can access any data provided by the Contact element.
 
84
 
 
85
    \sa RelationshipModel, Contact, {QContactManager}
 
86
*/
 
87
 
 
88
QT_BEGIN_NAMESPACE_CONTACTS
 
89
 
 
90
class QDeclarativeContactModelPrivate
 
91
{
 
92
public:
 
93
    QDeclarativeContactModelPrivate()
 
94
        :m_manager(0),
 
95
        m_storageLocations(QContactAbstractRequest::UserDataStorage),
 
96
        m_fetchHint(0),
 
97
        m_filter(0),
 
98
        m_error(QContactManager::NoError),
 
99
        m_autoUpdate(true),
 
100
        m_componentCompleted(false),
 
101
        m_progressiveLoading(true)
 
102
    {
 
103
    }
 
104
    ~QDeclarativeContactModelPrivate()
 
105
    {
 
106
        if (m_manager)
 
107
            delete m_manager;
 
108
    }
 
109
 
 
110
    QList<QDeclarativeContact*> m_contacts;
 
111
    QMap<QContactId, QDeclarativeContact*> m_contactMap;
 
112
    QContactManager* m_manager;
 
113
    QContactAbstractRequest::StorageLocations m_storageLocations;
 
114
    QDeclarativeContactFetchHint* m_fetchHint;
 
115
    QList<QDeclarativeContactSortOrder*> m_sortOrders;
 
116
    QDeclarativeContactFilter* m_filter;
 
117
 
 
118
    QVersitReader m_reader;
 
119
    QVersitWriter m_writer;
 
120
    QStringList m_importProfiles;
 
121
 
 
122
    QContactManager::Error m_error;
 
123
 
 
124
    bool m_autoUpdate;
 
125
    bool m_componentCompleted;
 
126
    QUrl m_lastExportUrl;
 
127
    QUrl m_lastImportUrl;
 
128
    QAtomicInt m_lastRequestId;
 
129
    QHash<QContactAbstractRequest *, int> m_requestIdHash;
 
130
    QList<QContactFetchRequest*> m_pendingRequests;
 
131
    QList<QContact> m_pendingContacts;
 
132
    bool m_progressiveLoading;
 
133
};
 
134
 
 
135
QDeclarativeContactModel::QDeclarativeContactModel(QObject *parent) :
 
136
    QAbstractListModel(parent),
 
137
    d(new QDeclarativeContactModelPrivate)
 
138
{
 
139
    QHash<int, QByteArray> roleNames;
 
140
    roleNames = QAbstractItemModel::roleNames();
 
141
    roleNames.insert(ContactRole, "contact");
 
142
    setRoleNames(roleNames);
 
143
 
 
144
    connect(this, SIGNAL(managerChanged()), SLOT(doUpdate()));
 
145
    connect(this, SIGNAL(storageLocationsChanged()), SLOT(doUpdate()));
 
146
    connect(this, SIGNAL(filterChanged()), SLOT(doUpdate()));
 
147
    connect(this, SIGNAL(fetchHintChanged()), SLOT(doUpdate()));
 
148
    connect(this, SIGNAL(sortOrdersChanged()), SLOT(doUpdate()));
 
149
    
 
150
    //import vcard
 
151
    connect(&d->m_reader, SIGNAL(stateChanged(QVersitReader::State)), this, SLOT(startImport(QVersitReader::State)));
 
152
    connect(&d->m_writer, SIGNAL(stateChanged(QVersitWriter::State)), this, SLOT(contactsExported(QVersitWriter::State)));
 
153
}
 
154
 
 
155
/*!
 
156
  \qmlproperty string ContactModel::manager
 
157
 
 
158
  This property holds the manager uri of the contact backend engine.
 
159
  */
 
160
QString QDeclarativeContactModel::manager() const
 
161
{
 
162
    if (d->m_manager)
 
163
        return d->m_manager->managerName();
 
164
    return QString();
 
165
}
 
166
void QDeclarativeContactModel::setManager(const QString& managerName)
 
167
{
 
168
    if (d->m_manager)
 
169
        delete d->m_manager;
 
170
    d->m_manager = new QContactManager(managerName);
 
171
 
 
172
    connect(d->m_manager, SIGNAL(dataChanged()), this, SLOT(update()));
 
173
    connect(d->m_manager, SIGNAL(contactsAdded(QList<QContactId>)), this, SLOT(onContactsAdded(QList<QContactId>)));
 
174
    connect(d->m_manager, SIGNAL(contactsRemoved(QList<QContactId>)), this, SLOT(onContactsRemoved(QList<QContactId>)));
 
175
    connect(d->m_manager, SIGNAL(contactsChanged(QList<QContactId>)), this, SLOT(onContactsChanged(QList<QContactId>)));
 
176
 
 
177
    if (d->m_error != QContactManager::NoError) {
 
178
        d->m_error = QContactManager::NoError;
 
179
        emit errorChanged();
 
180
    }
 
181
 
 
182
    emit managerChanged();
 
183
}
 
184
 
 
185
/*!
 
186
  \qmlproperty enumeration ContactModel::StorageLocation
 
187
 
 
188
  Defines the different storage locations for saving contacts and model population purposes.
 
189
 
 
190
  \list
 
191
  \li ContactModel::UserDataStorage        A storage location where user data is stored.
 
192
  \li ContactModel::SystemStorage          A storage location where system files are stored.
 
193
  \endlist
 
194
 
 
195
  Depending on the backend implementation, the access rights for different storage locations might vary.
 
196
 
 
197
  \sa ContactModel::storageLocations
 
198
  \sa ContactModel::saveContact
 
199
*/
 
200
 
 
201
/*!
 
202
  \qmlsignal ContactModel::storageLocationsChanged()
 
203
 
 
204
  This signal is emitted, when \l ContactModel::storageLocations property changes.
 
205
 
 
206
  \sa ContactModel::storageLocations
 
207
 */
 
208
 
 
209
/*!
 
210
  \qmlproperty int ContactModel::storageLocations
 
211
 
 
212
  This property indicates which storage location is used to populate the model.
 
213
 
 
214
  Only one storage location can be used for each model.
 
215
 
 
216
  Storage location is a backend specific feature. Some backends support it and some might just ignore it. If backend
 
217
  is having some specific requirements and they're not met, backend returns StorageLocationsNotExistingError.
 
218
 
 
219
  \sa ContactModel::StorageLocation
 
220
  \sa ContactModel::saveContact
 
221
*/
 
222
int QDeclarativeContactModel::storageLocations() const
 
223
{
 
224
    return d->m_storageLocations;
 
225
}
 
226
 
 
227
void QDeclarativeContactModel::setStorageLocations(int storageLocations)
 
228
{
 
229
    QContactAbstractRequest::StorageLocations newStorageLocation = 0;
 
230
    // only one storage location for a model is supported
 
231
    switch (storageLocations) {
 
232
    case UserDataStorage:
 
233
        newStorageLocation = QContactAbstractRequest::UserDataStorage;
 
234
        break;
 
235
    case SystemStorage:
 
236
        newStorageLocation = QContactAbstractRequest::SystemStorage;
 
237
        break;
 
238
    case (UserDataStorage | SystemStorage):
 
239
        qWarning() << Q_FUNC_INFO << "Model does not support multiple storage locations";
 
240
        updateError(QContactManager::NotSupportedError);
 
241
        return;
 
242
    default:
 
243
        qWarning() << Q_FUNC_INFO << "Unknown storage location";
 
244
        updateError(QContactManager::BadArgumentError);
 
245
        return;
 
246
    }
 
247
    if (d->m_storageLocations != newStorageLocation) {
 
248
        d->m_storageLocations = newStorageLocation;
 
249
        emit storageLocationsChanged();
 
250
    }
 
251
}
 
252
 
 
253
void QDeclarativeContactModel::componentComplete()
 
254
{
 
255
    if (!d->m_manager)
 
256
        setManager(QString());
 
257
 
 
258
    d->m_componentCompleted = true;
 
259
 
 
260
    if (d->m_autoUpdate)
 
261
        update();
 
262
}
 
263
/*!
 
264
  \qmlproperty bool ContactModel::autoUpdate
 
265
 
 
266
  This property indicates whether or not the contact model should be updated automatically, default value is true.
 
267
  */
 
268
void QDeclarativeContactModel::setAutoUpdate(bool autoUpdate)
 
269
{
 
270
    if (autoUpdate == d->m_autoUpdate)
 
271
        return;
 
272
    d->m_autoUpdate = autoUpdate;
 
273
    emit autoUpdateChanged();
 
274
}
 
275
 
 
276
bool QDeclarativeContactModel::autoUpdate() const
 
277
{
 
278
    return d->m_autoUpdate;
 
279
}
 
280
 
 
281
void QDeclarativeContactModel::update()
 
282
{
 
283
    if (!d->m_componentCompleted)
 
284
        return;
 
285
    QMetaObject::invokeMethod(this, "fetchAgain", Qt::QueuedConnection);
 
286
}
 
287
 
 
288
void QDeclarativeContactModel::doUpdate()
 
289
{
 
290
    if (d->m_autoUpdate)
 
291
        update();
 
292
}
 
293
 
 
294
/*!
 
295
  \qmlproperty string ContactModel::error
 
296
 
 
297
  This property holds the latest error code returned by the contact manager.
 
298
 
 
299
  This property is read only.
 
300
  */
 
301
QString QDeclarativeContactModel::error() const
 
302
{
 
303
    if (d->m_manager) {
 
304
        switch (d->m_error) {
 
305
        case QContactManager::DoesNotExistError:
 
306
            return QStringLiteral("DoesNotExist");
 
307
        case QContactManager::AlreadyExistsError:
 
308
            return QStringLiteral("AlreadyExists");
 
309
        case QContactManager::InvalidDetailError:
 
310
            return QStringLiteral("InvalidDetail");
 
311
        case QContactManager::InvalidRelationshipError:
 
312
            return QStringLiteral("InvalidRelationship");
 
313
        case QContactManager::LockedError:
 
314
            return QStringLiteral("LockedError");
 
315
        case QContactManager::DetailAccessError:
 
316
            return QStringLiteral("DetailAccessError");
 
317
        case QContactManager::PermissionsError:
 
318
            return QStringLiteral("PermissionsError");
 
319
        case QContactManager::OutOfMemoryError:
 
320
            return QStringLiteral("OutOfMemory");
 
321
        case QContactManager::NotSupportedError:
 
322
            return QStringLiteral("NotSupported");
 
323
        case QContactManager::BadArgumentError:
 
324
            return QStringLiteral("BadArgument");
 
325
        case QContactManager::UnspecifiedError:
 
326
            return QStringLiteral("UnspecifiedError");
 
327
        case QContactManager::VersionMismatchError:
 
328
            return QStringLiteral("VersionMismatch");
 
329
        case QContactManager::LimitReachedError:
 
330
            return QStringLiteral("LimitReached");
 
331
        case QContactManager::InvalidContactTypeError:
 
332
            return QStringLiteral("InvalidContactType");
 
333
        default:
 
334
            break;
 
335
        }
 
336
    }
 
337
    return QStringLiteral("NoError");
 
338
}
 
339
 
 
340
 
 
341
/*!
 
342
  \qmlproperty list<string> ContactModel::availableManagers
 
343
 
 
344
  This property holds the list of available manager names.
 
345
  This property is read only.
 
346
  */
 
347
QStringList QDeclarativeContactModel::availableManagers() const
 
348
{
 
349
    return QContactManager::availableManagers();
 
350
}
 
351
static QString urlToLocalFileName(const QUrl& url)
 
352
{
 
353
   if (!url.isValid()) {
 
354
      return url.toString();
 
355
   } else if (url.scheme() == "qrc") {
 
356
      return url.toString().remove(0, 5).prepend(':');
 
357
   } else {
 
358
      return url.toLocalFile();
 
359
   }
 
360
 
 
361
}
 
362
 
 
363
/*!
 
364
  \qmlmethod void ContactModel::importContacts(url url, list<string> profiles)
 
365
 
 
366
  Import contacts from a vcard by the given \a url and optional \a profiles.
 
367
  Only one import operation can be active at a time.
 
368
  Supported profiles are:
 
369
  \list
 
370
  \li "Sync"  Imports contacts in sync mode, currently, this is the same as passing in an empty list, and is generally what you want.
 
371
  \li "Backup" imports contacts in backup mode, use this mode if the vCard was generated by exporting in backup mode.
 
372
 
 
373
  \endlist
 
374
 
 
375
  \sa QVersitContactHandlerFactory
 
376
  \sa QVersitContactHandlerFactory::ProfileSync()
 
377
  \sa QVersitContactHandlerFactory::ProfileBackup()
 
378
 
 
379
  */
 
380
void QDeclarativeContactModel::importContacts(const QUrl& url, const QStringList& profiles)
 
381
{
 
382
    // Reader is capable of handling only one request at the time.
 
383
    ImportError importError = ImportNotReadyError;
 
384
    if (d->m_reader.state() != QVersitReader::ActiveState) {
 
385
 
 
386
        d->m_importProfiles = profiles;
 
387
 
 
388
        //TODO: need to allow download vcard from network
 
389
        QFile*  file = new QFile(urlToLocalFileName(url));
 
390
        bool ok = file->open(QIODevice::ReadOnly);
 
391
        if (ok) {
 
392
            d->m_reader.setDevice(file);
 
393
            if (d->m_reader.startReading()) {
 
394
                d->m_lastImportUrl = url;
 
395
                return;
 
396
            }
 
397
            importError = QDeclarativeContactModel::ImportError(d->m_reader.error());
 
398
        } else {
 
399
            importError = ImportIOError;
 
400
        }
 
401
    }
 
402
    emit importCompleted(importError, url);
 
403
}
 
404
 
 
405
/*!
 
406
  \qmlmethod void ContactModel::exportContacts(url url, list<string> profiles, list<variant> declarativeContacts)
 
407
 
 
408
  Export all contacts of this model into a vcard file to the given \a url by optional \a profiles.
 
409
  The optional \a declarativeContacts list can be used to export an arbitrary list of QDeclarativeContact objects
 
410
  not necessarily belonging to the data set of this model.
 
411
  At the moment only the local file url is supported in export method.
 
412
  Also, only one export operation can be active at a time.
 
413
  Supported profiles are:
 
414
  \list
 
415
  \li "Sync"  exports contacts in sync mode, currently, this is the same as passing in an empty list, and is generally what you want.
 
416
  \li "Backup" exports contacts in backup mode, this will add non-standard properties to the generated vCard
 
417
              to try to save every detail of the contacts. Only use this if the vCard is going to be imported using the backup profile.
 
418
#include "moc_qdeclarativecontactmodel_p.cpp"
 
419
  \endlist
 
420
 
 
421
  \sa QVersitContactHandlerFactory
 
422
  \sa QVersitContactHandlerFactory::ProfileSync()
 
423
  \sa QVersitContactHandlerFactory::ProfileBackup()
 
424
  */
 
425
void QDeclarativeContactModel::exportContacts(const QUrl& url, const QStringList& profiles, const QVariantList &declarativeContacts)
 
426
{
 
427
    // Writer is capable of handling only one request at the time.
 
428
    ExportError exportError = ExportNotReadyError;
 
429
    if (d->m_writer.state() != QVersitWriter::ActiveState) {
 
430
        QString profile = profiles.isEmpty()? QString() : profiles.at(0);
 
431
        //only one profile string supported now.
 
432
        QVersitContactExporter exporter(profile);
 
433
 
 
434
        QList<QContact> contacts;
 
435
        if (declarativeContacts.isEmpty()) {
 
436
            foreach (QDeclarativeContact* dc, d->m_contacts) {
 
437
                contacts.append(dc->contact());
 
438
            }
 
439
 
 
440
        } else {
 
441
            foreach (const QVariant &contactVariant, declarativeContacts) {
 
442
                QObject *rawObject = contactVariant.value<QObject*>();
 
443
                QDeclarativeContact *dc = qobject_cast<QDeclarativeContact*>(rawObject);
 
444
                if (dc) {
 
445
                    contacts.append(dc->contact());
 
446
                }
 
447
            }
 
448
        }
 
449
 
 
450
        exporter.exportContacts(contacts, QVersitDocument::VCard30Type);
 
451
        QList<QVersitDocument> documents = exporter.documents();
 
452
        QFile* file = new QFile(urlToLocalFileName(url));
 
453
        bool ok = file->open(QIODevice::WriteOnly);
 
454
        if (ok) {
 
455
            d->m_writer.setDevice(file);
 
456
            if (d->m_writer.startWriting(documents)) {
 
457
                d->m_lastExportUrl = url;
 
458
                return;
 
459
            }
 
460
            exportError = QDeclarativeContactModel::ExportError(d->m_writer.error());
 
461
        } else {
 
462
            exportError = ExportIOError;
 
463
        }
 
464
    }
 
465
    emit exportCompleted(exportError, url);
 
466
}
 
467
 
 
468
void QDeclarativeContactModel::contactsExported(QVersitWriter::State state)
 
469
{
 
470
    if (state == QVersitWriter::FinishedState || state == QVersitWriter::CanceledState) {
 
471
         delete d->m_writer.device();
 
472
         d->m_writer.setDevice(0);
 
473
         emit exportCompleted(QDeclarativeContactModel::ExportError(d->m_writer.error()), d->m_lastExportUrl);
 
474
    }
 
475
}
 
476
 
 
477
int QDeclarativeContactModel::rowCount(const QModelIndex &parent) const
 
478
{
 
479
    Q_UNUSED(parent);
 
480
    return d->m_contacts.count();
 
481
}
 
482
 
 
483
 
 
484
 
 
485
/*!
 
486
  \qmlproperty Filter ContactModel::filter
 
487
 
 
488
  This property holds the filter instance used by the contact model.
 
489
 
 
490
  \sa Filter
 
491
  */
 
492
QDeclarativeContactFilter* QDeclarativeContactModel::filter() const
 
493
{
 
494
    return d->m_filter;
 
495
}
 
496
 
 
497
void QDeclarativeContactModel::setFilter(QDeclarativeContactFilter* filter)
 
498
{
 
499
    if (d->m_filter != filter) {
 
500
        if (d->m_filter) {
 
501
            disconnect(d->m_filter, SIGNAL(filterChanged()), this, SLOT(update()));
 
502
        }
 
503
        d->m_filter = filter;
 
504
        if (d->m_filter) {
 
505
            connect(d->m_filter, SIGNAL(filterChanged()), SLOT(update()), Qt::UniqueConnection);
 
506
        }
 
507
        emit filterChanged();
 
508
    }
 
509
}
 
510
 
 
511
/*!
 
512
  \qmlproperty FetchHint ContactModel::fetchHint
 
513
 
 
514
  This property holds the fetch hint instance used by the contact model.
 
515
 
 
516
  \sa FetchHint
 
517
  */
 
518
QDeclarativeContactFetchHint* QDeclarativeContactModel::fetchHint() const
 
519
{
 
520
    return d->m_fetchHint;
 
521
}
 
522
void QDeclarativeContactModel::setFetchHint(QDeclarativeContactFetchHint* fetchHint)
 
523
{
 
524
    if (fetchHint && fetchHint != d->m_fetchHint) {
 
525
        if (d->m_fetchHint)
 
526
            delete d->m_fetchHint;
 
527
        d->m_fetchHint = fetchHint;
 
528
        emit fetchHintChanged();
 
529
    }
 
530
}
 
531
 
 
532
/*!
 
533
  \qmlproperty list<Contact> ContactModel::contacts
 
534
 
 
535
  This property holds the list of contacts.
 
536
 
 
537
  \sa Contact
 
538
  */
 
539
QQmlListProperty<QDeclarativeContact> QDeclarativeContactModel::contacts()
 
540
{
 
541
    return QQmlListProperty<QDeclarativeContact>(this,
 
542
                                                         0,
 
543
                                                         contacts_append,
 
544
                                                         contacts_count,
 
545
                                                         contacts_at,
 
546
                                                         contacts_clear);
 
547
}
 
548
 
 
549
 
 
550
 
 
551
void QDeclarativeContactModel::contacts_append(QQmlListProperty<QDeclarativeContact>* prop, QDeclarativeContact* contact)
 
552
{
 
553
    Q_UNUSED(prop);
 
554
    Q_UNUSED(contact);
 
555
    qWarning() << Q_FUNC_INFO << "appending contacts is not currently supported";
 
556
}
 
557
 
 
558
int QDeclarativeContactModel::contacts_count(QQmlListProperty<QDeclarativeContact>* prop)
 
559
{
 
560
    return static_cast<QDeclarativeContactModel*>(prop->object)->d->m_contacts.count();
 
561
}
 
562
 
 
563
QDeclarativeContact* QDeclarativeContactModel::contacts_at(QQmlListProperty<QDeclarativeContact>* prop, int index)
 
564
{
 
565
    return static_cast<QDeclarativeContactModel*>(prop->object)->d->m_contacts.at(index);
 
566
}
 
567
 
 
568
void QDeclarativeContactModel::contacts_clear(QQmlListProperty<QDeclarativeContact>* prop)
 
569
{
 
570
    QDeclarativeContactModel* model = static_cast<QDeclarativeContactModel*>(prop->object);
 
571
    model->clearContacts();
 
572
    emit model->contactsChanged();
 
573
}
 
574
 
 
575
 
 
576
/*!
 
577
  \qmlproperty list<SortOrder> ContactModel::sortOrders
 
578
 
 
579
  This property holds a list of sort orders used by the contacts model.
 
580
  \sa SortOrder
 
581
  */
 
582
QQmlListProperty<QDeclarativeContactSortOrder> QDeclarativeContactModel::sortOrders()
 
583
{
 
584
    return QQmlListProperty<QDeclarativeContactSortOrder>(this,
 
585
                                                                  0,
 
586
                                                                  sortOrder_append,
 
587
                                                                  sortOrder_count,
 
588
                                                                  sortOrder_at,
 
589
                                                                  sortOrder_clear);
 
590
}
 
591
 
 
592
void QDeclarativeContactModel::startImport(QVersitReader::State state)
 
593
{
 
594
    if (state == QVersitReader::FinishedState || state == QVersitReader::CanceledState) {
 
595
        QVersitContactImporter importer(d->m_importProfiles);
 
596
        importer.importDocuments(d->m_reader.results());
 
597
        QList<QContact> contacts = importer.contacts();
 
598
 
 
599
        delete d->m_reader.device();
 
600
        d->m_reader.setDevice(0);
 
601
 
 
602
        if (d->m_manager) {
 
603
            if (!d->m_manager->saveContacts(&contacts)) {
 
604
                if (d->m_error != d->m_manager->error()) {
 
605
                    d->m_error = d->m_manager->error();
 
606
                    emit errorChanged();
 
607
                }
 
608
            }
 
609
        }
 
610
        emit importCompleted(QDeclarativeContactModel::ImportError(d->m_reader.error()), d->m_lastImportUrl);
 
611
    }
 
612
}
 
613
 
 
614
/*!
 
615
  \qmlsignal ContactModel::contactsFetched(int requestId, list<Contact> fetchedContacts)
 
616
 
 
617
  This signal is emitted, when a contact fetch request is finished.
 
618
 
 
619
  \sa ContactModel::fetchContacts
 
620
 */
 
621
 
 
622
/*!
 
623
    \qmlmethod int ContactModel::fetchContacts(list<string> contactIds)
 
624
 
 
625
    Starts a request to fetch contacts by the given \a contactIds, and returns the unique ID of this request.
 
626
    -1 is returned if the request can't be started.
 
627
 
 
628
    Note that the contacts fetched won't be added to the model, but can be accessed through the contactsFetched
 
629
    signal handler.
 
630
 
 
631
    \sa ContactModel::contactsFetched
 
632
  */
 
633
int QDeclarativeContactModel::fetchContacts(const QStringList &contactIds)
 
634
{
 
635
    if (contactIds.isEmpty())
 
636
        return -1;
 
637
 
 
638
    QContactFetchByIdRequest *fetchRequest = new QContactFetchByIdRequest(this);
 
639
    connect(fetchRequest, SIGNAL(stateChanged(QContactAbstractRequest::State)),
 
640
            this, SLOT(onFetchContactsRequestStateChanged(QContactAbstractRequest::State)));
 
641
    fetchRequest->setManager(d->m_manager);
 
642
 
 
643
    QList<QContactId> ids;
 
644
    foreach (const QString &contactId, contactIds)
 
645
        ids.append(QContactId::fromString(contactId));
 
646
    fetchRequest->setIds(ids);
 
647
    int requestId = d->m_lastRequestId.fetchAndAddOrdered(1);
 
648
    d->m_requestIdHash.insert(fetchRequest, requestId);
 
649
    if (fetchRequest->start()) {
 
650
        return requestId;
 
651
    } else {
 
652
        d->m_requestIdHash.remove(fetchRequest);
 
653
        return -1;
 
654
    }
 
655
}
 
656
 
 
657
/*!
 
658
    \internal
 
659
 */
 
660
void QDeclarativeContactModel::onFetchContactsRequestStateChanged(QContactAbstractRequest::State state)
 
661
{
 
662
    if (state != QContactAbstractRequest::FinishedState || !sender())
 
663
        return;
 
664
 
 
665
    QContactFetchByIdRequest *request = qobject_cast<QContactFetchByIdRequest *>(sender());
 
666
    if (!request)
 
667
        return;
 
668
 
 
669
    checkError(request);
 
670
 
 
671
    const int requestId = d->m_requestIdHash.value(request, -1);
 
672
    if (requestId == -1)
 
673
        qWarning() << Q_FUNC_INFO << "transaction not found from the request hash";
 
674
    else
 
675
        d->m_requestIdHash.remove(request);
 
676
    QVariantList list;
 
677
    if (request->error() == QContactManager::NoError) {
 
678
        QList<QContact> contacts(request->contacts());
 
679
        foreach (const QContact &contact, contacts) {
 
680
            QDeclarativeContact *declarativeContact(0);
 
681
            declarativeContact = new QDeclarativeContact(this);
 
682
            declarativeContact->setContact(contact);
 
683
            list.append(QVariant::fromValue(declarativeContact));
 
684
        }
 
685
    }
 
686
    emit contactsFetched(requestId, list);
 
687
    request->deleteLater();
 
688
}
 
689
 
 
690
void QDeclarativeContactModel::clearContacts()
 
691
{
 
692
    qDeleteAll(d->m_contacts);
 
693
    d->m_contacts.clear();
 
694
    d->m_contactMap.clear();
 
695
}
 
696
 
 
697
void QDeclarativeContactModel::fetchAgain()
 
698
{
 
699
    QList<QContactSortOrder> sortOrders;
 
700
    foreach (QDeclarativeContactSortOrder* so, d->m_sortOrders) {
 
701
        sortOrders.append(so->sortOrder());
 
702
    }
 
703
    QContactFetchRequest* fetchRequest = new QContactFetchRequest(this);
 
704
 
 
705
    fetchRequest->setStorageLocations(d->m_storageLocations);
 
706
 
 
707
    fetchRequest->setManager(d->m_manager);
 
708
    fetchRequest->setSorting(sortOrders);
 
709
 
 
710
    if (d->m_filter){
 
711
        fetchRequest->setFilter(d->m_filter->filter());
 
712
    } else {
 
713
        fetchRequest->setFilter(QContactFilter());
 
714
    }
 
715
 
 
716
    fetchRequest->setFetchHint(d->m_fetchHint ? d->m_fetchHint->fetchHint() : QContactFetchHint());
 
717
 
 
718
    connect(fetchRequest, SIGNAL(resultsAvailable()), this, SLOT(requestUpdated()));
 
719
    connect(fetchRequest, SIGNAL(stateChanged(QContactAbstractRequest::State)),
 
720
            this, SLOT(fetchRequestStateChanged(QContactAbstractRequest::State)));
 
721
 
 
722
    // cancel all previous requests
 
723
    foreach (QContactFetchRequest *req, d->m_pendingRequests) {
 
724
        req->cancel();
 
725
        req->deleteLater();
 
726
    }
 
727
 
 
728
    d->m_pendingContacts.clear();
 
729
    d->m_pendingRequests.clear();
 
730
    d->m_pendingRequests.append(fetchRequest);
 
731
 
 
732
    // if we have no contacts yet, we can display results as soon as they arrive
 
733
    // but if we are updating the model after a sort or filter change, we have to
 
734
    // wait for all contacts before processing the update
 
735
    d->m_progressiveLoading = d->m_contacts.isEmpty();
 
736
 
 
737
    fetchRequest->start();
 
738
}
 
739
 
 
740
void QDeclarativeContactModel::requestUpdated()
 
741
{
 
742
 
 
743
    QContactFetchRequest* req = qobject_cast<QContactFetchRequest*>(QObject::sender());
 
744
    if (req) {
 
745
        QList<QContact> contacts = req->contacts();
 
746
 
 
747
        // if we are starting from scratch, we can show contact results as they arrive
 
748
        if (d->m_progressiveLoading) {
 
749
            QList<QDeclarativeContact*> dcs;
 
750
            foreach (const QContact &c, contacts) {
 
751
                if (d->m_contactMap.contains(c.id())) {
 
752
                    QDeclarativeContact* dc = d->m_contactMap.value(c.id());
 
753
                    dc->setContact(c);
 
754
                } else {
 
755
                    QDeclarativeContact* dc = new QDeclarativeContact(this);
 
756
                    if (dc) {
 
757
                        d->m_contactMap.insert(c.id(), dc);
 
758
                        dc->setContact(c);
 
759
                        dcs.append(dc);
 
760
                    }
 
761
                }
 
762
            }
 
763
 
 
764
            if (dcs.count() > 0) {
 
765
                beginInsertRows(QModelIndex(), d->m_contacts.count(), d->m_contacts.count() + dcs.count() - 1);
 
766
                // At this point we need to relay on the backend and assume that the partial results are following the fetch sorting property
 
767
                d->m_contacts += dcs;
 
768
                endInsertRows();
 
769
 
 
770
                emit contactsChanged();
 
771
            }
 
772
        } else {
 
773
            d->m_pendingContacts << contacts;
 
774
        }
 
775
 
 
776
        checkError(req);
 
777
    }
 
778
}
 
779
 
 
780
void QDeclarativeContactModel::fetchRequestStateChanged(QContactAbstractRequest::State newState)
 
781
{
 
782
    if (newState != QContactAbstractRequest::FinishedState)
 
783
        return;
 
784
 
 
785
    QContactFetchRequest* req = qobject_cast<QContactFetchRequest*>(QObject::sender());
 
786
    if (req) {
 
787
        // if we were not processing contacts as soon as they arrive, we need to process them here.
 
788
        if (!d->m_progressiveLoading) {
 
789
            // start by removing the contacts that don't belong to this result set anymore
 
790
            for (int i = d->m_contacts.count()-1; i >= 0; --i) {
 
791
                QDeclarativeContact *contact = d->m_contacts[i];
 
792
                if (!d->m_pendingContacts.contains(contact->contact())) {
 
793
                    beginRemoveRows(QModelIndex(), i, i);
 
794
                    d->m_contacts.removeAt(i);
 
795
                    d->m_contactMap.remove(contact->contact().id());
 
796
                    endRemoveRows();
 
797
                }
 
798
            }
 
799
 
 
800
            // now insert new contacts and move existing ones to their final positions
 
801
            int count = d->m_pendingContacts.count();
 
802
            for (int i = 0; i < count; ++i) {
 
803
                QContact c = d->m_pendingContacts[i];
 
804
                if (!d->m_contactMap.contains(c.id())) {
 
805
                    QDeclarativeContact* dc = new QDeclarativeContact(this);
 
806
                    dc->setContact(c);
 
807
                    beginInsertRows(QModelIndex(), i, i);
 
808
                    d->m_contacts.insert(i, dc);
 
809
                    d->m_contactMap.insert(c.id(),dc);
 
810
                    endInsertRows();
 
811
                } else {
 
812
                    QDeclarativeContact *contact = d->m_contactMap[c.id()];
 
813
 
 
814
                    int pos = d->m_contacts.indexOf(contact);
 
815
                    if (pos != i) {
 
816
                        beginMoveRows(QModelIndex(), pos, pos, QModelIndex(), i);
 
817
                        d->m_contacts.move(pos, i);
 
818
                        endMoveRows();
 
819
                    }
 
820
                }
 
821
            }
 
822
            emit contactsChanged();
 
823
        }
 
824
 
 
825
        // and now clear the pending contact list as the model is up-to-date
 
826
        d->m_pendingContacts.clear();
 
827
        d->m_pendingRequests.removeOne(req);
 
828
        req->deleteLater();
 
829
    }
 
830
}
 
831
 
 
832
/*!
 
833
  \qmlmethod ContactModel::saveContact(Contact contact, StorageLocation storageLocation = UserDataStorage)
 
834
 
 
835
  Save the given \a contact into the contacts backend.
 
836
 
 
837
  The location for storing the contact can be defined with \a storageLocation for new contacts.
 
838
  When the contact is updated, ie saved again, \a storageLocation is ignored and the contact
 
839
  is saved to the same location as it were before.
 
840
 
 
841
  Once saved successfully, the dirty flags of this contact will be reset.
 
842
 
 
843
  \sa Contact::modified
 
844
  */
 
845
void QDeclarativeContactModel::saveContact(QDeclarativeContact* dc, StorageLocation storageLocation)
 
846
{
 
847
    if (dc) {
 
848
        QContactSaveRequest* req = new QContactSaveRequest(this);
 
849
        req->setManager(d->m_manager);
 
850
        req->setContact(dc->contact());
 
851
        req->setStorageLocation(QContactAbstractRequest::StorageLocation(storageLocation));
 
852
        connect(req,SIGNAL(stateChanged(QContactAbstractRequest::State)), this, SLOT(onRequestStateChanged(QContactAbstractRequest::State)));
 
853
        req->start();
 
854
    }
 
855
}
 
856
 
 
857
void QDeclarativeContactModel::onRequestStateChanged(QContactAbstractRequest::State newState)
 
858
{
 
859
    if (newState != QContactAbstractRequest::FinishedState) {
 
860
        return;
 
861
    }
 
862
    if (!sender()) {
 
863
        qWarning() << Q_FUNC_INFO << "Called without a sender.";
 
864
        return;
 
865
    }
 
866
 
 
867
    QContactAbstractRequest *request = qobject_cast<QContactAbstractRequest *>(sender());
 
868
    if (!request)
 
869
        return;
 
870
    checkError(request);
 
871
    request->deleteLater();
 
872
}
 
873
 
 
874
void QDeclarativeContactModel::checkError(const QContactAbstractRequest *request)
 
875
{
 
876
    if (request) {
 
877
        updateError(request->error());
 
878
    }
 
879
}
 
880
 
 
881
void QDeclarativeContactModel::updateError(QContactManager::Error error)
 
882
{
 
883
    if (d->m_error != error) {
 
884
        d->m_error = error;
 
885
        emit errorChanged();
 
886
    }
 
887
}
 
888
 
 
889
void QDeclarativeContactModel::onContactsAdded(const QList<QContactId>& ids)
 
890
{
 
891
    if (d->m_autoUpdate && !ids.isEmpty()) {
 
892
        QList<QContactId> contactsIdsForThisModel = extractContactIdsInStorageLocationFromThisModel(ids);
 
893
        if (contactsIdsForThisModel.isEmpty())
 
894
            return;
 
895
        QContactFetchRequest *fetchRequest = createContactFetchRequest(contactsIdsForThisModel);
 
896
        connect(fetchRequest,SIGNAL(stateChanged(QContactAbstractRequest::State)),
 
897
                this, SLOT(onContactsAddedFetchRequestStateChanged(QContactAbstractRequest::State)));
 
898
        fetchRequest->start();
 
899
    }
 
900
}
 
901
 
 
902
QList<QContactId> QDeclarativeContactModel::extractContactIdsInStorageLocationFromThisModel(const QList<QContactId> &ids)
 
903
{
 
904
    QList<QContactId> idsForThisModel;
 
905
    foreach (const QContactId &id, ids) {
 
906
        if (d->m_storageLocations & extractStorageLocation(id))
 
907
            idsForThisModel.append(id);
 
908
    }
 
909
    return idsForThisModel;
 
910
}
 
911
 
 
912
QContactAbstractRequest::StorageLocations QDeclarativeContactModel::extractStorageLocation(const QContactId &id)
 
913
{
 
914
    const QContactEngineId *engineId = QContactManagerEngine::engineId(id);
 
915
    return engineId->storageLocation();
 
916
}
 
917
 
 
918
/*!
 
919
  \qmlmethod ContactModel::removeContact(string contactId)
 
920
  Remove the contact from the contacts store by given \a contactId.
 
921
  After removing a contact it is not possible to save it again.
 
922
  \sa Contact::contactId
 
923
  */
 
924
void QDeclarativeContactModel::removeContact(QString id)
 
925
{
 
926
    QList<QString> ids;
 
927
    ids << id;
 
928
    removeContacts(ids);
 
929
}
 
930
 
 
931
/*!
 
932
  \qmlmethod ContactModel::removeContacts(list<string> contactIds)
 
933
  Remove the list of contacts from the contacts store by given \a contactIds.
 
934
  \sa Contact::contactId
 
935
  */
 
936
 
 
937
void QDeclarativeContactModel::removeContacts(const QStringList &ids)
 
938
{
 
939
    QContactRemoveRequest* req = new QContactRemoveRequest(this);
 
940
    QList<QContactId> contactIdsAsList;
 
941
    req->setManager(d->m_manager);
 
942
 
 
943
    foreach (const QString& id, ids) {
 
944
        QContactId contactId = QContactId::fromString(id);
 
945
        if (!contactId.isNull())
 
946
            contactIdsAsList.append(contactId);
 
947
    }
 
948
    req->setContactIds(contactIdsAsList);
 
949
 
 
950
    connect(req,SIGNAL(stateChanged(QContactAbstractRequest::State)), this, SLOT(onRequestStateChanged(QContactAbstractRequest::State)));
 
951
 
 
952
    req->start();
 
953
}
 
954
 
 
955
 
 
956
void QDeclarativeContactModel::onContactsRemoved(const QList<QContactId> &ids)
 
957
{
 
958
    if (!d->m_autoUpdate)
 
959
        return;
 
960
 
 
961
    bool emitSignal = false;
 
962
    foreach (const QContactId &id, ids) {
 
963
        if (d->m_contactMap.contains(id)) {
 
964
            int row = 0;
 
965
            //TODO:need a fast lookup
 
966
            for (; row < d->m_contacts.count(); row++) {
 
967
                if (d->m_contacts.at(row)->contactId() == id.toString())
 
968
                    break;
 
969
            }
 
970
 
 
971
            if (row < d->m_contacts.count()) {
 
972
                beginRemoveRows(QModelIndex(), row, row);
 
973
                d->m_contacts.removeAt(row);
 
974
                d->m_contactMap.remove(id);
 
975
                endRemoveRows();
 
976
                emitSignal = true;
 
977
            }
 
978
        }
 
979
    }
 
980
    if (emitSignal)
 
981
        emit contactsChanged();
 
982
}
 
983
 
 
984
void QDeclarativeContactModel::onContactsChanged(const QList<QContactId> &ids)
 
985
{
 
986
    if (d->m_autoUpdate && !ids.isEmpty()) {
 
987
        QList<QContactId> contactsIdsForThisModel = extractContactIdsInStorageLocationFromThisModel(ids);
 
988
        if (contactsIdsForThisModel.isEmpty())
 
989
            return;
 
990
        QContactFetchRequest *fetchRequest = createContactFetchRequest(contactsIdsForThisModel);
 
991
        connect(fetchRequest, SIGNAL(stateChanged(QContactAbstractRequest::State)),
 
992
                this, SLOT(onContactsChangedFetchRequestStateChanged(QContactAbstractRequest::State)));
 
993
        fetchRequest->start();
 
994
    }
 
995
}
 
996
 
 
997
QContactFetchRequest *QDeclarativeContactModel::createContactFetchRequest(const QList<QContactId> &ids)
 
998
{
 
999
    QContactFetchRequest *fetchRequest = new QContactFetchRequest(this);
 
1000
    fetchRequest->setManager(d->m_manager);
 
1001
    fetchRequest->setFetchHint(d->m_fetchHint ? d->m_fetchHint->fetchHint() : QContactFetchHint());
 
1002
    // model supports only one storage location at the moment
 
1003
    fetchRequest->setStorageLocations(QFlags<QContactAbstractRequest::StorageLocation>(d->m_storageLocations));
 
1004
 
 
1005
    QContactIdFilter idFilter;
 
1006
    idFilter.setIds(ids);
 
1007
    if (d->m_filter) {
 
1008
        QContactIntersectionFilter filter;
 
1009
        filter.append(idFilter); // result handling assumes that id filter is the first filter
 
1010
        filter.append(d->m_filter->filter());
 
1011
        fetchRequest->setFilter(filter);
 
1012
    } else
 
1013
        fetchRequest->setFilter(idFilter);
 
1014
    return fetchRequest;
 
1015
}
 
1016
 
 
1017
QVariant QDeclarativeContactModel::data(const QModelIndex &index, int role) const
 
1018
{
 
1019
    //Check if QList itme's index is valid before access it, index should be between 0 and count - 1
 
1020
    if (index.row() < 0 || index.row() >= d->m_contacts.count()) {
 
1021
        return QVariant();
 
1022
    }
 
1023
 
 
1024
    QDeclarativeContact* dc = d->m_contacts.value(index.row());
 
1025
    Q_ASSERT(dc);
 
1026
    QContact c = dc->contact();
 
1027
 
 
1028
    switch(role) {
 
1029
        case Qt::DisplayRole:
 
1030
             return c.detail(QContactDetail::TypeDisplayLabel).value(QContactDisplayLabel::FieldLabel);
 
1031
        case Qt::DecorationRole:
 
1032
            return QPixmap();
 
1033
        case ContactRole:
 
1034
            return QVariant::fromValue(dc);
 
1035
    }
 
1036
    return QVariant();
 
1037
}
 
1038
 
 
1039
 
 
1040
void QDeclarativeContactModel::sortOrder_append(QQmlListProperty<QDeclarativeContactSortOrder> *p, QDeclarativeContactSortOrder *sortOrder)
 
1041
{
 
1042
    QDeclarativeContactModel* model = qobject_cast<QDeclarativeContactModel*>(p->object);
 
1043
    if (model && sortOrder) {
 
1044
        QObject::connect(sortOrder, SIGNAL(sortOrderChanged()), model, SIGNAL(sortOrdersChanged()));
 
1045
        model->d->m_sortOrders.append(sortOrder);
 
1046
        emit model->sortOrdersChanged();
 
1047
    }
 
1048
}
 
1049
 
 
1050
int  QDeclarativeContactModel::sortOrder_count(QQmlListProperty<QDeclarativeContactSortOrder> *p)
 
1051
{
 
1052
    QDeclarativeContactModel* model = qobject_cast<QDeclarativeContactModel*>(p->object);
 
1053
    if (model)
 
1054
        return model->d->m_sortOrders.size();
 
1055
    return 0;
 
1056
}
 
1057
QDeclarativeContactSortOrder * QDeclarativeContactModel::sortOrder_at(QQmlListProperty<QDeclarativeContactSortOrder> *p, int idx)
 
1058
{
 
1059
    QDeclarativeContactModel* model = qobject_cast<QDeclarativeContactModel*>(p->object);
 
1060
 
 
1061
    QDeclarativeContactSortOrder* sortOrder = 0;
 
1062
    if (model) {
 
1063
        int i = 0;
 
1064
        foreach (QDeclarativeContactSortOrder* s, model->d->m_sortOrders) {
 
1065
            if (i == idx) {
 
1066
                sortOrder = s;
 
1067
                break;
 
1068
            } else {
 
1069
                i++;
 
1070
            }
 
1071
        }
 
1072
    }
 
1073
    return sortOrder;
 
1074
}
 
1075
void  QDeclarativeContactModel::sortOrder_clear(QQmlListProperty<QDeclarativeContactSortOrder> *p)
 
1076
{
 
1077
    QDeclarativeContactModel* model = qobject_cast<QDeclarativeContactModel*>(p->object);
 
1078
 
 
1079
    if (model) {
 
1080
        model->d->m_sortOrders.clear();
 
1081
        emit model->sortOrdersChanged();
 
1082
    }
 
1083
}
 
1084
/*!
 
1085
    \internal
 
1086
 
 
1087
    It's invoked by the fetch request from onContactsAdded().
 
1088
 */
 
1089
void QDeclarativeContactModel::onContactsAddedFetchRequestStateChanged(QContactAbstractRequest::State state)
 
1090
{
 
1091
 
 
1092
    if (state != QContactAbstractRequest::FinishedState || !sender())
 
1093
        return;
 
1094
    QContactFetchRequest *request = qobject_cast<QContactFetchRequest *>(sender());
 
1095
    if (!request)
 
1096
        return;
 
1097
 
 
1098
    checkError(request);
 
1099
 
 
1100
    if (request->error() == QContactManager::NoError) {
 
1101
        QList<QContact> fetchedContacts(request->contacts());
 
1102
        bool contactsAdded = false;
 
1103
        foreach (const QContact &c,fetchedContacts) {
 
1104
            if (d->m_contactMap.contains(c.id())) {
 
1105
                qWarning() <<Q_FUNC_INFO <<"contact to be added already exists in the model";
 
1106
                continue;
 
1107
            }
 
1108
            QDeclarativeContact* dc = new QDeclarativeContact(this);
 
1109
            dc->setContact(c);
 
1110
            int index = contactIndex(dc);
 
1111
            beginInsertRows(QModelIndex(), index, index);
 
1112
            d->m_contacts.insert(index, dc);
 
1113
            d->m_contactMap.insert(c.id(), dc);
 
1114
            if (!contactsAdded)
 
1115
                contactsAdded = true;
 
1116
            endInsertRows();
 
1117
        }
 
1118
        if (contactsAdded)
 
1119
            emit contactsChanged();
 
1120
    }
 
1121
    request->deleteLater();
 
1122
}
 
1123
 
 
1124
 
 
1125
static bool contactListDoesNotContainContactWithId(const QList<QContact> &contactList, const QContactId &contactId) {
 
1126
    foreach (const QContact &contact, contactList) {
 
1127
        if (contact.id() == contactId)
 
1128
            return false;
 
1129
    }
 
1130
    return true;
 
1131
}
 
1132
 
 
1133
/*!
 
1134
    \internal
 
1135
 
 
1136
    It's invoked by the fetch request from onContactsChanged().
 
1137
 */
 
1138
void QDeclarativeContactModel::onContactsChangedFetchRequestStateChanged(QContactAbstractRequest::State state)
 
1139
{
 
1140
    if (state != QContactAbstractRequest::FinishedState || !sender())
 
1141
        return;
 
1142
 
 
1143
    QContactFetchRequest *request = qobject_cast<QContactFetchRequest *>(sender());
 
1144
    if (!request)
 
1145
        return;
 
1146
 
 
1147
    checkError(request);
 
1148
    bool contactsUpdated = false;
 
1149
    if (request->error() == QContactManager::NoError || request->error() == QContactManager::DoesNotExistError) {
 
1150
        QList<QContact> fetchedContacts(request->contacts());
 
1151
        QList<QContactId> requestedContactIds;
 
1152
        //read requested contacts ids from the filter
 
1153
        if (request->filter().type() == QContactFilter::IdFilter) {
 
1154
            QContactIdFilter idFilter(request->filter());
 
1155
            requestedContactIds = idFilter.ids();
 
1156
        } else {
 
1157
            QContactIntersectionFilter intersectionFilter(request->filter());
 
1158
            QContactIdFilter idFilter(intersectionFilter.filters().at(0)); // assuming that id filter is the first filter
 
1159
            requestedContactIds = idFilter.ids();
 
1160
        }
 
1161
        //handle updated contacts which needs removal from model
 
1162
        //all contacts requested but not received are removed
 
1163
        foreach (const QContactId &id, requestedContactIds) {
 
1164
            if (contactListDoesNotContainContactWithId(fetchedContacts, id)) {
 
1165
                for (int i=0;i<d->m_contacts.size();++i) {
 
1166
                    if (d->m_contacts.at(i)->contactId() == id.toString()) {
 
1167
                        beginRemoveRows(QModelIndex(), i, i);
 
1168
                        d->m_contacts.removeAt(i);
 
1169
                        d->m_contactMap.remove(id);
 
1170
                        endRemoveRows();
 
1171
                        contactsUpdated = true;
 
1172
                    }
 
1173
                }
 
1174
            }
 
1175
        }
 
1176
        foreach (const QContact &fetchedContact, fetchedContacts) {
 
1177
            QString contactIdString(fetchedContact.id().toString());
 
1178
            bool fetchedContactFound = false;
 
1179
            for (int i = 0; i < d->m_contacts.size(); ++i) {
 
1180
                //handle updated contacts which should be updated in the model
 
1181
                if (d->m_contacts.at(i)->contactId() == contactIdString) {
 
1182
                    QDeclarativeContact* dc = d->m_contacts.at(i);
 
1183
                    dc->setContact(fetchedContact);
 
1184
 
 
1185
                    // Since the contact can change the position due the sort order we need take care of it
 
1186
                    // First we need to remove it from previous position and notify the model about that
 
1187
                    beginRemoveRows(QModelIndex(), i, i);
 
1188
                    d->m_contactMap.remove(fetchedContact.id());
 
1189
                    d->m_contacts.removeAt(i);
 
1190
                    endRemoveRows();
 
1191
 
 
1192
                    // Calculate the new position
 
1193
                    int index = contactIndex(dc);
 
1194
                    // Notify the model about the new item position
 
1195
                    beginInsertRows(QModelIndex(), index, index);
 
1196
                    d->m_contacts.insert(index, dc);
 
1197
                    d->m_contactMap.insert(fetchedContact.id(),dc);
 
1198
                    if (!contactsUpdated)
 
1199
                        contactsUpdated = true;
 
1200
                    endInsertRows();
 
1201
 
 
1202
                    fetchedContactFound = true;
 
1203
                    break;
 
1204
                }
 
1205
            }
 
1206
            //handle updated contacts which needs to be added in the model
 
1207
            if (!fetchedContactFound) {
 
1208
                QDeclarativeContact* dc = new QDeclarativeContact(this);
 
1209
                dc->setContact(fetchedContact);
 
1210
                int index = contactIndex(dc);
 
1211
                beginInsertRows(QModelIndex(), index, index);
 
1212
                d->m_contacts.insert(index, dc);
 
1213
                d->m_contactMap.insert(fetchedContact.id(),dc);
 
1214
                contactsUpdated = true;
 
1215
                endInsertRows();
 
1216
            }
 
1217
        }
 
1218
    }
 
1219
 
 
1220
    if (contactsUpdated)
 
1221
        emit contactsChanged();
 
1222
 
 
1223
    request->deleteLater();
 
1224
}
 
1225
 
 
1226
int QDeclarativeContactModel::contactIndex(const QDeclarativeContact* contact)
 
1227
{
 
1228
    if (d->m_sortOrders.count() > 0) {
 
1229
        QList<QContactSortOrder> mSortOrders;
 
1230
        foreach (QDeclarativeContactSortOrder *sortOrder, d->m_sortOrders)
 
1231
            mSortOrders.append(sortOrder->sortOrder());
 
1232
        for (int i = 0; i < d->m_contacts.size(); i++) {
 
1233
            // check to see if the new contact should be inserted here
 
1234
            int comparison = QContactManagerEngine::compareContact(d->m_contacts.at(i)->contact(),
 
1235
                                                                   contact->contact(),
 
1236
                                                                   mSortOrders);
 
1237
            //if the contacts are equal or cannot be compared
 
1238
            //we return the current position.The default case is if the new contact
 
1239
            //should appear before the compared contact in m_contacts
 
1240
            if (comparison >= 0)
 
1241
                return i;
 
1242
        }
 
1243
    }
 
1244
    return d->m_contacts.size();
 
1245
}
 
1246
 
 
1247
#include "moc_qdeclarativecontactmodel_p.cpp"
 
1248
 
 
1249
QT_END_NAMESPACE_CONTACTS