This repository has been archived by the owner on Sep 4, 2021. It is now read-only.
/
seasidecache.h
505 lines (410 loc) · 19.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/*
* Copyright (C) 2013 Jolla Mobile <andrew.den.exter@jollamobile.com>
*
* You may use this file under the terms of the BSD license as follows:
*
* "Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Nemo Mobile nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
*/
#ifndef SEASIDECACHE_H
#define SEASIDECACHE_H
#include "contactcacheexport.h"
36
#include "cacheconfiguration.h"
37
#include "seasidenamegrouper.h"
38
39
#include <qtcontacts-extensions.h>
40
#include <QContactStatusFlags>
41
42
43
44
45
46
47
48
49
50
51
52
#include <QContact>
#include <QContactManager>
#include <QContactFetchRequest>
#include <QContactFetchByIdRequest>
#include <QContactRemoveRequest>
#include <QContactSaveRequest>
#include <QContactRelationshipFetchRequest>
#include <QContactRelationshipSaveRequest>
#include <QContactRelationshipRemoveRequest>
#include <QContactIdFilter>
#include <QContactIdFetchRequest>
53
#include <QContactName>
54
55
#include <QTranslator>
56
#include <QBasicTimer>
57
#include <QHash>
58
59
60
61
62
#include <QSet>
#include <QElapsedTimer>
#include <QAbstractListModel>
63
64
QTCONTACTS_USE_NAMESPACE
65
66
67
68
69
70
class CONTACTCACHE_EXPORT SeasideNameGroupChangeListener
{
public:
SeasideNameGroupChangeListener() {}
~SeasideNameGroupChangeListener() {}
71
virtual void nameGroupsUpdated(const QHash<QString, QSet<quint32> > &groups) = 0;
72
73
74
75
76
77
78
79
80
81
82
83
84
85
};
class CONTACTCACHE_EXPORT SeasideCache : public QObject
{
Q_OBJECT
public:
enum FilterType {
FilterNone,
FilterAll,
FilterFavorites,
FilterOnline,
FilterTypesCount
};
86
87
88
89
enum FetchDataType {
FetchNone = 0,
FetchAccountUri = (1 << 0),
FetchPhoneNumber = (1 << 1),
90
FetchEmailAddress = (1 << 2),
91
92
93
94
95
FetchOrganization = (1 << 3),
FetchTypesMask = (FetchAccountUri |
FetchPhoneNumber |
FetchEmailAddress |
FetchOrganization)
96
97
};
98
enum DisplayLabelOrder {
99
100
FirstNameFirst = CacheConfiguration::FirstNameFirst,
LastNameFirst = CacheConfiguration::LastNameFirst
101
102
103
104
};
enum ContactState {
ContactAbsent,
105
ContactPartial,
106
ContactRequested,
107
ContactComplete
108
109
};
110
111
112
113
114
enum {
// Must be after the highest bit used in QContactStatusFlags::Flag
HasValidOnlineAccount = (QContactStatusFlags::IsOnline << 1)
};
115
116
117
118
119
120
struct ItemData
{
virtual ~ItemData() {}
virtual void displayLabelOrderChanged(DisplayLabelOrder order) = 0;
121
virtual void updateContact(const QContact &newContact, QContact *oldContact, ContactState state) = 0;
122
123
124
125
126
127
128
129
virtual void constituentsFetched(const QList<int> &ids) = 0;
virtual void mergeCandidatesFetched(const QList<int> &ids) = 0;
virtual void aggregationOperationCompleted() = 0;
virtual QList<int> constituents() const = 0;
};
130
131
struct CacheItem;
struct ItemListener
132
{
133
134
ItemListener() : next(0), key(0) {}
virtual ~ItemListener() {}
135
136
137
138
139
140
virtual void itemUpdated(CacheItem *item) = 0;
virtual void itemAboutToBeRemoved(CacheItem *item) = 0;
ItemListener *next;
void *key;
141
142
143
144
};
struct CacheItem
{
145
CacheItem() : itemData(0), iid(0), statusFlags(0), contactState(ContactAbsent), listeners(0) {}
146
CacheItem(const QContact &contact)
147
148
: contact(contact), itemData(0), iid(internalId(contact)),
statusFlags(contact.detail<QContactStatusFlags>().flagsValue()), contactState(ContactAbsent), listeners(0) {}
149
150
QContactId apiId() const { return SeasideCache::apiId(contact); }
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
ItemListener *appendListener(ItemListener *listener, void *key)
{
if (listeners) {
ItemListener *existing(listeners);
while (existing->next) {
existing = existing->next;
}
existing->next = listener;
} else {
listeners = listener;
}
listener->next = 0;
listener->key = key;
return listener;
}
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
bool removeListener(ItemListener *listener)
{
if (listeners) {
ItemListener *existing(listeners);
ItemListener **previous = &listeners;
while (existing) {
if (existing == listener) {
*previous = listener->next;
return true;
}
previous = &existing->next;
existing = existing->next;
}
}
return false;
}
188
189
ItemListener *listener(void *key)
{
190
191
192
ItemListener *existing(listeners);
while (existing && (existing->key != key) && (existing->next)) {
existing = existing->next;
193
}
194
return (existing && (existing->key == key)) ? existing : 0;
195
196
}
197
198
QContact contact;
ItemData *itemData;
199
quint32 iid;
200
quint64 statusFlags;
201
ContactState contactState;
202
ItemListener *listeners;
203
QString nameGroup;
204
QString displayLabel;
205
206
207
208
};
struct ContactLinkRequest
{
209
ContactLinkRequest(const QContactId &id) : contactId(id), constituentsFetched(false) {}
210
211
ContactLinkRequest(const ContactLinkRequest &req) : contactId(req.contactId), constituentsFetched(req.constituentsFetched) {}
212
QContactId contactId;
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
bool constituentsFetched;
};
class ListModel : public QAbstractListModel
{
public:
ListModel(QObject *parent = 0) : QAbstractListModel(parent) {}
virtual ~ListModel() {}
virtual void sourceAboutToRemoveItems(int begin, int end) = 0;
virtual void sourceItemsRemoved() = 0;
virtual void sourceAboutToInsertItems(int begin, int end) = 0;
virtual void sourceItemsInserted(int begin, int end) = 0;
virtual void sourceDataChanged(int begin, int end) = 0;
230
231
virtual void sourceItemsChanged() = 0;
232
233
virtual void makePopulated() = 0;
virtual void updateDisplayLabelOrder() = 0;
234
virtual void updateSortProperty() = 0;
235
virtual void updateGroupProperty() = 0;
236
237
};
238
239
240
241
struct ResolveListener
{
virtual ~ResolveListener() {}
242
243
244
245
246
247
248
249
250
virtual void addressResolved(const QString &first, const QString &second, CacheItem *item) = 0;
};
struct ChangeListener
{
virtual ~ChangeListener() {}
virtual void itemUpdated(CacheItem *item) = 0;
virtual void itemAboutToBeRemoved(CacheItem *item) = 0;
251
252
};
253
static SeasideCache *instance();
254
static QContactManager *manager();
255
256
257
static QContactId apiId(const QContact &contact);
static QContactId apiId(quint32 iid);
258
259
static bool validId(const QContactId &id);
260
261
262
263
static quint32 internalId(const QContact &contact);
static quint32 internalId(const QContactId &id);
264
static void registerModel(ListModel *model, FilterType type, FetchDataType requiredTypes = FetchNone, FetchDataType extraTypes = FetchNone);
265
266
267
268
269
270
271
272
static void unregisterModel(ListModel *model);
static void registerUser(QObject *user);
static void unregisterUser(QObject *user);
static void registerNameGroupChangeListener(SeasideNameGroupChangeListener *listener);
static void unregisterNameGroupChangeListener(SeasideNameGroupChangeListener *listener);
273
274
275
276
277
static void registerChangeListener(ChangeListener *listener);
static void unregisterChangeListener(ChangeListener *listener);
static void unregisterResolveListener(ResolveListener *listener);
278
279
static void setNameGrouper(SeasideNameGrouper *grouper);
280
static DisplayLabelOrder displayLabelOrder();
281
static QString sortProperty();
282
static QString groupProperty();
283
284
285
static int contactId(const QContact &contact);
286
static CacheItem *existingItem(const QContactId &id);
287
static CacheItem *existingItem(quint32 iid);
288
static CacheItem *itemById(const QContactId &id, bool requireComplete = true);
289
static CacheItem *itemById(int id, bool requireComplete = true);
290
291
static QContactId selfContactId();
static QContact contactById(const QContactId &id);
292
293
static void ensureCompletion(CacheItem *cacheItem);
294
static void refreshContact(CacheItem *cacheItem);
295
296
297
static QString nameGroup(const CacheItem *cacheItem);
static QString determineNameGroup(const CacheItem *cacheItem);
298
299
300
static QStringList allNameGroups();
static QHash<QString, QSet<quint32> > nameGroupMembers();
301
302
303
304
305
306
307
308
309
static CacheItem *itemByPhoneNumber(const QString &number, bool requireComplete = true);
static CacheItem *itemByEmailAddress(const QString &address, bool requireComplete = true);
static CacheItem *itemByOnlineAccount(const QString &localUid, const QString &remoteUid, bool requireComplete = true);
static CacheItem *resolvePhoneNumber(ResolveListener *listener, const QString &number, bool requireComplete = true);
static CacheItem *resolveEmailAddress(ResolveListener *listener, const QString &address, bool requireComplete = true);
static CacheItem *resolveOnlineAccount(ResolveListener *listener, const QString &localUid, const QString &remoteUid, bool requireComplete = true);
310
static bool saveContact(const QContact &contact);
311
static bool removeContact(const QContact &contact);
312
313
314
315
static void aggregateContacts(const QContact &contact1, const QContact &contact2);
static void disaggregateContacts(const QContact &contact1, const QContact &contact2);
316
317
static bool fetchConstituents(const QContact &contact);
static bool fetchMergeCandidates(const QContact &contact);
318
319
320
321
static int importContacts(const QString &path);
static QString exportContacts();
322
static const QList<quint32> *contacts(FilterType filterType);
323
324
static bool isPopulated(FilterType filterType);
325
326
327
static QString primaryName(const QString &firstName, const QString &lastName);
static QString secondaryName(const QString &firstName, const QString &lastName);
328
static void decomposeDisplayLabel(const QString &formattedDisplayLabel, QContactName *nameDetail);
329
330
static QString generateDisplayLabel(const QContact &contact, DisplayLabelOrder order = FirstNameFirst);
static QString generateDisplayLabelFromNonNameDetails(const QContact &contact);
331
static QUrl filteredAvatarUrl(const QContact &contact, const QStringList &metadataFragments = QStringList());
332
333
334
static QString normalizePhoneNumber(const QString &input, bool validate = false);
static QString minimizePhoneNumber(const QString &input, bool validate = false);
335
336
337
338
bool event(QEvent *event);
// For synchronizeLists()
339
int insertRange(int index, int count, const QList<quint32> &source, int sourceIndex) { return insertRange(m_syncFilter, index, count, source, sourceIndex); }
340
int removeRange(int index, int count) { removeRange(m_syncFilter, index, count); return 0; }
341
342
343
protected:
void timerEvent(QTimerEvent *event);
344
void setSortOrder(const QString &property);
345
void startRequest(bool *idleProcessing);
346
347
348
349
350
351
private slots:
void contactsAvailable();
void contactIdsAvailable();
void relationshipsAvailable();
void requestStateChanged(QContactAbstractRequest::State state);
352
void addressRequestStateChanged(QContactAbstractRequest::State state);
353
354
355
void updateContacts();
void contactsAdded(const QList<QContactId> &contactIds);
void contactsChanged(const QList<QContactId> &contactIds);
356
void contactsPresenceChanged(const QList<QContactId> &contactIds);
357
void contactsRemoved(const QList<QContactId> &contactIds);
358
359
360
void displayLabelOrderChanged(CacheConfiguration::DisplayLabelOrder order);
void sortPropertyChanged(const QString &sortProperty);
void groupPropertyChanged(const QString &groupProperty);
361
void displayStatusChanged(const QString &);
362
363
private:
364
365
366
367
368
enum PopulateProgress {
Unpopulated,
FetchFavorites,
FetchMetadata,
FetchOnline,
369
Populated
370
371
};
372
373
374
375
376
SeasideCache();
~SeasideCache();
static void checkForExpiry();
377
void keepPopulated(quint32 requiredTypes, quint32 extraTypes);
378
379
void requestUpdate();
380
void appendContacts(const QList<QContact> &contacts, FilterType filterType, bool partialFetch, const QSet<QContactDetail::DetailType> &queryDetailTypes);
381
void fetchContacts();
382
void updateContacts(const QList<QContactId> &contactIds, QList<QContactId> *updateList);
383
void applyPendingContactUpdates();
384
void applyContactUpdates(const QList<QContact> &contacts, const QSet<QContactDetail::DetailType> &queryDetailTypes);
385
386
void resolveUnknownAddresses(const QString &first, const QString &second, CacheItem *item);
387
bool updateContactIndexing(const QContact &oldContact, const QContact &contact, quint32 iid, const QSet<QContactDetail::DetailType> &queryDetailTypes, CacheItem *item);
388
void updateCache(CacheItem *item, const QContact &contact, bool partialFetch, bool initialInsert);
389
void reportItemUpdated(CacheItem *item);
390
391
void removeRange(FilterType filter, int index, int count);
392
int insertRange(FilterType filter, int index, int count, const QList<quint32> &queryIds, int queryIndex);
393
394
395
396
void contactDataChanged(quint32 iid);
void contactDataChanged(quint32 iid, FilterType filter);
void removeContactData(quint32 iid, FilterType filter);
397
398
void makePopulated(FilterType filter);
399
400
401
void addToContactNameGroup(quint32 iid, const QString &group, QSet<QString> *modifiedGroups = 0);
void removeFromContactNameGroup(quint32 iid, const QString &group, QSet<QString> *modifiedGroups = 0);
void notifyNameGroupsChanged(const QSet<QString> &groups);
402
403
404
void updateConstituentAggregations(const QContactId &contactId);
void completeContactAggregation(const QContactId &contact1Id, const QContactId &contact2Id);
405
406
407
void resolveAddress(ResolveListener *listener, const QString &first, const QString &second, bool requireComplete);
408
409
CacheItem *itemMatchingPhoneNumber(const QString &number, const QString &normalized, bool requireComplete);
410
411
int contactIndex(quint32 iid, FilterType filter);
412
static QContactRelationship makeRelationship(const QString &type, const QContactId &id1, const QContactId &id2);
413
414
static QContactRelationship makeRelationship(const QString &type, const QContact &contact1, const QContact &contact2);
415
416
QList<quint32> m_contacts[FilterTypesCount];
417
418
419
QBasicTimer m_expiryTimer;
QBasicTimer m_fetchTimer;
QHash<quint32, CacheItem> m_people;
420
QMultiHash<QString, quint32> m_phoneNumberIds;
421
QHash<QString, quint32> m_emailAddressIds;
422
QHash<QPair<QString, QString>, quint32> m_onlineAccountIds;
423
QHash<QContactId, QContact> m_contactsToSave;
424
QHash<QString, QSet<quint32> > m_contactNameGroups;
425
QList<QContact> m_contactsToCreate;
426
427
428
429
430
431
QHash<FilterType, QPair<QSet<QContactDetail::DetailType>, QList<QContact> > > m_contactsToAppend;
QList<QPair<QSet<QContactDetail::DetailType>, QList<QContact> > > m_contactsToUpdate;
QList<QContactId> m_contactsToRemove;
QList<QContactId> m_changedContacts;
QList<QContactId> m_presenceChangedContacts;
QSet<QContactId> m_aggregatedContacts;
432
433
QList<QContactId> m_contactsToFetchConstituents;
QList<QContactId> m_contactsToFetchCandidates;
434
QList<QContactId> m_contactsToLinkTo;
435
436
437
QList<QPair<ContactLinkRequest, ContactLinkRequest> > m_contactPairsToLink;
QList<QContactRelationship> m_relationshipsToSave;
QList<QContactRelationship> m_relationshipsToRemove;
438
QScopedPointer<SeasideNameGrouper> m_nameGrouper;
439
QList<SeasideNameGroupChangeListener*> m_nameGroupChangeListeners;
440
QList<ChangeListener*> m_changeListeners;
441
442
QList<ListModel *> m_models[FilterTypesCount];
QSet<QObject *> m_users;
443
QHash<QContactId,int> m_expiredContacts;
444
445
446
447
448
449
450
451
QContactFetchRequest m_fetchRequest;
QContactFetchByIdRequest m_fetchByIdRequest;
QContactIdFetchRequest m_contactIdRequest;
QContactRelationshipFetchRequest m_relationshipsFetchRequest;
QContactRemoveRequest m_removeRequest;
QContactSaveRequest m_saveRequest;
QContactRelationshipSaveRequest m_relationshipSaveRequest;
QContactRelationshipRemoveRequest m_relationshipRemoveRequest;
452
453
QList<QContactSortOrder> m_sortOrder;
QList<QContactSortOrder> m_onlineSortOrder;
454
FilterType m_syncFilter;
455
456
457
int m_populated;
int m_cacheIndex;
int m_queryIndex;
458
459
int m_fetchProcessedCount;
int m_fetchByIdProcessedCount;
460
DisplayLabelOrder m_displayLabelOrder;
461
QString m_sortProperty;
462
QString m_groupProperty;
463
bool m_keepPopulated;
464
PopulateProgress m_populateProgress;
465
bool m_populating; // true if current m_fetchRequest makes progress
466
quint32 m_fetchTypes;
467
468
quint32 m_extraFetchTypes;
quint32 m_dataTypesFetched;
469
470
471
bool m_updatesPending;
bool m_refreshRequired;
bool m_contactsUpdated;
472
bool m_displayOff;
473
474
QSet<QContactId> m_constituentIds;
QSet<QContactId> m_candidateIds;
475
476
477
478
struct ResolveData {
QString first;
QString second;
479
QString compare; // only used in m_unknownAddresses
480
481
482
bool requireComplete;
ResolveListener *listener;
};
483
QHash<QContactFetchRequest *, ResolveData> m_resolveAddresses;
484
QSet<ResolveData> m_pendingResolve; // these have active requests already
485
QList<ResolveData> m_unknownResolveAddresses;
486
QList<ResolveData> m_unknownAddresses;
487
QSet<QString> m_resolvedPhoneNumbers;
488
489
490
491
492
QElapsedTimer m_timer;
QElapsedTimer m_fetchPostponed;
static SeasideCache *instancePtr;
493
static int contactNameGroupCount;
494
static QStringList allContactNameGroups;
495
496
static QTranslator *engEnTranslator;
static QTranslator *translator;
497
498
499
friend bool operator==(const SeasideCache::ResolveData &lhs, const SeasideCache::ResolveData &rhs);
friend uint qHash(const SeasideCache::ResolveData &key, uint seed);
500
501
};
502
503
504
bool operator==(const SeasideCache::ResolveData &lhs, const SeasideCache::ResolveData &rhs);
uint qHash(const SeasideCache::ResolveData &key, uint seed = 0);
505
#endif