phonebookengines/cntlistmodel/src/cntcache.cpp
branchRCL_3
changeset 62 5b6f26637ad3
equal deleted inserted replaced
58:d4f567ce2e7c 62:5b6f26637ad3
       
     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