phonebookengines/cntlistmodel/src/cntnamefetcher.cpp
changeset 81 640d30f4fb64
parent 77 c18f9fa7f42e
child 84 63017c97b1d6
equal deleted inserted replaced
77:c18f9fa7f42e 81:640d30f4fb64
     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: Private data and helper classes used by class CntCache.
       
    15 *
       
    16 */
       
    17 
       
    18 #include <e32base.h>
       
    19 #include <s32mem.h>
       
    20 #include <e32std.h>
       
    21 
       
    22 #include <xqutils.h>
       
    23 #include <QEvent>
       
    24 #include <QFile>
       
    25 #include <QDir>
       
    26 #include <hbapplication.h>
       
    27 #include <hbstringutil.h>
       
    28 
       
    29 #include <cntdb.h>
       
    30 #include <cntuids.h>
       
    31 #include <cntdebug.h>
       
    32 
       
    33 #include "cntnamefetcher.h"
       
    34 
       
    35 // constants used when fetching names from CntSrv
       
    36 #define KCntSearchResultList 99
       
    37 #define KCntOpenDataBase 100
       
    38 _LIT(KCntServerExe, "CNTSRV.EXE");
       
    39 _LIT(KCntServerName, "CNTSRV");
       
    40 const TInt KAsyncMessageSlots = 6;
       
    41 const TInt KCntServerMajorVersionNumber=1;
       
    42 const TInt KCntServerMinorVersionNumber=1;
       
    43 const TInt KCntServerBuildVersionNumber=1;
       
    44 static const QEvent::Type CntAsynchOperation = QEvent::User;
       
    45 
       
    46 // constants used for file cache
       
    47 static const QString cacheFolder = "20022EF9";
       
    48 static const QString cacheFilename = "contactcache.dat";
       
    49 
       
    50 /*!
       
    51      Internal class used by CntSrvConnection to issues requests to CntSrv.
       
    52   */
       
    53 class CntSrvSession : public RSessionBase
       
    54 {
       
    55 public:
       
    56     CntSrvSession() { mConnected = false; }
       
    57     ~CntSrvSession() { RHandleBase::Close(); }
       
    58     void executeSqlQueryL(const TDesC &sqlQuery, QList<CntNameCacheItem *> &names, CntNameOrder nameFormat, int sizeHintKB);
       
    59 
       
    60 private:
       
    61     void connectCntSrvL();
       
    62 
       
    63 private:
       
    64     bool mConnected;
       
    65 };
       
    66 
       
    67 CntSrvConnection::CntSrvConnection()
       
    68     : mSession(NULL),
       
    69       mIsAsynchronous(false)
       
    70 {
       
    71 }
       
    72 
       
    73 CntSrvConnection::~CntSrvConnection()
       
    74 {
       
    75     disconnect();
       
    76 
       
    77     if (mThread.isRunning()) {
       
    78         mThread.quit();
       
    79         mThread.wait();
       
    80     }
       
    81 
       
    82     delete mSession;
       
    83 
       
    84     mNames.clear();
       
    85 }
       
    86 
       
    87 void CntSrvConnection::setAsynchronous()
       
    88 {
       
    89     mIsAsynchronous = true;
       
    90     mThread.start();
       
    91     moveToThread(&mThread);
       
    92 }
       
    93 
       
    94 bool CntSrvConnection::executeSqlQuery(const QString &sqlQuery, CntNameOrder nameFormat, int sizeHintKB)
       
    95 {
       
    96     CNT_ENTRY
       
    97 
       
    98     if (!mSession) {
       
    99         mSession = new CntSrvSession();
       
   100     }
       
   101 
       
   102     if (mIsAsynchronous) {
       
   103         mSqlQuery = sqlQuery;
       
   104         mNameFormat = nameFormat;
       
   105         mSizeHintKB = sizeHintKB;
       
   106         HbApplication::instance()->postEvent(this, new QEvent(CntAsynchOperation));
       
   107     } else {
       
   108         mNames.clear();
       
   109         TPtrC queryPtr(sqlQuery.utf16(), sqlQuery.length());
       
   110         TRAPD(err, mSession->executeSqlQueryL(queryPtr, mNames, nameFormat, sizeHintKB));
       
   111         if (err != KErrNone) {
       
   112             qDeleteAll(mNames);
       
   113             mNames.clear();
       
   114             CNT_EXIT
       
   115             return false;
       
   116         }
       
   117     }
       
   118 
       
   119     CNT_EXIT
       
   120     
       
   121     return true;
       
   122 }
       
   123 
       
   124 bool CntSrvConnection::event(QEvent *event)
       
   125 {
       
   126     if (event->type() == CntAsynchOperation) {
       
   127         CNT_ENTRY
       
   128 
       
   129         mNames.clear();
       
   130         TPtrC ptr(mSqlQuery.utf16(), mSqlQuery.length());
       
   131         TRAPD(err, mSession->executeSqlQueryL(ptr, mNames, mNameFormat, mSizeHintKB));
       
   132         if (err != KErrNone) {
       
   133             qDeleteAll(mNames);
       
   134             mNames.clear();
       
   135         }
       
   136         emit namesRead();
       
   137         qStableSort(mNames.begin(), mNames.end(), CntNameFetcher::compareNames);
       
   138         delete mSession;
       
   139         mSession = NULL;
       
   140         emit namesSorted();
       
   141 
       
   142         CNT_EXIT
       
   143 
       
   144         return true;
       
   145     }
       
   146     
       
   147     return QObject::event(event);
       
   148 }
       
   149 
       
   150 /*!
       
   151     Executes a special SQL query: the first column must be the contact id and
       
   152     the subsequent columns must be varchar fields.
       
   153     
       
   154     \param sqlQuery the SQL to execute
       
   155     \param names the list where the results will be stored
       
   156     \param nameFormat the format the names should be stored in 
       
   157     \param sizeHintKB the expected size of the buffer needed to fit the results; a too
       
   158                       small value will effectively double the fetch time, since the
       
   159                       buffer is then resized and the data refetched a second time
       
   160  */
       
   161 void CntSrvSession::executeSqlQueryL(const TDesC& sqlQuery, QList<CntNameCacheItem*> &names, CntNameOrder nameFormat, int sizeHintKB)
       
   162 {
       
   163     int listSize = 0;
       
   164 
       
   165     // read the ids and names from the database
       
   166     if (!mConnected) {
       
   167         connectCntSrvL();
       
   168     }
       
   169 
       
   170     // allocate tmeporary buffer
       
   171     TInt bufferSize = sizeHintKB * 1024;
       
   172     CBufFlat* buffer = CBufFlat::NewL(256);
       
   173     CleanupStack::PushL(buffer);
       
   174 
       
   175     // try to fetch the results, if the fetch fails with
       
   176     // a positive value, it means the buffer was too small
       
   177     // in this case the buffer is resized and the results
       
   178     // are fetched again
       
   179     for (TInt tries = 0; tries < 2 && bufferSize > 0; ++tries) {
       
   180         buffer->ResizeL(bufferSize);
       
   181         TPtr8 bufferPtr = buffer->Ptr(0);
       
   182         TIpcArgs args;
       
   183         args.Set(0, &bufferPtr);
       
   184         args.Set(1, &sqlQuery);
       
   185         bufferSize = SendReceive(KCntSearchResultList, args);
       
   186         CNT_LOG_ARGS("buffer size =" << bufferSize)
       
   187         User::LeaveIfError(bufferSize);
       
   188     } 
       
   189 
       
   190     // store the formatted names into the list
       
   191     RBufReadStream readStream;
       
   192     TInt id;
       
   193     TBuf<256> firstName;
       
   194     TBuf<256> lastName;
       
   195 
       
   196     readStream.Open(*buffer);
       
   197     for (int i = 0; (id = readStream.ReadInt32L()) != 0; ++i) {
       
   198         readStream >> firstName;
       
   199         readStream >> lastName;
       
   200         CntNameCacheItem* item = new (ELeave) CntNameCacheItem(
       
   201             id,
       
   202             QString::fromUtf16(firstName.Ptr(), firstName.Length()),
       
   203             QString::fromUtf16(lastName.Ptr(), lastName.Length()),
       
   204             nameFormat);
       
   205         if (i >= listSize - 1) {
       
   206             // if the list is runnning out of space, resize it;
       
   207             // initial size is 1000 and after that it doubles
       
   208             // every time it runs out of space
       
   209             if (listSize == 0) {
       
   210                 listSize = 1000;
       
   211             } else {
       
   212                 listSize *= 2;
       
   213             }
       
   214             QT_TRY {
       
   215                 names.reserve(listSize);
       
   216             } QT_CATCH (...) {
       
   217                 // clean up and return
       
   218                 CleanupStack::PopAndDestroy(buffer);
       
   219                 qDeleteAll(names);
       
   220                 names.clear();
       
   221                 return;
       
   222             }
       
   223         }
       
   224         names.append(item);
       
   225     }
       
   226 
       
   227     CleanupStack::PopAndDestroy(buffer);
       
   228 }
       
   229 
       
   230 /*!
       
   231     Connect to / create a contacts server session.
       
   232  */
       
   233 void CntSrvSession::connectCntSrvL()
       
   234 {
       
   235     // Assume the server is already running and attempt to create a session
       
   236     // with a maximum of KAsyncMessageSlots message slots.
       
   237     TInt err = CreateSession(KCntServerName,
       
   238                              TVersion(KCntServerMajorVersionNumber, KCntServerMinorVersionNumber, KCntServerBuildVersionNumber),
       
   239                              KAsyncMessageSlots);
       
   240     
       
   241     // Server is not running
       
   242     if (err == KErrNotFound) {
       
   243         // Use the RProcess API to start the server.
       
   244         RProcess server;
       
   245         User::LeaveIfError(server.Create(KCntServerExe, KNullDesC));
       
   246         
       
   247         // Enforce server to be at system default priority EPriorityForeground
       
   248         server.SetPriority(EPriorityForeground);
       
   249         
       
   250         // Synchronize with the server.
       
   251         TRequestStatus reqStatus;
       
   252         server.Rendezvous(reqStatus);
       
   253         server.Resume();
       
   254         
       
   255         // Server will call the reciprocal static synchronization call.
       
   256         User::WaitForRequest(reqStatus);
       
   257         server.Close();
       
   258         User::LeaveIfError(reqStatus.Int());
       
   259         
       
   260         // Create the server session.
       
   261         User::LeaveIfError(CreateSession(KCntServerName,
       
   262                                          TVersion(KCntServerMajorVersionNumber, KCntServerMinorVersionNumber, KCntServerBuildVersionNumber),
       
   263                                          KAsyncMessageSlots));
       
   264     } else {
       
   265         User::LeaveIfError(err);
       
   266     }
       
   267     
       
   268     TIpcArgs args;
       
   269     args.Set(0, &KNullDesC);
       
   270     User::LeaveIfError(SendReceive(KCntOpenDataBase, args));
       
   271 
       
   272     mConnected = true;
       
   273 }
       
   274 
       
   275 /*!
       
   276     Creates a CntNameFetcher object.
       
   277  */
       
   278 CntNameFetcher::CntNameFetcher()
       
   279     : mDbConnection(NULL),
       
   280       mAsynchDbConnection(NULL),
       
   281       mSettingsManager(NULL),
       
   282       mNameFormatSetting(NULL),
       
   283       mBufferSizeEstimate(0)
       
   284 {
       
   285     CNT_ENTRY
       
   286 
       
   287     // get name format setting and listen to changes
       
   288     mSettingsManager = new XQSettingsManager();
       
   289     mNameFormatSetting = new XQSettingsKey(XQSettingsKey::TargetCentralRepository, KCRCntSettings.iUid, KCntNameOrdering);
       
   290     mNameFormat = static_cast<CntNameOrder>(mSettingsManager->readItemValue(*mNameFormatSetting, XQSettingsManager::TypeInt).toInt());
       
   291     mSettingsManager->startMonitoring(*mNameFormatSetting, XQSettingsManager::TypeInt);
       
   292     connect(mSettingsManager, SIGNAL(valueChanged(const XQSettingsKey&, const QVariant&)), this, SLOT(setNameFormat(const XQSettingsKey&, const QVariant&)));
       
   293 
       
   294     // connect to contacts server
       
   295     mDbConnection = new CntSrvConnection();
       
   296 
       
   297     CNT_EXIT
       
   298 }
       
   299 
       
   300 /*!
       
   301     Destroys a CntNameFetcher object.
       
   302  */
       
   303 CntNameFetcher::~CntNameFetcher()
       
   304 {
       
   305     CNT_ENTRY
       
   306 
       
   307     delete mSettingsManager;
       
   308     delete mNameFormatSetting;
       
   309     delete mDbConnection;
       
   310     delete mAsynchDbConnection;
       
   311 
       
   312     CNT_EXIT
       
   313 }
       
   314 
       
   315 /*!
       
   316     Reads names from the file cache.
       
   317 
       
   318     \return true if the names were read successfully from the cache file
       
   319 
       
   320  */
       
   321 bool CntNameFetcher::readNamesFromCache(QList<CntNameCacheItem*> &names)
       
   322 {
       
   323     CNT_ENTRY
       
   324 
       
   325     bool success = true;
       
   326     quint32 itemCount;
       
   327     quint32 nameFormat;
       
   328 
       
   329     QFile cacheFile(XQUtils::phoneMemoryRootPath() + cacheFolder + "\\" + cacheFilename);
       
   330     if (!cacheFile.open(QIODevice::ReadOnly)) {
       
   331         return false;
       
   332     }
       
   333 
       
   334     QDataStream in(&cacheFile);
       
   335 
       
   336     mBufferSizeEstimate = 0;
       
   337     QT_TRY {
       
   338         // read header: nr of items, name format
       
   339         in >> itemCount;
       
   340         in >> nameFormat;
       
   341         names.reserve(itemCount);
       
   342 
       
   343         // populate list with names
       
   344         while (itemCount-- > 0) {
       
   345             CntNameCacheItem *item = CntNameCacheItem::internalize(in, (CntNameOrder) nameFormat);
       
   346             names.append(item);
       
   347             mBufferSizeEstimate += 4 + 2 * item->name().length();
       
   348         }
       
   349     } QT_CATCH (...) {
       
   350         qDeleteAll(names);
       
   351         names.clear();
       
   352         success = false;
       
   353     }
       
   354     
       
   355     cacheFile.close();
       
   356     
       
   357     CNT_EXIT
       
   358     
       
   359     return success;
       
   360 }
       
   361 
       
   362 /*!
       
   363     Write names to the file cache.
       
   364  */
       
   365 bool CntNameFetcher::writeNamesToCache(const QList<CntNameCacheItem*> &names) const
       
   366 {
       
   367     CNT_ENTRY
       
   368 
       
   369     bool success = true;
       
   370 
       
   371     // create folder for cache file if it does not already exist
       
   372     QString path = XQUtils::phoneMemoryRootPath() + cacheFolder;
       
   373     if (!QDir(path).exists()) {
       
   374         QDir dir(XQUtils::phoneMemoryRootPath());
       
   375         if (!dir.mkdir(cacheFolder)) {
       
   376             CNT_EXIT_ARGS("failed to create folder: " << path)
       
   377             return false;
       
   378         }
       
   379 
       
   380         // have to use native Symbian code to make the dir hidden
       
   381         RFs fs;
       
   382         fs.Connect();
       
   383         TPtrC pathPtr(path.utf16(), path.length());
       
   384         if (fs.SetAtt(pathPtr, KEntryAttHidden, 0) != KErrNone) {
       
   385             fs.Close();
       
   386             return false;
       
   387         }
       
   388         fs.Close();
       
   389     }    
       
   390 
       
   391     // open cache file for writing
       
   392     QFile cacheFile(XQUtils::phoneMemoryRootPath() + cacheFolder + "\\" + cacheFilename);
       
   393     if (!cacheFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
       
   394         CNT_EXIT_ARGS("failed to create file")
       
   395         return false;
       
   396     }
       
   397     QDataStream out(&cacheFile);
       
   398 
       
   399     // write the names to the cache file
       
   400     QT_TRY {
       
   401         // write header
       
   402         out << names.size();
       
   403         out << (quint32) mNameFormat;
       
   404 
       
   405         // write list with names
       
   406         foreach (CntNameCacheItem* name, names) {
       
   407             name->externalize(out);
       
   408         }
       
   409     } QT_CATCH (...) {
       
   410         success = false;
       
   411     }
       
   412 
       
   413     cacheFile.close();
       
   414 
       
   415     CNT_EXIT
       
   416 
       
   417     return success;
       
   418 }
       
   419 
       
   420 /*!
       
   421     Reads the name of one contact from the contact database synchronously.
       
   422     
       
   423     \param contactId the id of the contact
       
   424  */
       
   425 CntNameCacheItem* CntNameFetcher::readOneName(QContactLocalId contactId) const
       
   426 {
       
   427     CNT_ENTRY
       
   428 
       
   429     QString sqlQuery = QString("SELECT contact_id, first_name, last_name FROM contact WHERE (type_flags>>24)<=1 AND contact_id=%1").arg(contactId);
       
   430     mDbConnection->executeSqlQuery(sqlQuery, mNameFormat, 2);
       
   431     
       
   432     if (mDbConnection->names().size() == 0) {
       
   433         return NULL;
       
   434     }
       
   435 
       
   436     CNT_EXIT
       
   437     
       
   438     return mDbConnection->names().at(0);
       
   439 }
       
   440 
       
   441 /*!
       
   442     Reads the names of all contacts from the contact database asynchronously.
       
   443  */
       
   444 void CntNameFetcher::readAllNamesAsynch()
       
   445 {
       
   446     CNT_ENTRY
       
   447     
       
   448     if (mAsynchDbConnection != NULL) {
       
   449         // an asynch fetch is already in progress, so no need to start a new one
       
   450         return;
       
   451     }
       
   452     
       
   453     if (mBufferSizeEstimate == 0) {
       
   454         mBufferSizeEstimate = 240 * 1024;
       
   455     }
       
   456     
       
   457     CNT_LOG_ARGS("buffer size =" << mBufferSizeEstimate)
       
   458     
       
   459     mAsynchDbConnection = new CntSrvConnection();
       
   460     mAsynchDbConnection->setAsynchronous();
       
   461     connect(mAsynchDbConnection, SIGNAL(namesRead()), this, SIGNAL(databaseAccessComplete()));
       
   462     connect(mAsynchDbConnection, SIGNAL(namesSorted()), this, SLOT(sendCompletionSignal()));
       
   463     mAsynchDbConnection->executeSqlQuery("SELECT contact_id, first_name, last_name FROM contact WHERE (type_flags>>24)<=1", mNameFormat, 16 + mBufferSizeEstimate / 1024);
       
   464     
       
   465     CNT_EXIT
       
   466 }
       
   467 
       
   468 /*!
       
   469     Sorts the names quickly and in a locale aware manner.
       
   470  */
       
   471 void CntNameFetcher::sortNames(QList<CntNameCacheItem *> &names) const
       
   472 {
       
   473     CNT_ENTRY
       
   474 
       
   475     qStableSort(names.begin(), names.end(), CntNameFetcher::compareNames);
       
   476 
       
   477     CNT_EXIT
       
   478 }
       
   479 
       
   480 /*! 
       
   481     Compares a pair of contact names and returns true if the first
       
   482     one should be presented before the second one in a list. This
       
   483     static function is used e.g. when sorting lists of names.
       
   484  */
       
   485 bool CntNameFetcher::compareNames(const CntNameCacheItem* a, const CntNameCacheItem* b)
       
   486 {
       
   487     QString aName = a->name();
       
   488     QString bName = b->name();
       
   489 
       
   490     if (aName.isEmpty()) {
       
   491         return false;
       
   492     } else if (bName.isEmpty()) {
       
   493         return true;
       
   494     }
       
   495 
       
   496     return (HbStringUtil::compareC(aName, bName) < 0);
       
   497 }
       
   498 
       
   499 /*!
       
   500     Notifies clients that the name format has changed. This function is called by the framework
       
   501     if the name format settings is changed, see the constructor.
       
   502  */
       
   503 void CntNameFetcher::setNameFormat(const XQSettingsKey &/*key*/, const QVariant &value)
       
   504 {
       
   505     CNT_ENTRY
       
   506 
       
   507     bool ok = false;
       
   508     CntNameOrder newNameFormat = static_cast<CntNameOrder>(value.toInt(&ok));
       
   509     if (ok && newNameFormat != mNameFormat) {
       
   510         mNameFormat = newNameFormat;
       
   511         emit nameFormatChanged(mNameFormat);
       
   512     }
       
   513 
       
   514     CNT_EXIT
       
   515 }
       
   516 
       
   517 /*!
       
   518     Emits the results of a completed asynch database operation.
       
   519  */
       
   520 void CntNameFetcher::sendCompletionSignal()
       
   521 {
       
   522     CNT_ENTRY
       
   523 
       
   524     emit namesAvailable(mAsynchDbConnection->names());
       
   525 
       
   526     delete mAsynchDbConnection;
       
   527     mAsynchDbConnection = NULL;
       
   528 
       
   529     CNT_EXIT
       
   530 }
       
   531 
       
   532 /*!
       
   533     Creates a CntNameCacheItem object.
       
   534  */
       
   535 CntNameCacheItem::CntNameCacheItem(QContactLocalId id, const QString& firstName, const QString& lastName, CntNameOrder nameFormat)
       
   536 {
       
   537     mContactId = id;
       
   538     setFormattedName(firstName, lastName, nameFormat);
       
   539 }
       
   540 
       
   541 /*!
       
   542     Destroys a CntNameCacheItem object.
       
   543  */
       
   544 CntNameCacheItem::~CntNameCacheItem()
       
   545 {
       
   546 }
       
   547 
       
   548 /*!
       
   549     Changes the format used to present the name.
       
   550  */
       
   551 void CntNameCacheItem::setNameFormat(CntNameOrder newFormat)
       
   552 {
       
   553     QString firstName = mName.mid(mFirstNamePosition&0xffff, mFirstNamePosition>>16);
       
   554     QString lastName = mName.mid(mLastNamePosition&0xffff, mLastNamePosition>>16);
       
   555     setFormattedName(firstName, lastName, newFormat);
       
   556 }
       
   557 
       
   558 /*!
       
   559     Copies the contents of the other cache item to this one.
       
   560  */
       
   561 void CntNameCacheItem::operator=(const CntNameCacheItem &other)
       
   562 {
       
   563     mContactId = other.mContactId;
       
   564     mFirstNamePosition = other.mFirstNamePosition;
       
   565     mLastNamePosition = other.mLastNamePosition;
       
   566     mName = other.mName;
       
   567 }
       
   568 
       
   569 /*!
       
   570     Externalizes a CntNameCacheItem object.
       
   571  */
       
   572 void CntNameCacheItem::externalize(QDataStream &stream)
       
   573 {
       
   574     stream << mContactId;
       
   575     stream << mFirstNamePosition;
       
   576     stream << mLastNamePosition;
       
   577     stream << mName;
       
   578 }
       
   579 
       
   580 /*!
       
   581     Internalizes a CntNameCacheItem object.
       
   582  */
       
   583 CntNameCacheItem* CntNameCacheItem::internalize(QDataStream &stream, CntNameOrder nameFormat)
       
   584 {
       
   585     quint32 id;
       
   586     quint32 firstNamePosition;
       
   587     quint32 lastNamePosition;
       
   588     QString name;
       
   589     
       
   590     stream >> id;
       
   591     stream >> firstNamePosition;
       
   592     stream >> lastNamePosition;
       
   593     stream >> name;
       
   594     
       
   595     QString firstName = name.mid(firstNamePosition&0xffff, firstNamePosition>>16);
       
   596     QString lastName = name.mid(lastNamePosition&0xffff, lastNamePosition>>16);
       
   597 
       
   598     return new CntNameCacheItem(id, firstName, lastName, nameFormat);
       
   599 }
       
   600 
       
   601 /*!
       
   602     Sets the formatted name and positions of the first name and last name,
       
   603     according to the name format in the parameter.
       
   604  */
       
   605 void CntNameCacheItem::setFormattedName(const QString& firstName, const QString& lastName, CntNameOrder nameFormat)
       
   606 {
       
   607     int firstNameLength = firstName.length();
       
   608     int lastNameLength = lastName.length();
       
   609 
       
   610     if (lastNameLength == 0) {
       
   611         mName = firstName;
       
   612         mFirstNamePosition = firstNameLength << 16;
       
   613         mLastNamePosition = 0;
       
   614     } else if (firstNameLength == 0) {
       
   615         mName = lastName;
       
   616         mFirstNamePosition = 0;
       
   617         mLastNamePosition = lastNameLength << 16;
       
   618     } else {
       
   619         if (nameFormat == CntOrderLastFirst) {
       
   620             mName = lastName + " " + firstName;
       
   621             mFirstNamePosition = (firstNameLength << 16) | (lastNameLength + 1);
       
   622             mLastNamePosition = (lastNameLength << 16);
       
   623         } else if (nameFormat == CntOrderLastCommaFirst) {
       
   624             mName = lastName + ", " + firstName;
       
   625             mFirstNamePosition = (firstNameLength << 16) | (lastNameLength + 2);
       
   626             mLastNamePosition = (lastNameLength << 16);
       
   627         } else {
       
   628             mName = firstName + " " + lastName;
       
   629             mFirstNamePosition = (firstNameLength << 16);
       
   630             mLastNamePosition = (lastNameLength << 16) | (firstNameLength + 1);
       
   631         }
       
   632     }
       
   633 }
       
   634 
       
   635 QString CntNameCacheItem::firstName() const
       
   636 {
       
   637     return mName.mid(mFirstNamePosition&0xffff, mFirstNamePosition>>16);
       
   638 }
       
   639 
       
   640 QString CntNameCacheItem::lastName() const
       
   641 {
       
   642     return mName.mid(mLastNamePosition&0xffff, mLastNamePosition>>16);
       
   643 }