--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/emailservices/nmutilities/src/nmcontacthistorymodel_p.cpp Wed Sep 15 12:09:55 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<QContactLocalId> 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<NmContactHistoryModelItemData> 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<QContactLocalId> 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<QContactLocalId> 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<QString, QString> 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<QContactLocalId> 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<NmContactHistoryModelItemData> 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<QString, QString> 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<NmContactHistoryModelItemData> 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<NmContactHistoryModelItemData> 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)
+// --------------------------------------------------------------------------
+