17 */ |
17 */ |
18 |
18 |
19 #include <hbapplication.h> |
19 #include <hbapplication.h> |
20 #include <qtcontacts.h> |
20 #include <qtcontacts.h> |
21 #include <qcontactmanager.h> |
21 #include <qcontactmanager.h> |
|
22 #include <QTimer> |
|
23 |
22 #include <cntdebug.h> |
24 #include <cntdebug.h> |
23 #include "cntcache.h" |
25 #include "cntcache.h" |
|
26 #include "cntnamefetcher.h" |
24 #include "cntcache_p.h" |
27 #include "cntcache_p.h" |
25 #include "cntinfoprovider.h" |
|
26 |
28 |
27 // set the singleton instance pointer to NULL |
29 // set the singleton instance pointer to NULL |
28 CntCache* CntCache::mInstance = NULL; |
30 CntCache* CntCache::mInstance = NULL; |
29 |
31 |
30 // value for first cache order to be assigned |
32 // value for first cache order to be assigned |
31 static const int CacheOrderStartValue = 1; |
33 static const int CacheOrderStartValue = 1; |
32 // for avoiding wrap around with cache orders |
34 // for avoiding wrap around with cache orders |
33 static const int MaxCacheOrderValue = 10000000; |
35 static const int MaxCacheOrderValue = 10000000; |
34 // number of items to read quickly when a new instance is requested or cache is cleared |
36 // number of items to read quickly when a new instance is requested or cache is cleared |
35 static const int ItemsToReadUrgently = 12; |
37 static const int ItemsToReadUrgently = 13; |
36 // number of items to read ahead into cache; this number is for one direction |
38 // number of items to read ahead into cache; this number is for one direction |
37 static const int ItemsToCacheAhead = 24; |
39 static const int ItemsToCacheAhead = 24; |
38 // cache size for info items (name, text, icon1name, icon2name) |
40 // cache size for info items (name, text, icon1name, icon2name) |
39 static const int InfoCacheSize = 128; |
41 static const int InfoCacheSize = 128; |
40 // cache size for icon items (iconName and HbIcon) |
42 // cache size for icon items (iconName and HbIcon) |
44 // default empty text info field for a contact; it cannot be empty |
46 // default empty text info field for a contact; it cannot be empty |
45 // as the listview will then ignore it, causing rendering problems |
47 // as the listview will then ignore it, causing rendering problems |
46 static const QString EmptyTextField = " "; |
48 static const QString EmptyTextField = " "; |
47 |
49 |
48 /*! |
50 /*! |
49 Creates the CntCache singleton instance. |
|
50 */ |
|
51 CntCache::CntCache() |
|
52 : mContactManager(new QContactManager()), |
|
53 mWorker(new CntCacheThread()), |
|
54 mNextInfoCacheOrder(CacheOrderStartValue), |
|
55 mNextIconCacheOrder(CacheOrderStartValue), |
|
56 mEmittedContactId(-1), |
|
57 mUrgentContacts(0) |
|
58 { |
|
59 CNT_ENTRY |
|
60 |
|
61 // listen to worker updates |
|
62 connect(mWorker, SIGNAL(infoFieldUpdated(int, const ContactInfoField&, const QString&)), |
|
63 this, SLOT(onNewInfo(int, const ContactInfoField&, const QString&))); |
|
64 connect(mWorker, SIGNAL(iconUpdated(const QString&, const HbIcon&)), |
|
65 this, SLOT(onNewIcon(const QString&, const HbIcon&))); |
|
66 connect(mWorker, SIGNAL(infoCancelled(int)), this, SLOT(onInfoCancelled(int))); |
|
67 connect(mWorker, SIGNAL(iconCancelled(const QString&)), this, SLOT(onIconCancelled(const QString&))); |
|
68 connect(mWorker, SIGNAL(allJobsDone()), this, SLOT(scheduleOneReadAheadItem())); |
|
69 |
|
70 // listen to the database for changes to contacts |
|
71 connect(mContactManager, SIGNAL(contactsChanged(const QList<QContactLocalId>&)), this, SLOT(updateContactsInCache(const QList<QContactLocalId>&))); |
|
72 connect(mContactManager, SIGNAL(contactsRemoved(const QList<QContactLocalId>&)), this, SLOT(removeContactsFromCache(const QList<QContactLocalId>&))); |
|
73 |
|
74 // shutdown only when the whole application shuts down |
|
75 connect(HbApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(onShutdown())); |
|
76 |
|
77 CNT_EXIT |
|
78 } |
|
79 |
|
80 /*! |
|
81 Destructs the CntCache singleton instance. |
|
82 */ |
|
83 CntCache::~CntCache() |
|
84 { |
|
85 CNT_ENTRY |
|
86 |
|
87 delete mWorker; |
|
88 delete mContactManager; |
|
89 |
|
90 qDeleteAll(mInfoCache); |
|
91 mInfoCache.clear(); |
|
92 qDeleteAll(mIconCache); |
|
93 mIconCache.clear(); |
|
94 |
|
95 CNT_EXIT |
|
96 } |
|
97 |
|
98 /*! |
|
99 Provides a pointer to the CntCache singleton instance. |
51 Provides a pointer to the CntCache singleton instance. |
100 */ |
52 */ |
101 CntCache* CntCache::instance() |
53 CntCache* CntCache::instance(QContactManager *manager) |
102 { |
54 { |
103 if (mInstance == NULL) { |
55 if (!mInstance) { |
104 mInstance = new CntCache(); |
56 mInstance = new CntCache(manager); |
105 } |
57 } |
106 |
58 |
107 // whenever a client requests an instance the client will want to get all info |
59 // whenever a client requests an instance the client will want to get all info |
108 // for the first couple of contacts (~a screenfull) as fast as possible |
60 // for the first couple of contacts (~a screenfull) as fast as possible |
109 mInstance->mUrgentContacts = ItemsToReadUrgently; |
61 mInstance->mUrgentContacts = ItemsToReadUrgently; |
170 // notified when the icon is received |
121 // notified when the icon is received |
171 iconItem->contactIds.insert(contactId); |
122 iconItem->contactIds.insert(contactId); |
172 // also reschedule it |
123 // also reschedule it |
173 mWorker->scheduleIconJob(iconName, row); |
124 mWorker->scheduleIconJob(iconName, row); |
174 } |
125 } |
175 } |
126 } else { |
176 else { |
|
177 // needed icon is not in cache, so schedule it for retrieval |
127 // needed icon is not in cache, so schedule it for retrieval |
178 CntIconCacheItem* iconItem = createIconCacheItem(iconName); |
128 CntIconCacheItem* iconItem = createIconCacheItem(iconName); |
179 iconItem->contactIds.insert(contactId); |
129 iconItem->contactIds.insert(contactId); |
180 mWorker->scheduleIconJob(iconName, row); |
130 mWorker->scheduleIconJob(iconName, row); |
181 } |
131 } |
182 } |
132 } |
183 } |
133 } |
184 |
134 |
|
135 // set return text |
|
136 text = infoItem->text; |
|
137 |
185 // update cache order |
138 // update cache order |
186 infoItem->cacheOrder = mNextInfoCacheOrder++; |
139 infoItem->cacheOrder = mNextInfoCacheOrder++; |
187 infoItem->latestRow = row; |
140 infoItem->latestRow = row; |
188 |
141 } else { |
189 name = infoItem->name; |
142 // the contact info is not in cache, schedule it for retrieval |
190 text = infoItem->text; |
143 if (contactExists(contactId)) { |
191 } |
|
192 else { |
|
193 // the item is not in cache, so fetch the name and schedule the rest |
|
194 // of the info for retrieval |
|
195 if (fetchContactName(contactId, name)) { |
|
196 // contact found, so add new entry to cache |
144 // contact found, so add new entry to cache |
197 CntInfoCacheItem* item = createInfoCacheItem(contactId); |
145 CntInfoCacheItem* item = createInfoCacheItem(contactId); |
198 item->name = name; |
|
199 item->text = text; |
146 item->text = text; |
200 item->latestRow = row; |
147 item->latestRow = row; |
201 |
148 |
202 // ask the worker thread to fetch the information asynchronously |
149 // ask the worker thread to fetch the information asynchronously |
203 mWorker->scheduleInfoJob(contactId, row); |
150 mWorker->scheduleInfoJob(contactId, row); |
204 } |
151 } |
205 } |
152 } |
206 |
153 |
|
154 name = contactName(contactId); |
207 CNT_EXIT_ARGS("name:" << name << "sec:" << text) |
155 CNT_EXIT_ARGS("name:" << name << "sec:" << text) |
208 |
156 |
209 return CntContactInfo(contactId, name, text, icons[0], icons[1]); |
157 return CntContactInfo(contactId, name, text, icons[0], icons[1]); |
210 } |
158 } |
211 |
159 |
212 /*! |
160 /*! |
213 Clears the cache of names (not icons). This function can be useful |
161 Creates a list of contact ids sorted according the corresponding contact names. |
214 for example when the format of contact names changes. |
162 |
215 */ |
163 \param idFilter the IDs to be returned; if NULL, all contact IDs are returned |
216 void CntCache::clearCache() |
164 \return the list of ids, sorted according the contact name |
|
165 */ |
|
166 QList<QContactLocalId> CntCache::sortIdsByName(const QSet<QContactLocalId>* idFilter) const |
217 { |
167 { |
218 CNT_ENTRY |
168 CNT_ENTRY |
219 |
169 |
220 // clear info cache |
170 QList<QContactLocalId> sortedIds; |
|
171 |
|
172 // allocate memory in advance to avoid repeated reallocation during population |
|
173 // an extra 16 items are allocated to leave room for a few more contacts |
|
174 // before reallocation is needed |
|
175 if (!idFilter) { |
|
176 sortedIds.reserve(mSortedNames.count() + 16); |
|
177 } else { |
|
178 sortedIds.reserve(idFilter->count() + 16); |
|
179 } |
|
180 |
|
181 // the entries in mSortedNames are already sorted, so just pick |
|
182 // out the ids from that list in the order that they appear |
|
183 if (!idFilter) { |
|
184 foreach (CntNameCacheItem* item, mSortedNames) { |
|
185 sortedIds.append(item->contactId()); |
|
186 } |
|
187 } else { |
|
188 foreach (CntNameCacheItem* item, mSortedNames) { |
|
189 if (idFilter->contains(item->contactId())) { |
|
190 sortedIds.append(item->contactId()); |
|
191 } |
|
192 } |
|
193 } |
|
194 |
|
195 CNT_EXIT |
|
196 |
|
197 return sortedIds; |
|
198 } |
|
199 |
|
200 /*! |
|
201 Overloaded version of the function for string based searching of contact names. |
|
202 Currently for multi part names only space and dash variations are used for filtering, |
|
203 e.g. "Axx Bxx" or "Axx-Bxx" are the only possible matches along with the original string. |
|
204 |
|
205 \param searchList list of strings which are used for search |
|
206 \return the list of ids, sorted according the contact name |
|
207 */ |
|
208 QList<QContactLocalId> CntCache::sortIdsByName(const QStringList searchList) const |
|
209 { |
|
210 CNT_ENTRY |
|
211 |
|
212 QList<QContactLocalId> sortedIds; |
|
213 int iterNames = 0; |
|
214 int iterList = 0; |
|
215 QString firstName = 0; |
|
216 QString lastName = 0; |
|
217 QString tempString = 0; |
|
218 QString tempDash = 0; |
|
219 QString tempSpace = 0; |
|
220 int matchesFound = 0; |
|
221 const QChar dash = '-'; |
|
222 const QChar space = ' '; |
|
223 QStringList searchVariations; |
|
224 |
|
225 for (iterList = 0; iterList < searchList.size(); iterList++) |
|
226 { |
|
227 tempString = searchList.at(iterList); |
|
228 tempDash = tempString; |
|
229 tempSpace = tempString; |
|
230 tempDash.insert(0, dash); |
|
231 tempSpace.insert(0, space); |
|
232 |
|
233 searchVariations.append(tempString); |
|
234 searchVariations.append(tempDash); |
|
235 searchVariations.append(tempSpace); |
|
236 } |
|
237 |
|
238 for (iterNames = 0; iterNames < mSortedNames.size(); iterNames++) |
|
239 { |
|
240 matchesFound = 0; |
|
241 firstName = (mSortedNames.at(iterNames))->firstName(); |
|
242 lastName = (mSortedNames.at(iterNames))->lastName(); |
|
243 for (iterList = 0; iterList < searchVariations.size(); iterList += 3) |
|
244 { |
|
245 // if the current name doesn't contain any of the possible variations then it can be skipped |
|
246 if ( !( firstName.startsWith(searchVariations.at(iterList), Qt::CaseInsensitive) || |
|
247 lastName.startsWith(searchVariations.at(iterList), Qt::CaseInsensitive) || |
|
248 firstName.contains(searchVariations.at(iterList+1), Qt::CaseInsensitive) || |
|
249 lastName.contains(searchVariations.at(iterList+1), Qt::CaseInsensitive) || |
|
250 firstName.contains(searchVariations.at(iterList+2), Qt::CaseInsensitive) || |
|
251 lastName.contains(searchVariations.at(iterList+2), Qt::CaseInsensitive) ) ) |
|
252 { |
|
253 break; |
|
254 } |
|
255 } |
|
256 if (iterList == searchVariations.size()) |
|
257 { |
|
258 sortedIds.append(mSortedNames.at(iterNames)->contactId()); |
|
259 } |
|
260 } |
|
261 |
|
262 CNT_EXIT |
|
263 |
|
264 return sortedIds; |
|
265 } |
|
266 |
|
267 /*! |
|
268 Creates the CntCache singleton instance. |
|
269 */ |
|
270 CntCache::CntCache(QContactManager *manager) |
|
271 : mContactManager(manager), |
|
272 mWorker(new CntCacheThread()), |
|
273 mNameFetcher(new CntNameFetcher()), |
|
274 mNextInfoCacheOrder(CacheOrderStartValue), |
|
275 mNextIconCacheOrder(CacheOrderStartValue), |
|
276 mEmittedContactId(-1), |
|
277 mUrgentContacts(0), |
|
278 mHasModifiedNames(false), |
|
279 mAllNamesFetchStarted(false) |
|
280 { |
|
281 CNT_ENTRY |
|
282 |
|
283 // listen to name fetcher |
|
284 connect(mNameFetcher, SIGNAL(nameFormatChanged(CntNameOrder)), this, SLOT(reformatNames(CntNameOrder))); |
|
285 connect(mNameFetcher, SIGNAL(databaseAccessComplete()), mWorker, SLOT(resumeJobs())); |
|
286 connect(mNameFetcher, SIGNAL(namesAvailable(QList<CntNameCacheItem *>)), this, SLOT(setNameList(QList<CntNameCacheItem *>))); |
|
287 |
|
288 // listen to info fetcher |
|
289 connect(mWorker, SIGNAL(infoFieldUpdated(int, const ContactInfoField&, const QString&)), |
|
290 this, SLOT(onNewInfo(int, const ContactInfoField&, const QString&))); |
|
291 connect(mWorker, SIGNAL(infoCancelled(int)), this, SLOT(onInfoCancelled(int))); |
|
292 |
|
293 // listen to icon fetcher |
|
294 connect(mWorker, SIGNAL(iconUpdated(const QString&, const HbIcon&)), |
|
295 this, SLOT(onNewIcon(const QString&, const HbIcon&))); |
|
296 connect(mWorker, SIGNAL(iconCancelled(const QString&)), this, SLOT(onIconCancelled(const QString&))); |
|
297 connect(mWorker, SIGNAL(allJobsDone()), this, SLOT(scheduleOneReadAheadItem())); |
|
298 |
|
299 // listen to contact manager |
|
300 connect(mContactManager, SIGNAL(contactsChanged(const QList<QContactLocalId>&)), this, SLOT(updateContacts(const QList<QContactLocalId>&))); |
|
301 connect(mContactManager, SIGNAL(contactsRemoved(const QList<QContactLocalId>&)), this, SLOT(removeContacts(const QList<QContactLocalId>&))); |
|
302 connect(mContactManager, SIGNAL(contactsAdded(const QList<QContactLocalId>&)), this, SLOT(addContacts(const QList<QContactLocalId>&))); |
|
303 |
|
304 // listen to application -- shut down cache only when the whole application quits |
|
305 connect(HbApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(onShutdown())); |
|
306 |
|
307 // load all names to RAM |
|
308 loadNames(); |
|
309 |
|
310 CNT_EXIT |
|
311 } |
|
312 |
|
313 /*! |
|
314 Destructs the CntCache singleton instance. |
|
315 */ |
|
316 CntCache::~CntCache() |
|
317 { |
|
318 CNT_ENTRY |
|
319 |
|
320 if (mHasModifiedNames) { |
|
321 mNameFetcher->writeNamesToCache(mSortedNames); |
|
322 } |
|
323 |
|
324 delete mWorker; |
|
325 delete mNameFetcher; |
|
326 |
221 qDeleteAll(mInfoCache); |
327 qDeleteAll(mInfoCache); |
222 mInfoCache.clear(); |
328 mInfoCache.clear(); |
223 mNextInfoCacheOrder = CacheOrderStartValue; |
329 |
224 mUrgentContacts = ItemsToReadUrgently; |
330 qDeleteAll(mIconCache); |
|
331 mIconCache.clear(); |
|
332 |
|
333 qDeleteAll(mNameCache); |
|
334 mNameCache.clear(); |
|
335 mSortedNames.clear(); |
225 |
336 |
226 CNT_EXIT |
337 CNT_EXIT |
227 } |
338 } |
228 |
339 |
229 /*! |
340 /*! |
371 } |
482 } |
372 |
483 |
373 CNT_EXIT |
484 CNT_EXIT |
374 } |
485 } |
375 |
486 |
376 /*! |
487 /*! |
377 Update contacts in cache. |
488 Fetch the names of all contacts. |
378 |
489 */ |
379 /param contactIds ids of the contact that will be updated |
490 void CntCache::loadNames() |
380 */ |
|
381 void CntCache::updateContactsInCache(const QList<QContactLocalId>& contactIds) |
|
382 { |
491 { |
383 CNT_ENTRY |
492 CNT_ENTRY |
|
493 |
|
494 // read names from file cache |
|
495 mNameFetcher->readNamesFromCache(mSortedNames); |
|
496 |
|
497 // insert the names into the id-to-name map |
|
498 foreach (CntNameCacheItem* item, mSortedNames) { |
|
499 mNameCache.insert(item->contactId(), item); |
|
500 } |
|
501 |
|
502 // if there are no names in file cache, start the asynch |
|
503 // read of all names immediately (normally it is done |
|
504 // after secondary info has been read) |
|
505 if (mSortedNames.count() == 0) { |
|
506 mWorker->postponeJobs(); |
|
507 mAllNamesFetchStarted = true; |
|
508 mNameFetcher->readAllNamesAsynch(); |
|
509 } |
|
510 |
|
511 CNT_EXIT |
|
512 } |
|
513 |
|
514 /*! |
|
515 Checks whether a contact exists. |
|
516 */ |
|
517 bool CntCache::contactExists(QContactLocalId contactId) const |
|
518 { |
|
519 return mNameCache.contains(contactId); |
|
520 } |
|
521 |
|
522 /*! |
|
523 Fetch the name of one contact. |
|
524 */ |
|
525 QString CntCache::contactName(QContactLocalId contactId) const |
|
526 { |
|
527 CNT_ENTRY |
384 |
528 |
385 QString name; |
529 QString name; |
386 |
530 |
387 foreach (QContactLocalId contactId, contactIds) { |
531 QHash<QContactLocalId, CntNameCacheItem*>::const_iterator i = mNameCache.find(contactId); |
388 if (mInfoCache.contains(contactId) && fetchContactName(contactId, name)) { |
532 if (i != mNameCache.end()) { |
389 CntInfoCacheItem* infoItem = mInfoCache.value(contactId); |
533 name = i.value()->name(); |
390 infoItem->name = name; |
534 } |
391 mWorker->scheduleInfoJob(contactId, infoItem->latestRow); |
535 |
392 } |
536 CNT_EXIT |
393 } |
537 |
394 |
538 return name; |
395 foreach (QContactLocalId contactId, contactIds) { |
|
396 emitContactInfoUpdated(contactId); |
|
397 } |
|
398 |
|
399 CNT_EXIT |
|
400 } |
|
401 |
|
402 /*! |
|
403 Removes contacts from cache. |
|
404 |
|
405 /param contactIds ids of the contact that will be removed |
|
406 */ |
|
407 void CntCache::removeContactsFromCache(const QList<QContactLocalId>& contactIds) |
|
408 { |
|
409 CNT_ENTRY |
|
410 |
|
411 foreach (QContactLocalId contactId, contactIds) { |
|
412 if (mInfoCache.contains(contactId)) { |
|
413 CntInfoCacheItem* item = mInfoCache.take(contactId); |
|
414 delete item; |
|
415 } |
|
416 } |
|
417 |
|
418 foreach (QContactLocalId contactId, contactIds) { |
|
419 emitContactInfoUpdated(contactId); |
|
420 } |
|
421 |
|
422 CNT_EXIT |
|
423 } |
|
424 |
|
425 /*! |
|
426 Uses an optimized function to fetch the name of a contact from |
|
427 the database. |
|
428 |
|
429 /param contactId the id of the contact to fetch |
|
430 /param contactName the name will be stored here if the function is successful |
|
431 /return true if the name was fetched successfully |
|
432 */ |
|
433 bool CntCache::fetchContactName(int contactId, QString& contactName) |
|
434 { |
|
435 CNT_ENTRY_ARGS( contactId ) |
|
436 |
|
437 bool foundContact = false; |
|
438 |
|
439 QContactFetchHint nameOnlyFetchHint; |
|
440 /*QStringList details; |
|
441 details << QContactDisplayLabel::DefinitionName; |
|
442 nameOnlyFetchHint.setDetailDefinitionsHint(details);*/ |
|
443 nameOnlyFetchHint.setOptimizationHints(QContactFetchHint::NoRelationships); |
|
444 QContact contact = mContactManager->contact(contactId, nameOnlyFetchHint); |
|
445 |
|
446 if (mContactManager->error() == QContactManager::NoError) { |
|
447 contactName = contact.displayLabel(); |
|
448 foundContact = true; |
|
449 } |
|
450 |
|
451 CNT_EXIT_ARGS( foundContact ) |
|
452 |
|
453 return foundContact; |
|
454 } |
539 } |
455 |
540 |
456 /*! |
541 /*! |
457 Collects all contact IDs near the latest fetch from the UI. These will be fetched and |
542 Collects all contact IDs near the latest fetch from the UI. These will be fetched and |
458 precached when UI activity slows down. |
543 precached when UI activity slows down. |
648 void CntCache::onShutdown() |
739 void CntCache::onShutdown() |
649 { |
740 { |
650 CNT_ENTRY |
741 CNT_ENTRY |
651 |
742 |
652 mInstance = NULL; |
743 mInstance = NULL; |
|
744 |
|
745 disconnect(mContactManager, SIGNAL(contactsChanged(const QList<QContactLocalId>&)), this, SLOT(updateContacts(const QList<QContactLocalId>&))); |
|
746 disconnect(mContactManager, SIGNAL(contactsRemoved(const QList<QContactLocalId>&)), this, SLOT(removeContacts(const QList<QContactLocalId>&))); |
|
747 disconnect(mContactManager, SIGNAL(contactsAdded(const QList<QContactLocalId>&)), this, SLOT(addContacts(const QList<QContactLocalId>&))); |
|
748 |
653 deleteLater(); |
749 deleteLater(); |
654 |
750 |
655 CNT_EXIT |
751 CNT_EXIT |
656 } |
752 } |
657 |
753 |
658 |
754 /*! |
659 /*! |
755 Updates the names in cache according to newFormat. |
660 Creates an empty object. |
756 |
|
757 This slot is called when name fetcher signals that the format of |
|
758 names has been changed. |
|
759 */ |
|
760 void CntCache::reformatNames(CntNameOrder newFormat) |
|
761 { |
|
762 foreach (CntNameCacheItem* item, mSortedNames) { |
|
763 item->setNameFormat(newFormat); |
|
764 } |
|
765 |
|
766 mNameFetcher->sortNames(mSortedNames); |
|
767 |
|
768 mNameFetcher->writeNamesToCache(mSortedNames); |
|
769 mHasModifiedNames = false; |
|
770 |
|
771 emit dataChanged(); |
|
772 } |
|
773 |
|
774 /*! |
|
775 Replaces the names in cache with the ones in this list. |
|
776 |
|
777 \param newSortedNames the sorted list with names; this list will be cleared and |
|
778 ownership will be taken of the items in the list |
|
779 */ |
|
780 void CntCache::setNameList(QList<CntNameCacheItem *> newSortedNames) |
|
781 { |
|
782 CNT_ENTRY |
|
783 |
|
784 bool hasModifiedContacts = false; |
|
785 int count = newSortedNames.count(); |
|
786 |
|
787 // check if there have been any changes |
|
788 if (mSortedNames.count() != count) { |
|
789 hasModifiedContacts = true; |
|
790 } else { |
|
791 for (int i = 0; i < count; ++i) { |
|
792 CntNameCacheItem *oldItem = mSortedNames.at(i); |
|
793 CntNameCacheItem *newItem = newSortedNames.at(i); |
|
794 if (oldItem->contactId() != newItem->contactId() || oldItem->name() != newItem->name()) { |
|
795 hasModifiedContacts = true; |
|
796 break; |
|
797 } |
|
798 } |
|
799 } |
|
800 |
|
801 // the list has changed, so use the new list instead |
|
802 if (hasModifiedContacts) { |
|
803 qDeleteAll(mSortedNames); |
|
804 mNameCache.clear(); |
|
805 mSortedNames.clear(); |
|
806 |
|
807 foreach (CntNameCacheItem* item, newSortedNames) { |
|
808 mSortedNames.append(item); |
|
809 mNameCache.insert(item->contactId(), item); |
|
810 } |
|
811 |
|
812 // write names to file cache |
|
813 mNameFetcher->writeNamesToCache(mSortedNames); |
|
814 |
|
815 // notify clients that the list of names has changed |
|
816 emit dataChanged(); |
|
817 } else { |
|
818 qDeleteAll(newSortedNames); |
|
819 } |
|
820 |
|
821 CNT_EXIT |
|
822 } |
|
823 |
|
824 /*! |
|
825 Updates data in response to some contacts having changed and |
|
826 then notifies observers that these contacts have changed. |
|
827 */ |
|
828 void CntCache::updateContacts(const QList<QContactLocalId> &changedContacts) |
|
829 { |
|
830 QString name; |
|
831 QList<CntNameCacheItem*> items; |
|
832 |
|
833 // reloads the names of the changed contacts and updates the |
|
834 // list of sorted names accordingly |
|
835 foreach (QContactLocalId contactId, changedContacts) { |
|
836 CntNameCacheItem *newItem = mNameFetcher->readOneName(contactId); |
|
837 if (newItem != NULL) { |
|
838 CntNameCacheItem *oldItem = mNameCache.value(contactId); |
|
839 if (oldItem->name() != newItem->name()) { |
|
840 QList<CntNameCacheItem*>::iterator oldPos = qLowerBound(mSortedNames.begin(), mSortedNames.end(), oldItem, CntNameFetcher::compareNames); |
|
841 while (*oldPos != oldItem && oldPos != mSortedNames.end()) { |
|
842 ++oldPos; |
|
843 } |
|
844 QList<CntNameCacheItem*>::iterator newPos = qUpperBound(mSortedNames.begin(), mSortedNames.end(), newItem, CntNameFetcher::compareNames); |
|
845 if (oldPos < newPos) { |
|
846 mSortedNames.move(oldPos - mSortedNames.begin(), (newPos - mSortedNames.begin()) - 1); |
|
847 } else { |
|
848 mSortedNames.move(oldPos - mSortedNames.begin(), newPos - mSortedNames.begin()); |
|
849 } |
|
850 *oldItem = *newItem; |
|
851 mHasModifiedNames = true; |
|
852 } |
|
853 } |
|
854 } |
|
855 |
|
856 // if any of the changed items have cached info, the info |
|
857 // is scheduled for refreshing |
|
858 foreach (QContactLocalId contactId, changedContacts) { |
|
859 if (mInfoCache.contains(contactId)) { |
|
860 CntInfoCacheItem* infoItem = mInfoCache.value(contactId); |
|
861 mWorker->scheduleInfoJob(contactId, infoItem->latestRow); |
|
862 } |
|
863 } |
|
864 |
|
865 // inform clients about these changes |
|
866 emit contactsChanged(changedContacts); |
|
867 } |
|
868 |
|
869 /*! |
|
870 Updates data in response to some contacts having been removed |
|
871 and then notifies observers that the contacts have been removed. |
|
872 */ |
|
873 void CntCache::removeContacts(const QList<QContactLocalId> &removedContacts) |
|
874 { |
|
875 // removed the deleted contacts from the name cache and from the |
|
876 // list of sorted names |
|
877 foreach (QContactLocalId contactId, removedContacts) { |
|
878 CntNameCacheItem *item = mNameCache.take(contactId); |
|
879 if (item) { |
|
880 QList<CntNameCacheItem*>::iterator pos = qLowerBound(mSortedNames.begin(), mSortedNames.end(), item, CntNameFetcher::compareNames); |
|
881 while (*pos != item && pos != mSortedNames.end()) { |
|
882 ++pos; |
|
883 } |
|
884 mSortedNames.erase(pos); |
|
885 delete item; |
|
886 mHasModifiedNames = true; |
|
887 } |
|
888 } |
|
889 |
|
890 // info for these deleted items should be removed from cache |
|
891 foreach (QContactLocalId contactId, removedContacts) { |
|
892 if (mInfoCache.contains(contactId)) { |
|
893 CntInfoCacheItem* item = mInfoCache.take(contactId); |
|
894 delete item; |
|
895 } |
|
896 } |
|
897 |
|
898 // inform clients about these deleted contacts |
|
899 emit contactsRemoved(removedContacts); |
|
900 } |
|
901 |
|
902 /*! |
|
903 Updates data in response to some contacts having been added |
|
904 and then notifies observers that the contacts have been added. |
|
905 */ |
|
906 void CntCache::addContacts(const QList<QContactLocalId> &addedContacts) |
|
907 { |
|
908 // add the new contacts to the name cache and to the |
|
909 // list of sorted names |
|
910 foreach (QContactLocalId contactId, addedContacts) { |
|
911 CntNameCacheItem *item = mNameFetcher->readOneName(contactId); |
|
912 if (item != NULL) { |
|
913 mNameCache.insert(contactId, item); |
|
914 QList<CntNameCacheItem*>::iterator i = qUpperBound(mSortedNames.begin(), mSortedNames.end(), item, CntNameFetcher::compareNames); |
|
915 mSortedNames.insert(i, item); |
|
916 mHasModifiedNames = true; |
|
917 } |
|
918 } |
|
919 |
|
920 // inform clients about the new contacts |
|
921 emit contactsAdded(addedContacts); |
|
922 } |
|
923 |
|
924 /*! |
|
925 Creates an empty CntContactInfo object. |
661 */ |
926 */ |
662 CntContactInfo::CntContactInfo() |
927 CntContactInfo::CntContactInfo() |
663 : d(new CntContactInfoData()) |
928 : d(new CntContactInfoData()) |
664 { |
929 { |
665 } |
930 } |
666 |
931 |
667 /*! |
932 /*! |
668 Creates an object with all info fields set. |
933 Creates a CntContactInfo object with all info fields set. |
669 */ |
934 */ |
670 CntContactInfo::CntContactInfo(int id, const QString& name, const QString& text, const HbIcon& icon1, const HbIcon& icon2) |
935 CntContactInfo::CntContactInfo(int id, const QString& name, const QString& text, const HbIcon& icon1, const HbIcon& icon2) |
671 : d(new CntContactInfoData()) |
936 : d(new CntContactInfoData()) |
672 { |
937 { |
673 d->id = id; |
938 d->id = id; |