phonebookui/cntlistmodel/cntcache.cpp
author hgs
Fri, 15 Oct 2010 12:24:46 +0300
changeset 81 640d30f4fb64
permissions -rw-r--r--
201041
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
81
hgs
parents:
diff changeset
     1
/*
hgs
parents:
diff changeset
     2
* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
hgs
parents:
diff changeset
     3
* All rights reserved.
hgs
parents:
diff changeset
     4
* This component and the accompanying materials are made available
hgs
parents:
diff changeset
     5
* under the terms of "Eclipse Public License v1.0"
hgs
parents:
diff changeset
     6
* which accompanies this distribution, and is available
hgs
parents:
diff changeset
     7
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
hgs
parents:
diff changeset
     8
*
hgs
parents:
diff changeset
     9
* Initial Contributors:
hgs
parents:
diff changeset
    10
* Nokia Corporation - initial contribution.
hgs
parents:
diff changeset
    11
*
hgs
parents:
diff changeset
    12
* Contributors:
hgs
parents:
diff changeset
    13
*
hgs
parents:
diff changeset
    14
* Description: Asynchronously fetches and caches basic contact info
hgs
parents:
diff changeset
    15
*              and icons.
hgs
parents:
diff changeset
    16
*
hgs
parents:
diff changeset
    17
*/
hgs
parents:
diff changeset
    18
hgs
parents:
diff changeset
    19
#include <hbapplication.h>
hgs
parents:
diff changeset
    20
#include <qtcontacts.h>
hgs
parents:
diff changeset
    21
#include <qcontactmanager.h>
hgs
parents:
diff changeset
    22
#include <QTimer>
hgs
parents:
diff changeset
    23
#include <cntcache.h>
hgs
parents:
diff changeset
    24
#include <cntcacheitems.h>
hgs
parents:
diff changeset
    25
#include <cntnamefetcher.h>
hgs
parents:
diff changeset
    26
#include <cntinfofetcher.h>
hgs
parents:
diff changeset
    27
#include <cnticonfetcher.h>
hgs
parents:
diff changeset
    28
#include <cntdebug.h>
hgs
parents:
diff changeset
    29
hgs
parents:
diff changeset
    30
/*!
hgs
parents:
diff changeset
    31
    \class CntContactInfo
hgs
parents:
diff changeset
    32
    \brief Info about one contact, intended for list views.
hgs
parents:
diff changeset
    33
hgs
parents:
diff changeset
    34
   This class contains info about one contact. The info is mainly intended
hgs
parents:
diff changeset
    35
   to be used in list views:
hgs
parents:
diff changeset
    36
     - name: the name of the contact, formatted for displaying
hgs
parents:
diff changeset
    37
     - text: secondary information like a phone number
hgs
parents:
diff changeset
    38
     - icon1: the main icon
hgs
parents:
diff changeset
    39
     - icon2: the smaller secondary icon
hgs
parents:
diff changeset
    40
hgs
parents:
diff changeset
    41
    \class CntCache
hgs
parents:
diff changeset
    42
    \brief Asynchronously fetches contact info and icons.
hgs
parents:
diff changeset
    43
hgs
parents:
diff changeset
    44
    Singleton class that acts as a proxy to get CntContactInfo objects for
hgs
parents:
diff changeset
    45
    contacts. It also implements caching for faster access. This is why the
hgs
parents:
diff changeset
    46
    fetchContactInfo() function takes a row number and the full list of
hgs
parents:
diff changeset
    47
    contact IDs rather than just a contact ID -- it allows precaching.
hgs
parents:
diff changeset
    48
hgs
parents:
diff changeset
    49
    The usage pattern for clients is to call fetchContactInfo() to get at
hgs
parents:
diff changeset
    50
    least the name of the contact. If all the info is cached then it will be
hgs
parents:
diff changeset
    51
    provided. If not, then the uncached info is fetched asynchronously and
hgs
parents:
diff changeset
    52
    contactInfoUpdated() signals are emitted as the pieces of information
hgs
parents:
diff changeset
    53
    arrive -- up to three times per contact; once for text, once for icon1
hgs
parents:
diff changeset
    54
    and once for icon2.
hgs
parents:
diff changeset
    55
hgs
parents:
diff changeset
    56
    Internally CntCache uses three fetchers; one for names, one for info and
hgs
parents:
diff changeset
    57
    one for icons.
hgs
parents:
diff changeset
    58
 */
hgs
parents:
diff changeset
    59
hgs
parents:
diff changeset
    60
// set the singleton instance pointer to NULL
hgs
parents:
diff changeset
    61
CntCache* CntCache::mInstance = NULL;
hgs
parents:
diff changeset
    62
hgs
parents:
diff changeset
    63
// the event for starting to process all outstanding jobs
hgs
parents:
diff changeset
    64
const QEvent::Type ProcessJobsEvent = QEvent::User;
hgs
parents:
diff changeset
    65
hgs
parents:
diff changeset
    66
// different states of postponement 
hgs
parents:
diff changeset
    67
const int JobsNotPostponed = 0;
hgs
parents:
diff changeset
    68
const int JobsPostponedForDuration = 1;
hgs
parents:
diff changeset
    69
const int JobsPostponedUntilResume = 2;
hgs
parents:
diff changeset
    70
hgs
parents:
diff changeset
    71
// number of items to read ahead into cache; this number is for one direction
hgs
parents:
diff changeset
    72
const int ItemsToCacheAhead = 24;
hgs
parents:
diff changeset
    73
hgs
parents:
diff changeset
    74
// cache size for info items
hgs
parents:
diff changeset
    75
const int InfoCacheSize = 128;
hgs
parents:
diff changeset
    76
hgs
parents:
diff changeset
    77
// cache size for icon items; must be larger than 2 * ItemsToCacheAhead
hgs
parents:
diff changeset
    78
const int IconCacheSize = 60;
hgs
parents:
diff changeset
    79
hgs
parents:
diff changeset
    80
// duration of urgency mode in milliseconds
hgs
parents:
diff changeset
    81
const int UrgencyModeDuration = 100;
hgs
parents:
diff changeset
    82
hgs
parents:
diff changeset
    83
// duration of a postponement in milliseconds
hgs
parents:
diff changeset
    84
const int PostponeJobsDuration = 300;
hgs
parents:
diff changeset
    85
hgs
parents:
diff changeset
    86
// number of icons in a CntContactInfo object
hgs
parents:
diff changeset
    87
const int IconsInCntContactInfo = 2;
hgs
parents:
diff changeset
    88
hgs
parents:
diff changeset
    89
// default empty text info field for a contact; it cannot be empty
hgs
parents:
diff changeset
    90
// as the listview will then ignore it, causing rendering problems
hgs
parents:
diff changeset
    91
const QString EmptyTextField = " ";
hgs
parents:
diff changeset
    92
hgs
parents:
diff changeset
    93
/*!
hgs
parents:
diff changeset
    94
    Provides a pointer to the CntCache singleton instance.
hgs
parents:
diff changeset
    95
    
hgs
parents:
diff changeset
    96
    \param client a pointer to the client
hgs
parents:
diff changeset
    97
    \param manager  
hgs
parents:
diff changeset
    98
 */
hgs
parents:
diff changeset
    99
CntCache* CntCache::createSession(void *client, QContactManager *manager)
hgs
parents:
diff changeset
   100
{
hgs
parents:
diff changeset
   101
	CNT_STATIC_ENTRY_ARGS("client =" << client << ", mngr =" << (void*) manager)
hgs
parents:
diff changeset
   102
hgs
parents:
diff changeset
   103
    if (!mInstance) {
hgs
parents:
diff changeset
   104
        mInstance = new CntCache(manager);
hgs
parents:
diff changeset
   105
    }
hgs
parents:
diff changeset
   106
hgs
parents:
diff changeset
   107
    // increase reference counter for cache clients
hgs
parents:
diff changeset
   108
    mInstance->mClients.insert(client);
hgs
parents:
diff changeset
   109
hgs
parents:
diff changeset
   110
    // whenever a client requests an instance, the client will want to get all info
hgs
parents:
diff changeset
   111
    // for the first screenful of contacts urgently
hgs
parents:
diff changeset
   112
    mInstance->startUrgencyMode();
hgs
parents:
diff changeset
   113
hgs
parents:
diff changeset
   114
	CNT_EXIT_ARGS("instance =" << (void*) mInstance << ", refCount =" << mInstance->mClients.count())
hgs
parents:
diff changeset
   115
hgs
parents:
diff changeset
   116
    return mInstance;
hgs
parents:
diff changeset
   117
}
hgs
parents:
diff changeset
   118
hgs
parents:
diff changeset
   119
/*!
hgs
parents:
diff changeset
   120
    Disconnects from CntCache.
hgs
parents:
diff changeset
   121
 */
hgs
parents:
diff changeset
   122
void CntCache::closeSession(void *client)
hgs
parents:
diff changeset
   123
{
hgs
parents:
diff changeset
   124
	CNT_ENTRY
hgs
parents:
diff changeset
   125
hgs
parents:
diff changeset
   126
    // delete singleton instance if there are no more clients
hgs
parents:
diff changeset
   127
    mInstance->mClients.remove(client);
hgs
parents:
diff changeset
   128
    if (mInstance->mClients.count() == 0) {
hgs
parents:
diff changeset
   129
    	CNT_LOG_ARGS("no more clients, so deleting singleton instance")
hgs
parents:
diff changeset
   130
        mInstance = NULL;
hgs
parents:
diff changeset
   131
        delete this;
hgs
parents:
diff changeset
   132
    }
hgs
parents:
diff changeset
   133
hgs
parents:
diff changeset
   134
	CNT_EXIT
hgs
parents:
diff changeset
   135
}
hgs
parents:
diff changeset
   136
hgs
parents:
diff changeset
   137
/*! 
hgs
parents:
diff changeset
   138
    Fetches visuals for a contact: name, text (e.g. phone number or social
hgs
parents:
diff changeset
   139
    status) and two icons (e.g. avatar, presence). Previously cached content,
hgs
parents:
diff changeset
   140
    at the very least the name, will be returned immediately. Availability of
hgs
parents:
diff changeset
   141
    more information will be checked asynchronously and sent to clients via
hgs
parents:
diff changeset
   142
    contactInfoUpdated() signals.
hgs
parents:
diff changeset
   143
    
hgs
parents:
diff changeset
   144
    The function takes a row and a list rather than just a contact ID because
hgs
parents:
diff changeset
   145
    of read ahead caching - contacts near the requested contacts are expected
hgs
parents:
diff changeset
   146
    to be needed soon and are therefore precached.
hgs
parents:
diff changeset
   147
    
hgs
parents:
diff changeset
   148
    \param row the row of the contact to fetch
hgs
parents:
diff changeset
   149
    \param idList a list with all the IDs in the list
hgs
parents:
diff changeset
   150
    \return a contact with some details filled in
hgs
parents:
diff changeset
   151
 */
hgs
parents:
diff changeset
   152
CntContactInfo* CntCache::fetchContactInfo(int row, const QList<QContactLocalId>& idList)
hgs
parents:
diff changeset
   153
{
hgs
parents:
diff changeset
   154
    CNT_ENTRY_ARGS(row << "/" << idList.count())
hgs
parents:
diff changeset
   155
hgs
parents:
diff changeset
   156
    Q_ASSERT(row >= 0 && row < idList.count());
hgs
parents:
diff changeset
   157
hgs
parents:
diff changeset
   158
    QString name;
hgs
parents:
diff changeset
   159
    QString text = EmptyTextField;
hgs
parents:
diff changeset
   160
    HbIcon icons[IconsInCntContactInfo];
hgs
parents:
diff changeset
   161
hgs
parents:
diff changeset
   162
    QContactLocalId contactId = idList.at(row);
hgs
parents:
diff changeset
   163
hgs
parents:
diff changeset
   164
    if (contactId != mLastEmittedContactId) {
hgs
parents:
diff changeset
   165
        // this is a new request from the UI (rather than a response to
hgs
parents:
diff changeset
   166
        // a change that the cache just emitted)
hgs
parents:
diff changeset
   167
        if (!mIsInUrgencyMode) {
hgs
parents:
diff changeset
   168
            postponeJobs(JobsPostponedForDuration, PostponeJobsDuration);
hgs
parents:
diff changeset
   169
        }
hgs
parents:
diff changeset
   170
        updateReadAheadCache(row, idList);
hgs
parents:
diff changeset
   171
    }
hgs
parents:
diff changeset
   172
hgs
parents:
diff changeset
   173
    // fetch the contact
hgs
parents:
diff changeset
   174
    if (mInfoCache.contains(contactId)) {
hgs
parents:
diff changeset
   175
        // the contact's info is cached
hgs
parents:
diff changeset
   176
        CntInfoCacheItem* infoItem = mInfoCache.value(contactId);
hgs
parents:
diff changeset
   177
        for (int i = 0; i < IconsInCntContactInfo; ++i) {
hgs
parents:
diff changeset
   178
            QString iconName = infoItem->icons[i];
hgs
parents:
diff changeset
   179
            if (!iconName.isEmpty()) {
hgs
parents:
diff changeset
   180
                if (mIconCache.contains(iconName)) {
hgs
parents:
diff changeset
   181
                    CntIconCacheItem* iconItem = mIconCache.value(iconName);
hgs
parents:
diff changeset
   182
                    if (iconItem->requestedBy.count() > 0) {
hgs
parents:
diff changeset
   183
                    // icon is being fetched -> add this contact to list of requestors
hgs
parents:
diff changeset
   184
                        iconItem->requestedBy << contactId;
hgs
parents:
diff changeset
   185
                    }
hgs
parents:
diff changeset
   186
                    iconItem->lastRequest = QTime::currentTime();
hgs
parents:
diff changeset
   187
                    icons[i] = iconItem->icon;
hgs
parents:
diff changeset
   188
                } else {
hgs
parents:
diff changeset
   189
                    // needed icon is not in cache, so schedule it for retrieval
hgs
parents:
diff changeset
   190
                    CntIconCacheItem* iconItem = createIconCacheItem(iconName);
hgs
parents:
diff changeset
   191
                    iconItem->requestedBy << contactId;
hgs
parents:
diff changeset
   192
                    mIconFetcher->scheduleJob(new CntIconJob(iconName), row);
hgs
parents:
diff changeset
   193
                }
hgs
parents:
diff changeset
   194
            }
hgs
parents:
diff changeset
   195
        }
hgs
parents:
diff changeset
   196
hgs
parents:
diff changeset
   197
        // set return text
hgs
parents:
diff changeset
   198
        text = infoItem->text;
hgs
parents:
diff changeset
   199
hgs
parents:
diff changeset
   200
        // update cache order
hgs
parents:
diff changeset
   201
        infoItem->lastRequest = QTime::currentTime();
hgs
parents:
diff changeset
   202
    } else if (contactExists(contactId)) {
hgs
parents:
diff changeset
   203
        // contact exists but info is not in cache, so schedule it for retrieval
hgs
parents:
diff changeset
   204
        CntInfoCacheItem* item = createInfoCacheItem(contactId);
hgs
parents:
diff changeset
   205
        item->text = text;
hgs
parents:
diff changeset
   206
        mInfoFetcher->scheduleJob(new CntInfoJob(contactId), row);
hgs
parents:
diff changeset
   207
    } else {
hgs
parents:
diff changeset
   208
        return NULL;
hgs
parents:
diff changeset
   209
    }
hgs
parents:
diff changeset
   210
hgs
parents:
diff changeset
   211
    name = contactName(contactId);
hgs
parents:
diff changeset
   212
hgs
parents:
diff changeset
   213
    if (!mProcessingJobs && mJobsPostponed == JobsNotPostponed) {
hgs
parents:
diff changeset
   214
        // there might be new jobs now
hgs
parents:
diff changeset
   215
        mProcessingJobs = true;
hgs
parents:
diff changeset
   216
        HbApplication::instance()->postEvent(this, new QEvent(ProcessJobsEvent));
hgs
parents:
diff changeset
   217
    }
hgs
parents:
diff changeset
   218
hgs
parents:
diff changeset
   219
    CNT_EXIT_ARGS("name:" << name << "text:" << text)
hgs
parents:
diff changeset
   220
hgs
parents:
diff changeset
   221
    return new CntContactInfo(contactId, name, text, icons[0], icons[1]);
hgs
parents:
diff changeset
   222
}
hgs
parents:
diff changeset
   223
hgs
parents:
diff changeset
   224
/*! 
hgs
parents:
diff changeset
   225
    Creates a list of contact ids sorted according the corresponding contact names.
hgs
parents:
diff changeset
   226
hgs
parents:
diff changeset
   227
    \param idFilter the IDs to be returned; if NULL, all contact IDs are returned
hgs
parents:
diff changeset
   228
    \return the list of ids, sorted by contact name
hgs
parents:
diff changeset
   229
 */
hgs
parents:
diff changeset
   230
QList<QContactLocalId> CntCache::sortIdsByName(const QSet<QContactLocalId>* idFilter) const
hgs
parents:
diff changeset
   231
{
hgs
parents:
diff changeset
   232
    CNT_ENTRY
hgs
parents:
diff changeset
   233
hgs
parents:
diff changeset
   234
    QList<QContactLocalId> sortedIds;
hgs
parents:
diff changeset
   235
    
hgs
parents:
diff changeset
   236
    // allocate memory in advance to avoid repeated reallocation during population
hgs
parents:
diff changeset
   237
    // an extra 16 items are allocated to leave room for a few more contacts
hgs
parents:
diff changeset
   238
    // before reallocation is needed
hgs
parents:
diff changeset
   239
    if (!idFilter) {
hgs
parents:
diff changeset
   240
        sortedIds.reserve(mSortedNames.count() + 16);
hgs
parents:
diff changeset
   241
    } else {
hgs
parents:
diff changeset
   242
        sortedIds.reserve(idFilter->count() + 16);
hgs
parents:
diff changeset
   243
    }
hgs
parents:
diff changeset
   244
hgs
parents:
diff changeset
   245
    // the entries in mSortedNames are already sorted, so just pick
hgs
parents:
diff changeset
   246
    // out the ids from that list in the order that they appear
hgs
parents:
diff changeset
   247
    if (!idFilter) {
hgs
parents:
diff changeset
   248
        foreach (CntNameCacheItem* item, mSortedNames) {
hgs
parents:
diff changeset
   249
            sortedIds.append(item->contactId());
hgs
parents:
diff changeset
   250
        }
hgs
parents:
diff changeset
   251
    } else {
hgs
parents:
diff changeset
   252
        foreach (CntNameCacheItem* item, mSortedNames) {
hgs
parents:
diff changeset
   253
            if (idFilter->contains(item->contactId())) {
hgs
parents:
diff changeset
   254
                sortedIds.append(item->contactId());
hgs
parents:
diff changeset
   255
            }
hgs
parents:
diff changeset
   256
        }
hgs
parents:
diff changeset
   257
    }
hgs
parents:
diff changeset
   258
hgs
parents:
diff changeset
   259
    CNT_EXIT
hgs
parents:
diff changeset
   260
hgs
parents:
diff changeset
   261
    return sortedIds;
hgs
parents:
diff changeset
   262
}
hgs
parents:
diff changeset
   263
hgs
parents:
diff changeset
   264
/*!
hgs
parents:
diff changeset
   265
    Overloaded version of the function for string based searching of contact
hgs
parents:
diff changeset
   266
    names. Currently for multi part names only space and dash variations are
hgs
parents:
diff changeset
   267
    used for filtering, e.g. "A B" matches "Beta, Alfa" and "Alfa, Beta",
hgs
parents:
diff changeset
   268
    but also "Gamma, Alfa-Beta" and "Gamma, Alfa Beta" and "Alfa Beta, Gamma".
hgs
parents:
diff changeset
   269
    
hgs
parents:
diff changeset
   270
    \param searchList list of strings to search for
hgs
parents:
diff changeset
   271
    \return the list of ids, sorted by contact name
hgs
parents:
diff changeset
   272
 */
hgs
parents:
diff changeset
   273
QList<QContactLocalId> CntCache::sortIdsByName(const QStringList &searchList) const
hgs
parents:
diff changeset
   274
{
hgs
parents:
diff changeset
   275
    CNT_ENTRY_ARGS("time:" << User::FastCounter());
hgs
parents:
diff changeset
   276
hgs
parents:
diff changeset
   277
    QList<QContactLocalId> sortedIds;
hgs
parents:
diff changeset
   278
    QSet<int> checkedNames;
hgs
parents:
diff changeset
   279
    QStringList searchListSorted;
hgs
parents:
diff changeset
   280
hgs
parents:
diff changeset
   281
    // the given search string must be ordered to descending order according to word length
hgs
parents:
diff changeset
   282
    // so the search algorithm finds the correct contacts, this prevents cases where search string
hgs
parents:
diff changeset
   283
    // is e.g. "ax axx" so names starting with "axxyyz axyz" don't cause any problems for the search
hgs
parents:
diff changeset
   284
    foreach (QString oneString, searchList) {
hgs
parents:
diff changeset
   285
        searchListSorted.append(oneString.toLower());
hgs
parents:
diff changeset
   286
    }
hgs
parents:
diff changeset
   287
    qSort(searchListSorted.begin(), searchListSorted.end(), qGreater<QString>());
hgs
parents:
diff changeset
   288
hgs
parents:
diff changeset
   289
    for (int iter = 0; iter < mSortedNames.size(); iter++) {
hgs
parents:
diff changeset
   290
        int searchIndex;
hgs
parents:
diff changeset
   291
        QString currentName = (mSortedNames.at(iter))->name();
hgs
parents:
diff changeset
   292
        checkedNames.clear();
hgs
parents:
diff changeset
   293
hgs
parents:
diff changeset
   294
        for (searchIndex = 0; searchIndex < searchListSorted.size(); searchIndex++) {
hgs
parents:
diff changeset
   295
            int currentPos;
hgs
parents:
diff changeset
   296
            int tempStartPos = 0;
hgs
parents:
diff changeset
   297
            for (currentPos = 0; currentPos <= currentName.length(); currentPos++) {
hgs
parents:
diff changeset
   298
                // at the moment only differentiating character is the space (" ")
hgs
parents:
diff changeset
   299
                if (currentPos == currentName.length() || currentName.at(currentPos) == ' ') {
hgs
parents:
diff changeset
   300
                    QString tempName = currentName.mid(tempStartPos, currentPos - tempStartPos);
hgs
parents:
diff changeset
   301
hgs
parents:
diff changeset
   302
                    if (!checkedNames.contains(tempStartPos)
hgs
parents:
diff changeset
   303
                        && tempName.startsWith(searchListSorted.at(searchIndex), Qt::CaseInsensitive)) {
hgs
parents:
diff changeset
   304
                        checkedNames.insert(tempStartPos);
hgs
parents:
diff changeset
   305
                        break;
hgs
parents:
diff changeset
   306
                    }
hgs
parents:
diff changeset
   307
                    tempStartPos = ++currentPos;
hgs
parents:
diff changeset
   308
                }
hgs
parents:
diff changeset
   309
            }
hgs
parents:
diff changeset
   310
            // if the name is parsed completely through then it can't be a match
hgs
parents:
diff changeset
   311
            if (currentPos > currentName.length()) {
hgs
parents:
diff changeset
   312
                break;
hgs
parents:
diff changeset
   313
            }
hgs
parents:
diff changeset
   314
        }
hgs
parents:
diff changeset
   315
        // if the whole search parameter list is parsed, then the name must match the given search string
hgs
parents:
diff changeset
   316
        if (searchIndex == searchListSorted.size()) {
hgs
parents:
diff changeset
   317
            sortedIds.append(mSortedNames.at(iter)->contactId());
hgs
parents:
diff changeset
   318
        }
hgs
parents:
diff changeset
   319
    }
hgs
parents:
diff changeset
   320
hgs
parents:
diff changeset
   321
    CNT_EXIT_ARGS("time:" << User::FastCounter());
hgs
parents:
diff changeset
   322
hgs
parents:
diff changeset
   323
    return sortedIds;
hgs
parents:
diff changeset
   324
}
hgs
parents:
diff changeset
   325
hgs
parents:
diff changeset
   326
/*!
hgs
parents:
diff changeset
   327
    Creates the CntCache singleton instance.
hgs
parents:
diff changeset
   328
 */
hgs
parents:
diff changeset
   329
CntCache::CntCache(QContactManager *manager)
hgs
parents:
diff changeset
   330
    : mContactManager(manager),
hgs
parents:
diff changeset
   331
      mNameFetcher(new CntNameFetcher()),
hgs
parents:
diff changeset
   332
      mInfoFetcher(new CntInfoFetcher(mContactManager)),
hgs
parents:
diff changeset
   333
      mIconFetcher(new CntIconFetcher()),
hgs
parents:
diff changeset
   334
      mProcessingJobs(false),
hgs
parents:
diff changeset
   335
      mJobsPostponed(JobsNotPostponed),
hgs
parents:
diff changeset
   336
      mIsInUrgencyMode(false),
hgs
parents:
diff changeset
   337
      mLastEmittedContactId(-1),
hgs
parents:
diff changeset
   338
      mHasModifiedNames(false),
hgs
parents:
diff changeset
   339
      mAllNamesFetchStarted(false)
hgs
parents:
diff changeset
   340
{
hgs
parents:
diff changeset
   341
    CNT_ENTRY
hgs
parents:
diff changeset
   342
hgs
parents:
diff changeset
   343
    // listen to name fetcher
hgs
parents:
diff changeset
   344
    QObject::connect(mNameFetcher, SIGNAL(nameFormatChanged(CntNameOrder)),
hgs
parents:
diff changeset
   345
            this, SLOT(reformatNames(CntNameOrder)));
hgs
parents:
diff changeset
   346
    QObject::connect(mNameFetcher, SIGNAL(databaseAccessComplete()),
hgs
parents:
diff changeset
   347
            this, SLOT(resumeJobs()));
hgs
parents:
diff changeset
   348
    QObject::connect(mNameFetcher, SIGNAL(namesAvailable(QList<CntNameCacheItem *>)),
hgs
parents:
diff changeset
   349
            this, SLOT(setNameList(QList<CntNameCacheItem *>)));
hgs
parents:
diff changeset
   350
hgs
parents:
diff changeset
   351
    // listen to info fetcher
hgs
parents:
diff changeset
   352
    QObject::connect(mInfoFetcher, SIGNAL(infoUpdated(QContactLocalId, const ContactInfoField &, const QString &)),
hgs
parents:
diff changeset
   353
            this, SLOT(updateCachedInfo(QContactLocalId, const ContactInfoField &, const QString &)));
hgs
parents:
diff changeset
   354
    QObject::connect(mInfoFetcher, SIGNAL(infoCancelled(QContactLocalId)),
hgs
parents:
diff changeset
   355
            this, SLOT(cancelInfoFetch(QContactLocalId)));
hgs
parents:
diff changeset
   356
hgs
parents:
diff changeset
   357
    // listen to icon fetcher
hgs
parents:
diff changeset
   358
    QObject::connect(mIconFetcher, SIGNAL(iconFetched(const QString &, const HbIcon &)),
hgs
parents:
diff changeset
   359
            this, SLOT(updateCachedIcon(const QString &, const HbIcon &)));
hgs
parents:
diff changeset
   360
    QObject::connect(mIconFetcher, SIGNAL(iconCancelled(const QString &)),
hgs
parents:
diff changeset
   361
            this, SLOT(cancelIconFetch(const QString &)));
hgs
parents:
diff changeset
   362
hgs
parents:
diff changeset
   363
    // listen to contact manager
hgs
parents:
diff changeset
   364
    QObject::connect(mContactManager, SIGNAL(contactsChanged(const QList<QContactLocalId>&)),
hgs
parents:
diff changeset
   365
            this, SLOT(updateContacts(const QList<QContactLocalId>&)));
hgs
parents:
diff changeset
   366
    QObject::connect(mContactManager, SIGNAL(contactsRemoved(const QList<QContactLocalId>&)),
hgs
parents:
diff changeset
   367
            this, SLOT(removeContacts(const QList<QContactLocalId>&)));
hgs
parents:
diff changeset
   368
    QObject::connect(mContactManager, SIGNAL(contactsAdded(const QList<QContactLocalId>&)),
hgs
parents:
diff changeset
   369
            this, SLOT(addContacts(const QList<QContactLocalId>&)));
hgs
parents:
diff changeset
   370
hgs
parents:
diff changeset
   371
    // listen to timer events; this is for postponing and resuming jobs
hgs
parents:
diff changeset
   372
    mResumeJobsTimer.setSingleShot(true);
hgs
parents:
diff changeset
   373
    QObject::connect(&mResumeJobsTimer, SIGNAL(timeout()), this, SLOT(resumeJobs()));
hgs
parents:
diff changeset
   374
hgs
parents:
diff changeset
   375
    // load all names to cache
hgs
parents:
diff changeset
   376
    loadNames();
hgs
parents:
diff changeset
   377
hgs
parents:
diff changeset
   378
    CNT_EXIT
hgs
parents:
diff changeset
   379
}
hgs
parents:
diff changeset
   380
hgs
parents:
diff changeset
   381
/*!
hgs
parents:
diff changeset
   382
    Destructs the CntCache singleton instance.
hgs
parents:
diff changeset
   383
 */
hgs
parents:
diff changeset
   384
CntCache::~CntCache()
hgs
parents:
diff changeset
   385
{
hgs
parents:
diff changeset
   386
    CNT_ENTRY
hgs
parents:
diff changeset
   387
hgs
parents:
diff changeset
   388
    QObject::disconnect(this);
hgs
parents:
diff changeset
   389
hgs
parents:
diff changeset
   390
    if (mHasModifiedNames) {
hgs
parents:
diff changeset
   391
        mNameFetcher->writeNamesToCache(mSortedNames);
hgs
parents:
diff changeset
   392
    }
hgs
parents:
diff changeset
   393
hgs
parents:
diff changeset
   394
    delete mNameFetcher;
hgs
parents:
diff changeset
   395
    delete mInfoFetcher;
hgs
parents:
diff changeset
   396
    delete mIconFetcher;
hgs
parents:
diff changeset
   397
hgs
parents:
diff changeset
   398
    qDeleteAll(mInfoCache);
hgs
parents:
diff changeset
   399
    mInfoCache.clear();
hgs
parents:
diff changeset
   400
hgs
parents:
diff changeset
   401
    qDeleteAll(mIconCache);
hgs
parents:
diff changeset
   402
    mIconCache.clear();
hgs
parents:
diff changeset
   403
hgs
parents:
diff changeset
   404
    qDeleteAll(mNameCache);
hgs
parents:
diff changeset
   405
    mNameCache.clear();
hgs
parents:
diff changeset
   406
hgs
parents:
diff changeset
   407
    mSortedNames.clear();   // contains same data as mNameCache, so no qDeleteAll
hgs
parents:
diff changeset
   408
hgs
parents:
diff changeset
   409
    CNT_EXIT
hgs
parents:
diff changeset
   410
}
hgs
parents:
diff changeset
   411
hgs
parents:
diff changeset
   412
/*!
hgs
parents:
diff changeset
   413
    Postpones outstanding jobs until milliseconds ms has passed or resumeJobs() is called.
hgs
parents:
diff changeset
   414
    
hgs
parents:
diff changeset
   415
    \param postponement Type the type of postponement; UntilResume or ForDuration
hgs
parents:
diff changeset
   416
    \param milliseconds The duration of the delay
hgs
parents:
diff changeset
   417
 */
hgs
parents:
diff changeset
   418
void CntCache::postponeJobs(int postponementType, int duration)
hgs
parents:
diff changeset
   419
{
hgs
parents:
diff changeset
   420
    CNT_ENTRY_ARGS("ms =" << duration)
hgs
parents:
diff changeset
   421
hgs
parents:
diff changeset
   422
    Q_ASSERT((postponementType == JobsPostponedUntilResume
hgs
parents:
diff changeset
   423
             || postponementType == JobsPostponedForDuration)
hgs
parents:
diff changeset
   424
             && duration >= 0);
hgs
parents:
diff changeset
   425
hgs
parents:
diff changeset
   426
    mJobsPostponed = postponementType;
hgs
parents:
diff changeset
   427
    mResumeJobsTimer.stop();
hgs
parents:
diff changeset
   428
hgs
parents:
diff changeset
   429
    if (postponementType == JobsPostponedForDuration) {
hgs
parents:
diff changeset
   430
        mResumeJobsTimer.start(duration);
hgs
parents:
diff changeset
   431
    }
hgs
parents:
diff changeset
   432
hgs
parents:
diff changeset
   433
    CNT_EXIT_ARGS("type =" << mJobsPostponed)
hgs
parents:
diff changeset
   434
}
hgs
parents:
diff changeset
   435
hgs
parents:
diff changeset
   436
/*!
hgs
parents:
diff changeset
   437
    Postpones outstanding jobs until resumeJobs() is called. This must always be called after
hgs
parents:
diff changeset
   438
    postponeJobs.
hgs
parents:
diff changeset
   439
 */
hgs
parents:
diff changeset
   440
void CntCache::resumeJobs()
hgs
parents:
diff changeset
   441
{
hgs
parents:
diff changeset
   442
    CNT_ENTRY
hgs
parents:
diff changeset
   443
hgs
parents:
diff changeset
   444
    Q_ASSERT(!mProcessingJobs && mJobsPostponed != JobsNotPostponed);
hgs
parents:
diff changeset
   445
hgs
parents:
diff changeset
   446
    mResumeJobsTimer.stop();
hgs
parents:
diff changeset
   447
    mJobsPostponed = JobsNotPostponed;
hgs
parents:
diff changeset
   448
    mProcessingJobs = true;
hgs
parents:
diff changeset
   449
    HbApplication::instance()->postEvent(this, new QEvent(ProcessJobsEvent));
hgs
parents:
diff changeset
   450
hgs
parents:
diff changeset
   451
    CNT_EXIT
hgs
parents:
diff changeset
   452
}
hgs
parents:
diff changeset
   453
hgs
parents:
diff changeset
   454
/*!
hgs
parents:
diff changeset
   455
    Listens for ProcessJobsEvents and calls processJobs() if there is such an event.
hgs
parents:
diff changeset
   456
 */
hgs
parents:
diff changeset
   457
bool CntCache::event(QEvent* event)
hgs
parents:
diff changeset
   458
{
hgs
parents:
diff changeset
   459
    if (event->type() == ProcessJobsEvent) {
hgs
parents:
diff changeset
   460
        processJobs();
hgs
parents:
diff changeset
   461
        return true;
hgs
parents:
diff changeset
   462
    }
hgs
parents:
diff changeset
   463
hgs
parents:
diff changeset
   464
    return QObject::event(event);
hgs
parents:
diff changeset
   465
}
hgs
parents:
diff changeset
   466
hgs
parents:
diff changeset
   467
/*!
hgs
parents:
diff changeset
   468
    Processes all scheduled jobs in all fetchers. The loop runs until all
hgs
parents:
diff changeset
   469
    jobs are done or postponed.
hgs
parents:
diff changeset
   470
 */
hgs
parents:
diff changeset
   471
void CntCache::processJobs()
hgs
parents:
diff changeset
   472
{
hgs
parents:
diff changeset
   473
    CNT_ENTRY
hgs
parents:
diff changeset
   474
hgs
parents:
diff changeset
   475
    // process fetcher jobs in order of priority
hgs
parents:
diff changeset
   476
    forever {
hgs
parents:
diff changeset
   477
        // 1: has all jobs been postponed?
hgs
parents:
diff changeset
   478
        if (mJobsPostponed != JobsNotPostponed) {
hgs
parents:
diff changeset
   479
            CNT_EXIT_ARGS("jobs postponed")
hgs
parents:
diff changeset
   480
            mProcessingJobs = false;
hgs
parents:
diff changeset
   481
            return;
hgs
parents:
diff changeset
   482
hgs
parents:
diff changeset
   483
        // 2: is there a request to fetch info?
hgs
parents:
diff changeset
   484
        } else if (mInfoFetcher->hasScheduledJobs()) {
hgs
parents:
diff changeset
   485
            mInfoFetcher->processNextJob();
hgs
parents:
diff changeset
   486
hgs
parents:
diff changeset
   487
        // 3: is there a request to fetch an icon?
hgs
parents:
diff changeset
   488
        } else if (mIconFetcher->hasScheduledJobs()) {
hgs
parents:
diff changeset
   489
            // quit the loop; it will be started again when the icon has been fetched
hgs
parents:
diff changeset
   490
            if (!mIconFetcher->isProcessingJob()) {
hgs
parents:
diff changeset
   491
                mIconFetcher->processNextJob();
hgs
parents:
diff changeset
   492
            }
hgs
parents:
diff changeset
   493
            mProcessingJobs = false;
hgs
parents:
diff changeset
   494
            CNT_EXIT_ARGS("jobs postponed until icon fetch returns")
hgs
parents:
diff changeset
   495
            return;
hgs
parents:
diff changeset
   496
hgs
parents:
diff changeset
   497
        // 4: are there any cancelled info jobs?
hgs
parents:
diff changeset
   498
        } else if (mInfoFetcher->hasCancelledJobs() && !mInfoFetcher->isProcessingJob()) {
hgs
parents:
diff changeset
   499
            mInfoFetcher->processNextJob();
hgs
parents:
diff changeset
   500
hgs
parents:
diff changeset
   501
        // 5: are there any cancelled icon jobs?
hgs
parents:
diff changeset
   502
        } else if (mIconFetcher->hasCancelledJobs() && !mIconFetcher->isProcessingJob()) {
hgs
parents:
diff changeset
   503
            mIconFetcher->processNextJob();
hgs
parents:
diff changeset
   504
hgs
parents:
diff changeset
   505
        // 6: is there an "all names" job?
hgs
parents:
diff changeset
   506
        } else if (mNameFetcher->hasScheduledJobs()) {
hgs
parents:
diff changeset
   507
            // fetch all contact names from the database so that the current
hgs
parents:
diff changeset
   508
            // list of names (from the file cache) can be synched with the
hgs
parents:
diff changeset
   509
            // database
hgs
parents:
diff changeset
   510
            if (!mNameFetcher->isProcessingJob()) {
hgs
parents:
diff changeset
   511
                mNameFetcher->processNextJob();
hgs
parents:
diff changeset
   512
            }
hgs
parents:
diff changeset
   513
            mProcessingJobs = false;
hgs
parents:
diff changeset
   514
            postponeJobs(JobsPostponedUntilResume);
hgs
parents:
diff changeset
   515
            CNT_EXIT_ARGS("jobs postponed while fetching all names")
hgs
parents:
diff changeset
   516
            return;
hgs
parents:
diff changeset
   517
hgs
parents:
diff changeset
   518
        // 7: are there contacts left to precache?
hgs
parents:
diff changeset
   519
        } else if (mReadAheadCache.count() > 0) {
hgs
parents:
diff changeset
   520
            int contactId = mReadAheadCache.first().first;
hgs
parents:
diff changeset
   521
            int contactRow = mReadAheadCache.takeFirst().second;
hgs
parents:
diff changeset
   522
            if (!mInfoCache.contains(contactId) && contactExists(contactId)) {
hgs
parents:
diff changeset
   523
                // contact exists, but is not in cache, so schedule it for retrieval
hgs
parents:
diff changeset
   524
                CntInfoCacheItem* item = createInfoCacheItem(contactId);
hgs
parents:
diff changeset
   525
                item->text = EmptyTextField;
hgs
parents:
diff changeset
   526
                mInfoFetcher->scheduleJob(new CntInfoJob(contactId), contactRow);
hgs
parents:
diff changeset
   527
            }
hgs
parents:
diff changeset
   528
        // nothing more to do, so exit loop
hgs
parents:
diff changeset
   529
        } else {
hgs
parents:
diff changeset
   530
            mProcessingJobs = false;
hgs
parents:
diff changeset
   531
            CNT_EXIT_ARGS("no more jobs")
hgs
parents:
diff changeset
   532
            return;
hgs
parents:
diff changeset
   533
        }
hgs
parents:
diff changeset
   534
hgs
parents:
diff changeset
   535
        // allow events to be handled before continuing with the next job
hgs
parents:
diff changeset
   536
        HbApplication::processEvents();
hgs
parents:
diff changeset
   537
    }
hgs
parents:
diff changeset
   538
}
hgs
parents:
diff changeset
   539
hgs
parents:
diff changeset
   540
/*! 
hgs
parents:
diff changeset
   541
    Processes a new info field that has arrived from the info fetcher.
hgs
parents:
diff changeset
   542
    If the contact is in the info cache, then the info cache is updated
hgs
parents:
diff changeset
   543
    accordingly.
hgs
parents:
diff changeset
   544
    
hgs
parents:
diff changeset
   545
    A contactInfoUpdated() signal is usually also emitted. The exception is if
hgs
parents:
diff changeset
   546
    the info is the name of an icon and that icon is not in the icon cache. In
hgs
parents:
diff changeset
   547
    this case the icon is scheduled to be fetched and a signal will eventually
hgs
parents:
diff changeset
   548
    be emitted when the icon has been fetched (or cancelled).
hgs
parents:
diff changeset
   549
 */
hgs
parents:
diff changeset
   550
void CntCache::updateCachedInfo(QContactLocalId contactId, const ContactInfoField& infoField, const QString& infoValue)
hgs
parents:
diff changeset
   551
{
hgs
parents:
diff changeset
   552
    CNT_ENTRY_ARGS( "id:" << contactId   << "infotype:" << infoField   << "infovalue:" << infoValue )
hgs
parents:
diff changeset
   553
hgs
parents:
diff changeset
   554
    Q_ASSERT(infoField == ContactInfoTextField || infoField == ContactInfoIcon1Field || infoField == ContactInfoIcon2Field);
hgs
parents:
diff changeset
   555
hgs
parents:
diff changeset
   556
    bool hasNewInfo;
hgs
parents:
diff changeset
   557
hgs
parents:
diff changeset
   558
    if (!mInfoCache.contains(contactId)) {
hgs
parents:
diff changeset
   559
        // contact is not in cache, so nothing needs to be done except notify
hgs
parents:
diff changeset
   560
        // clients that this contact has (possibly) been changed
hgs
parents:
diff changeset
   561
        hasNewInfo = true;
hgs
parents:
diff changeset
   562
    } else if (infoField == ContactInfoTextField) {
hgs
parents:
diff changeset
   563
        // update cache with new text for contact
hgs
parents:
diff changeset
   564
        mInfoCache.value(contactId)->text = infoValue;
hgs
parents:
diff changeset
   565
        hasNewInfo = true;
hgs
parents:
diff changeset
   566
    } else {
hgs
parents:
diff changeset
   567
        // update cache with new icon name for contact
hgs
parents:
diff changeset
   568
        int iconIndex = (infoField == ContactInfoIcon1Field ? 0 : 1);
hgs
parents:
diff changeset
   569
        CntInfoCacheItem* item = mInfoCache.value(contactId);
hgs
parents:
diff changeset
   570
        QString iconName = infoValue;
hgs
parents:
diff changeset
   571
        if (item->icons[iconIndex] != iconName) {
hgs
parents:
diff changeset
   572
            item->icons[iconIndex] = iconName;
hgs
parents:
diff changeset
   573
            if (iconName.isEmpty()) {
hgs
parents:
diff changeset
   574
                hasNewInfo = true;
hgs
parents:
diff changeset
   575
            } else if (mIconCache.contains(iconName)) {
hgs
parents:
diff changeset
   576
                hasNewInfo = true;
hgs
parents:
diff changeset
   577
            } else if (iconName.startsWith("qtg_", Qt::CaseInsensitive)) {
hgs
parents:
diff changeset
   578
                CntIconCacheItem* iconItem = createIconCacheItem(iconName);
hgs
parents:
diff changeset
   579
                iconItem->icon = HbIcon(iconName);
hgs
parents:
diff changeset
   580
                hasNewInfo = true;
hgs
parents:
diff changeset
   581
            } else {
hgs
parents:
diff changeset
   582
                CntIconCacheItem* iconItem = createIconCacheItem(iconName);
hgs
parents:
diff changeset
   583
                iconItem->requestedBy << contactId;
hgs
parents:
diff changeset
   584
                QList<CntNameCacheItem*>::iterator pos = qLowerBound(mSortedNames.begin(), mSortedNames.end(), mNameCache.value(contactId), CntNameFetcher::compareNames);
hgs
parents:
diff changeset
   585
                while (pos != mSortedNames.end() && (*pos)->contactId() != contactId) {
hgs
parents:
diff changeset
   586
                    ++pos;
hgs
parents:
diff changeset
   587
                }
hgs
parents:
diff changeset
   588
                mIconFetcher->scheduleJob(new CntIconJob(iconName), pos - mSortedNames.begin());
hgs
parents:
diff changeset
   589
                hasNewInfo = false;
hgs
parents:
diff changeset
   590
            }
hgs
parents:
diff changeset
   591
        } else {
hgs
parents:
diff changeset
   592
            hasNewInfo = false;
hgs
parents:
diff changeset
   593
        }
hgs
parents:
diff changeset
   594
    }
hgs
parents:
diff changeset
   595
hgs
parents:
diff changeset
   596
    if (hasNewInfo) {
hgs
parents:
diff changeset
   597
        emitContactInfoUpdated(contactId);
hgs
parents:
diff changeset
   598
    }
hgs
parents:
diff changeset
   599
hgs
parents:
diff changeset
   600
    if (!mProcessingJobs && mJobsPostponed == JobsNotPostponed) {
hgs
parents:
diff changeset
   601
        // there might be new jobs now
hgs
parents:
diff changeset
   602
        mProcessingJobs = true;
hgs
parents:
diff changeset
   603
        HbApplication::instance()->postEvent(this, new QEvent(ProcessJobsEvent));
hgs
parents:
diff changeset
   604
    }
hgs
parents:
diff changeset
   605
hgs
parents:
diff changeset
   606
    CNT_EXIT
hgs
parents:
diff changeset
   607
}
hgs
parents:
diff changeset
   608
hgs
parents:
diff changeset
   609
/*! 
hgs
parents:
diff changeset
   610
    Handle the case where a request for contact info is cancelled by the
hgs
parents:
diff changeset
   611
    info fetcher because of too many scheduled jobs.
hgs
parents:
diff changeset
   612
 */
hgs
parents:
diff changeset
   613
void CntCache::cancelInfoFetch(QContactLocalId contactId)
hgs
parents:
diff changeset
   614
{
hgs
parents:
diff changeset
   615
    CNT_ENTRY_ARGS( "cid =" << contactId )
hgs
parents:
diff changeset
   616
hgs
parents:
diff changeset
   617
    if (mInfoCache.contains(contactId)) {
hgs
parents:
diff changeset
   618
        delete mInfoCache.take(contactId);
hgs
parents:
diff changeset
   619
    }
hgs
parents:
diff changeset
   620
hgs
parents:
diff changeset
   621
    emitContactInfoUpdated(contactId);
hgs
parents:
diff changeset
   622
hgs
parents:
diff changeset
   623
    CNT_EXIT
hgs
parents:
diff changeset
   624
}
hgs
parents:
diff changeset
   625
hgs
parents:
diff changeset
   626
/*! 
hgs
parents:
diff changeset
   627
    Processes a new icon that has arrived from the icon fetcher.
hgs
parents:
diff changeset
   628
    The icon cache is updated and a contactInfoUpdated() signal is
hgs
parents:
diff changeset
   629
    emitted.
hgs
parents:
diff changeset
   630
 */
hgs
parents:
diff changeset
   631
void CntCache::updateCachedIcon(const QString& iconName, const HbIcon& icon)
hgs
parents:
diff changeset
   632
{
hgs
parents:
diff changeset
   633
    CNT_ENTRY_ARGS( "icon =" << iconName )
hgs
parents:
diff changeset
   634
hgs
parents:
diff changeset
   635
    if (mIconCache.contains(iconName)) {
hgs
parents:
diff changeset
   636
        CntIconCacheItem* item = mIconCache.value(iconName);
hgs
parents:
diff changeset
   637
        item->icon = icon;
hgs
parents:
diff changeset
   638
        foreach (QContactLocalId contactId, item->requestedBy) {
hgs
parents:
diff changeset
   639
            emitContactInfoUpdated(contactId);
hgs
parents:
diff changeset
   640
        }
hgs
parents:
diff changeset
   641
        item->requestedBy.clear();
hgs
parents:
diff changeset
   642
hgs
parents:
diff changeset
   643
        if (!mProcessingJobs && mJobsPostponed == JobsNotPostponed) {
hgs
parents:
diff changeset
   644
            // there might still be unfinished icon jobs; only one icon job is
hgs
parents:
diff changeset
   645
            // done at a time
hgs
parents:
diff changeset
   646
            mProcessingJobs = true;
hgs
parents:
diff changeset
   647
            HbApplication::instance()->postEvent(this, new QEvent(ProcessJobsEvent));
hgs
parents:
diff changeset
   648
        }
hgs
parents:
diff changeset
   649
    }
hgs
parents:
diff changeset
   650
hgs
parents:
diff changeset
   651
    CNT_EXIT
hgs
parents:
diff changeset
   652
}
hgs
parents:
diff changeset
   653
hgs
parents:
diff changeset
   654
/*! 
hgs
parents:
diff changeset
   655
    Handle the case where a request for an icon is cancelled by the icon
hgs
parents:
diff changeset
   656
    fetcher because of too many scheduled jobs.
hgs
parents:
diff changeset
   657
 */
hgs
parents:
diff changeset
   658
void CntCache::cancelIconFetch(const QString& iconName)
hgs
parents:
diff changeset
   659
{
hgs
parents:
diff changeset
   660
    CNT_ENTRY_ARGS(iconName)
hgs
parents:
diff changeset
   661
hgs
parents:
diff changeset
   662
    if (mIconCache.contains(iconName)) {
hgs
parents:
diff changeset
   663
        CntIconCacheItem* item = mIconCache.take(iconName);
hgs
parents:
diff changeset
   664
        foreach (QContactLocalId contactId, item->requestedBy) {
hgs
parents:
diff changeset
   665
            emitContactInfoUpdated(contactId);
hgs
parents:
diff changeset
   666
        }
hgs
parents:
diff changeset
   667
        delete item;
hgs
parents:
diff changeset
   668
    }
hgs
parents:
diff changeset
   669
hgs
parents:
diff changeset
   670
    CNT_EXIT
hgs
parents:
diff changeset
   671
}
hgs
parents:
diff changeset
   672
hgs
parents:
diff changeset
   673
/*! 
hgs
parents:
diff changeset
   674
    Creates a new item in the info cache. If the cache is full,
hgs
parents:
diff changeset
   675
    then the least recently accessed item is removed from cache.
hgs
parents:
diff changeset
   676
    
hgs
parents:
diff changeset
   677
    /param contactId id of contact for which to create the new cache item
hgs
parents:
diff changeset
   678
    /return the newly created cache item
hgs
parents:
diff changeset
   679
 */
hgs
parents:
diff changeset
   680
CntInfoCacheItem * CntCache::createInfoCacheItem(QContactLocalId contactId)
hgs
parents:
diff changeset
   681
{
hgs
parents:
diff changeset
   682
    CNT_ENTRY_ARGS(contactId)
hgs
parents:
diff changeset
   683
hgs
parents:
diff changeset
   684
    if (mInfoCache.count() >= InfoCacheSize) {
hgs
parents:
diff changeset
   685
        // cache is full, so remove the oldest contact
hgs
parents:
diff changeset
   686
        CntInfoCacheItem* oldestItem = NULL;
hgs
parents:
diff changeset
   687
        QTime oldestRequest;
hgs
parents:
diff changeset
   688
hgs
parents:
diff changeset
   689
        foreach (CntInfoCacheItem* i, mInfoCache) {
hgs
parents:
diff changeset
   690
            if (oldestItem == NULL || i->lastRequest < oldestRequest) {
hgs
parents:
diff changeset
   691
                oldestRequest = i->lastRequest;
hgs
parents:
diff changeset
   692
                oldestItem = i;
hgs
parents:
diff changeset
   693
            }
hgs
parents:
diff changeset
   694
        }
hgs
parents:
diff changeset
   695
hgs
parents:
diff changeset
   696
        if (oldestItem != NULL) {
hgs
parents:
diff changeset
   697
            mInfoCache.remove(oldestItem->contactId);
hgs
parents:
diff changeset
   698
            delete oldestItem;
hgs
parents:
diff changeset
   699
        }
hgs
parents:
diff changeset
   700
    }
hgs
parents:
diff changeset
   701
    
hgs
parents:
diff changeset
   702
    // create and insert the new item
hgs
parents:
diff changeset
   703
    CntInfoCacheItem* item = new CntInfoCacheItem();
hgs
parents:
diff changeset
   704
    item->contactId = contactId;
hgs
parents:
diff changeset
   705
    item->lastRequest = QTime::currentTime();
hgs
parents:
diff changeset
   706
    mInfoCache.insert(contactId, item);
hgs
parents:
diff changeset
   707
    
hgs
parents:
diff changeset
   708
    CNT_EXIT
hgs
parents:
diff changeset
   709
hgs
parents:
diff changeset
   710
    return item;
hgs
parents:
diff changeset
   711
}
hgs
parents:
diff changeset
   712
hgs
parents:
diff changeset
   713
/*! 
hgs
parents:
diff changeset
   714
    Creates a new item in the icon cache. If the cache is full,
hgs
parents:
diff changeset
   715
    then the least recently accessed item is removed from cache.
hgs
parents:
diff changeset
   716
    
hgs
parents:
diff changeset
   717
    /param iconName name of the icon for which to create the new cache item
hgs
parents:
diff changeset
   718
    /return the newly created cache item
hgs
parents:
diff changeset
   719
 */
hgs
parents:
diff changeset
   720
CntIconCacheItem* CntCache::createIconCacheItem(const QString& iconName)
hgs
parents:
diff changeset
   721
{
hgs
parents:
diff changeset
   722
    CNT_ENTRY_ARGS(iconName)
hgs
parents:
diff changeset
   723
hgs
parents:
diff changeset
   724
    if (mIconCache.count() >= IconCacheSize) {
hgs
parents:
diff changeset
   725
        // cache is full, so remove the oldest icon
hgs
parents:
diff changeset
   726
        CntIconCacheItem* oldestItem = NULL;
hgs
parents:
diff changeset
   727
        QTime oldestRequest;
hgs
parents:
diff changeset
   728
hgs
parents:
diff changeset
   729
        foreach (CntIconCacheItem* i, mIconCache) {
hgs
parents:
diff changeset
   730
            if (oldestItem == NULL || i->lastRequest < oldestRequest) {
hgs
parents:
diff changeset
   731
                oldestRequest = i->lastRequest;
hgs
parents:
diff changeset
   732
                oldestItem = i;
hgs
parents:
diff changeset
   733
            }
hgs
parents:
diff changeset
   734
        }
hgs
parents:
diff changeset
   735
hgs
parents:
diff changeset
   736
        if (oldestItem) {
hgs
parents:
diff changeset
   737
            mIconCache.remove(oldestItem->iconName);
hgs
parents:
diff changeset
   738
            delete oldestItem;
hgs
parents:
diff changeset
   739
        }
hgs
parents:
diff changeset
   740
    }
hgs
parents:
diff changeset
   741
hgs
parents:
diff changeset
   742
    // create and insert the new item
hgs
parents:
diff changeset
   743
    CntIconCacheItem* item = new CntIconCacheItem();
hgs
parents:
diff changeset
   744
    item->iconName = iconName;
hgs
parents:
diff changeset
   745
    item->lastRequest = QTime::currentTime();
hgs
parents:
diff changeset
   746
    mIconCache.insert(iconName, item);
hgs
parents:
diff changeset
   747
hgs
parents:
diff changeset
   748
    CNT_EXIT
hgs
parents:
diff changeset
   749
hgs
parents:
diff changeset
   750
    return item;
hgs
parents:
diff changeset
   751
}
hgs
parents:
diff changeset
   752
hgs
parents:
diff changeset
   753
/*!
hgs
parents:
diff changeset
   754
    Notifies clients that a contact might have changed.
hgs
parents:
diff changeset
   755
    Clients can then request the info via fetchContactInfo() 
hgs
parents:
diff changeset
   756
    if they are interested.
hgs
parents:
diff changeset
   757
 */
hgs
parents:
diff changeset
   758
void CntCache::emitContactInfoUpdated(QContactLocalId contactId)
hgs
parents:
diff changeset
   759
{
hgs
parents:
diff changeset
   760
	CNT_ENTRY_ARGS(contactId)
hgs
parents:
diff changeset
   761
hgs
parents:
diff changeset
   762
    mLastEmittedContactId = contactId;
hgs
parents:
diff changeset
   763
    emit contactInfoUpdated(contactId);
hgs
parents:
diff changeset
   764
    mLastEmittedContactId = -1;
hgs
parents:
diff changeset
   765
hgs
parents:
diff changeset
   766
	CNT_EXIT
hgs
parents:
diff changeset
   767
}
hgs
parents:
diff changeset
   768
hgs
parents:
diff changeset
   769
/*! 
hgs
parents:
diff changeset
   770
    Collects all contact IDs near the latest fetch from the UI. These will be fetched and
hgs
parents:
diff changeset
   771
    precached when UI activity slows down.
hgs
parents:
diff changeset
   772
hgs
parents:
diff changeset
   773
    \param mostRecentRow the row of the contact that was most recently fetched
hgs
parents:
diff changeset
   774
    \param idList a list with all the IDs in the list
hgs
parents:
diff changeset
   775
 */
hgs
parents:
diff changeset
   776
void CntCache::updateReadAheadCache(int mostRecentRow, const QList<QContactLocalId>& idList)
hgs
parents:
diff changeset
   777
{
hgs
parents:
diff changeset
   778
    CNT_ENTRY_ARGS(mostRecentRow)
hgs
parents:
diff changeset
   779
hgs
parents:
diff changeset
   780
    int row;
hgs
parents:
diff changeset
   781
hgs
parents:
diff changeset
   782
    mReadAheadCache.clear();
hgs
parents:
diff changeset
   783
hgs
parents:
diff changeset
   784
    // step through the area near to last fetch item and make sure all
hgs
parents:
diff changeset
   785
    // contacts in it are also in cache or in the read ahead list
hgs
parents:
diff changeset
   786
    for (int i = 1; i <= ItemsToCacheAhead; ++i) {
hgs
parents:
diff changeset
   787
        for (int j = 0; j < 2; ++j) {
hgs
parents:
diff changeset
   788
            if (j == 0) {
hgs
parents:
diff changeset
   789
                row = mostRecentRow - i;
hgs
parents:
diff changeset
   790
                if (row < 0) {
hgs
parents:
diff changeset
   791
                    continue;
hgs
parents:
diff changeset
   792
                }
hgs
parents:
diff changeset
   793
            } else {
hgs
parents:
diff changeset
   794
                row = mostRecentRow + i;
hgs
parents:
diff changeset
   795
                if (row >= idList.count()) {
hgs
parents:
diff changeset
   796
                    continue;
hgs
parents:
diff changeset
   797
                }
hgs
parents:
diff changeset
   798
            }
hgs
parents:
diff changeset
   799
            
hgs
parents:
diff changeset
   800
            int contactId = idList.at(row);
hgs
parents:
diff changeset
   801
            if (!mInfoCache.contains(contactId)) {
hgs
parents:
diff changeset
   802
                // contact is not in cache, so put the id to items to read into cache
hgs
parents:
diff changeset
   803
                mReadAheadCache.append(QPair<QContactLocalId, int>(contactId, row));
hgs
parents:
diff changeset
   804
            } else {
hgs
parents:
diff changeset
   805
                // contact is in cache; update lastRequest as we want to keep this item in cache
hgs
parents:
diff changeset
   806
                mInfoCache.value(contactId)->lastRequest = QTime::currentTime();
hgs
parents:
diff changeset
   807
            }
hgs
parents:
diff changeset
   808
        }
hgs
parents:
diff changeset
   809
    }
hgs
parents:
diff changeset
   810
hgs
parents:
diff changeset
   811
    CNT_EXIT
hgs
parents:
diff changeset
   812
}
hgs
parents:
diff changeset
   813
hgs
parents:
diff changeset
   814
/*!
hgs
parents:
diff changeset
   815
    Starts the urgency mode, where all contact info is fetched immediately,
hgs
parents:
diff changeset
   816
    regardless of whether there is activity in the UI or not.
hgs
parents:
diff changeset
   817
 */
hgs
parents:
diff changeset
   818
void CntCache::startUrgencyMode()
hgs
parents:
diff changeset
   819
{
hgs
parents:
diff changeset
   820
    CNT_ENTRY
hgs
parents:
diff changeset
   821
hgs
parents:
diff changeset
   822
    mIsInUrgencyMode = true;
hgs
parents:
diff changeset
   823
    QTimer::singleShot(UrgencyModeDuration, this, SLOT(stopUrgencyMode()));
hgs
parents:
diff changeset
   824
hgs
parents:
diff changeset
   825
    CNT_EXIT
hgs
parents:
diff changeset
   826
}
hgs
parents:
diff changeset
   827
hgs
parents:
diff changeset
   828
/*!
hgs
parents:
diff changeset
   829
    Starts the urgency mode, where all contact info is fetched immediately,
hgs
parents:
diff changeset
   830
    regardless of whether there is activity in the UI or not.
hgs
parents:
diff changeset
   831
 */
hgs
parents:
diff changeset
   832
void CntCache::stopUrgencyMode()
hgs
parents:
diff changeset
   833
{
hgs
parents:
diff changeset
   834
    CNT_ENTRY
hgs
parents:
diff changeset
   835
hgs
parents:
diff changeset
   836
    mIsInUrgencyMode = false;
hgs
parents:
diff changeset
   837
hgs
parents:
diff changeset
   838
    CNT_EXIT
hgs
parents:
diff changeset
   839
}
hgs
parents:
diff changeset
   840
hgs
parents:
diff changeset
   841
/*!
hgs
parents:
diff changeset
   842
    Fetch the names of all contacts.
hgs
parents:
diff changeset
   843
 */
hgs
parents:
diff changeset
   844
void CntCache::loadNames()
hgs
parents:
diff changeset
   845
{
hgs
parents:
diff changeset
   846
    CNT_ENTRY
hgs
parents:
diff changeset
   847
    
hgs
parents:
diff changeset
   848
    // read names from file cache
hgs
parents:
diff changeset
   849
    mNameFetcher->readNamesFromCache(mSortedNames);
hgs
parents:
diff changeset
   850
hgs
parents:
diff changeset
   851
    // insert the names into the id-to-name map
hgs
parents:
diff changeset
   852
    foreach (CntNameCacheItem* item, mSortedNames) {
hgs
parents:
diff changeset
   853
        mNameCache.insert(item->contactId(), item);
hgs
parents:
diff changeset
   854
    }
hgs
parents:
diff changeset
   855
hgs
parents:
diff changeset
   856
    // schedule the job for reading all names from the database; it will be processed once
hgs
parents:
diff changeset
   857
    // info and icons for the first screenful of contacts have been read
hgs
parents:
diff changeset
   858
    mNameFetcher->scheduleJob(new CntAllNamesJob());
hgs
parents:
diff changeset
   859
    mProcessingJobs = true;
hgs
parents:
diff changeset
   860
    HbApplication::instance()->postEvent(this, new QEvent(ProcessJobsEvent));
hgs
parents:
diff changeset
   861
hgs
parents:
diff changeset
   862
    CNT_EXIT
hgs
parents:
diff changeset
   863
}
hgs
parents:
diff changeset
   864
hgs
parents:
diff changeset
   865
/*!
hgs
parents:
diff changeset
   866
    Checks whether a contact exists.
hgs
parents:
diff changeset
   867
 */
hgs
parents:
diff changeset
   868
bool CntCache::contactExists(QContactLocalId contactId) const
hgs
parents:
diff changeset
   869
{
hgs
parents:
diff changeset
   870
    CNT_ENTRY_ARGS(contactId)
hgs
parents:
diff changeset
   871
    CNT_EXIT_ARGS(mNameCache.contains(contactId))
hgs
parents:
diff changeset
   872
hgs
parents:
diff changeset
   873
    return mNameCache.contains(contactId);
hgs
parents:
diff changeset
   874
}
hgs
parents:
diff changeset
   875
hgs
parents:
diff changeset
   876
/*!
hgs
parents:
diff changeset
   877
    Fetch the name of one contact.
hgs
parents:
diff changeset
   878
 */
hgs
parents:
diff changeset
   879
QString CntCache::contactName(QContactLocalId contactId) const
hgs
parents:
diff changeset
   880
{
hgs
parents:
diff changeset
   881
    CNT_ENTRY_ARGS(contactId)
hgs
parents:
diff changeset
   882
hgs
parents:
diff changeset
   883
    QString name;
hgs
parents:
diff changeset
   884
hgs
parents:
diff changeset
   885
    QHash<QContactLocalId, CntNameCacheItem*>::const_iterator i = mNameCache.find(contactId);
hgs
parents:
diff changeset
   886
    if (i != mNameCache.end()) {
hgs
parents:
diff changeset
   887
        name = i.value()->name();
hgs
parents:
diff changeset
   888
    }
hgs
parents:
diff changeset
   889
hgs
parents:
diff changeset
   890
    CNT_EXIT_ARGS(name)
hgs
parents:
diff changeset
   891
hgs
parents:
diff changeset
   892
    return name;
hgs
parents:
diff changeset
   893
}
hgs
parents:
diff changeset
   894
hgs
parents:
diff changeset
   895
/*! 
hgs
parents:
diff changeset
   896
    Updates the names in cache according to newFormat.
hgs
parents:
diff changeset
   897
hgs
parents:
diff changeset
   898
    \param newFormat the new name format, e.g. "Lastname, Firstname"
hgs
parents:
diff changeset
   899
 */
hgs
parents:
diff changeset
   900
void CntCache::reformatNames(CntNameOrder newFormat)
hgs
parents:
diff changeset
   901
{
hgs
parents:
diff changeset
   902
	CNT_ENTRY
hgs
parents:
diff changeset
   903
hgs
parents:
diff changeset
   904
    foreach (CntNameCacheItem* item, mSortedNames) {
hgs
parents:
diff changeset
   905
        item->setNameFormat(newFormat);
hgs
parents:
diff changeset
   906
    }
hgs
parents:
diff changeset
   907
hgs
parents:
diff changeset
   908
    mNameFetcher->sortNames(mSortedNames);
hgs
parents:
diff changeset
   909
    mNameFetcher->writeNamesToCache(mSortedNames);
hgs
parents:
diff changeset
   910
    mHasModifiedNames = false;
hgs
parents:
diff changeset
   911
hgs
parents:
diff changeset
   912
    emit dataChanged();
hgs
parents:
diff changeset
   913
hgs
parents:
diff changeset
   914
	CNT_EXIT
hgs
parents:
diff changeset
   915
}
hgs
parents:
diff changeset
   916
hgs
parents:
diff changeset
   917
/*! 
hgs
parents:
diff changeset
   918
    Replaces the names in cache with the ones in this list.
hgs
parents:
diff changeset
   919
    
hgs
parents:
diff changeset
   920
    \param newSortedNames the sorted list with names; this list will be cleared and
hgs
parents:
diff changeset
   921
                          ownership will be taken of the items in the list
hgs
parents:
diff changeset
   922
 */
hgs
parents:
diff changeset
   923
void CntCache::setNameList(QList<CntNameCacheItem *> newSortedNames)
hgs
parents:
diff changeset
   924
{
hgs
parents:
diff changeset
   925
    CNT_ENTRY
hgs
parents:
diff changeset
   926
    
hgs
parents:
diff changeset
   927
    bool hasModifiedContacts = false;
hgs
parents:
diff changeset
   928
    int count = newSortedNames.count();
hgs
parents:
diff changeset
   929
hgs
parents:
diff changeset
   930
    CNT_LOG_ARGS("curr_count=" << mSortedNames.count() << "db_count=" << count);
hgs
parents:
diff changeset
   931
hgs
parents:
diff changeset
   932
    // check if there have been any changes
hgs
parents:
diff changeset
   933
    if (mSortedNames.count() != count) {
hgs
parents:
diff changeset
   934
        hasModifiedContacts = true;
hgs
parents:
diff changeset
   935
    } else {
hgs
parents:
diff changeset
   936
        for (int i = 0; i < count; ++i) {
hgs
parents:
diff changeset
   937
            CntNameCacheItem *oldItem = mSortedNames.at(i);
hgs
parents:
diff changeset
   938
            CntNameCacheItem *newItem = newSortedNames.at(i);
hgs
parents:
diff changeset
   939
            CNT_LOG_ARGS("name=" << oldItem->name());
hgs
parents:
diff changeset
   940
            if (oldItem->contactId() != newItem->contactId() || oldItem->name() != newItem->name()) {
hgs
parents:
diff changeset
   941
                hasModifiedContacts = true;
hgs
parents:
diff changeset
   942
                break;
hgs
parents:
diff changeset
   943
            }
hgs
parents:
diff changeset
   944
        }
hgs
parents:
diff changeset
   945
    }
hgs
parents:
diff changeset
   946
hgs
parents:
diff changeset
   947
    // the list has changed, so use the new list instead
hgs
parents:
diff changeset
   948
    if (hasModifiedContacts) {
hgs
parents:
diff changeset
   949
    	CNT_LOG_ARGS("has modified contacts -> use new list")
hgs
parents:
diff changeset
   950
        qDeleteAll(mSortedNames);
hgs
parents:
diff changeset
   951
        mNameCache.clear();
hgs
parents:
diff changeset
   952
        mSortedNames.clear();
hgs
parents:
diff changeset
   953
        
hgs
parents:
diff changeset
   954
        foreach (CntNameCacheItem* item, newSortedNames) {
hgs
parents:
diff changeset
   955
            mSortedNames.append(item);
hgs
parents:
diff changeset
   956
            mNameCache.insert(item->contactId(), item);
hgs
parents:
diff changeset
   957
        }
hgs
parents:
diff changeset
   958
        
hgs
parents:
diff changeset
   959
        // write names to file cache
hgs
parents:
diff changeset
   960
        mNameFetcher->writeNamesToCache(mSortedNames);
hgs
parents:
diff changeset
   961
        
hgs
parents:
diff changeset
   962
        // notify clients that the list of names has changed
hgs
parents:
diff changeset
   963
        emit dataChanged();
hgs
parents:
diff changeset
   964
    } else {
hgs
parents:
diff changeset
   965
        qDeleteAll(newSortedNames);
hgs
parents:
diff changeset
   966
    }
hgs
parents:
diff changeset
   967
    
hgs
parents:
diff changeset
   968
    CNT_EXIT
hgs
parents:
diff changeset
   969
}
hgs
parents:
diff changeset
   970
hgs
parents:
diff changeset
   971
/*! 
hgs
parents:
diff changeset
   972
    Updates data in response to some contacts having changed and
hgs
parents:
diff changeset
   973
    then notifies observers that these contacts have changed.
hgs
parents:
diff changeset
   974
 */
hgs
parents:
diff changeset
   975
void CntCache::updateContacts(const QList<QContactLocalId> &changedContacts)
hgs
parents:
diff changeset
   976
{
hgs
parents:
diff changeset
   977
	CNT_ENTRY
hgs
parents:
diff changeset
   978
hgs
parents:
diff changeset
   979
    QString name;
hgs
parents:
diff changeset
   980
    QList<CntNameCacheItem*> items;
hgs
parents:
diff changeset
   981
hgs
parents:
diff changeset
   982
    // reloads the names of the changed contacts and updates the
hgs
parents:
diff changeset
   983
    // list of sorted names accordingly
hgs
parents:
diff changeset
   984
    foreach (QContactLocalId contactId, changedContacts) {
hgs
parents:
diff changeset
   985
        CntNameCacheItem *newItem = mNameFetcher->fetchOneName(contactId);
hgs
parents:
diff changeset
   986
        if (newItem != NULL) {
hgs
parents:
diff changeset
   987
            CntNameCacheItem *oldItem = mNameCache.value(contactId);
hgs
parents:
diff changeset
   988
            if (oldItem->name() != newItem->name()) {
hgs
parents:
diff changeset
   989
                QList<CntNameCacheItem*>::iterator oldPos = qLowerBound(mSortedNames.begin(), mSortedNames.end(), oldItem, CntNameFetcher::compareNames);
hgs
parents:
diff changeset
   990
                while (oldPos != mSortedNames.end() && *oldPos != oldItem) {
hgs
parents:
diff changeset
   991
                     ++oldPos;
hgs
parents:
diff changeset
   992
                }
hgs
parents:
diff changeset
   993
                QList<CntNameCacheItem*>::iterator newPos = qUpperBound(mSortedNames.begin(), mSortedNames.end(), newItem, CntNameFetcher::compareNames);
hgs
parents:
diff changeset
   994
                if (oldPos < newPos) {
hgs
parents:
diff changeset
   995
                    mSortedNames.move(oldPos - mSortedNames.begin(), (newPos - mSortedNames.begin()) - 1);
hgs
parents:
diff changeset
   996
                } else {
hgs
parents:
diff changeset
   997
                    mSortedNames.move(oldPos - mSortedNames.begin(), newPos - mSortedNames.begin());
hgs
parents:
diff changeset
   998
                }
hgs
parents:
diff changeset
   999
                *oldItem = *newItem;
hgs
parents:
diff changeset
  1000
                mHasModifiedNames = true;
hgs
parents:
diff changeset
  1001
            }
hgs
parents:
diff changeset
  1002
        }
hgs
parents:
diff changeset
  1003
    }
hgs
parents:
diff changeset
  1004
hgs
parents:
diff changeset
  1005
    // if any of the changed items have cached info, the info
hgs
parents:
diff changeset
  1006
    // is scheduled for refreshing
hgs
parents:
diff changeset
  1007
    foreach (QContactLocalId contactId, changedContacts) {
hgs
parents:
diff changeset
  1008
        if (mInfoCache.contains(contactId)) {
hgs
parents:
diff changeset
  1009
            QList<CntNameCacheItem*>::iterator pos = qLowerBound(mSortedNames.begin(), mSortedNames.end(), mNameCache.value(contactId), CntNameFetcher::compareNames);
hgs
parents:
diff changeset
  1010
            while (pos != mSortedNames.end() && (*pos)->contactId() != contactId) {
hgs
parents:
diff changeset
  1011
                ++pos;
hgs
parents:
diff changeset
  1012
            }
hgs
parents:
diff changeset
  1013
            mInfoFetcher->scheduleJob(new CntInfoJob(contactId), pos - mSortedNames.begin());
hgs
parents:
diff changeset
  1014
        }
hgs
parents:
diff changeset
  1015
    }
hgs
parents:
diff changeset
  1016
hgs
parents:
diff changeset
  1017
    // inform clients about these changes
hgs
parents:
diff changeset
  1018
    emit contactsChanged(changedContacts);
hgs
parents:
diff changeset
  1019
hgs
parents:
diff changeset
  1020
    if (!mProcessingJobs && mJobsPostponed == JobsNotPostponed) {
hgs
parents:
diff changeset
  1021
        // there might be new jobs now
hgs
parents:
diff changeset
  1022
        mProcessingJobs = true;
hgs
parents:
diff changeset
  1023
        HbApplication::instance()->postEvent(this, new QEvent(ProcessJobsEvent));
hgs
parents:
diff changeset
  1024
    }
hgs
parents:
diff changeset
  1025
hgs
parents:
diff changeset
  1026
	CNT_EXIT
hgs
parents:
diff changeset
  1027
}
hgs
parents:
diff changeset
  1028
hgs
parents:
diff changeset
  1029
/*! 
hgs
parents:
diff changeset
  1030
    Updates data in response to some contacts having been removed
hgs
parents:
diff changeset
  1031
    and then notifies observers that the contacts have been removed.
hgs
parents:
diff changeset
  1032
 */
hgs
parents:
diff changeset
  1033
void CntCache::removeContacts(const QList<QContactLocalId> &removedContacts)
hgs
parents:
diff changeset
  1034
{
hgs
parents:
diff changeset
  1035
	CNT_ENTRY
hgs
parents:
diff changeset
  1036
hgs
parents:
diff changeset
  1037
    // removed the deleted contacts from the name cache and from the
hgs
parents:
diff changeset
  1038
    // list of sorted names
hgs
parents:
diff changeset
  1039
    foreach (QContactLocalId contactId, removedContacts) {
hgs
parents:
diff changeset
  1040
        if (mNameCache.contains(contactId)) {
hgs
parents:
diff changeset
  1041
            CntNameCacheItem *item = mNameCache.take(contactId);
hgs
parents:
diff changeset
  1042
            QList<CntNameCacheItem*>::iterator pos = qLowerBound(mSortedNames.begin(), mSortedNames.end(), item, CntNameFetcher::compareNames);
hgs
parents:
diff changeset
  1043
            while (*pos != item && pos != mSortedNames.end()) {
hgs
parents:
diff changeset
  1044
                ++pos;
hgs
parents:
diff changeset
  1045
            }
hgs
parents:
diff changeset
  1046
            mSortedNames.erase(pos);
hgs
parents:
diff changeset
  1047
            delete item;
hgs
parents:
diff changeset
  1048
            mHasModifiedNames = true;
hgs
parents:
diff changeset
  1049
        }
hgs
parents:
diff changeset
  1050
    }
hgs
parents:
diff changeset
  1051
hgs
parents:
diff changeset
  1052
    // info for these deleted items should be removed from cache
hgs
parents:
diff changeset
  1053
    foreach (QContactLocalId contactId, removedContacts) {
hgs
parents:
diff changeset
  1054
        if (mInfoCache.contains(contactId)) {
hgs
parents:
diff changeset
  1055
            CntInfoCacheItem* item = mInfoCache.take(contactId);
hgs
parents:
diff changeset
  1056
            delete item;
hgs
parents:
diff changeset
  1057
        }
hgs
parents:
diff changeset
  1058
    }
hgs
parents:
diff changeset
  1059
hgs
parents:
diff changeset
  1060
    // inform clients about these deleted contacts
hgs
parents:
diff changeset
  1061
    emit contactsRemoved(removedContacts);
hgs
parents:
diff changeset
  1062
hgs
parents:
diff changeset
  1063
	CNT_EXIT
hgs
parents:
diff changeset
  1064
}
hgs
parents:
diff changeset
  1065
hgs
parents:
diff changeset
  1066
/*! 
hgs
parents:
diff changeset
  1067
    Updates data in response to some contacts having been added
hgs
parents:
diff changeset
  1068
    and then notifies observers that the contacts have been added.
hgs
parents:
diff changeset
  1069
 */
hgs
parents:
diff changeset
  1070
void CntCache::addContacts(const QList<QContactLocalId> &addedContacts)
hgs
parents:
diff changeset
  1071
{
hgs
parents:
diff changeset
  1072
	CNT_ENTRY
hgs
parents:
diff changeset
  1073
hgs
parents:
diff changeset
  1074
    // add the new contacts to the name cache and to the
hgs
parents:
diff changeset
  1075
    // list of sorted names
hgs
parents:
diff changeset
  1076
    foreach (QContactLocalId contactId, addedContacts) {
hgs
parents:
diff changeset
  1077
        CntNameCacheItem *item = mNameFetcher->fetchOneName(contactId);
hgs
parents:
diff changeset
  1078
        if (item != NULL) {
hgs
parents:
diff changeset
  1079
            mNameCache.insert(contactId, item);
hgs
parents:
diff changeset
  1080
            QList<CntNameCacheItem*>::iterator i = qUpperBound(mSortedNames.begin(), mSortedNames.end(), item, CntNameFetcher::compareNames);
hgs
parents:
diff changeset
  1081
            mSortedNames.insert(i, item);
hgs
parents:
diff changeset
  1082
            mHasModifiedNames = true;
hgs
parents:
diff changeset
  1083
        }
hgs
parents:
diff changeset
  1084
    }
hgs
parents:
diff changeset
  1085
hgs
parents:
diff changeset
  1086
    // inform clients about the new contacts
hgs
parents:
diff changeset
  1087
    emit contactsAdded(addedContacts);
hgs
parents:
diff changeset
  1088
hgs
parents:
diff changeset
  1089
	CNT_EXIT
hgs
parents:
diff changeset
  1090
}