plugins/contacts/symbian/contactsmodel/cntplsql/src/cpplcontacttable.cpp
changeset 0 876b1a06bc25
child 5 603d3f8b6302
equal deleted inserted replaced
-1:000000000000 0:876b1a06bc25
       
     1 /*
       
     2 * Copyright (c) 2007-2009 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: 
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include "pltables.h"
       
    20 #include "dbsqlconstants.h"
       
    21 #include "cntpersistenceutility.h"
       
    22 #include <cntdef.h>
       
    23 
       
    24 // forward declaration to allow this to compile. 
       
    25 // Which header file is this declared in and do we actually still need the properties here?
       
    26 class CLplContactProperties;
       
    27 
       
    28 /**
       
    29 NewL
       
    30 
       
    31 @param aDatabase A handle to the database.
       
    32 @param aProperties A contact properties object.
       
    33 
       
    34 @return A pointer to a new CPplContactTable object.
       
    35 */
       
    36 CPplContactTable* CPplContactTable::NewL(RSqlDatabase& aDatabase, CLplContactProperties& aProperties)
       
    37 	{
       
    38 	CPplContactTable* self = CPplContactTable::NewLC(aDatabase, aProperties);
       
    39 	CleanupStack::Pop(self);
       
    40 	return self;
       
    41 	}
       
    42 
       
    43 
       
    44 /**
       
    45 NewLC
       
    46 
       
    47 @param aDatabase A handle to the database.
       
    48 @param aProperties A contact properties object.
       
    49 
       
    50 @return A pointer to a new CPplContactTable object.
       
    51 */
       
    52 CPplContactTable* CPplContactTable::NewLC(RSqlDatabase& aDatabase, CLplContactProperties& aProperties)
       
    53 	{
       
    54 	CPplContactTable* self = new (ELeave) CPplContactTable(aDatabase, aProperties);
       
    55 	CleanupStack::PushL(self);
       
    56 	self->ConstructL();
       
    57 	return self;
       
    58 	}
       
    59 
       
    60 
       
    61 /**
       
    62 Set up the CCntSqlStatement objects held by the class.
       
    63 */
       
    64 void CPplContactTable::ConstructL()
       
    65 	{	
       
    66 	iCardTemplateIds = CContactIdArray::NewL();
       
    67 	
       
    68 	// Statement types
       
    69 	TCntSqlStatementType insertType(EInsert, KSqlContactTableName);
       
    70 	TCntSqlStatementType selectType(ESelect, KSqlContactTableName);
       
    71 	TCntSqlStatementType updateType(EUpdate, KSqlContactTableName);
       
    72 	TCntSqlStatementType deleteType(EDelete, KSqlContactTableName);
       
    73 
       
    74 	// Where clause
       
    75 
       
    76 	// sizes of the clause
       
    77 	const TInt KWhereClauseBufSize(KContactId().Size() + 
       
    78 		KWhereStringEqualsStringFormatText().Size() + KContactIdParam().Size() );
       
    79 
       
    80 	// for WHERE contact_id = [contact id value]
       
    81 	HBufC* whereIdClause = HBufC::NewLC(KWhereClauseBufSize);
       
    82 	whereIdClause->Des().AppendFormat(KWhereStringEqualsStringFormatText, &KContactId, 
       
    83 		&KContactIdParam );
       
    84 
       
    85 	// INSERT
       
    86 
       
    87 	// insert record into contact table
       
    88 	// For a statement in the following format:
       
    89 	// 	INSERT INTO contact 
       
    90 	//		(contact_id, template_id...[etc...], binary_fields) 
       
    91 	//		VALUES (NULL, 37, .......);
       
    92 	//
       
    93 	// Actual parameters are added when inserting a contact based
       
    94 	// in available fields
       
    95 	iInsertStmnt = TSqlProvider::GetSqlStatementL(insertType);
       
    96 
       
    97 	// SELECT
       
    98 
       
    99 	// delete select
       
   100 	// For a statement in the following format:
       
   101 	// 	SELECT type_flags, access_count, template_id FROM contact 
       
   102 	//		WHERE contact_id = [contact id value];
       
   103 	//
       
   104 	iDeleteSelectStmnt = TSqlProvider::GetSqlStatementL(selectType);	
       
   105 	iDeleteSelectStmnt->SetParamL(KContactTypeFlags, KNullDesC() );
       
   106 	iDeleteSelectStmnt->SetParamL(KContactAccessCount, KNullDesC() );
       
   107 	iDeleteSelectStmnt->SetParamL(KContactTemplateId, KNullDesC() );
       
   108 	iDeleteSelectStmnt->SetConditionL(*whereIdClause);
       
   109 
       
   110 	// UPDATE
       
   111 	
       
   112 	// update record from contact table
       
   113 	// For a statement in the following format:
       
   114 	// 	UPDATE contact SET template_id = [new template id value]
       
   115 	//      ...,
       
   116 	//      binary_fields = [new binary fields value]
       
   117 	//		WHERE contact_id = [contact id value];
       
   118 	//
       
   119 	iUpdateStmnt = TSqlProvider::GetSqlStatementL(updateType);
       
   120 	iUpdateStmnt->SetConditionL(*whereIdClause);
       
   121 
       
   122 	// type_flags update
       
   123 	// For a statement in the following format:
       
   124 	// 	UPDATE contact SET type_flags = [new type flags value]
       
   125 	//		WHERE contact_id = [contact id value];
       
   126 	//
       
   127 	iUpdateFlagsStmnt = TSqlProvider::GetSqlStatementL(updateType);	
       
   128 	iUpdateFlagsStmnt->SetParamL(KContactTypeFlags, KContactTypeFlagsParam);
       
   129 	iUpdateFlagsStmnt->SetConditionL(*whereIdClause);
       
   130 
       
   131 	// AccessCount update
       
   132 	// For a statement in the following format:
       
   133 	// 	UPDATE contact SET access_count = [new access count value]
       
   134 	//		WHERE contact_id = [contact id value];
       
   135 	//
       
   136 	iAccessCountUpdateStmnt = TSqlProvider::GetSqlStatementL(updateType);	
       
   137 	iAccessCountUpdateStmnt->SetParamL(KContactAccessCount, KContactAccessCountParam);
       
   138 	iAccessCountUpdateStmnt->SetConditionL(*whereIdClause);
       
   139 
       
   140 	// DELETE
       
   141 
       
   142 	// delete record from contact table
       
   143 	// For a statement in the following format:
       
   144 	// 	DELETE FROM contact WHERE contact_id = [contact id value];
       
   145 	//
       
   146 	iDeleteStmnt = TSqlProvider::GetSqlStatementL(deleteType);	
       
   147 	iDeleteStmnt->SetConditionL(*whereIdClause);
       
   148 
       
   149 	// Set up the field lookup table hash map
       
   150 	iFieldMap.InsertL(KUidContactFieldGivenNameValue, KContactFirstNameParam() );
       
   151 	iFieldMap.InsertL(KUidContactFieldGivenNamePronunciationValue, KContactFirstNamePrnParam() );
       
   152 	iFieldMap.InsertL(KUidContactFieldFamilyNameValue, KContactLastNameParam() );
       
   153 	iFieldMap.InsertL(KUidContactFieldFamilyNamePronunciationValue, KContactLastNamePrnParam() );
       
   154 	iFieldMap.InsertL(KUidContactFieldCompanyNameValue, KContactCompanyNameParam() );
       
   155 	iFieldMap.InsertL(KUidContactFieldCompanyNamePronunciationValue, KContactCompanyNamePrnParam() );
       
   156 
       
   157 	CleanupStack::PopAndDestroy(); //whereIdClause
       
   158 	}
       
   159 
       
   160 /**
       
   161 Destructor
       
   162 
       
   163 Tidy up CCntSqlStatement objects
       
   164 */
       
   165 CPplContactTable::~CPplContactTable()
       
   166 	{
       
   167 	delete iInsertStmnt;
       
   168 	delete iDeleteSelectStmnt;
       
   169 	delete iUpdateFlagsStmnt;
       
   170 	delete iUpdateStmnt;
       
   171 	delete iAccessCountUpdateStmnt;
       
   172 	delete iDeleteStmnt;
       
   173 	iFieldMap.Close();
       
   174 	delete iCardTemplateIds;
       
   175 	}
       
   176 
       
   177 
       
   178 /**
       
   179 CPplContactTable constructor
       
   180 */
       
   181 CPplContactTable::CPplContactTable(RSqlDatabase& aDatabase, CLplContactProperties& aProperties):
       
   182 	iProperties(aProperties),
       
   183 	iDatabase(aDatabase)
       
   184 	{
       
   185 	}
       
   186 
       
   187 
       
   188 /**
       
   189 Update the access count for the given template ID. If the template is marked for deletion and 
       
   190 no one is referencing it any longer, it is deleted.
       
   191 
       
   192 @param aTemplateRefId
       
   193 @param aIncrement If ETrue increase the reference count otherwise decrease the reference count.
       
   194 */
       
   195 void CPplContactTable::UpdateTemplateAccessCounterL(TContactItemId aTemplateRefId, TBool aIncrement)
       
   196 	{
       
   197 	if (aTemplateRefId == KGoldenTemplateId || aTemplateRefId == KNullContactId)
       
   198 		{
       
   199 		return;
       
   200 		}
       
   201 
       
   202 	// Get the access count and type flags for the template
       
   203 	RSqlStatement selectStmnt;
       
   204 	CleanupClosePushL(selectStmnt);
       
   205 	selectStmnt.PrepareL(iDatabase, iDeleteSelectStmnt->SqlStringL() );
       
   206 	const TInt KContactIdParamIndex(KFirstIndex); // first and only parameter in the query
       
   207 	User::LeaveIfError(selectStmnt.BindInt(KContactIdParamIndex, aTemplateRefId) );
       
   208 
       
   209 	TInt err(selectStmnt.Next() );
       
   210 	if (err != KSqlAtRow)
       
   211 		{
       
   212 		User::Leave(err);
       
   213 		}
       
   214 
       
   215 	TInt oldAccessCount(selectStmnt.ColumnInt(iDeleteSelectStmnt->ParameterIndex(KContactAccessCount() ) ) );
       
   216 	TInt newAccessCount = oldAccessCount + (aIncrement ? 1 : -1);
       
   217 	TInt typeFlags(selectStmnt.ColumnInt(iDeleteSelectStmnt->ParameterIndex(KContactTypeFlags() ) ) );
       
   218 	TInt attributes((typeFlags & EContactAttributes_Mask) >> EContactAttributes_Shift); 
       
   219 	CleanupStack::PopAndDestroy(&selectStmnt);
       
   220 
       
   221 	// set the new access count for the template
       
   222 	RSqlStatement updateStmnt;
       
   223 	CleanupClosePushL(updateStmnt);
       
   224 	updateStmnt.PrepareL(iDatabase, iAccessCountUpdateStmnt->SqlStringL() );
       
   225 	
       
   226 	const TInt KAccessCountParamIndex(KFirstParam);					// first parameter in query...
       
   227 	const TInt KTemplateIdParamIndex(KAccessCountParamIndex + 1);	// ...and the second.
       
   228 
       
   229 	User::LeaveIfError(updateStmnt.BindInt(KAccessCountParamIndex, newAccessCount) );
       
   230 	User::LeaveIfError(updateStmnt.BindInt(KTemplateIdParamIndex, aTemplateRefId) );
       
   231 	User::LeaveIfError(updateStmnt.Exec() );
       
   232 	CleanupStack::PopAndDestroy(&updateStmnt);
       
   233 
       
   234 	// should the template be deleted  -- i.e. nobody accessing it and marked as deleted?
       
   235 	if (newAccessCount <= 0 && (attributes & CContactItem::EDeleted) )
       
   236 		{
       
   237 		TBool lowDiskErr(EFalse);
       
   238 		CContactItem* templ = DeleteLC(aTemplateRefId, lowDiskErr);
       
   239 		CleanupStack::PopAndDestroy(templ);
       
   240 		if (lowDiskErr)
       
   241 			{
       
   242 			User::Leave(KErrDiskFull);
       
   243 			}
       
   244 		}
       
   245 	}
       
   246 
       
   247 void CPplContactTable::CreateInDbL(CContactItem& aItem)
       
   248 	{
       
   249 	CreateInDbL(aItem, 0);
       
   250 	}
       
   251 
       
   252 /**
       
   253 Add the given contact item to the database.
       
   254 
       
   255 @param aItem The contact item to be added to the database. 
       
   256 @param aSessionId The ID of the session that issued the request.  Used to
       
   257 prevent Phonebook Synchroniser deadlock.
       
   258 
       
   259 @return Contact item ID of the contact added to the database.
       
   260 */
       
   261 void CPplContactTable::CreateInDbL(CContactItem& aItem, TUint aSessionId)
       
   262 	{
       
   263 	if (aItem.Type() != KUidContactTemplate) // Not creating system template?
       
   264 		{
       
   265 		// Make sure the System template is loaded.
       
   266 		iProperties.SystemTemplateL();
       
   267 		}
       
   268 		
       
   269 	if (aItem.Type() == KUidContactICCEntry) 
       
   270 		{
       
   271 		TInt ret = iProperties.ContactSynchroniserL(aSessionId).ValidateWriteContact(static_cast<CContactICCEntry&>(aItem) );
       
   272 		User::LeaveIfError(ret);	
       
   273 		}
       
   274 
       
   275 	// Mark fields as template fields if the contact item is a contact card template.
       
   276 	const TBool KIsTemplateCard = (aItem.Type() == KUidContactCardTemplate);
       
   277 	CContactItemFieldSet& fieldset = aItem.CardFields();
       
   278 	for (TInt i = fieldset.Count() - 1; i >= 0; --i)
       
   279 		{
       
   280 		fieldset[i].SetTemplateField(KIsTemplateCard);
       
   281 		}
       
   282 
       
   283 	// Set iLastModified and iCreationDate to current time.
       
   284 	TTime lastModified = aItem.LastModified();
       
   285    	lastModified.UniversalTime();
       
   286    	aItem.SetLastModified(lastModified);
       
   287    	aItem.SetCreationDate(lastModified); 
       
   288 
       
   289 	// ID of newly created item obtained from autoincrementing ID column.
       
   290 	// -- get an id from the database	
       
   291 	RSqlStatement selectIdStatement;
       
   292 	CleanupClosePushL(selectIdStatement);
       
   293 		
       
   294 	User::LeaveIfError(selectIdStatement.Prepare(iDatabase, KSelectLastIdSqlStmnt()));
       
   295 
       
   296 	TInt err;
       
   297 	TInt lastId((-1));
       
   298 	if((err = selectIdStatement.Next()) == KSqlAtRow)
       
   299 		{
       
   300 		lastId = selectIdStatement.ColumnInt(0);
       
   301 		}
       
   302 
       
   303 	if(err == KSqlAtEnd)
       
   304 		{
       
   305 		lastId = -1;
       
   306 		}
       
   307 	
       
   308 	aItem.SetId(lastId + 1);
       
   309 	
       
   310 	CleanupStack::PopAndDestroy(&selectIdStatement);
       
   311 
       
   312 	// Increment Template reference counter.
       
   313 	UpdateTemplateAccessCounterL(aItem.TemplateRefId(), ETrue);
       
   314 
       
   315 	// Write contact data to the database.
       
   316 	WriteContactItemL(aItem, EInsert);
       
   317 	}
       
   318 
       
   319 /**
       
   320 Updates the given contact item in the database.
       
   321 
       
   322 @param aItem The contact item to be updated
       
   323 */
       
   324 void CPplContactTable::UpdateL(const CContactItem& aItem)
       
   325 	{
       
   326 	// If contact is marked as deleted and access count is zero then delete the
       
   327 	// contact otherwise update it.
       
   328 	if (aItem.IsDeleted() && (aItem.AccessCount() == 0) )
       
   329 		{
       
   330 		//update access field in contact table
       
   331 		RSqlStatement updateStmnt;
       
   332 		CleanupClosePushL(updateStmnt);
       
   333 		updateStmnt.PrepareL(iDatabase, iAccessCountUpdateStmnt->SqlStringL() );
       
   334 		
       
   335 		const TInt KAccessCountParamIndex(KFirstParam);					// first parameter in query...
       
   336 		const TInt KContactIdParamIndex(KAccessCountParamIndex + 1);	// ...and the second.
       
   337 
       
   338 		User::LeaveIfError(updateStmnt.BindInt(KAccessCountParamIndex, 0) );
       
   339 		User::LeaveIfError(updateStmnt.BindInt(KContactIdParamIndex, aItem.Id()) );
       
   340 		User::LeaveIfError(updateStmnt.Exec() );
       
   341 		CleanupStack::PopAndDestroy(&updateStmnt);
       
   342 
       
   343 		TBool lowDiskErr(EFalse);
       
   344 		CContactItem* templ = DeleteLC(aItem.Id(), lowDiskErr);
       
   345 		CleanupStack::PopAndDestroy(templ);
       
   346 		if (lowDiskErr)
       
   347 			{
       
   348 			User::Leave(KErrDiskFull);
       
   349 			}
       
   350 		}
       
   351 	else
       
   352 		{
       
   353 		WriteContactItemL(aItem, EUpdate);
       
   354 		}
       
   355 	}
       
   356 
       
   357 /**
       
   358 Performs database write operations for the given contact item.
       
   359 
       
   360 @param aItem the contact item to be written
       
   361 @param aType the type of operation (insert or update) to 
       
   362 */
       
   363 void CPplContactTable::WriteContactItemL(const CContactItem& aItem, TCntSqlStatement aType)
       
   364 	{
       
   365 	// check the correct type of statement/operation has been supplied
       
   366 	if (aType != EInsert && aType != EUpdate)
       
   367 		{
       
   368 		User::Leave(KErrArgument);
       
   369 		}
       
   370 
       
   371 	// temporary reference to the CCntSqlStatements member variables to take advantage 
       
   372 	// of the commonality between update and insert operations.
       
   373 	CCntSqlStatement* tempCntStmnt;
       
   374 	if (aType == EInsert)
       
   375 		{
       
   376         iInsertStmnt->ClearParams();
       
   377         iInsertStmnt->SetParamL(KContactId, KContactIdParam);
       
   378         iInsertStmnt->SetParamL(KContactTemplateId, KContactTemplateIdParam);
       
   379         iInsertStmnt->SetParamL(KContactTypeFlags, KContactTypeFlagsParam);
       
   380         iInsertStmnt->SetParamL(KContactAccessCount, KContactAccessCountParam);
       
   381         iInsertStmnt->SetParamL(KContactCreationDate, KContactCreationDateParam);
       
   382         iInsertStmnt->SetParamL(KContactLastModified, KContactLastModifiedParam);
       
   383         iInsertStmnt->SetParamL(KContactGuidString, KContactGuidStringParam);
       
   384         iInsertStmnt->SetParamL(KContactFirstNamePrn, KContactFirstNamePrnParam);
       
   385         iInsertStmnt->SetParamL(KContactLastNamePrn, KContactLastNamePrnParam);
       
   386         iInsertStmnt->SetParamL(KContactCompanyNamePrn, KContactCompanyNamePrnParam);
       
   387         iInsertStmnt->SetParamL(KContactTextFieldHeader, KContactTextFieldHeaderParam);
       
   388         iInsertStmnt->SetParamL(KContactBinaryFieldHeader, KContactBinaryFieldHeaderParam);
       
   389         iInsertStmnt->SetParamL(KContactTextFields, KContactTextFieldsParam);
       
   390         iInsertStmnt->SetParamL(KContactBinaryFields, KContactBinaryFieldsParam);
       
   391         
       
   392         for (TInt fieldNum = aItem.CardFields().Count() - 1; fieldNum >= 0; --fieldNum) 
       
   393             {
       
   394             const CContactItemField& field = aItem.CardFields()[fieldNum];
       
   395             const TInt nameFieldUid = NameFieldUid(field);
       
   396             
       
   397             if (nameFieldUid != KErrNotFound && field.StorageType() == KStorageTypeText)
       
   398                 {
       
   399                 TInt length = field.TextStorage()->Text().Length();
       
   400                 // check if field should be stored in the Identity table.
       
   401                 if (nameFieldUid == TInt(KUidContactFieldGivenNameValue) && length)
       
   402                     {
       
   403                     iInsertStmnt->SetParamL(KContactFirstName, KContactFirstNameParam);
       
   404                     }
       
   405                 if (nameFieldUid == TInt(KUidContactFieldFamilyNameValue) && length)
       
   406                     {
       
   407                     iInsertStmnt->SetParamL(KContactLastName, KContactLastNameParam);
       
   408                     }
       
   409                 if (nameFieldUid == TInt(KUidContactFieldCompanyNameValue) && length)
       
   410                     {
       
   411                     iInsertStmnt->SetParamL(KContactCompanyName, KContactCompanyNameParam);
       
   412                     }         
       
   413                 }
       
   414             }
       
   415 		tempCntStmnt = iInsertStmnt;
       
   416 		}
       
   417 	else
       
   418 	    {
       
   419         iUpdateStmnt->ClearParams();
       
   420         iUpdateStmnt->SetParamL(KContactTemplateId, KContactTemplateIdParam);
       
   421 	    
       
   422         _LIT(KOwnCardInvariant, "((((%S>>%d==%d)*%d) | ((NOT(%S>>%d==%d))*%S))<<%d)| %S");
       
   423         
       
   424 	    HBufC* typeFlagsParameter = HBufC::NewLC(KOwnCardInvariant().Size() + KContactTypeFlags().Size() + KContactTypeFlags().Size() + 
       
   425 	            KContactTypeParam().Size() + KAttributesAndHintParam().Size() + 6*sizeof(TInt));
       
   426 	    typeFlagsParameter->Des().AppendFormat(KOwnCardInvariant, &KContactTypeFlags, EContactType_Shift, EContactTypeFlags_OwnCard, EContactTypeFlags_OwnCard,
       
   427 	            &KContactTypeFlags, EContactType_Shift, EContactTypeFlags_OwnCard, &KContactTypeParam, EContactType_Shift, &KAttributesAndHintParam);
       
   428 	    
       
   429 	    iUpdateStmnt->SetParamL(KContactTypeFlags, *typeFlagsParameter);
       
   430 	    
       
   431 	    iUpdateStmnt->SetParamL(KContactAccessCount, KContactAccessCountParam);
       
   432 	    iUpdateStmnt->SetParamL(KContactLastModified, KContactLastModifiedParam);
       
   433 	    iUpdateStmnt->SetParamL(KContactGuidString, KContactGuidStringParam);
       
   434 	    iUpdateStmnt->SetParamL(KContactFirstNamePrn, KContactFirstNamePrnParam);
       
   435 	    iUpdateStmnt->SetParamL(KContactLastNamePrn, KContactLastNamePrnParam);
       
   436 	    iUpdateStmnt->SetParamL(KContactCompanyNamePrn, KContactCompanyNamePrnParam);
       
   437 	    iUpdateStmnt->SetParamL(KContactTextFieldHeader, KContactTextFieldHeaderParam);
       
   438 	    iUpdateStmnt->SetParamL(KContactBinaryFieldHeader, KContactBinaryFieldHeaderParam);
       
   439 	    iUpdateStmnt->SetParamL(KContactTextFields, KContactTextFieldsParam);
       
   440 	    iUpdateStmnt->SetParamL(KContactBinaryFields, KContactBinaryFieldsParam);
       
   441 	    
       
   442         for (TInt fieldNum = aItem.CardFields().Count() - 1; fieldNum >= 0; --fieldNum) 
       
   443             {
       
   444             const CContactItemField& field = aItem.CardFields()[fieldNum];
       
   445             const TInt nameFieldUid = NameFieldUid(field);
       
   446             
       
   447             if (nameFieldUid != KErrNotFound && field.StorageType() == KStorageTypeText)
       
   448                 {
       
   449                 TInt length = field.TextStorage()->Text().Length();
       
   450                 // check if field should be stored in the Identity table.
       
   451                 if (nameFieldUid == TInt(KUidContactFieldGivenNameValue) && length)
       
   452                     {
       
   453                     iUpdateStmnt->SetParamL(KContactFirstName, KContactFirstNameParam);
       
   454                     }
       
   455                 if (nameFieldUid == TInt(KUidContactFieldFamilyNameValue) && length)
       
   456                     {
       
   457                     iUpdateStmnt->SetParamL(KContactLastName, KContactLastNameParam);
       
   458                     }
       
   459                 if (nameFieldUid == TInt(KUidContactFieldCompanyNameValue) && length)
       
   460                     {
       
   461                     iUpdateStmnt->SetParamL(KContactCompanyName, KContactCompanyNameParam);
       
   462                     }         
       
   463                 }
       
   464             }
       
   465         
       
   466         CleanupStack::PopAndDestroy(); //typeFlagsParameter
       
   467 	    tempCntStmnt = iUpdateStmnt;
       
   468 	    }
       
   469 	
       
   470 	RSqlStatement stmnt;
       
   471 	CleanupClosePushL(stmnt);
       
   472  	stmnt.PrepareL(iDatabase, tempCntStmnt->SqlStringL() );
       
   473 
       
   474 	// get the identity-type fields and build the hint fields
       
   475 	THintField hint;
       
   476 	const RArray<TUid>* custFiltFields = NULL;
       
   477 
       
   478 	if (aItem.Type() != KUidContactTemplate)
       
   479 		{
       
   480 		custFiltFields = &iProperties.CustomFilterableFieldsL(); // doesn't take ownership
       
   481 		}
       
   482 
       
   483 	for (TInt fieldNum = aItem.CardFields().Count() - 1; fieldNum >= 0; --fieldNum) 
       
   484 		{
       
   485 		const CContactItemField& field = aItem.CardFields()[fieldNum];
       
   486 		const TInt nameFieldUid = CPplContactTable::NameFieldUid(field);
       
   487 
       
   488 		// check if field should be stored in the Identity table.
       
   489 		if (nameFieldUid != KErrNotFound)
       
   490 			{
       
   491 			TPtrC textToSet = field.TextStorage()->Text();
       
   492 			if(textToSet.Length() > 0)
       
   493 			    {
       
   494 			    const TInt KParamIndex(User::LeaveIfError(stmnt.ParameterIndex(iFieldMap.FindL(nameFieldUid) ) ) );
       
   495     			User::LeaveIfError(stmnt.BindText(KParamIndex, textToSet));
       
   496 			    }			}
       
   497 		else if (field.StorageType() == KStorageTypeText &&  // the field is textual
       
   498 				 field.TextStorage()->Text().Length() &&     // ignore empty fields
       
   499 				 custFiltFields != NULL)
       
   500 			{
       
   501 			// the field is not stored in contact table but potentially maps to a hint
       
   502 			hint.UpdateHintL(field, *custFiltFields);
       
   503 			}
       
   504 		}
       
   505 
       
   506 	
       
   507 	
       
   508 	// bind other values to statement
       
   509 	if(aType == EInsert) 
       
   510 		{
       
   511 		TInt typeFlags(GenerateTypeFlags(aItem.Type(), aItem.Attributes(), hint.iValue) );
       
   512 		User::LeaveIfError(stmnt.BindInt(
       
   513 				User::LeaveIfError(stmnt.ParameterIndex(KContactTypeFlagsParam() ) ), typeFlags) );
       
   514 		}
       
   515 	else
       
   516 		{
       
   517 		User::LeaveIfError(stmnt.BindInt(
       
   518 				User::LeaveIfError(stmnt.ParameterIndex(KContactTypeParam() ) ), TCntPersistenceUtility::ContactTypeUidToTypeFlags(aItem.Type()) >> EContactType_Shift ) );
       
   519 		
       
   520 		TInt attrHint = (aItem.Attributes() << EContactAttributes_Shift) & EContactAttributes_Mask;
       
   521 		attrHint |= hint.iValue & EContactHintFlags_Mask;
       
   522 		User::LeaveIfError(stmnt.BindInt(
       
   523 				User::LeaveIfError(stmnt.ParameterIndex(KAttributesAndHintParam() ) ), attrHint ) );		
       
   524 		}
       
   525 	User::LeaveIfError(stmnt.BindInt(
       
   526 		User::LeaveIfError(stmnt.ParameterIndex(KContactTemplateIdParam() ) ), aItem.TemplateRefId()) );
       
   527 	User::LeaveIfError(stmnt.BindInt(
       
   528 		User::LeaveIfError(stmnt.ParameterIndex(KContactAccessCountParam() ) ), aItem.AccessCount()) );
       
   529 	if (aType == EInsert)
       
   530 		{
       
   531 		User::LeaveIfError(stmnt.BindInt64(
       
   532 			User::LeaveIfError(stmnt.ParameterIndex(KContactCreationDateParam() ) ), aItem.LastModified().Int64() ) );
       
   533 		}
       
   534 	TTime time;
       
   535 	time.UniversalTime();	
       
   536 	User::LeaveIfError(stmnt.BindInt64(
       
   537 		User::LeaveIfError(stmnt.ParameterIndex(KContactLastModifiedParam() ) ), time.Int64() ) );
       
   538 	User::LeaveIfError(stmnt.BindText(
       
   539 		User::LeaveIfError(stmnt.ParameterIndex(KContactGuidStringParam() ) ), const_cast<CContactItem&>(aItem).Guid() ) );
       
   540 	User::LeaveIfError(stmnt.BindInt(
       
   541 		User::LeaveIfError(stmnt.ParameterIndex(KContactIdParam() ) ), aItem.Id() ) );
       
   542 
       
   543 	// build the clob/blob parts of the update statement
       
   544 	RSqlParamWriteStream textHeader;
       
   545 	User::LeaveIfError(textHeader.BindBinary(stmnt, 
       
   546 		User::LeaveIfError(stmnt.ParameterIndex(KContactTextFieldHeaderParam() ) ) ) );	
       
   547 	CEmbeddedStore* textEmbeddedStore = CEmbeddedStore::NewLC(textHeader);
       
   548 
       
   549 	RSqlParamWriteStream binHeader;
       
   550 	User::LeaveIfError(binHeader.BindBinary(stmnt, 
       
   551 		User::LeaveIfError(stmnt.ParameterIndex(KContactBinaryFieldHeaderParam() ) ) ) );	
       
   552 	CEmbeddedStore* binaryEmbeddedStore = CEmbeddedStore::NewLC(binHeader);
       
   553 	
       
   554 	RSqlParamWriteStream textFields;
       
   555 	User::LeaveIfError(textFields.BindText(stmnt, 
       
   556 		User::LeaveIfError(stmnt.ParameterIndex(KContactTextFieldsParam() ) ) ) );
       
   557 	CleanupClosePushL(textFields);
       
   558 	
       
   559 	RSqlParamWriteStream binFields;
       
   560 	User::LeaveIfError(binFields.BindBinary(stmnt, 
       
   561 		User::LeaveIfError(stmnt.ParameterIndex(KContactBinaryFieldsParam() ) ) ) );
       
   562 	CEmbeddedStore* binaryEmbeddedBlobStore=CEmbeddedStore::NewLC(binFields);
       
   563 	
       
   564 	const CContactTemplate* sysTemplate = NULL;
       
   565 	if (aItem.Type() != KUidContactTemplate && aItem.Type() != KUidContactGroup)
       
   566 		{
       
   567 		// System template is needed unless we are creating a template.
       
   568 		sysTemplate = &iProperties.SystemTemplateL();
       
   569 		}
       
   570 
       
   571 	TCntPersistenceUtility::WriteBlobL(*textEmbeddedStore, textFields, *binaryEmbeddedStore, *binaryEmbeddedBlobStore, aItem, sysTemplate);
       
   572 
       
   573 	textHeader.CommitL();
       
   574 	textFields.CommitL();
       
   575 	binHeader.CommitL();
       
   576 	binFields.CommitL();
       
   577 
       
   578 	// execute the statement
       
   579 	User::LeaveIfError(stmnt.Exec() );
       
   580 
       
   581 	textHeader.Close();
       
   582 	binHeader.Close();
       
   583 	textFields.Close();
       
   584 	binFields.Close();
       
   585 	
       
   586 	CleanupStack::PopAndDestroy(5, &stmnt); //binaryEmbeddedBlobStore, textFields, binaryEmbeddedStore, textEmbeddedStore, stmnt
       
   587 	}
       
   588 
       
   589 /**
       
   590 Gets the variables for the three contact item fields represented by the type flags database field.
       
   591 
       
   592 @param aTypeFlags the type flags field to be decoded
       
   593 @param aType the type variable to be got
       
   594 @param aAttributes the attribute variable to be got
       
   595 @param aHintFields the hint fields variable to be got
       
   596 */
       
   597 void CPplContactTable::GetTypeFlagFields(TInt aTypeFlags, TUid& aType, TUint& aAttributes, TUint& aHintFields)
       
   598 	{
       
   599 	aType 		=  TCntPersistenceUtility::TypeFlagsToContactTypeUid(aTypeFlags); 
       
   600 	aAttributes = (aTypeFlags & EContactAttributes_Mask) >> EContactAttributes_Shift; 
       
   601 	aHintFields = TCntPersistenceUtility::TypeFlagsToHint(aTypeFlags);
       
   602 	}
       
   603 
       
   604 /**
       
   605 Creates a TInt of type_flags for insertion into the database.
       
   606 
       
   607 @return A bitmap representing all three parameter values ready to be inserted 
       
   608 into the database as a type_flags column value.
       
   609 
       
   610 @param aType
       
   611 @param aAttributes
       
   612 @param aHintFields
       
   613 */
       
   614 TInt CPplContactTable::GenerateTypeFlags(TUid aType, TUint aAttributes, TUint aHintFields)
       
   615 	{
       
   616 	TInt tmpVal = TCntPersistenceUtility::ContactTypeUidToTypeFlags(aType);
       
   617 	tmpVal |= (aAttributes << EContactAttributes_Shift) & EContactAttributes_Mask;
       
   618 	tmpVal |= aHintFields & EContactHintFlags_Mask;
       
   619 	return tmpVal;
       
   620 	}
       
   621 
       
   622 void CPplContactTable::DeleteL(const CContactItem& aItem, TBool& aLowDiskErrorOccurred)
       
   623 	{
       
   624 	CContactItem* item = DeleteLC(aItem.Id(), aLowDiskErrorOccurred);
       
   625 	CleanupStack::PopAndDestroy(item);
       
   626 	}
       
   627 
       
   628 /**
       
   629 Delete a contact item from the contact table
       
   630 
       
   631 @param aItemId contact item id
       
   632 @param aLowDiskErrorOccurred outparameter; will be set to ETrue if an attempt to delete in
       
   633 		low disk condition occured
       
   634 */
       
   635 CContactItem* CPplContactTable::DeleteLC(TContactItemId  aItemId, TBool& aLowDiskErrorOccurred)
       
   636 	{
       
   637 	// You can't delete the system template, because you couldn't read any cards otherwise.
       
   638 	__ASSERT_ALWAYS(aItemId != KGoldenTemplateId, User::Leave(KErrNotSupported) );
       
   639 
       
   640     // the contact assigned to own card is being deleted, so set cached own card id to "not found"
       
   641     if (iOwnCardId == aItemId) {
       
   642         iOwnCardId = KErrNotFound;
       
   643     }
       
   644 
       
   645 	// select the relevant bits from the contact table for the contact item 
       
   646 	// and put them in a new contact item
       
   647 	RSqlStatement selectStmnt;
       
   648 	CleanupClosePushL(selectStmnt);
       
   649 	selectStmnt.PrepareL(iDatabase, iDeleteSelectStmnt->SqlStringL() );
       
   650 	const TInt KContactIdParamIndex(KFirstIndex); // first and only parameter in the query	
       
   651 	User::LeaveIfError(selectStmnt.BindInt(KContactIdParamIndex, aItemId ) );
       
   652 
       
   653 	// execute query
       
   654 	TInt err(selectStmnt.Next() );
       
   655 	if (err != KSqlAtRow)
       
   656 		{
       
   657 		if (err == KSqlAtEnd)
       
   658 			{
       
   659 			User::Leave(KErrNotFound);
       
   660 			}
       
   661 		User::LeaveIfError(err);
       
   662 		}
       
   663 	
       
   664 	// Obtain the contact type and create a new contact item of this type.
       
   665 	TInt typeFlags = selectStmnt.ColumnInt(iDeleteSelectStmnt->ParameterIndex(KContactTypeFlags() ) ) ;
       
   666 	TInt accessCount =  selectStmnt.ColumnInt(iDeleteSelectStmnt->ParameterIndex(KContactAccessCount() ) ) ;
       
   667 	TContactItemId templateId = selectStmnt.ColumnInt(iDeleteSelectStmnt->ParameterIndex(KContactTemplateId() ) ) ;
       
   668 
       
   669 	CleanupStack::PopAndDestroy(&selectStmnt);
       
   670 
       
   671 	TUid type = TCntPersistenceUtility::TypeFlagsToContactTypeUid(typeFlags);
       
   672 	CContactItem* item = CContactItem::NewLC(type);
       
   673 	item->SetId(aItemId);
       
   674 	item->SetAttributes((typeFlags & EContactAttributes_Mask) >> EContactAttributes_Shift); 
       
   675 	item->SetAccessCount(accessCount);
       
   676 	item->SetTemplateRefId(templateId);
       
   677 	
       
   678 	if (item->IsDeletable() )
       
   679 		{
       
   680 		// delete it here
       
   681 		RSqlStatement deleteStmnt;
       
   682 		CleanupClosePushL(deleteStmnt);
       
   683 		deleteStmnt.PrepareL(iDatabase, iDeleteStmnt->SqlStringL() );
       
   684 		User::LeaveIfError(deleteStmnt.BindInt(KContactIdParamIndex, aItemId) );
       
   685 		TInt err = deleteStmnt.Exec();
       
   686 		CleanupStack::PopAndDestroy(&deleteStmnt);
       
   687 
       
   688 		if (err == KErrDiskFull)
       
   689 			{
       
   690 			aLowDiskErrorOccurred = ETrue;
       
   691 			}
       
   692 		else
       
   693 			{
       
   694 			User::LeaveIfError(err);
       
   695 			}
       
   696 		}
       
   697 	else // Not deletable because of access count > 0.
       
   698 		{
       
   699 		if (!item->IsDeleted() )
       
   700 			{
       
   701 			// Set and persist the deleted flag.
       
   702 			item->SetDeleted(ETrue);
       
   703 
       
   704 			// update attributes in the contact table
       
   705 			typeFlags |= (item->Attributes()) << EContactAttributes_Shift;
       
   706 			RSqlStatement updateStmnt;
       
   707 			CleanupClosePushL(updateStmnt);
       
   708 			updateStmnt.PrepareL(iDatabase, iUpdateFlagsStmnt->SqlStringL() );
       
   709 			const TInt KTypeFlagsParamIndex(KFirstParam);				// first parameter in query...
       
   710 			const TInt KContactIdParamIndex(KTypeFlagsParamIndex + 1);	// ...and the second.
       
   711 			User::LeaveIfError(updateStmnt.BindInt(KTypeFlagsParamIndex, typeFlags) );
       
   712 			User::LeaveIfError(updateStmnt.BindInt(KContactIdParamIndex, item->Id()) );
       
   713 			User::LeaveIfError(updateStmnt.Exec() );
       
   714 			CleanupStack::PopAndDestroy(&updateStmnt);
       
   715 			}
       
   716 		}
       
   717 
       
   718 	if (!item->IsDeleted() && !aLowDiskErrorOccurred)
       
   719 		{
       
   720 		// Decrement Template reference counter.
       
   721 		UpdateTemplateAccessCounterL(item->TemplateRefId(), EFalse);
       
   722 		}
       
   723 
       
   724 	// Ownership is passed to the caller, who can do additional analysis of the item.
       
   725 	return item;
       
   726 	}
       
   727 
       
   728 
       
   729 /**
       
   730 Create the contact table in the database.
       
   731 */
       
   732 void CPplContactTable::CreateTableL()
       
   733 	{
       
   734 	User::LeaveIfError(iDatabase.Exec(KContactCreateStmnt) );
       
   735 	}
       
   736 
       
   737 
       
   738 /**
       
   739 Change the type of the given contact item to the given type.
       
   740 
       
   741 @param aItemId Contact item ID whose type is to be changed.
       
   742 @param aNewType New type for contact item.
       
   743 */
       
   744 void CPplContactTable::ChangeTypeL(TContactItemId aItemId, TUid aNewType)
       
   745 	{
       
   746    	if(aItemId == KNullContactId)
       
   747    	    {
       
   748    	    return;
       
   749    	    }
       
   750 	
       
   751 	// get the type flags for the contact item
       
   752 	const TInt bufSize(KSelectFlagsSqlStmntFormat().Size() + NumDigits(aItemId) );
       
   753 	HBufC* buf = HBufC::NewLC(bufSize);
       
   754 	TPtr selectTypeFlagsSqlStmnt(buf->Des() );
       
   755 	selectTypeFlagsSqlStmnt.AppendFormat(KSelectFlagsSqlStmntFormat, aItemId);
       
   756 	TSqlScalarFullSelectQuery selectTypeFlagsQuery(iDatabase);
       
   757 	TInt typeFlags = selectTypeFlagsQuery.SelectIntL(selectTypeFlagsSqlStmnt);
       
   758 	CleanupStack::PopAndDestroy(buf);
       
   759 
       
   760 	// deconstruct the type flags into the different fields and then rebuild it with the new type
       
   761 	TUid type;
       
   762 	TUint attributes;
       
   763 	TUint hintFields;
       
   764 	GetTypeFlagFields(typeFlags, type, attributes, hintFields);
       
   765 	typeFlags = GenerateTypeFlags(aNewType, attributes, hintFields); // use new type
       
   766 
       
   767 	// update type flags in the contact table
       
   768 	RSqlStatement updateStmnt;
       
   769 	CleanupClosePushL(updateStmnt);
       
   770 	updateStmnt.PrepareL(iDatabase, iUpdateFlagsStmnt->SqlStringL() );
       
   771 	User::LeaveIfError(updateStmnt.BindInt(updateStmnt.ParameterIndex(KContactTypeFlagsParam() ), typeFlags) );
       
   772 	User::LeaveIfError(updateStmnt.BindInt(updateStmnt.ParameterIndex(KContactIdParam()), aItemId) );
       
   773 	User::LeaveIfError(updateStmnt.Exec() );
       
   774 	CleanupStack::PopAndDestroy(&updateStmnt);
       
   775 	}
       
   776 
       
   777 /**
       
   778 CPplContactTable::THintField constructor.
       
   779 */
       
   780 CPplContactTable::THintField::THintField()
       
   781 	: iValue(0)
       
   782 	{
       
   783 	}
       
   784 
       
   785 
       
   786 /**
       
   787 CPplContactTable::THintField constructor.
       
   788 */
       
   789 CPplContactTable::THintField::THintField(TUint16 aExtHint, TUint8 aHint)
       
   790 	{
       
   791 	iValue = ((aExtHint << 8) | aHint);
       
   792 	}
       
   793 
       
   794 
       
   795 /** 
       
   796 Update the hint value using the given contact field and custom filterable
       
   797 fields.
       
   798 
       
   799 @param aField Contact field.
       
   800 @param aCustFiltFields Custom filterable fields.
       
   801 */
       
   802 void CPplContactTable::THintField::UpdateHintL(const CContactItemField& aField, const RArray<TUid>& aCustFiltFields)
       
   803 	{
       
   804 	const CContentType& type = aField.ContentType();
       
   805 
       
   806 	if (type.ContainsFieldType(KUidContactFieldVCardMapWORK) )
       
   807 		{
       
   808 		iValue |= CContactDatabase::EWork;
       
   809 		}
       
   810 
       
   811 	if (type.ContainsFieldType(KUidContactFieldVCardMapHOME) )
       
   812 		{
       
   813 		iValue |= CContactDatabase::EHome;
       
   814 		}
       
   815 
       
   816 	if (type.ContainsFieldType(KUidContactFieldPhoneNumber) )
       
   817 		{
       
   818 		iValue |= CContactDatabase::EPhonable;
       
   819 
       
   820 		if(type.ContainsFieldType(KUidContactFieldVCardMapCELL) )
       
   821 			{
       
   822 			iValue |= CContactDatabase::ESmsable;
       
   823 			}
       
   824 		else if(!type.ContainsFieldType(KUidContactFieldVCardMapPAGER) )
       
   825 			{
       
   826 			iValue |= CContactDatabase::ELandLine;
       
   827 			}
       
   828 		}
       
   829 
       
   830 	if (type.ContainsFieldType(KUidContactFieldRingTone) )
       
   831 		{
       
   832 		CContactFieldStorage* storage = aField.Storage();
       
   833 		if ( storage && storage->IsFull() )
       
   834 			{
       
   835 			iValue |= CContactDatabase::ERingTone;
       
   836 			}
       
   837 		}
       
   838 
       
   839 	if (type.ContainsFieldType( KUidContactsVoiceDialField ) )
       
   840 		{
       
   841 		CContactFieldStorage* storage = aField.Storage();
       
   842 		if (storage && storage->IsFull() )
       
   843 			{
       
   844 			iValue |= CContactDatabase::EVoiceDial;
       
   845 			}
       
   846 		}
       
   847 
       
   848 	if(type.ContainsFieldType(KUidContactFieldFax) )
       
   849 		{
       
   850 		iValue |= CContactDatabase::EFaxable;
       
   851 		iValue |= CContactDatabase::EPhonable;
       
   852 		}
       
   853 
       
   854 	if(type.ContainsFieldType(KUidContactFieldIMAddress) )
       
   855 		{
       
   856 		CContactFieldStorage* storage = aField.Storage();
       
   857 		if(storage && storage->IsFull() )
       
   858 			{
       
   859 			iValue |= CContactDatabase::EIMAddress;
       
   860 			if(type.ContainsFieldType(KUidContactFieldVCardMapWV) )
       
   861 				{
       
   862 				iValue |= CContactDatabase::EWirelessVillage;
       
   863 				}
       
   864 			}
       
   865 		}
       
   866 
       
   867 	if (type.ContainsFieldType(KUidContactFieldEMail) )
       
   868 		{
       
   869 		iValue |= CContactDatabase::EMailable;
       
   870 		}
       
   871 
       
   872 	// Now check if given field type maps to one of the given (licensee) custom
       
   873 	// filterable fields.
       
   874 	
       
   875 	TInt index(KErrNotFound);
       
   876 
       
   877 	const TInt KCount = aCustFiltFields.Count();
       
   878 	for (TInt i = 0; i < KCount; ++i)
       
   879 		{
       
   880 		if (type.ContainsFieldType(aCustFiltFields[i]) )
       
   881 			{
       
   882 			index = i;
       
   883 			break;
       
   884 			}
       
   885 		}
       
   886 
       
   887 	if (index != KErrNotFound)
       
   888 		{
       
   889 		switch (index)
       
   890 			{
       
   891 			case 0:
       
   892 				iValue |= CContactDatabase::ECustomFilter1;
       
   893 				break;
       
   894 			case 1:
       
   895 				iValue |= CContactDatabase::ECustomFilter2;
       
   896 				break;
       
   897 			case 2:
       
   898 				iValue |= CContactDatabase::ECustomFilter3;
       
   899 				break;
       
   900 			case 3:
       
   901 				iValue |= CContactDatabase::ECustomFilter4;
       
   902 				break;
       
   903 			default:
       
   904 				__ASSERT_DEBUG(EFalse, User::Leave(KErrNotSupported) );
       
   905 				break;
       
   906 			}
       
   907 		}
       
   908 	}
       
   909 
       
   910 
       
   911 /**
       
   912 Get the hint extension value (upper 8 bits).
       
   913 
       
   914 @return Hint extension value.
       
   915 */
       
   916 TUint16 CPplContactTable::THintField::ExtHint()
       
   917 	{
       
   918 	return static_cast<TUint16>((iValue >> 8) & KMaxTUint16);
       
   919 	}
       
   920 
       
   921 
       
   922 /**
       
   923 Get the non-extended hint value (lower 8 bits).
       
   924 
       
   925 @return Non-extended hint value.
       
   926 */
       
   927 TInt8 CPplContactTable::THintField::Hint()
       
   928 	{
       
   929 	return static_cast<TInt8>(iValue & KMaxTUint8);
       
   930 	}
       
   931 
       
   932 
       
   933 
       
   934 /**
       
   935 Return the Identity field uid for the given contact field.
       
   936 
       
   937 @param Contact field.
       
   938 
       
   939 @return Identity field index corresponding to the given contact field.
       
   940 */
       
   941 TInt CPplContactTable::NameFieldUid(const CContactItemField& nameField)
       
   942 	{
       
   943 	// For all the name fields stored in the Identity table...
       
   944 	for (TInt nameFieldNum = 0; nameFieldNum < sizeof(KFastAccessFieldUids) / sizeof(TInt); ++nameFieldNum)
       
   945 		{
       
   946 		if (nameField.ContentType().ContainsFieldType(TUid::Uid(KFastAccessFieldUids[nameFieldNum]) ) )
       
   947 			{
       
   948 			return KFastAccessFieldUids[nameFieldNum];
       
   949 			}
       
   950 		}
       
   951 	return KErrNotFound;
       
   952 	}
       
   953 
       
   954 /**
       
   955   Utility function to calculate the number of digits in an integer.
       
   956   If a negative number, counts the - sign as an extra digit.
       
   957   
       
   958   @param aNum an integer
       
   959   
       
   960   @return TUint the number of digits
       
   961 */
       
   962 TUint CPplContactTable::NumDigits(TInt aNum)
       
   963 	{
       
   964   	TInt numDig(1);
       
   965   	if (aNum < 0)
       
   966   		{
       
   967   		++numDig;
       
   968   		aNum = -aNum;
       
   969   		}
       
   970   	while( (aNum /= 10) > 0)
       
   971   		{
       
   972   		++numDig;
       
   973   		}
       
   974   	return numDig;
       
   975   	}
       
   976   	
       
   977 /**	
       
   978 Utility method used to check if contact table is empty or not
       
   979 
       
   980 @return ETrue is the contact table is empty and EFalse otherwise
       
   981 */
       
   982 TBool CPplContactTable::IsTableEmptyL()
       
   983 	{
       
   984 	TInt count = 0;
       
   985 
       
   986 	HBufC* selectString = HBufC::NewLC(KCountSelect().Length() + 
       
   987 						KSqlContactTableName().Length()); 
       
   988 	TPtr ptrSelectString = selectString->Des();
       
   989 	ptrSelectString.Format(KCountSelect, &KSqlContactTableName);
       
   990 
       
   991 	TSqlScalarFullSelectQuery scalarQuery(iDatabase);
       
   992 	
       
   993 	count = scalarQuery.SelectIntL(ptrSelectString);
       
   994 	CleanupStack::PopAndDestroy(selectString);
       
   995 
       
   996 	return (count == 0);	
       
   997 	}
       
   998 
       
   999 /**
       
  1000 Utility method used to retrieve card template ids
       
  1001 */
       
  1002 CContactIdArray& CPplContactTable::CardTemplateIdsL()
       
  1003 	{
       
  1004 	iCardTemplateIds->Reset();
       
  1005 	
       
  1006 	HBufC* selectString = HBufC::NewLC(KTwoTypeField().Length() + KContactId().Length() + KContactTypeFlags().Length() + 
       
  1007 						KSqlContactTableName().Length() + KContactTypeFlags().Length() + 3); 
       
  1008 	TPtr ptrSelectString = selectString->Des();
       
  1009 	ptrSelectString.Format(KTwoTypeField, &KContactId, &KContactTypeFlags, &KSqlContactTableName, &KContactTypeFlags, EContactType_Shift, EContactTypeFlags_CardTemplate);
       
  1010 	
       
  1011 	RSqlStatement selectStmnt;
       
  1012 	CleanupClosePushL(selectStmnt);
       
  1013 	selectStmnt.PrepareL(iDatabase, ptrSelectString );
       
  1014 	
       
  1015 	const TInt KIdIndex = selectStmnt.ColumnIndex(KContactId);
       
  1016 	const TInt KTypeFlagsIndex = selectStmnt.ColumnIndex(KContactTypeFlags);
       
  1017 	
       
  1018 	TInt err;
       
  1019 	while((err = selectStmnt.Next()) == KSqlAtRow)
       
  1020 		{
       
  1021 		TInt typeFlags = selectStmnt.ColumnInt(KTypeFlagsIndex);
       
  1022 		TInt attr = (typeFlags & EContactAttributes_Mask) >> EContactAttributes_Shift; 
       
  1023 		if((attr & EContactAttrsFlags_Deleted) == 0)
       
  1024 		    {
       
  1025 		    //Only add templates are not marked as deleted.
       
  1026     		iCardTemplateIds->AddL(selectStmnt.ColumnInt(KIdIndex));	
       
  1027 		    }
       
  1028 		}
       
  1029 	
       
  1030 	if (err != KSqlAtEnd)
       
  1031 		{
       
  1032 		User::Leave(err);
       
  1033 		}
       
  1034 
       
  1035 	CleanupStack::PopAndDestroy(2,selectString);
       
  1036 	
       
  1037 	return *iCardTemplateIds;
       
  1038 	}
       
  1039 
       
  1040 /**
       
  1041 Utility method used to retrieve own card id
       
  1042 */
       
  1043 TContactItemId CPplContactTable::OwnCardIdL()
       
  1044 	{
       
  1045 	if (iOwnCardId != 0)
       
  1046 	    {
       
  1047     	RDebug::Print(_L("CPplContactTable::OwnCardIdL() exit %d"), iOwnCardId);
       
  1048 	    return iOwnCardId;
       
  1049 	    }
       
  1050 	    
       
  1051 	HBufC* selectString = HBufC::NewLC(KOneTypeField().Length() + KContactId().Length() + 
       
  1052 						KSqlContactTableName().Length() + KContactTypeFlags().Length() + 3); 
       
  1053 	TPtr ptrSelectString = selectString->Des();
       
  1054 	ptrSelectString.Format(KOneTypeField, &KContactId, &KSqlContactTableName, &KContactTypeFlags, EContactType_Shift, EContactTypeFlags_OwnCard);
       
  1055 	
       
  1056 	RSqlStatement selectStmnt;
       
  1057 	CleanupClosePushL(selectStmnt);
       
  1058 	selectStmnt.PrepareL(iDatabase, ptrSelectString );
       
  1059 	
       
  1060 	const TInt idIndex = selectStmnt.ColumnIndex(KContactId);
       
  1061 	
       
  1062 	TInt err;
       
  1063 	if((err = selectStmnt.Next()) == KSqlAtRow)
       
  1064 		{
       
  1065 		iOwnCardId = selectStmnt.ColumnInt(idIndex);	
       
  1066 		}
       
  1067 	else
       
  1068 		{
       
  1069 		User::LeaveIfError(err);
       
  1070 		iOwnCardId = KErrNotFound;
       
  1071 		}
       
  1072 	
       
  1073 	CleanupStack::PopAndDestroy(2, selectString);
       
  1074 	
       
  1075 	return iOwnCardId;
       
  1076 	}
       
  1077 	
       
  1078 /**
       
  1079 Utility method used to set own card id
       
  1080 */	
       
  1081 void CPplContactTable::SetOwnCardIdL(TContactItemId aId, TBool aPersist)
       
  1082 	{
       
  1083 	if (iOwnCardId != aId)
       
  1084 	    {
       
  1085 	    if (aPersist)
       
  1086 	        {
       
  1087 	        //Change old own card to be contact card.
       
  1088             ChangeTypeL(iOwnCardId, KUidContactCard);
       
  1089 			iOwnCardId = KErrNotFound;
       
  1090         
       
  1091 	        //set given card as own card.
       
  1092     	    ChangeTypeL(aId, KUidContactOwnCard);
       
  1093     	    }
       
  1094 
       
  1095 	    //update cached own card id
       
  1096     	iOwnCardId = aId;
       
  1097 	    }
       
  1098 	}