diff -r 64e38f08e49c -r 47d84de1c893 emailservices/nmutilities/src/nmcontacthistorymodel_p.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emailservices/nmutilities/src/nmcontacthistorymodel_p.cpp Mon Oct 04 00:05:37 2010 +0300 @@ -0,0 +1,515 @@ +/* +* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: Private implementation of Contact History Model API +* +*/ + +#include "emailmru.h" +#include "nmcontacthistorymodel_p.h" + +// -------------------------------------------------------------------------- +// Start of implementation (NmContactHistoryModelPrivate) +// -------------------------------------------------------------------------- +/*! + Constructor of NmContactHistoryModelPrivate + + \param type The valid values are described by + NmContactHistoryModelPrivate::HistoryModelType enum. +*/ +NmContactHistoryModelPrivate::NmContactHistoryModelPrivate( + const NmContactHistoryModelType modelType) : + mType(modelType), + mContactManager(0), + mModelReady(false) +{ + mContactManager = new QContactManager("symbian"); + mNameOrder = EmailMRU::nameOrder(); +} + +/*! + Destructor of ContactHistoryModel +*/ +NmContactHistoryModelPrivate::~NmContactHistoryModelPrivate() +{ + delete mContactManager; + mPrivateItemList.clear(); + mModelItemList.clear(); +} + +/*! + Searches contact & MRU databases according to query parameters. + Emits QueryCompleted() when ready. + + \param query Text to be searched + \return none + + Note:: QContactManager supports max. ten characters long queries. +*/ +void NmContactHistoryModelPrivate::queryDatabases(const QString& query) +{ + mModelReady = false; + // Clear contacts in the list + mPrivateItemList.clear(); + mModelItemList.clear(); + mMruList.clear(); + mMruMatches.clear(); + + // Modify search to suit our needs + // Space must be removed, because it is understood as logigal AND + // with QContactManager API + QString modifiedQuery = query; + + int spcPosition = query.indexOf(" "); + + if ( spcPosition != -1 ) + { + modifiedQuery = query.left(spcPosition); + } + + queryMruDatabase(modifiedQuery); + populateListWithMruItems(modifiedQuery); + + if (mContactManager) + { + // Get matching IDs from Contacts DB + QList cnt_ids = queryContactDatabase(modifiedQuery); + + // Populate mPrivateItemList with contact items. + populateListWithContactItems(cnt_ids, modifiedQuery); + } + + // Currently we will always emit 0 as completion code. + + //TODO: Will be removed, Debug Code. + for (int i = 0; i < mPrivateItemList.size(); i++) + { + QSharedPointer itemData = mPrivateItemList[i]; + + QString dbgString = itemData->mItems[0].mItemText; + dbgString.append(" "); + dbgString.append(itemData->mItems[1].mItemText); + + qDebug(dbgString.toLatin1()); + + + } + + emit queryCompleted(0); +} + +/*! + Internal helper function for queryDatabases() + Not meant to be used alone. + + \param query Text to be searched + \return list of Contact items. + \sa queryDatabases( ) +*/ +QList NmContactHistoryModelPrivate::queryContactDatabase( + const QString &query) +{ + // Define filter + QContactDetailFilter df; + + df.setDetailDefinitionName(QContactEmailAddress::DefinitionName, + QContactEmailAddress::FieldEmailAddress ); + + df.setMatchFlags( QContactFilter::MatchKeypadCollation ); + + // Construct pattern + QString pattern = query + QChar(30) + QString("vqwerty"); + df.setValue( pattern ); + + // Get matching IDs + QList cnt_ids = mContactManager->contactIds( df ); + + return cnt_ids; +} + +/*! + Internal helper function for queryDatabases() + Not meant to be used alone. + + \param query Text to be searched from MRU + \return true on success. + \sa queryDatabases( ) +*/ +bool NmContactHistoryModelPrivate::queryMruDatabase( + const QString &query) +{ + if (mType == EmailAddressModel) + { + bool mruListFilled = fillMruMatchList(); + + if (!mruListFilled) + { + return false; + } + + QHashIterator i(mMruList); + + while (i.hasNext()) + { + i.next(); + + QString address = i.key(); + QString name = i.value(); + + if ((name.length() == 0) && (address.contains('@'))) + { + name = address.left(address.indexOf("@")); + } + + if (address.contains(query, Qt::CaseInsensitive)) + { + mMruMatches.insert(name, address); + } + else if (name.contains(query, Qt::CaseInsensitive)) + { + mMruMatches.insert(name, address); + } + } + } + + return true; +} + +/*! + Internal helper function for queryDatabases() + Not meant to be used alone. + + \param cnt_ids List of contact IDs + \param modifiedQuery Query + \sa queryDatabases( ) +*/ +void NmContactHistoryModelPrivate::populateListWithContactItems( + const QList cnt_ids, + const QString &modifiedQuery) +{ + int cntCount = cnt_ids.count(); + // Populate mPrivateItemList with contact items. + for ( int cntIndex = 0; cntIndex < cntCount; cntIndex++) + { + QContactLocalId cid = cnt_ids.at( cntIndex ); + // Fetch extended contact information from DB by ID + QContact contact = mContactManager->contact( cid ); + + // Get number of associated emails for contact + int numberOfEmails = contact.details( + QContactEmailAddress::DefinitionName).count(); + + if (numberOfEmails == 0) + { + continue; // Scotty, I need warp speed. + } + + // Get contact name details + QContactName contactName = contact.detail( + QContactName::DefinitionName); + + QString firstName = contactName.value( + QContactName::FieldFirstName); + QString lastName = contactName.value( + QContactName::FieldLastName); + + for (int emailIndex = 0; emailIndex < numberOfEmails; emailIndex++) + { + // For Display name (ex. John Doe) + NmContactHistoryModelSubItem itemSubItem1; + // For Email address (ex. john.doe@company.com) + NmContactHistoryModelSubItem itemSubItem2; + + int queryLength = modifiedQuery.length(); + + // Obey the contacts setting (first name last name order) + itemSubItem1.mItemText = obeyContactOrder(firstName, lastName); + + if( firstName.indexOf(modifiedQuery, 0, Qt::CaseInsensitive) == 0) + { + itemSubItem1.mMatchingRanges.append(0); + itemSubItem1.mMatchingRanges.append(queryLength-1); + } + + if( lastName.indexOf(modifiedQuery, 0, Qt::CaseInsensitive) == 0) + { + int indexLN = itemSubItem1.mItemText.indexOf(lastName, + firstName.length(), + Qt::CaseInsensitive ); + + itemSubItem1.mMatchingRanges.append(indexLN); + itemSubItem1.mMatchingRanges.append(indexLN+(queryLength-1)); + } + + itemSubItem2.mItemText = contact.details ( + QContactEmailAddress::DefinitionName )[emailIndex].value ( + QContactEmailAddress::FieldEmailAddress ); + + if (itemSubItem2.mItemText.indexOf(modifiedQuery, 0, + Qt::CaseInsensitive) == 0 ) + { + itemSubItem2.mMatchingRanges.append(0); + itemSubItem2.mMatchingRanges.append(queryLength-1); + } + + if ((itemSubItem1.mMatchingRanges.count() != 0) || + (itemSubItem2.mMatchingRanges.count() != 0) ) + { + QSharedPointer itemData + (new NmContactHistoryModelItemData); + + itemData->mContactId = cid; + itemData->mItems.append(itemSubItem1); + itemData->mItems.append(itemSubItem2); + + mPrivateItemList.append(itemData); + } + } + } +} + +/*! + Internal helper function for queryDatabases() + Not meant to be used alone. + + \param modifiedQuery Query + \sa queryDatabases( ) +*/ +void NmContactHistoryModelPrivate::populateListWithMruItems( + const QString &query) +{ + QMapIterator i(mMruMatches); + + while (i.hasNext()) + { + i.next(); + // For Display name (ex. John Doe) + NmContactHistoryModelSubItem itemSubItem1; + // For Email address (ex. john.doe@company.com) + NmContactHistoryModelSubItem itemSubItem2; + + itemSubItem1.mItemText = i.key(); + itemSubItem2.mItemText = i.value(); + + // markup for first item. + if( i.key().indexOf(query, 0, Qt::CaseInsensitive) == 0) + { + itemSubItem1.mMatchingRanges.append(0); + itemSubItem1.mMatchingRanges.append(query.length()-1); + } + + QRegExp rx("[,\\s]", Qt::CaseInsensitive); + bool separatorExists = i.key().contains(rx); + + if (separatorExists) + { + int indexLN = i.key().indexOf(",", 0, Qt::CaseInsensitive); + + if (indexLN == -1) + { + indexLN = i.key().indexOf(" ", 0, Qt::CaseInsensitive); + } + + if (indexLN > 0) + { + int matchPos = i.key().indexOf(query, indexLN, Qt::CaseInsensitive); + + if (matchPos > 0) + { + itemSubItem1.mMatchingRanges.append(matchPos); + itemSubItem1.mMatchingRanges.append((matchPos+query.length())-1); + } + } + } + + // markup for second item. + if (itemSubItem2.mItemText.indexOf(query, 0, Qt::CaseInsensitive) == 0 ) + { + itemSubItem2.mMatchingRanges.append(0); + itemSubItem2.mMatchingRanges.append(query.length()-1); + } + + // If match, add to data list. + if ((itemSubItem1.mMatchingRanges.count() != 0) || + (itemSubItem2.mMatchingRanges.count() != 0) ) + { + QSharedPointer itemData + (new NmContactHistoryModelItemData); + + itemData->mContactId = 0; // No ID available, use 0. + itemData->mItems.append(itemSubItem1); + itemData->mItems.append(itemSubItem2); + + mPrivateItemList.append(itemData); + } + } +} + +/*! + After queryDatabases has completed this will be called from public class() + Not meant to be used alone. (NmContactHistoryModel is using this when needed) + + \sa queryDatabases( ) +*/ +void NmContactHistoryModelPrivate::refreshDataModel() +{ + mModelItemList.clear(); + + for (int cntIndex = 0; + cntIndex < mPrivateItemList.count(); + cntIndex++) + { + // Construct modelItem to be added to list. + NmContactHistoryModelItem modelItem; + + QSharedPointer itemData( + mPrivateItemList[cntIndex]); + + int id = itemData->mContactId; + modelItem.setContactId(itemData->mContactId); + + for (int itemIndex = 0; + itemIndex < itemData->mItems.count(); + itemIndex++) + { + QString key = itemData->mItems[itemIndex].mItemText; + modelItem.appendSubItem(itemData->mItems[itemIndex]); + } + + // Append modelItem to list. + mModelItemList.append(modelItem); + } + + // Notify views that we are done updating model data. + mModelReady = true; + +} + +/*! + This is called by public class NmContactHistoryModel when rowcount() is requested + Not meant to be used alone. + +*/ +int NmContactHistoryModelPrivate::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return mModelItemList.count(); +} + +/*! + This is called by public class NmContactHistoryModel when data() is requested + Not meant to be used alone. + +*/ +QVariant NmContactHistoryModelPrivate::data(const QModelIndex &index, int role) const +{ + if ( mModelReady ) + { + if (!index.isValid() || + index.row() >= mModelItemList.count() || + index.row() < 0) + { + return QVariant(); + } + + if (role == Qt::DisplayRole) + { + QVariant v; + NmContactHistoryModelItem i = mModelItemList.at(index.row()); + v.setValue(i); + return v; + } + } + + return QVariant(); +} + +/*! + Fills MruMatchList, called from queryMruDatabase. + Function uses Email MRU API to fetch information from CenRep + + \sa queryMruDatabase( ) +*/ +bool NmContactHistoryModelPrivate::fillMruMatchList() +{ + //TODO: Possible optimization, remove extra calls EmailMRU(), We need to get list only once. + EmailMRU *mru = new EmailMRU(); + + if (mru) + { + int addressCount = mru->entryCount(); + + for (int i = addressCount; i > 0; i--) + { + QString key, value; // "Email or Number" & "Display Name" + bool success; + + success = mru->getEntry(i, value, key); + + if (success) + { + mMruList.insertMulti(key, value); + } + } + + delete mru; + return true; + } + else + { + return false; + } +} + +/*! + This is called from populateListWithContactItems() when correct order of + first name, last name setting is required + + \param firstName First name + \param lastName Last name + + \sa populateListWithContactItems( ) + + \return concennated string formatted as contact setting specifies. +*/ +QString NmContactHistoryModelPrivate::obeyContactOrder(const QString &firstName, + const QString &lastName) +{ + QString result; + + switch (mNameOrder) + { + case LastNameFirstName: + result = lastName + " " + firstName; + break; + + case LastNameCommaFirstName: + result = lastName + ", " + firstName; + break; + + case FirstNameLastName: + result = firstName + " " + lastName; + break; + + default: + result = firstName + " " + lastName; + break; + } + + return result; +} + +// -------------------------------------------------------------------------- +// End of implementation (NmContactHistoryModelPrivate) +// -------------------------------------------------------------------------- +