phonebookengines/contactsmodel/cntplsql/src/cqwertypredictivesearchtable.cpp
changeset 46 efe85016a067
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookengines/contactsmodel/cntplsql/src/cqwertypredictivesearchtable.cpp	Wed Jun 23 18:02:44 2010 +0300
@@ -0,0 +1,360 @@
+/*
+* 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: 
+*
+*/
+
+#include "cqwertypredictivesearchtable.h"
+#include "cqwertykeymap.h"
+#include "dbsqlconstants.h"
+#include <QStringList>
+
+// This macro suppresses own logs
+//#define NO_PRED_SEARCH_LOGS
+#include "predictivesearchlog.h"
+
+
+// Max amount of tokens stored from contact
+const TInt KMaxTokens = 7;
+// Max amount of mail addresses stored from contact
+const TInt KMaxMailAddresses = 3;
+
+// How many characters are stored at most in the tokens
+// Since BIGINT is a signed 64-bit integer, store only 10 characters
+// to prevent overflow when comparing upper and lower limits.
+const TInt KMaxTokenLength = 10;
+
+// Template for table names
+const TInt KMaxTableNameLength = 4;
+_LIT(KTableNameFormat, "qm%d");
+
+// Template for create table commands
+_LIT(KPredSearchCreateQwertyMailTableFormat,
+"CREATE TABLE %S (contact_id INTEGER PRIMARY KEY,\
+ n BIGINT NULL, n2 BIGINT NULL, n3 BIGINT NULL, n4 BIGINT NULL,\
+ n5 BIGINT NULL, n6 BIGINT NULL, n7 BIGINT NULL,\
+ first_name CHAR(16) NULL, last_name CHAR(16) NULL);");
+
+// Template for index names
+// e.g. index0_n2
+_LIT(KIndexNameFormat, "index%d_%S");
+
+// Template for create index commands
+// CREATE INDEX <index name> on <table> (<column>);");
+_LIT(KPredSearchCreateQwertyMailIndexFormat, "CREATE INDEX %S on %S (%S);");
+
+const QString KMailPrefix = "mailto:";
+
+
+/**
+@param aDatabase A handle to the database.
+@param aProperties A contact properties object.
+
+@return A pointer to a new CQwertyPredictiveSearchTable object.
+*/
+CQwertyPredictiveSearchTable*
+CQwertyPredictiveSearchTable::NewL(RSqlDatabase& aDatabase)
+	{
+	PRINT(_L("CQwertyPredictiveSearchTable::NewL"));
+	CQwertyPredictiveSearchTable* self = CQwertyPredictiveSearchTable::NewLC(aDatabase);
+	CleanupStack::Pop(self);
+	PRINT(_L("CQwertyPredictiveSearchTable::NewL ends"));
+	return self;
+	}
+
+
+/**
+@param aDatabase A handle to the database.
+@param aProperties A contact properties object.
+
+@return A pointer to a new CQwertyPredictiveSearchTable object.
+*/
+CQwertyPredictiveSearchTable*
+CQwertyPredictiveSearchTable::NewLC(RSqlDatabase& aDatabase)
+	{
+	PRINT(_L("CQwertyPredictiveSearchTable::NewLC"));
+	CQwertyPredictiveSearchTable* self =
+		new (ELeave) CQwertyPredictiveSearchTable(aDatabase);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	PRINT(_L("CQwertyPredictiveSearchTable::NewLC ends"));
+	return self;
+	}
+
+
+/**
+Destructor
+*/
+CQwertyPredictiveSearchTable::~CQwertyPredictiveSearchTable()
+	{
+	PRINT(_L("CQwertyPredictiveSearchTable dtor"));
+	PRINT(_L("CQwertyPredictiveSearchTable dtor ends"));
+	}
+
+
+/**
+Create the QWERTY tables and its indexes in the database.
+*/
+void CQwertyPredictiveSearchTable::CreateTableL()
+	{
+	PRINT(_L("CQwertyPredictiveSearchTable::CreateTableL"));
+
+	// How many columns have index
+    const TInt KIndexedColumnCount = 9;
+    // Names of columns that have index
+    const TDesC* indexColumns[] = {
+        &KPredSearchQwertyMailNameAsNumber,
+        &KPredSearchQwertyMailNameAsNumber2,
+        &KPredSearchQwertyMailNameAsNumber3,
+        &KPredSearchQwertyMailNameAsNumber4,
+        &KPredSearchQwertyMailNameAsNumber5,
+        &KPredSearchQwertyMailNameAsNumber6,
+        &KPredSearchQwertyMailNameAsNumber7,
+        &KPredSearchQwertyMailFirstName,
+        &KPredSearchQwertyMailLastName};
+    
+    TInt maxColumnLength(0); // Length of longest column name
+    for (TInt column = 0; column < KIndexedColumnCount; ++column)
+        {
+        TInt columnNameLength = indexColumns[column]->Length();
+        if (columnNameLength > maxColumnLength)
+            {
+            maxColumnLength = columnNameLength;
+            }
+        }    
+    
+	// Space needed to represent number CQwertyKeyMap::EAmountOfKeysInQwertyKeypad
+	const TInt KCharsNeededForTableNumber = 2;
+	const TInt KMaxIndexNameLength =
+		KIndexNameFormat().Length() + maxColumnLength + KCharsNeededForTableNumber;
+
+	HBufC* tableName = HBufC::NewLC(KMaxTableNameLength);
+	TPtr ptrTableName = tableName->Des();
+	HBufC* createTableCmd =
+		HBufC::NewLC(KPredSearchCreateQwertyMailTableFormat().Length() +
+					 KMaxTableNameLength);
+	TPtr ptrCreateTableCmd = createTableCmd->Des();
+
+	HBufC* indexName = HBufC::NewLC(KMaxIndexNameLength);
+	TPtr ptrIndexName = indexName->Des();
+	HBufC* createIndexCmd = HBufC::NewLC(KPredSearchCreateQwertyMailIndexFormat().Length() +
+									  KMaxIndexNameLength +
+									  KMaxTableNameLength +
+									  maxColumnLength);
+	TPtr ptrCreateIndexCmd = createIndexCmd->Des();
+
+	for (TInt table = 0; table < CQwertyKeyMap::EAmountOfKeysInQwertyKeypad; ++table)
+		{
+		ptrTableName.Format(KTableNameFormat, table);
+
+		ptrCreateTableCmd.Format(KPredSearchCreateQwertyMailTableFormat, tableName);
+		PRINT1(_L("SQL command: %S"), createTableCmd);
+		User::LeaveIfError(iDatabase.Exec(*createTableCmd));
+
+		// Create indexes for each required column of the current table
+		for (TInt column = 0; column < KIndexedColumnCount; ++column)
+			{
+			ptrIndexName.Format(KIndexNameFormat, table, indexColumns[column]);
+
+			ptrCreateIndexCmd.Format(KPredSearchCreateQwertyMailIndexFormat,
+								     indexName, tableName, indexColumns[column]);
+//			PRINT1(_L("SQL command: %S"), createIndexCmd);
+			User::LeaveIfError(iDatabase.Exec(*createIndexCmd));			
+			}
+		}
+	CleanupStack::PopAndDestroy(createIndexCmd);
+	CleanupStack::PopAndDestroy(indexName);
+	CleanupStack::PopAndDestroy(createTableCmd);
+	CleanupStack::PopAndDestroy(tableName);
+	
+	PRINT(_L("CQwertyPredictiveSearchTable::CreateTableL ends"));
+	}
+
+
+TBool CQwertyPredictiveSearchTable::IsValidChar(const QChar aChar) const
+	{
+#if defined(USE_ORBIT_KEYMAP)
+	return static_cast<CQwertyKeyMap*>(iKeyMap)->IsValidChar(aChar);
+#else
+	const QChar PAD_CHAR = '!'; // This is a hack, must have same value as in cqwertykeymap.cpp
+	return static_cast<CQwertyKeyMap*>(iKeyMap)->UseHardcodedKeyMap(aChar) != PAD_CHAR;
+#endif
+	}
+
+
+HBufC* CQwertyPredictiveSearchTable::TableNameL(const QChar aCh) const
+	{
+	TInt tableNumber = static_cast<CQwertyKeyMap*>(iKeyMap)->MapKeyNameToValue(aCh);
+	if (tableNumber == CQwertyKeyMap::KPadCharValue)
+		{
+		User::Leave(KErrArgument);
+		}
+
+	HBufC* tableName = HBufC::NewL(KMaxTableNameLength);
+	TPtr ptrTableName = tableName->Des();
+	ptrTableName.Format(KTableNameFormat, tableNumber);
+	return tableName;
+	}
+
+
+QList<QChar> CQwertyPredictiveSearchTable::FillAllTables() const
+	{
+	QList<QChar> tables;
+
+	for (TInt key = 0; key < CQwertyKeyMap::EAmountOfKeysInQwertyKeypad; ++key)
+		{
+		tables.append(iKeyMap->ArrayIndexToMappedChar(key));
+		}
+
+	return tables;
+	}
+
+
+void CQwertyPredictiveSearchTable::FillKeyboardSpecificFieldsL(
+	RSqlStatement& aSqlStatement,
+	QStringList aTokens)
+	{
+	const TDesC* paramNames[] = {
+		&KPredSearchQwertyMailNameAsNumberParam,
+		&KPredSearchQwertyMailNameAsNumberParam2,
+		&KPredSearchQwertyMailNameAsNumberParam3,
+		&KPredSearchQwertyMailNameAsNumberParam4,
+		&KPredSearchQwertyMailNameAsNumberParam5,
+		&KPredSearchQwertyMailNameAsNumberParam6,
+		&KPredSearchQwertyMailNameAsNumberParam7};
+	for (TInt i = 0; i < aTokens.count(); ++i)
+		{
+		// TODO: It'd be better to add new fn into CQwertyKeyMap, that computes
+		// the qint64 value like CQwertyKeyMap::ComputeValue().
+		QString dummyLowerLimit;
+		QString upperLimit;
+		User::LeaveIfError(iKeyMap->GetNumericLimits(aTokens[i],
+													 dummyLowerLimit,
+													 upperLimit));
+		bool ok(false);
+		qint64 value(0); // qint64 is same as qlonglong
+		QT_TRYCATCH_LEAVING(value = upperLimit.toLongLong(&ok));
+		if (!ok)
+			{
+			User::Leave(KErrArgument);
+			}
+		// Decrement by one to get the correct value
+		User::LeaveIfError(aSqlStatement.BindInt64(
+			User::LeaveIfError(aSqlStatement.ParameterIndex(*paramNames[i])), --value));
+		}
+	}
+
+
+/**
+* Fetch up to 3 mail addresses
+*/
+QStringList CQwertyPredictiveSearchTable::GetTableSpecificFields(
+	const CContactItem& aItem,
+	TBool& aMandatoryFieldsPresent) const
+	{
+	PRINT(_L("CQwertyPredictiveSearchTable::GetTableSpecificFields"));
+
+	QStringList mailAddresses;
+	
+	// Check that the contact item is a card, own card or ICC entry.
+	const TUid KType = aItem.Type();
+	if (KType != KUidContactCard &&
+		KType != KUidContactOwnCard &&
+		KType != KUidContactICCEntry)
+		{
+		aMandatoryFieldsPresent = EFalse;
+		return mailAddresses;
+		}
+
+	TInt storedAddressCount(0);
+	for (TInt i = aItem.CardFields().Count();
+		 i > 0 && storedAddressCount < KMaxMailAddresses;
+		 --i)
+		{
+		CContactItemField& field = aItem.CardFields()[i - 1];
+		if (field.ContentType().ContainsFieldType(KUidContactFieldEMail) &&
+			field.StorageType() == KStorageTypeText &&
+			field.TextStorage()->IsFull()) // IsFull() returns true if field not empty
+			{
+			TPtrC mailAddress = field.TextStorage()->Text();
+			PRINT2(_L("contact id=%d has mail='%S'"), aItem.Id(), &mailAddress);
+
+			QString wholeAddress((QChar*)mailAddress.Ptr(), mailAddress.Length());
+			QString address = wholeAddress;
+			if (wholeAddress.startsWith(KMailPrefix)) // Skip prefix
+				{
+				address = wholeAddress.mid(KMailPrefix.length());
+#if defined(WRITE_PRED_SEARCH_LOGS)
+				const TInt KLogLength = 40;
+				TBuf<KLogLength> log(address.left(KLogLength).utf16());
+				PRINT1(_L("prefix removed, mail='%S'"), &log);
+#endif
+				}
+			mailAddresses.append(iKeyMap->GetMappedString(address));
+			++storedAddressCount;
+			}
+		}
+	PRINT1(_L("CQwertyPredictiveSearchTable::GetTableSpecificFields found %d mail addrs"),
+		   mailAddresses.count());
+	aMandatoryFieldsPresent = (mailAddresses.count() > 0);
+	return mailAddresses;
+	}
+
+
+/**
+Set up the CCntSqlStatement objects held by the class.
+*/
+void CQwertyPredictiveSearchTable::ConstructL()
+	{
+	PRINT(_L("CQwertyPredictiveSearchTable::ConstructL"));
+
+	CPplPredictiveSearchTableBase::ConstructL();
+
+	// Set details of INSERT
+	iInsertStmnt->SetParamL(KPredSearchQwertyMailContactId,
+	                        KPredSearchQwertyMailContactIdParam);
+	iInsertStmnt->SetParamL(KPredSearchQwertyMailNameAsNumber,
+							KPredSearchQwertyMailNameAsNumberParam);
+	iInsertStmnt->SetParamL(KPredSearchQwertyMailNameAsNumber2,
+							KPredSearchQwertyMailNameAsNumberParam2);
+	iInsertStmnt->SetParamL(KPredSearchQwertyMailNameAsNumber3,
+							KPredSearchQwertyMailNameAsNumberParam3);
+	iInsertStmnt->SetParamL(KPredSearchQwertyMailNameAsNumber4,
+							KPredSearchQwertyMailNameAsNumberParam4);
+	iInsertStmnt->SetParamL(KPredSearchQwertyMailNameAsNumber5,
+							KPredSearchQwertyMailNameAsNumberParam5);
+	iInsertStmnt->SetParamL(KPredSearchQwertyMailNameAsNumber6,
+							KPredSearchQwertyMailNameAsNumberParam6);
+	iInsertStmnt->SetParamL(KPredSearchQwertyMailNameAsNumber7,
+							KPredSearchQwertyMailNameAsNumberParam7);
+
+	iInsertStmnt->SetParamL(KPredSearchQwertyMailFirstName,
+							KPredSearchQwertyMailFirstNameParam);
+	iInsertStmnt->SetParamL(KPredSearchQwertyMailLastName,
+							KPredSearchQwertyMailLastNameParam);
+
+	PRINT(_L("CQwertyPredictiveSearchTable::ConstructL create key map"));
+	iKeyMap = CQwertyKeyMap::NewL();
+
+	PRINT(_L("CQwertyPredictiveSearchTable::ConstructL ends"));
+	}
+
+
+/**
+Constructor
+*/
+CQwertyPredictiveSearchTable::CQwertyPredictiveSearchTable(RSqlDatabase& aDatabase) :
+	CPplPredictiveSearchTableBase(aDatabase, KMaxTokens, KMaxTokenLength)
+	{
+	}