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