|
1 /* |
|
2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Class for asynchronously fetching and caching basic |
|
15 * contact info (see CntContactInfo) for list views. |
|
16 * |
|
17 */ |
|
18 |
|
19 #include <hbapplication.h> |
|
20 #include <qtcontacts.h> |
|
21 #include <qcontactmanager.h> |
|
22 #include <cntdebug.h> |
|
23 #include "cntcache.h" |
|
24 #include "cntcache_p.h" |
|
25 #include "cntinfoprovider.h" |
|
26 |
|
27 // set the singleton instance pointer to NULL |
|
28 CntCache* CntCache::mInstance = NULL; |
|
29 |
|
30 // value for first cache order to be assigned |
|
31 static const int CacheOrderStartValue = 1; |
|
32 // for avoiding wrap around with cache orders |
|
33 static const int MaxCacheOrderValue = 10000000; |
|
34 // number of items to read quickly when a new instance is requested or cache is cleared |
|
35 static const int ItemsToReadUrgently = 12; |
|
36 // number of items to read ahead into cache; this number is for one direction |
|
37 static const int ItemsToCacheAhead = 24; |
|
38 // cache size for info items (name, text, icon1name, icon2name) |
|
39 static const int InfoCacheSize = 128; |
|
40 // cache size for icon items (iconName and HbIcon) |
|
41 static const int IconCacheSize = 50; |
|
42 // number of icons in a CntContactInfo object |
|
43 static const int IconsInCntContactInfo = 2; |
|
44 // default empty text info field for a contact; it cannot be empty |
|
45 // as the listview will then ignore it, causing rendering problems |
|
46 static const QString EmptyTextField = " "; |
|
47 |
|
48 /*! |
|
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 mInstance = NULL; |
|
96 |
|
97 CNT_EXIT |
|
98 } |
|
99 |
|
100 /*! |
|
101 Provides a pointer to the CntCache singleton instance. |
|
102 */ |
|
103 CntCache* CntCache::instance() |
|
104 { |
|
105 if (mInstance == NULL) { |
|
106 mInstance = new CntCache(); |
|
107 } |
|
108 |
|
109 // whenever a client requests an instance the client will want to get all info |
|
110 // for the first couple of contacts (~a screenfull) as fast as possible |
|
111 mInstance->mUrgentContacts = ItemsToReadUrgently; |
|
112 |
|
113 return mInstance; |
|
114 } |
|
115 |
|
116 /*! |
|
117 Fetches information about a contact: name, text (e.g. phone number or |
|
118 social status) and two icons (e.g. avatar, presence). Previously cached |
|
119 content - at the very least the name - will be returned immediately. |
|
120 Availability of more information will be checked asynchronously and |
|
121 sent to clients via contactInfoUpdated() signals. |
|
122 |
|
123 The function takes a row and a list rather than just a contact id because |
|
124 of read ahead caching - contacts near the requested contacts are expected |
|
125 to be needed soon and are therefore also scheduled for caching. |
|
126 |
|
127 \param row the row of the contact to fetch |
|
128 \param idList a list with all the IDs in the list |
|
129 \return a contact with some details filled in |
|
130 */ |
|
131 CntContactInfo CntCache::fetchContactInfo(int row, const QList<QContactLocalId>& idList) |
|
132 { |
|
133 CNT_ENTRY_ARGS(row << "/" << idList.count()) |
|
134 |
|
135 Q_ASSERT(row >= 0 && row < idList.count()); |
|
136 |
|
137 QString name; |
|
138 QString text = EmptyTextField; |
|
139 HbIcon icons[IconsInCntContactInfo]; |
|
140 |
|
141 int contactId = idList.at(row); |
|
142 |
|
143 if (contactId != mEmittedContactId) { |
|
144 // this request comes from the UI when a new view is created or in response to |
|
145 // some scrolling activity; in the former case, the client should |
|
146 // have set urgencymode on, but in the latter case: |
|
147 // 1) postpone all jobs so the UI can use as much of the CPU as possible |
|
148 // 2) update read ahead cache to contain all IDs of all items near this item |
|
149 if (mUrgentContacts > 0) { |
|
150 --mUrgentContacts; |
|
151 } |
|
152 else { |
|
153 mWorker->postponeJobs(); |
|
154 } |
|
155 updateReadAheadCache(row, idList); |
|
156 } |
|
157 |
|
158 // fetch contact |
|
159 if (mInfoCache.contains(contactId)) { |
|
160 // the item is in the cache |
|
161 CntInfoCacheItem* infoItem = mInfoCache.value(contactId); |
|
162 for (int i = 0; i < IconsInCntContactInfo; ++i) { |
|
163 QString iconName = infoItem->icons[i]; |
|
164 if (!iconName.isEmpty()) { |
|
165 if (mIconCache.contains(iconName)) { |
|
166 CntIconCacheItem* iconItem = mIconCache.value(iconName); |
|
167 iconItem->cacheOrder = mNextIconCacheOrder++; |
|
168 icons[i] = iconItem->icon; |
|
169 if (!iconItem->isFetched) { |
|
170 // if icon has not yet been received from backend, add |
|
171 // this id to the list of contacts that want to be |
|
172 // notified when the icon is received |
|
173 iconItem->contactIds.insert(contactId); |
|
174 // also reschedule it |
|
175 mWorker->scheduleIconJob(iconName, row); |
|
176 } |
|
177 } |
|
178 else { |
|
179 // needed icon is not in cache, so schedule it for retrieval |
|
180 CntIconCacheItem* iconItem = createIconCacheItem(iconName); |
|
181 iconItem->contactIds.insert(contactId); |
|
182 mWorker->scheduleIconJob(iconName, row); |
|
183 } |
|
184 } |
|
185 } |
|
186 |
|
187 // update cache order |
|
188 infoItem->cacheOrder = mNextInfoCacheOrder++; |
|
189 infoItem->latestRow = row; |
|
190 |
|
191 name = infoItem->name; |
|
192 text = infoItem->text; |
|
193 } |
|
194 else { |
|
195 // the item is not in cache, so fetch the name and schedule the rest |
|
196 // of the info for retrieval |
|
197 if (fetchContactName(contactId, name)) { |
|
198 // contact found, so add new entry to cache |
|
199 CntInfoCacheItem* item = createInfoCacheItem(contactId); |
|
200 item->name = name; |
|
201 item->text = text; |
|
202 item->latestRow = row; |
|
203 |
|
204 // ask the worker thread to fetch the information asynchronously |
|
205 mWorker->scheduleInfoJob(contactId, row); |
|
206 } |
|
207 } |
|
208 |
|
209 CNT_EXIT_ARGS("name:" << name << "sec:" << text) |
|
210 |
|
211 return CntContactInfo(contactId, name, text, icons[0], icons[1]); |
|
212 } |
|
213 |
|
214 /*! |
|
215 Clears the cache of names (not icons). This function can be useful |
|
216 for example when the format of contact names changes. |
|
217 */ |
|
218 void CntCache::clearCache() |
|
219 { |
|
220 CNT_ENTRY |
|
221 |
|
222 // clear info cache |
|
223 qDeleteAll(mInfoCache); |
|
224 mInfoCache.clear(); |
|
225 mNextInfoCacheOrder = CacheOrderStartValue; |
|
226 mUrgentContacts = ItemsToReadUrgently; |
|
227 |
|
228 CNT_EXIT |
|
229 } |
|
230 |
|
231 /*! |
|
232 Processes a new info field that has arrived from the worker thread. |
|
233 If the contact is in the info cache, then the info cache is updated |
|
234 accordingly. |
|
235 |
|
236 A contactInfoUpdated() signal is usually also emitted. The exception |
|
237 is if the info is the name of an icon and that icon is not in the icon |
|
238 cache. In this case the icon is fetched before a signal is emitted. |
|
239 */ |
|
240 void CntCache::onNewInfo(int contactId, const ContactInfoField& infoField, const QString& infoValue) |
|
241 { |
|
242 CNT_ENTRY_ARGS( "id:" << contactId << "infotype:" << infoField << "infovalue:" << infoValue ) |
|
243 |
|
244 Q_ASSERT(infoField == ContactInfoTextField || infoField == ContactInfoIcon1Field || infoField == ContactInfoIcon2Field); |
|
245 |
|
246 bool hasNewInfo; |
|
247 |
|
248 if (!mInfoCache.contains(contactId)) { |
|
249 // contact is not in cache, so nothing needs to be done |
|
250 // except notify clients that this contact has (possibly) |
|
251 // been changed |
|
252 hasNewInfo = true; |
|
253 } |
|
254 else if (infoField == ContactInfoTextField) { |
|
255 // update cache with new text for contact |
|
256 mInfoCache.value(contactId)->text = infoValue; |
|
257 hasNewInfo = true; |
|
258 } |
|
259 else { |
|
260 // update cache with new icon name for contact |
|
261 int iconIndex = (infoField == ContactInfoIcon1Field ? 0 : 1); |
|
262 |
|
263 CntInfoCacheItem* item = mInfoCache.value(contactId); |
|
264 QString iconName = infoValue; |
|
265 if (item->icons[iconIndex] != iconName) { |
|
266 item->icons[iconIndex] = iconName; |
|
267 if (iconName.isEmpty()) { |
|
268 hasNewInfo = true; |
|
269 } |
|
270 else if (mIconCache.contains(iconName)) { |
|
271 CntIconCacheItem* iconItem = mIconCache.value(iconName); |
|
272 if (!iconItem->isFetched) { |
|
273 iconItem->contactIds.insert(contactId); |
|
274 hasNewInfo = false; |
|
275 } |
|
276 else { |
|
277 hasNewInfo = true; |
|
278 } |
|
279 } |
|
280 else if (iconName.startsWith("qtg_", Qt::CaseInsensitive)) { |
|
281 createIconCacheItem(iconName); |
|
282 onNewIcon(iconName, HbIcon(iconName)); |
|
283 hasNewInfo = true; |
|
284 } |
|
285 else { |
|
286 CntIconCacheItem* iconItem = createIconCacheItem(iconName); |
|
287 iconItem->contactIds.insert(contactId); |
|
288 if (mInfoCache.contains(contactId)) { |
|
289 mWorker->scheduleIconJob(iconName, mInfoCache.value(contactId)->latestRow); |
|
290 } |
|
291 else { |
|
292 // less important icon, since this contact is not in cache |
|
293 mWorker->scheduleIconJob(iconName, 100000); |
|
294 } |
|
295 hasNewInfo = false; |
|
296 } |
|
297 } |
|
298 else { |
|
299 hasNewInfo = false; |
|
300 } |
|
301 } |
|
302 |
|
303 if (hasNewInfo) { |
|
304 emitContactInfoUpdated(contactId); |
|
305 } |
|
306 |
|
307 CNT_EXIT |
|
308 } |
|
309 |
|
310 /*! |
|
311 Handle the case where a request for contact info is cancelled by the |
|
312 worker because of too many subsequent requests. |
|
313 */ |
|
314 void CntCache::onInfoCancelled(int contactId) |
|
315 { |
|
316 CNT_ENTRY_ARGS( "id:" << contactId ) |
|
317 |
|
318 if (mInfoCache.contains(contactId)) { |
|
319 CntInfoCacheItem* item = mInfoCache.take(contactId); |
|
320 delete item; |
|
321 } |
|
322 |
|
323 emitContactInfoUpdated(contactId); |
|
324 |
|
325 CNT_EXIT |
|
326 } |
|
327 |
|
328 /*! |
|
329 Processes a new icon that has arrived from the worker thread. |
|
330 The icon cache is updated and a contactInfoUpdated() signal is |
|
331 emitted for all contacts that use this icon. |
|
332 */ |
|
333 void CntCache::onNewIcon(const QString& iconName, const HbIcon& icon) |
|
334 { |
|
335 CNT_ENTRY_ARGS( iconName ) |
|
336 |
|
337 QSet<int> contactsToNotify; |
|
338 |
|
339 if (mIconCache.contains(iconName)) { |
|
340 CntIconCacheItem* item = mIconCache.value(iconName); |
|
341 item->icon = icon; |
|
342 item->isFetched = true; |
|
343 contactsToNotify = item->contactIds; |
|
344 item->contactIds.clear(); |
|
345 } |
|
346 |
|
347 foreach (int contactId, contactsToNotify) { |
|
348 emitContactInfoUpdated(contactId); |
|
349 } |
|
350 |
|
351 CNT_EXIT |
|
352 } |
|
353 |
|
354 /*! |
|
355 Handle the case where a request for an icon is cancelled by the worker because |
|
356 of too many subsequent requests. |
|
357 */ |
|
358 void CntCache::onIconCancelled(const QString& iconName) |
|
359 { |
|
360 CNT_ENTRY_ARGS( iconName ) |
|
361 |
|
362 QSet<int> contactsToNotify; |
|
363 |
|
364 if (mIconCache.contains(iconName)) { |
|
365 CntIconCacheItem* item = mIconCache.take(iconName); |
|
366 contactsToNotify = item->contactIds; |
|
367 item->contactIds.clear(); |
|
368 delete item; |
|
369 } |
|
370 |
|
371 foreach (int contactId, contactsToNotify) { |
|
372 emitContactInfoUpdated(contactId); |
|
373 } |
|
374 |
|
375 CNT_EXIT |
|
376 } |
|
377 |
|
378 /*! |
|
379 Update contacts in cache. |
|
380 |
|
381 /param contactIds ids of the contact that will be updated |
|
382 */ |
|
383 void CntCache::updateContactsInCache(const QList<QContactLocalId>& contactIds) |
|
384 { |
|
385 CNT_ENTRY |
|
386 |
|
387 QString name; |
|
388 |
|
389 foreach (QContactLocalId contactId, contactIds) { |
|
390 if (mInfoCache.contains(contactId) && fetchContactName(contactId, name)) { |
|
391 CntInfoCacheItem* infoItem = mInfoCache.value(contactId); |
|
392 infoItem->name = name; |
|
393 mWorker->scheduleInfoJob(contactId, infoItem->latestRow); |
|
394 } |
|
395 } |
|
396 |
|
397 foreach (QContactLocalId contactId, contactIds) { |
|
398 emitContactInfoUpdated(contactId); |
|
399 } |
|
400 |
|
401 CNT_EXIT |
|
402 } |
|
403 |
|
404 /*! |
|
405 Removes contacts from cache. |
|
406 |
|
407 /param contactIds ids of the contact that will be removed |
|
408 */ |
|
409 void CntCache::removeContactsFromCache(const QList<QContactLocalId>& contactIds) |
|
410 { |
|
411 CNT_ENTRY |
|
412 |
|
413 foreach (QContactLocalId contactId, contactIds) { |
|
414 if (mInfoCache.contains(contactId)) { |
|
415 CntInfoCacheItem* item = mInfoCache.take(contactId); |
|
416 delete item; |
|
417 } |
|
418 } |
|
419 |
|
420 foreach (QContactLocalId contactId, contactIds) { |
|
421 emitContactInfoUpdated(contactId); |
|
422 } |
|
423 |
|
424 CNT_EXIT |
|
425 } |
|
426 |
|
427 /*! |
|
428 Uses an optimized function to fetch the name of a contact from |
|
429 the database. |
|
430 |
|
431 /param contactId the id of the contact to fetch |
|
432 /param contactName the name will be stored here if the function is successful |
|
433 /return true if the name was fetched successfully |
|
434 */ |
|
435 bool CntCache::fetchContactName(int contactId, QString& contactName) |
|
436 { |
|
437 CNT_ENTRY_ARGS( contactId ) |
|
438 |
|
439 bool foundContact = false; |
|
440 |
|
441 QContactFetchHint nameOnlyFetchHint; |
|
442 /*QStringList details; |
|
443 details << QContactDisplayLabel::DefinitionName; |
|
444 nameOnlyFetchHint.setDetailDefinitionsHint(details);*/ |
|
445 nameOnlyFetchHint.setOptimizationHints(QContactFetchHint::NoRelationships); |
|
446 QContact contact = mContactManager->contact(contactId, nameOnlyFetchHint); |
|
447 |
|
448 if (mContactManager->error() == QContactManager::NoError) { |
|
449 contactName = contact.displayLabel(); |
|
450 foundContact = true; |
|
451 } |
|
452 |
|
453 CNT_EXIT_ARGS( foundContact ) |
|
454 |
|
455 return foundContact; |
|
456 } |
|
457 |
|
458 /*! |
|
459 Collects all contact IDs near the latest fetch from the UI. These will be fetched and |
|
460 precached when UI activity slows down. |
|
461 |
|
462 \param mostRecentRow the row of the contact that was most recently fetched |
|
463 \param idList a list with all the IDs in the list |
|
464 */ |
|
465 void CntCache::updateReadAheadCache(int mostRecentRow, const QList<QContactLocalId>& idList) |
|
466 { |
|
467 CNT_ENTRY_ARGS( mostRecentRow ) |
|
468 |
|
469 int row; |
|
470 |
|
471 mReadAheadCache.clear(); |
|
472 |
|
473 // step through the area near to last fetch item and make sure all |
|
474 // contacts in it are also in cache or in the read ahead list |
|
475 for (int i = 1; i <= ItemsToCacheAhead; ++i) { |
|
476 for (int j = 0; j < 2; ++j) { |
|
477 if (j == 0) { |
|
478 row = mostRecentRow - i; |
|
479 if (row <= 0) { |
|
480 continue; |
|
481 } |
|
482 } |
|
483 else { |
|
484 row = mostRecentRow + i; |
|
485 if (row >= idList.count()) { |
|
486 continue; |
|
487 } |
|
488 } |
|
489 |
|
490 int contactId = idList.at(row); |
|
491 if (!mInfoCache.contains(contactId)) { |
|
492 // contact is not in cache, so put the id to items to read into cache |
|
493 mReadAheadCache.append(QPair<int,int>(contactId,row)); |
|
494 } |
|
495 else { |
|
496 // contact is in cache; update cache order as we want to keep this item in cache |
|
497 mInfoCache.value(contactId)->cacheOrder = mNextInfoCacheOrder++; |
|
498 } |
|
499 } |
|
500 } |
|
501 |
|
502 CNT_EXIT |
|
503 } |
|
504 |
|
505 /*! |
|
506 Schedules one uncached item in the read-ahead list for retrieval. |
|
507 */ |
|
508 void CntCache::scheduleOneReadAheadItem() |
|
509 { |
|
510 CNT_ENTRY |
|
511 |
|
512 QString name; |
|
513 |
|
514 // pick the first contact from the read ahead cache and schedule it |
|
515 while (mReadAheadCache.count() > 0) { |
|
516 int contactId = mReadAheadCache.first().first; |
|
517 int contactRow = mReadAheadCache.takeFirst().second; |
|
518 if (!mInfoCache.contains(contactId)) { |
|
519 // contact is not in cache, so schedule it for retreival |
|
520 if (fetchContactName(contactId, name)) { |
|
521 // contact found, so add new entry to cache |
|
522 CntInfoCacheItem* item = createInfoCacheItem(contactId); |
|
523 item->name = name; |
|
524 item->text = EmptyTextField; |
|
525 item->latestRow = contactRow; |
|
526 |
|
527 // schedule the info for retrieval |
|
528 mWorker->scheduleInfoJob(contactId, contactRow); |
|
529 break; |
|
530 } |
|
531 } |
|
532 } |
|
533 |
|
534 CNT_EXIT |
|
535 } |
|
536 |
|
537 /*! |
|
538 Creates a new item in the info cache. If the cache is full, |
|
539 then the least recently accessed item is removed from cache. |
|
540 |
|
541 /param contactId id of contact for which to create the new cache item |
|
542 /return the newly created cache item |
|
543 */ |
|
544 CntInfoCacheItem* CntCache::createInfoCacheItem(int contactId) |
|
545 { |
|
546 CNT_ENTRY_ARGS( contactId ) |
|
547 |
|
548 if (mInfoCache.count() >= InfoCacheSize) { |
|
549 // cache is full, so remove the oldest contact |
|
550 int minCacheOrder = mNextInfoCacheOrder; |
|
551 CntInfoCacheItem* oldestItem = NULL; |
|
552 foreach (CntInfoCacheItem* i, mInfoCache) { |
|
553 if (i->cacheOrder < minCacheOrder) { |
|
554 minCacheOrder = i->cacheOrder; |
|
555 oldestItem = i; |
|
556 } |
|
557 } |
|
558 |
|
559 if (oldestItem) { |
|
560 mInfoCache.remove(oldestItem->contactId); |
|
561 delete oldestItem; |
|
562 } |
|
563 |
|
564 // cache maintenance: if the cache ids become too large, |
|
565 // reduce all of them by MaxCacheOrderValue |
|
566 if (mNextInfoCacheOrder >= MaxCacheOrderValue) { |
|
567 mNextInfoCacheOrder -= MaxCacheOrderValue; |
|
568 foreach (CntInfoCacheItem* i, mInfoCache) { |
|
569 i->cacheOrder -= MaxCacheOrderValue; |
|
570 } |
|
571 } |
|
572 } |
|
573 |
|
574 // create and insert the new item |
|
575 CntInfoCacheItem* item = new CntInfoCacheItem(); |
|
576 item->cacheOrder = mNextInfoCacheOrder++; |
|
577 item->contactId = contactId; |
|
578 mInfoCache.insert(contactId, item); |
|
579 |
|
580 CNT_EXIT |
|
581 |
|
582 return item; |
|
583 } |
|
584 |
|
585 /*! |
|
586 Creates a new item in the icon cache. If the cache is full, |
|
587 then the least recently accessed item is removed from cache. |
|
588 |
|
589 /param iconName name of the icon for which to create the new cache item |
|
590 /return the newly created cache item |
|
591 */ |
|
592 CntIconCacheItem* CntCache::createIconCacheItem(const QString& iconName) |
|
593 { |
|
594 CNT_ENTRY_ARGS( iconName ) |
|
595 |
|
596 if (mIconCache.count() >= IconCacheSize) { |
|
597 // cache is full, so remove the oldest icon |
|
598 int minCacheOrder = mNextIconCacheOrder; |
|
599 CntIconCacheItem* oldestItem = NULL; |
|
600 foreach (CntIconCacheItem* i, mIconCache) { |
|
601 if (i->cacheOrder < minCacheOrder) { |
|
602 minCacheOrder = i->cacheOrder; |
|
603 oldestItem = i; |
|
604 } |
|
605 } |
|
606 mIconCache.remove(oldestItem->iconName); |
|
607 delete oldestItem; |
|
608 |
|
609 // cache maintenance: if the cache orders become too large, |
|
610 // reduce all of them by MaxCacheOrderValue |
|
611 if (mNextIconCacheOrder >= MaxCacheOrderValue) { |
|
612 mNextIconCacheOrder -= MaxCacheOrderValue; |
|
613 foreach (CntIconCacheItem* i, mIconCache) { |
|
614 i->cacheOrder -= MaxCacheOrderValue; |
|
615 } |
|
616 } |
|
617 } |
|
618 |
|
619 // create and insert the new item |
|
620 CntIconCacheItem* item = new CntIconCacheItem(); |
|
621 item->cacheOrder = mNextIconCacheOrder++; |
|
622 item->iconName = iconName; |
|
623 item->isFetched = false; |
|
624 mIconCache.insert(iconName, item); |
|
625 |
|
626 CNT_EXIT |
|
627 |
|
628 return item; |
|
629 } |
|
630 |
|
631 /*! |
|
632 Notifies clients that a contact might have changed. |
|
633 Clients can then request the info via fetchContactInfo() |
|
634 if they are interested. |
|
635 */ |
|
636 void CntCache::emitContactInfoUpdated(int contactId) |
|
637 { |
|
638 CNT_ENTRY_ARGS( contactId ) |
|
639 |
|
640 mEmittedContactId = contactId; |
|
641 emit contactInfoUpdated(contactId); |
|
642 mEmittedContactId = -1; |
|
643 |
|
644 CNT_EXIT |
|
645 } |
|
646 |
|
647 /*! |
|
648 Deletes the cache. |
|
649 */ |
|
650 void CntCache::onShutdown() |
|
651 { |
|
652 CNT_ENTRY |
|
653 |
|
654 deleteLater(); |
|
655 |
|
656 CNT_EXIT |
|
657 } |
|
658 |
|
659 |
|
660 /*! |
|
661 Creates an empty object. |
|
662 */ |
|
663 CntContactInfo::CntContactInfo() |
|
664 : d(new CntContactInfoData()) |
|
665 { |
|
666 } |
|
667 |
|
668 /*! |
|
669 Creates an object with all info fields set. |
|
670 */ |
|
671 CntContactInfo::CntContactInfo(int id, const QString& name, const QString& text, const HbIcon& icon1, const HbIcon& icon2) |
|
672 : d(new CntContactInfoData()) |
|
673 { |
|
674 d->id = id; |
|
675 d->name = name; |
|
676 d->text = text; |
|
677 d->icon1 = icon1; |
|
678 d->icon2 = icon2; |
|
679 } |
|
680 |
|
681 /*! |
|
682 Destroys the object. |
|
683 */ |
|
684 CntContactInfo::~CntContactInfo() |
|
685 { |
|
686 } |
|
687 |
|
688 /*! |
|
689 Copy constructor. |
|
690 */ |
|
691 CntContactInfo::CntContactInfo(const CntContactInfo& other) |
|
692 : d(other.d) |
|
693 { |
|
694 } |
|
695 |
|
696 /*! |
|
697 Assignment operator. |
|
698 */ |
|
699 CntContactInfo& CntContactInfo::operator=(const CntContactInfo& other) |
|
700 { |
|
701 d = other.d; |
|
702 return *this; |
|
703 } |
|
704 |
|
705 /*! |
|
706 Getter function for the id. |
|
707 */ |
|
708 int CntContactInfo::id() const |
|
709 { |
|
710 return d->id; |
|
711 } |
|
712 |
|
713 /*! |
|
714 Getter function for the name. |
|
715 */ |
|
716 QString CntContactInfo::name() const |
|
717 { |
|
718 return d->name; |
|
719 } |
|
720 |
|
721 /*! |
|
722 Getter function for the text. |
|
723 */ |
|
724 QString CntContactInfo::text() const |
|
725 { |
|
726 return d->text; |
|
727 } |
|
728 |
|
729 /*! |
|
730 Getter function for the first icon. |
|
731 */ |
|
732 HbIcon CntContactInfo::icon1() const |
|
733 { |
|
734 return d->icon1; |
|
735 } |
|
736 |
|
737 /*! |
|
738 Getter function for the second icon. |
|
739 */ |
|
740 HbIcon CntContactInfo::icon2() const |
|
741 { |
|
742 return d->icon2; |
|
743 } |
|
744 |