diff -r f5050f1da672 -r 04becd199f91 javaextensions/pim/cntadapter/src.s60/cpimcontactitemadapter.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaextensions/pim/cntadapter/src.s60/cpimcontactitemadapter.cpp Tue Apr 27 16:30:29 2010 +0300 @@ -0,0 +1,1467 @@ +/* +* Copyright (c) 2008 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: Handles conversion between PIM API Contact Items and Contacts + * Model Contact Cards + * +*/ + + +// CLASS HEADER +#include "cpimcontactitemadapter.h" + +// INTERNAL INCLUDES +#include "cpimcontactcategorymanager.h" +#include "pimpanics.h" +#include "mpimcontactitem.h" +#include "mpimitemdata.h" +#include "cpimimagescaler.h" +#include "cpimcontactfieldinfo.h" +#include "logger.h" + +// EXTERNAL INCLUDES +#include // CContactCard etc. +#include // CContactTextField etc. +#include +#include + + + +// UNNAMED LOCAL NAMESPACE +namespace +{ +// Phonebook maps Syncronisation field values with specified +// hard-coded string values. At the time implementing, the header +// was not exported so it is necessary to define own constants +// with same values +_LIT(KPIMContactClassPrivate, "private"); +_LIT(KPIMContactClassPublic, "public"); +_LIT(KPIMContactClassConfidential, "none"); +} + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CPIMContactItemAdapter* CPIMContactItemAdapter::NewL( + CPIMContactCategoryManager& aCategoryManager) +{ + JELOG2(EPim); + CPIMContactItemAdapter* self = + new(ELeave) CPIMContactItemAdapter(aCategoryManager); + + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + + return self; +} + +// destructor +CPIMContactItemAdapter::~CPIMContactItemAdapter() +{ + JELOG2(EPim); + delete iImageScaler; + delete iFieldInfo; +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::CardL +// Converts from a PIM item data to a Contacts Model contact card. +// Returns: A contact card with the same information as given in +// the parameter item. The ownership of the card is +// transferred to the caller. +// ----------------------------------------------------------------------------- +// +CContactCard* CPIMContactItemAdapter::CardL(const MPIMContactItem& aItem) +{ + JELOG2(EPim); + CContactCard* card = CContactCard::NewLC(); + const MPIMItemData& item = aItem.ItemData(); + __ASSERT_DEBUG((aItem.ContactItemIdL() == 0), User::Panic( + KPIMPanicCategory, EPIMPanicInvalidItemID)); + CArrayFix* fields = item.FieldsLC(); + + TInt fieldCount = fields->Count(); + for (TInt i = 0; i < fieldCount; i++) + { + ConvertFieldL(aItem, *card, + static_cast(fields->At(i))); + } + + // Set default values if not present in PIM item + if (item.CountValues(EPIMContactClass) == 0) + { + CContentType* type = CContentType::NewL(KUidContactFieldClass, + KUidContactFieldVCardMapClass); + CleanupStack::PushL(type); + + // Add value to the contact field + CContactItemField* field = CContactItemField::NewLC(KStorageTypeText, + *type); + field->SetUserFlags(EContactCategoryNone); + CContactTextField* textField = field->TextStorage(); + textField->SetTextL(KPIMContactClassPrivate()); + card->AddFieldL(*field); + + CleanupStack::Pop(field); + CleanupStack::PopAndDestroy(type); + } + + CleanupStack::PopAndDestroy(fields); + CleanupStack::Pop(card); + return card; +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::FillItemL +// Converts from a Contacts Model contact card to the PIM representation. +// ----------------------------------------------------------------------------- +// +void CPIMContactItemAdapter::FillItemL(MPIMContactItem& aItem, // Item data container to fill with the data + const CContactCard& aCard) // Contact Card to convert +{ + JELOG2(EPim); + // convert fields + CContactItemFieldSet& fieldSet = aCard.CardFields(); + TInt fieldCount = fieldSet.Count(); + for (TInt i = 0; i < fieldCount; i++) + { + ConvertFieldL(fieldSet[i], aItem); + } + // convert categories + MPIMItemData& item = aItem.ItemData(); + CContactIdArray* groupArray = aCard.GroupsJoinedLC(); + TInt groupCount = groupArray->Count(); + for (TInt i = 0; i < groupCount; i++) + { + HBufC* label = iCategoryManager.GroupLabelL((*groupArray)[i]); + CleanupStack::PushL(label); + // Add item to this category if it doesn't belong to it already + if (item.FindCategory(*label) == KErrNotFound) + { + item.AddNewCategoryL(*label); + } + CleanupStack::PopAndDestroy(label); + } + CleanupStack::PopAndDestroy(groupArray); +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::UpdateCardL +// Updates the data in the Contacts Model contact card to match +// the data in the PIM item data container. +// ----------------------------------------------------------------------------- +// +void CPIMContactItemAdapter::UpdateCardL(const MPIMContactItem& aItem, // Item from which the data is read + CContactCard& aCard) // The card which is updated +{ + JELOG2(EPim); + CleanCard(aCard); + const MPIMItemData& itemData = aItem.ItemData(); + // Get fields + CArrayFix* fields = itemData.FieldsLC(); + TInt fieldCount = fields->Count(); + for (TInt i = 0; i < fieldCount; i++) + { + ConvertFieldL(aItem, aCard, (TPIMContactField)(fields->At(i))); + } + CleanupStack::PopAndDestroy(); // fields +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::UpdateCategoriesL +// Updates the category information in the database. +// ----------------------------------------------------------------------------- +// +void CPIMContactItemAdapter::UpdateCategoriesL(const MPIMContactItem& aItem, // Item containing the new categories + const CContactCard& aCard) // Item to update +{ + JELOG2(EPim); + const CDesCArray& pimCategories = aItem.ItemData().Categories(); + const TInt pimCategoryCount = pimCategories.Count(); + TBool* newCategoryTable = new(ELeave) TBool[pimCategoryCount]; + CleanupArrayDeletePushL(newCategoryTable); + TInt i = 0; + for (i = 0; i < pimCategoryCount; i++) + { + newCategoryTable[i] = ETrue; + } + + CContactIdArray* cardCategories = aCard.GroupsJoinedLC(); + TContactItemId id = aItem.ContactItemIdL(); + + // first remove extra groups + const TInt cardCategoryCount = cardCategories->Count(); + for (i = 0; i < cardCategoryCount; i++) + { + TContactItemId groupId = (*cardCategories)[i]; + HBufC* groupLabel = iCategoryManager.GroupLabelL(groupId); + TInt pos; + TInt found = pimCategories.Find(*groupLabel, pos, ECmpNormal); + delete groupLabel; + if (found != 0) + { + // removed group + iCategoryManager.RemoveFromGroupL(id, groupId); + } + else + { + // old group + newCategoryTable[pos] = EFalse; + } + } + // then add new categories + for (i = 0; i < pimCategoryCount; i++) + { + if (newCategoryTable[i]) + { + TPtrC category = pimCategories[i]; + iCategoryManager.AddToGroupL(id, category); + } + } + CleanupStack::PopAndDestroy(2); // cardCategories, newCategoryTable +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::ContactsModelFieldType +// Other items were commented in the header +// ----------------------------------------------------------------------------- +// +CArrayFix* CPIMContactItemAdapter::ContactsModelFieldTypeL( + TPIMContactField aContactField) const +{ + JELOG2(EPim); + return iFieldInfo->MatchPIMFieldL(aContactField); +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::CPIMContactItemAdapter +// C++ constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +CPIMContactItemAdapter::CPIMContactItemAdapter( + CPIMContactCategoryManager& aCategoryManager) : + iCategoryManager(aCategoryManager) +{ + JELOG2(EPim); +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::ConstructL +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +inline void CPIMContactItemAdapter::ConstructL() +{ + JELOG2(EPim); + iFieldInfo = CPIMContactFieldInfo::NewL(); + iImageScaler = CPIMImageScaler::NewL(); +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::CleanCardL +// Deletes all the supported fields from the contact card. +// Those fields which are not supported are left as is. +// ----------------------------------------------------------------------------- +// +void CPIMContactItemAdapter::CleanCard(CContactCard& aCard) +{ + JELOG2(EPim); + // convert fields + CContactItemFieldSet& fieldSet = aCard.CardFields(); + TInt fieldCount = fieldSet.Count(); + for (TInt i = 0; i < fieldCount; i++) + { + if (IsSupportedField(fieldSet[i])) + { + // as the field is removed, the array shrinks + aCard.RemoveField(i--); + fieldCount--; + } + } +} +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::IsSupportedFieldL +// Checks if we support this particular contact field. +// Returns: ETrue if the field is supported +// EFalse otherwise +// ----------------------------------------------------------------------------- +// +TBool CPIMContactItemAdapter::IsSupportedField(CContactItemField& aField) +{ + JELOG2(EPim); + const CContentType& type = aField.ContentType(); + if (type.FieldTypeCount() == 0) + { + // we don't support unknown types + return EFalse; + } + + TFieldType fieldTypeUid = type.FieldType(0); + TInt fieldType = fieldTypeUid.iUid; + switch (fieldType) + { + case KUidContactFieldAddressValue: + { + // Label addresses are also stored in the database using + // KUidContactFieldAddressValue, but we don't support them + if (type.ContainsFieldType(KUidContactFieldVCardMapADR)) + { + return ETrue; + } + else + { + return EFalse; + } + } + case KUidContactFieldPictureValue: + { + // Thumbnails are supported while pictures are not + if (type.ContainsFieldType(KUidContactFieldVCardMapPHOTO)) + { + return ETrue; + } + else + { + return EFalse; + } + } + case KUidContactFieldSIPIDValue: + case KUidContactFieldFamilyNameValue: + case KUidContactFieldGivenNameValue: + case KUidContactFieldSecondNameValue: + case KUidContactFieldFamilyNamePronunciationValue: + case KUidContactFieldGivenNamePronunciationValue: + case KUidContactFieldAdditionalNameValue: + case KUidContactFieldPrefixNameValue: + case KUidContactFieldSuffixNameValue: + case KUidContactFieldPhoneNumberValue: + case KUidContactFieldFaxValue: + case KUidContactFieldEMailValue: + case KUidContactFieldUrlValue: + case KUidContactFieldPostOfficeValue: + case KUidContactFieldExtendedAddressValue: + case KUidContactFieldPostCodeValue: + case KUidContactFieldLocalityValue: + case KUidContactFieldRegionValue: + case KUidContactFieldCountryValue: + case KUidContactFieldCompanyNameValue: + case KUidContactFieldNoteValue: + case KUidContactFieldBirthdayValue: + case KUidContactFieldJobTitleValue: + case KUidContactFieldDTMFValue: + case KUidContactFieldIMAddressValue: + case KUidContactFieldDepartmentNameValue: + case KUidContactFieldAssistantValue: + case KUidContactFieldChildrenValue: + case KUidContactFieldSpouseValue: + case KUidContactFieldAnniversaryValue: + case KUidContactFieldClassValue: + { + return ETrue; + } + default: + { + return EFalse; + } + } +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::ConvertFieldL +// Converts a field from a PIM Item to a Contact Card. +// ----------------------------------------------------------------------------- +// +void CPIMContactItemAdapter::ConvertFieldL(const MPIMContactItem& aItem, // item to read the field from + CContactCard& aCard, // card to write the field to + TPIMContactField aField) // field to convert +{ + JELOG2(EPim); + const MPIMItemData& itemData = aItem.ItemData(); + + // These are indexes in PIM Item address values + TInt plainAddressIndex = KErrNotFound; + TInt homeAddressIndex = KErrNotFound; + TInt workAddressIndex = KErrNotFound; + if (aField == EPIMContactAddr) + { + AddressAttributesL(itemData, plainAddressIndex, homeAddressIndex, + workAddressIndex); + ConvertAddressFieldL(itemData, aCard, aField, plainAddressIndex, + KPIMAttrNone); + ConvertAddressFieldL(itemData, aCard, aField, homeAddressIndex, + EPIMContactAttrHome); + ConvertAddressFieldL(itemData, aCard, aField, workAddressIndex, + EPIMContactAttrWork); + return; + } + + TInt valueCount = itemData.CountValues(aField); + for (TInt i = 0; i < valueCount; i++) + { + switch (aField) + { + case EPIMContactUid: + case EPIMContactRevision: + { + // uid and revision fields are totally ignored + break; + } + case EPIMContactBirthday: + case EPIMContactExtAnniversary: + { + ConvertDateFieldL(itemData, aCard, aField, i); + break; + } + case EPIMContactEmail: + case EPIMContactNickname: + case EPIMContactNote: + case EPIMContactOrg: + case EPIMContactTel: + case EPIMContactTitle: + case EPIMContactUrl: + case EPIMContactExtSip: + case EPIMContactExtDtmf: + case EPIMContactExtWvUserId: + case EPIMContactExtDepartment: + case EPIMContactExtAssistantName: + case EPIMContactExtChildren: + case EPIMContactExtSpouse: + case EPIMContactExtVoip: + case EPIMContactExtPTT: + case EPIMContactExtSWIS: + { + ConvertStringFieldL(itemData, aCard, aField, i); + break; + } + case EPIMContactName: + { + ConvertNameFieldL(itemData, aCard, aField, i); + break; + } + case EPIMContactPhoto: + { + ConvertPhotoFieldL(itemData, aCard, aField, i); + break; + } + case EPIMContactClass: + { + ConvertClassFieldL(itemData, aCard, aField, i); + break; + } + case EPIMContactFormattedName: + case EPIMContactFormattedAddr: + case EPIMContactPhotoUrl: + case EPIMContactPublicKey: + case EPIMContactPublicKeyString: + default: + { + __ASSERT_DEBUG(EFalse, User::Panic(KPIMPanicCategory, + EPIMPanicUnsupportedField)); + return; + } + } + } +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::ConvertFieldL +// Converts a field from a Contact Card to a PIM Item. +// ----------------------------------------------------------------------------- +// +void CPIMContactItemAdapter::ConvertFieldL(const CContactItemField& aField, // field to read data from + MPIMContactItem& aItem) // field to write the data to +{ + JELOG2(EPim); + TStorageType type = aField.StorageType(); + switch (type) + { + case KStorageTypeText: + { + ConvertTextFieldL(aField, aItem); + break; + } + case KStorageTypeStore: + { + ConvertStoreFieldL(aField, aItem); + break; + } + case KStorageTypeContactItemId: + { + break; + } + case KStorageTypeDateTime: + { + ConvertDateFieldL(aField, aItem); + break; + } + default: + { + __ASSERT_DEBUG(EFalse, User::Panic(KPIMPanicCategory, + EPIMPanicUnsupportedField)); + } + } +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::ConvertTextFieldL +// Converts a text field from a Contact Card to a PIM Item. +// ----------------------------------------------------------------------------- +// +void CPIMContactItemAdapter::ConvertTextFieldL(const CContactItemField& aField, // field to read data from + MPIMContactItem& aItem) // field to write the data to +{ + JELOG2(EPim); + MPIMItemData& itemData = aItem.ItemData(); + CContactTextField* textField = aField.TextStorage(); + const CContentType& type = aField.ContentType(); + + // Check that can we handle this field + if (!(textField->IsFull()) || (type.FieldTypeCount() == 0)) + { + return; + } + + TPtrC text = textField->Text(); + TFieldType fieldTypeUid = type.FieldType(0); + TPIMAttribute attributes = KPIMAttrNone; + + TPIMField field = iFieldInfo->MatchContactField(fieldTypeUid.iUid); + // Check which field we must handle + switch (field) + { + case EPIMContactName: + { + TPIMContactNameElement + nameElement = + static_cast(iFieldInfo->MatchContactArrayElement( + fieldTypeUid.iUid)); + AddNameFieldToItemL(text, aItem, nameElement, aField.Label()); + break; + } + case EPIMContactAddr: + { + TPIMContactAddrElement + addrElement = + static_cast(iFieldInfo->MatchContactArrayElement( + fieldTypeUid.iUid)); + attributes = iFieldInfo->FieldAttributes(aField.ContentType()); + + // Label addresses are also stored in the database using + // KUidContactFieldAddressValue, but we don't support them + if (fieldTypeUid.iUid == KUidContactFieldAddressValue) + { + if (type.ContainsFieldType(KUidContactFieldVCardMapADR)) + { + AddAddressFieldToItemL(text, aItem, EPIMContactAddrStreet, + attributes, aField.Label()); + } + } + else + { + AddAddressFieldToItemL(text, aItem, addrElement, attributes, + aField.Label()); + } + break; + } + case EPIMContactClass: + { + AddClassFieldToItemL(itemData, text, aField.Label()); + break; + } + case EPIMContactExtSip: + case EPIMContactExtVoip: + case EPIMContactExtPTT: + case EPIMContactExtSWIS: + { + // SIPID value can hold PoC (Push-To-Talk) Share view, SIP + // and VOIP (Voice Over IP) fields inside it. + // Apply internal attributes + CArrayFix* attrs = new(ELeave) CArrayFixFlat (3); + CleanupStack::PushL(attrs); + iFieldInfo->GetFieldInternalAttributesL(type, *attrs); + // VOIP (Internet telephone) field + if (type.ContainsFieldType(KUidContactFieldVCardMapVOIP)) + { + attributes = iFieldInfo->FieldAttributes(type); + field = EPIMContactExtVoip; + } + else if (type.ContainsFieldType(KUidContactFieldVCardMapPOC)) + { + field = EPIMContactExtPTT; + } + else if (type.ContainsFieldType(KUidContactFieldVCardMapSWIS)) + { + field = EPIMContactExtSWIS; + } + else + { + field = EPIMContactExtSip; + } + // Add field, attributes, internal attributes and label to the item + // Note that internal attributes are popped from the cleanup stack + // inside the following function and there is no need to pop after it + AddStringFieldWithLabelL(itemData, field, attributes, attrs, text, + aField.Label()); + break; + } + case EPIMContactEmail: + case EPIMContactNickname: + case EPIMContactNote: + case EPIMContactOrg: + case EPIMContactTel: + case EPIMContactTitle: + case EPIMContactUrl: + case EPIMContactExtDtmf: + case EPIMContactExtWvUserId: + case EPIMContactExtDepartment: + case EPIMContactExtAssistantName: + case EPIMContactExtChildren: + case EPIMContactExtSpouse: + { + // Get internal attributes from the content type + CArrayFix* attrs = new(ELeave) CArrayFixFlat (3); + CleanupStack::PushL(attrs); + iFieldInfo->GetFieldInternalAttributesL(type, *attrs); + // Add attributes. FAX is special so it must be handled separately + attributes = iFieldInfo->FieldAttributes(aField.ContentType()); + if (fieldTypeUid.iUid == KUidContactFieldFaxValue) + { + attributes |= EPIMContactAttrFax; + } + // Add field, attributes, internal attributes and label to the item + // Note that internal attributes are popped from the cleanup stack + // inside the following function and there is no need to pop after it + AddStringFieldWithLabelL(itemData, field, attributes, attrs, text, + aField.Label()); + break; + } + default: + { + // The field is not supported so we don't know what to do with it + // and it is ignored. NOTE that contacts are opened first before + // writing those to the contact database to ensure that unsupported + // fields will still be included the to item and no data will be lost + break; + } + } +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::AddStringFieldWithLabelL +// Adds a string field to the item, and optionally sets the fields label. +// ----------------------------------------------------------------------------- +// +void CPIMContactItemAdapter::AddStringFieldWithLabelL(MPIMItemData& aItem, + TPIMField aField, TPIMAttribute aAttributes, + CArrayFix* aInternalAttributes, const TPtrC aValue, + const TPtrC aLabel) +{ + JELOG2(EPim); + TInt valueCount = aItem.CountValues(aField); + TPIMFieldData fieldData(aField, aAttributes, aValue.AllocLC()); + + // Add data to the item + aItem.AddValueL(fieldData); + CleanupStack::Pop(); // aValue.AlloclC() + // Apply internal attributes + aItem.SetInternalAttributesL(aField, valueCount, aInternalAttributes); + // aItem now owns aInternalAttributes + CleanupStack::Pop(aInternalAttributes); + + // Set preferred index if it is set to this field value index + // Only one value index of this field can have preferred index set + // so we have to remove all existing preferred indexes. This has to + // be done to SMS attribute also. There cannot be more than one + // preferred SMS number in the S60 Phonebook + if (aAttributes & EPIMContactAttrPreferred || aAttributes + & EPIMContactAttrSms) + { + // Clear "preferred index" attribute from all other values + // except this one (previously added one) + for (TInt i = 0; i < valueCount; i++) + { + TPIMAttribute attributes = aItem.AttributesL(aField, i); + // Clear attributes from preferred index + if (aAttributes & EPIMContactAttrPreferred) + { + attributes &= ~EPIMContactAttrPreferred; + } + if (aAttributes & EPIMContactAttrSms) + { + attributes &= ~EPIMContactAttrSms; + } + aItem.SetAttributesL(aField, i, attributes); + } + } + + // Add label if necessary + if (aLabel.Length() > 0) + { + aItem.SetLabelL(aField, valueCount, 0, aLabel); + } +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::ConvertDateFieldL +// Converts a date field from a Contact Card to a PIM Item. +// ----------------------------------------------------------------------------- +// +void CPIMContactItemAdapter::ConvertDateFieldL(const CContactItemField& aField, // field to read data from + MPIMContactItem& aItem) // field to write the data to +{ + JELOG2(EPim); + MPIMItemData& itemData = aItem.ItemData(); + CContactDateField* dateField = aField.DateTimeStorage(); + if (!(dateField->IsFull())) + { + // if date is not set, we don't read it + return; + } + TTime time = dateField->Time(); + const CContentType& type = aField.ContentType(); + + TPIMField field(0); + // Check the field type + if (type.ContainsFieldType(KUidContactFieldBirthday)) + { + field = EPIMContactBirthday; + } + else if (type.ContainsFieldType(KUidContactFieldAnniversary)) + { + field = EPIMContactExtAnniversary; + } + + // Anniversary and Birthday are only dates so we are not interested + // in which is the time in these fields. This is because Phonebook + // doesn't take into account what time is used within these fields + // Time conversion between UTC and local time is not needed here + // because Phonebook handles only dates and PIM API times are in UTC + // format causing this date to be set to the start of the UTC date time + // and the date is shown correctly when midlet accesses it on the Java-side + TDateTime temp(time.DateTime()); + temp.SetHour(0); + temp.SetSecond(0); + temp.SetMinute(0); + temp.SetMicroSecond(0); + + // Count values and add new data + TInt valueCount = itemData.CountValues(field); + TPIMFieldData fieldData(field, KPIMAttrNone, TPIMDate(temp)); + itemData.AddValueL(fieldData); + + // Set label + if (aField.Label().Length() > 0) + { + itemData.SetLabelL(field, valueCount, 0, aField.Label()); + } +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::ConvertStoreFieldL +// Converts a store field from a Contact Card to a PIM Item. +// ----------------------------------------------------------------------------- +// +void CPIMContactItemAdapter::ConvertStoreFieldL( + const CContactItemField& aField, // field to read data from + MPIMContactItem& aItem) // field to write the data to +{ + JELOG2(EPim); + CContactStoreField* storeField = aField.StoreStorage(); + if (!(storeField->IsFull())) + { + return; + } + const CContentType& type = aField.ContentType(); + if (type.ContainsFieldType(KUidContactFieldPicture)) + { + // We don't care about other store fields + MPIMItemData& itemData = aItem.ItemData(); + HBufC8* data = storeField->Thing(); + if (data) + { + TInt dataLength = data->Length(); + CPIMByteArray* byteArray = new(ELeave) CPIMByteArray(dataLength); + CleanupStack::PushL(byteArray); + byteArray->AppendL(data->Ptr(), dataLength); + TPIMFieldData fieldData(EPIMContactPhoto, KPIMAttrNone, byteArray); + itemData.AddValueL(fieldData); + CleanupStack::Pop(); // byteArray + } + } +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::AddNameFieldToItemL +// Adds a name field to a PIM Item +// ----------------------------------------------------------------------------- +// +void CPIMContactItemAdapter::AddNameFieldToItemL(TPtrC aText, // text to add + MPIMContactItem& aItem, // item to add to + TPIMContactNameElement aElement, // element to add + TPtrC aLabel) // label of the field +{ + JELOG2(EPim); + MPIMItemData& itemData = aItem.ItemData(); + // 7 for array granularity + CDesCArrayFlat* nameArray = new(ELeave) CDesC16ArrayFlat(7); + CleanupStack::PushL(nameArray); + // do we already have a name field in the item + TInt nameCount = itemData.CountValues(EPIMContactName); + if (nameCount > 0) + { + const TPIMFieldData fieldData = itemData.ValueL(EPIMContactName, 0); + const CDesCArray& oldNameArray = fieldData.StringArrayValue(); + TInt elementCount = oldNameArray.Count(); + + for (TInt i = 0; i < elementCount; i++) + { + TPtrC16 oldName = oldNameArray[i]; + nameArray->AppendL(oldName); + } + // don't trust that item data has correct amount of elements + for (TInt i = elementCount; i < EPIMContactNameNumElements; i++) + { + nameArray->AppendL(KPIMNullArrayElement()); + } + // Add new element + nameArray->Delete(aElement); + nameArray->InsertL(aElement, aText); + TPIMFieldData newFieldData(EPIMContactName, KPIMAttrNone, nameArray); + itemData.SetValueL(newFieldData); + } + else + { + for (TInt i = 0; i < EPIMContactNameNumElements; i++) + { + nameArray->AppendL(KPIMNullArrayElement()); + } + // Add new element + nameArray->Delete(aElement); + nameArray->InsertL(aElement, aText); + TPIMFieldData newFieldData(EPIMContactName, KPIMAttrNone, nameArray); + itemData.AddValueL(newFieldData); + } + // Name array is now owned by the item + CleanupStack::Pop(nameArray); + // Add label if it exists + if (aLabel.Length() > 0) + { + itemData.SetLabelL(EPIMContactName, 0, aElement, aLabel); + } +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::AddAddressFieldToItemL +// Adds an address field to a PIM Item +// ----------------------------------------------------------------------------- +// +void CPIMContactItemAdapter::AddAddressFieldToItemL(TPtrC aText, // text to add + MPIMContactItem& aItem, // item to add to + TPIMContactAddrElement aElement, // element to add + TPIMAttribute aAttributes, // attributes of the address + TPtrC aLabel) // label +{ + JELOG2(EPim); + MPIMItemData& itemData = aItem.ItemData(); + // 7 for array granularity + CDesCArrayFlat* addrArray = new(ELeave) CDesC16ArrayFlat(7); + CleanupStack::PushL(addrArray); + // do we already have an address field in the item with the same attributes + TInt addrCount = itemData.CountValues(EPIMContactAddr); + TBool notFound = ETrue; + TInt index = -1; + for (TInt i = 0; (notFound) && (i < addrCount); i++) + { + if (itemData.AttributesL(EPIMContactAddr, i) == aAttributes) + { + const TPIMFieldData fieldData = itemData.ValueL(EPIMContactAddr, i); + const CDesCArray& oldAddrArray = fieldData.StringArrayValue(); + TInt elementCount = oldAddrArray.Count(); + for (TInt j = 0; j < elementCount; j++) + { + TPtrC oldAddr = oldAddrArray[j]; + addrArray->AppendL(oldAddr); + } + for (TInt j = elementCount; j < EPIMContactAddrNumElements; j++) + { + addrArray->AppendL(KPIMNullArrayElement()); + } + notFound = EFalse; + addrArray->Delete(aElement); + addrArray->InsertL(aElement, aText); + TPIMFieldData newFieldData(EPIMContactAddr, aAttributes, addrArray); + newFieldData.SetIndex(i); + itemData.SetValueL(newFieldData); + index = i; + } + } + if (notFound) + { + for (TInt i = 0; i < EPIMContactAddrNumElements; i++) + { + addrArray->AppendL(KPIMNullArrayElement); + } + addrArray->Delete(aElement); + addrArray->InsertL(aElement, aText); + TPIMFieldData fieldData(EPIMContactAddr, aAttributes, addrArray); + itemData.AddValueL(fieldData); + } + // Array is now owned by the item + CleanupStack::Pop(addrArray); + + // Add label if it exists + if (aLabel.Length() > 0) + { + // If the index is -1, it indicates that we are + // adding new string array at the end of the others + // so the index should be same as addrCount + index = (index == -1) ? addrCount : index; + itemData.SetLabelL(EPIMContactAddr, index, aElement, aLabel); + } +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::ConvertAddressFieldL +// Converts an address field from a PIM Item to a Contact Card. +// ----------------------------------------------------------------------------- +// +void CPIMContactItemAdapter::ConvertAddressFieldL(const MPIMItemData& aItem, // item to convert from + CContactCard& aCard, // card to write to + TPIMContactField aField, // field to convert + TInt aIndex, // index to the field + TPIMAttribute aAttributes) // attributes of the field +{ + JELOG2(EPim); + if (aIndex == KErrNotFound) + { + return; + } + const TPIMFieldData fieldData = aItem.ValueL(aField, aIndex); + const CDesCArray& addrArray = fieldData.StringArrayValue(); + EContactFieldCategory category = EContactCategoryNone; + if (aAttributes == EPIMContactAttrHome) + { + category = EContactCategoryHome; + } + if (aAttributes == EPIMContactAttrWork) + { + category = EContactCategoryWork; + } + + TInt addrCount = addrArray.Count(); + for (TInt i = 0; i < addrCount; i++) + { + if (addrArray[i].Compare(KPIMNullArrayElement()) == 0) + { + // we don't add null elements + continue; + } + + EnsureValidAddrElemLengthL(TPIMContactAddrElement(i), addrArray[i]); + + CContentType* type = iFieldInfo->AddressContentTypeL( + static_cast(i), category); + CleanupStack::PushL(type); + + CContactItemField* field = CContactItemField::NewLC(KStorageTypeText, + *type); + + // Add label to the field + TPIMContactAddrElement element = TPIMContactAddrElement(i); + const TPtrC label = aItem.LabelL(aField, aIndex, element); + if (label.Compare(KPIMNullArrayElement) != 0) + { + field->SetLabelL(label); + } + field->SetUserFlags(category); + // we don't store any label, Contacts Model should use default template + CContactTextField* textField = field->TextStorage(); + textField->SetTextL(addrArray[i]); + // Card takes the ownership of the field + aCard.AddFieldL(*field); + CleanupStack::Pop(field); + CleanupStack::PopAndDestroy(type); + } +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::ConvertNameFieldL +// Converts an address field from a PIM Item to a Contact Card. +// ----------------------------------------------------------------------------- +// +void CPIMContactItemAdapter::ConvertNameFieldL(const MPIMItemData& aItem, // item to convert from + CContactCard& aCard, // card to write to + TPIMContactField aField, // field to convert + TInt aIndex) // index to the field +{ + JELOG2(EPim); + const TPIMFieldData fieldData = aItem.ValueL(aField, aIndex); + const CDesCArray& nameArray = fieldData.StringArrayValue(); + EContactFieldCategory category = EContactCategoryHome; + + TInt nameCount = nameArray.Count(); + for (TInt i = 0; i < nameCount; i++) + { + if (nameArray[i].Compare(KPIMNullArrayElement()) == 0) + { + // we don't add null elements + continue; + } + + EnsureValidNameElemLengthL(TPIMContactNameElement(i), nameArray[i]); + + CContentType* type = iFieldInfo->NameContentTypeL( + static_cast(i)); + CleanupStack::PushL(type); + + CContactItemField* field = CContactItemField::NewLC(KStorageTypeText, + *type); + + // Add label to the field. aIndex should be 0 in this case because + // there are only one string array in the name field + TPIMContactNameElement element = TPIMContactNameElement(i); + const TPtrC label = aItem.LabelL(aField, aIndex, element); + if (label.Compare(KPIMNullArrayElement) != 0) + { + field->SetLabelL(label); + } + field->SetUserFlags(category); + // we don't store any label, Contacts Model should use default template + CContactTextField* textField = field->TextStorage(); + textField->SetTextL(nameArray[i]); + // Card takes ownership of the field + aCard.AddFieldL(*field); + CleanupStack::Pop(field); + CleanupStack::PopAndDestroy(type); + } +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::ConvertDateFieldL +// Converts a date field from a PIM Item to a Contact Card. +// ----------------------------------------------------------------------------- +// +void CPIMContactItemAdapter::ConvertDateFieldL(const MPIMItemData& aItem, // item to convert from + CContactCard& aCard, // card to write to + TPIMContactField aField, // field to convert + TInt aIndex) // index to the field +{ + JELOG2(EPim); + const TPIMFieldData fieldData = aItem.ValueL(aField, aIndex); + const TPIMDate& date = fieldData.DateValue(); + CContentType* type = NULL; + + switch (aField) + { + case EPIMContactBirthday: + { + type = CContentType::NewL(KUidContactFieldBirthday, + KUidContactFieldVCardMapBDAY); + CleanupStack::PushL(type); + break; + } + case EPIMContactExtAnniversary: + { + type = CContentType::NewL(KUidContactFieldAnniversary, + KUidContactFieldVCardMapAnniversary); + CleanupStack::PushL(type); + break; + } + default: + { + User::Panic(KPIMPanicCategory, EPIMPanicUnsupportedDateField); + break; + } + } + CContactItemField* field = CContactItemField::NewLC(KStorageTypeDateTime, + *type); + // set label if set in pim item + const TPtrC label = aItem.LabelL(aField, aIndex, 0); + if (label.Compare(KPIMNullArrayElement) != 0) + { + field->SetLabelL(label); + } + + field->SetUserFlags(EContactCategoryOther); + CContactDateField* dateField = field->DateTimeStorage(); + + // PIM API stores dates as UTC time. Phonebook instead expects that dates + // are stored as in local time format in the Contacts Model database + RTz tzServer; + User::LeaveIfError(tzServer.Connect()); + CleanupClosePushL(tzServer); + + // Create timezone converter + CTzConverter* converter = CTzConverter::NewL(tzServer); + CleanupStack::PushL(converter); + + TTime localTime(date); + User::LeaveIfError(converter->ConvertToLocalTime(localTime)); + CleanupStack::PopAndDestroy(2); // converter, tzServer + + // Anniversary and Birthday are only dates so we are not interested + // in which is the time in these fields. This is because Phonebook + // doesn't take into account what time is used within these fields + TDateTime temp(localTime.DateTime()); + temp.SetHour(0); + temp.SetMinute(0); + temp.SetSecond(0); + temp.SetMicroSecond(0); + + dateField->SetTime(TTime(temp)); + // Card takes ownership of the field + aCard.AddFieldL(*field); + CleanupStack::Pop(field); + CleanupStack::PopAndDestroy(type); +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::ConvertStringFieldL +// Converts a string field from a PIM Item to a Contact Card. +// ----------------------------------------------------------------------------- +// +void CPIMContactItemAdapter::ConvertStringFieldL(const MPIMItemData& aItem, // item to convert from + CContactCard& aCard, // card to write to + TPIMContactField aField, // field to convert + TInt aIndex) // index to the field +{ + JELOG2(EPim); + const CArrayFix& attrs = aItem.InternalAttributesL(aField, aIndex); + const TPIMFieldData fieldData = aItem.ValueL(aField, aIndex); + const TDesC& string = fieldData.StringValue(); + TPIMAttribute attributes = fieldData.Attributes(); + EContactFieldCategory category = EContactCategoryNone; + + EnsureValidStringValueLengthL(aField, string); + + if ((attributes & EPIMContactAttrHome) != 0) + { + category = EContactCategoryHome; + } + if ((attributes & EPIMContactAttrWork) != 0) + { + category = EContactCategoryWork; + } + CContentType* type = iFieldInfo->StringFieldContentTypeL(aField, + attributes, category); + CleanupStack::PushL(type); + // Apply internal attributes if any + TInt interalAttrCount = attrs.Count(); + for (TInt i = 0; i < interalAttrCount; i++) + { + TFieldType fieldType = attrs.At(i); + // Check to avoid duplicate field types in the content type + // this may be possible when unrecognized fields are added to + // internal attribute list (e.g incorrectly generated ContentType) + if (!type->ContainsFieldType(fieldType)) + { + type->AddFieldTypeL(fieldType); + } + } + // Create new contact item field which is a text storage + CContactItemField* field = + CContactItemField::NewLC(KStorageTypeText, *type); + // set label if set in pim item + const TPtrC label = aItem.LabelL(aField, aIndex, 0); + if (label.Compare(KPIMNullArrayElement) != 0) + { + field->SetLabelL(label); + } + + field->SetUserFlags(category); + CContactTextField* textField = field->TextStorage(); + textField->SetTextL(string); + // Card takes ownership of the field + aCard.AddFieldL(*field); + CleanupStack::Pop(field); + CleanupStack::PopAndDestroy(type); +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::ConvertPhotoFieldL +// Converts a photo field from a PIM Item to a Contact Card. +// ----------------------------------------------------------------------------- +// +void CPIMContactItemAdapter::ConvertPhotoFieldL(const MPIMItemData& aItem, // item to convert from + CContactCard& aCard, // card to write to + TPIMContactField aField, // field to convert + TInt aIndex) // index to the field +{ + JELOG2(EPim); + const TPIMFieldData fieldData = aItem.ValueL(aField, aIndex); + const CPIMByteArray& byteArray = fieldData.BinaryValue(); + EContactFieldCategory category = EContactCategoryNone; + CContentType* type = CContentType::NewL(KUidContactFieldPicture, + KUidContactFieldVCardMapPHOTO); + CleanupStack::PushL(type); + + CContactItemField* field = CContactItemField::NewLC(KStorageTypeStore, + *type); + field->SetUserFlags(category); + + const TUint8& byteRef = byteArray.At(0); + const TUint8* bytePtr = &byteRef; + TPtrC8 data(bytePtr, byteArray.Count()); + + HBufC8* thumbNail = iImageScaler->ScaleL(data); + CleanupStack::PushL(thumbNail); + + CContactStoreField* storeField = field->StoreStorage(); + storeField->SetThingL(*thumbNail); + CleanupStack::PopAndDestroy(); // thumbNail + // Card takes ownership of the field + aCard.AddFieldL(*field); + CleanupStack::Pop(field); + CleanupStack::PopAndDestroy(type); +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::ConvertClassFieldL +// Converts a CLASS field from a PIM Item to a Contact Card. +// ----------------------------------------------------------------------------- +// +void CPIMContactItemAdapter::ConvertClassFieldL(const MPIMItemData& aItemData, + CContactCard& aCard, TPIMContactField aField, TInt aIndex) +{ + JELOG2(EPim); + TPtrC classValueDes(KPIMContactClassPrivate()); + const TPIMFieldData fieldData = aItemData.ValueL(aField, aIndex); + const TInt classValue = fieldData.IntegerValue(); + CContentType* type = CContentType::NewL(KUidContactFieldClass, + KUidContactFieldVCardMapClass); + CleanupStack::PushL(type); + + switch (classValue) + { + case EPIMContactClassPrivate: + { + classValueDes.Set(KPIMContactClassPrivate()); + break; + } + case EPIMContactClassPublic: + { + classValueDes.Set(KPIMContactClassPublic()); + break; + } + case EPIMContactClassConfidential: + { + classValueDes.Set(KPIMContactClassConfidential()); + break; + } + default: + { + __ASSERT_DEBUG(EFalse, User::Invariant()); + break; // For a happy compiler + } + } + // Add value to the contact field + CContactItemField* field = + CContactItemField::NewLC(KStorageTypeText, *type); + field->SetUserFlags(EContactCategoryNone); + + // Set label if any + const TPtrC label = aItemData.LabelL(aField, aIndex, 0); + if (label.Compare(KPIMNullArrayElement) != 0) + { + field->SetLabelL(label); + } + + CContactTextField* textField = field->TextStorage(); + textField->SetTextL(classValueDes); + // Card takes ownership of the field + aCard.AddFieldL(*field); + CleanupStack::Pop(field); + CleanupStack::PopAndDestroy(type); +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::ConvertClassFieldL +// Converts a CLASS field from a Contact Card to PIM item +// ----------------------------------------------------------------------------- +// +void CPIMContactItemAdapter::AddClassFieldToItemL(MPIMItemData& aItemData, + TPtrC& aClassDesValue, TPtrC aLabel) +{ + JELOG2(EPim); + // Syncronisation is private for default + TPIMContactClassValue classValue = EPIMContactClassPrivate; + TInt valueCount = aItemData.CountValues(EPIMContactClass); + + if (aClassDesValue.Compare(KPIMContactClassPublic()) == 0) + { + classValue = EPIMContactClassPublic; + } + else if (aClassDesValue.Compare(KPIMContactClassPrivate()) == 0) + { + classValue = EPIMContactClassPrivate; + } + else if (aClassDesValue.Compare(KPIMContactClassConfidential()) == 0) + { + classValue = EPIMContactClassConfidential; + } + TPIMFieldData fieldData(EPIMContactClass, EPIMFieldInt, KPIMAttrNone, + classValue); + aItemData.AddValueL(fieldData); + // Label if any + if (aLabel.Length() > 0) + { + aItemData.SetLabelL(EPIMContactClass, valueCount, 0, aLabel); + } +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::AddressAttributesL +// Checks the optimal attributes for the addresses +// ----------------------------------------------------------------------------- +void CPIMContactItemAdapter::AddressAttributesL(const MPIMItemData& aItem, + TInt& aPlainAddressIndex, TInt& aHomeAddressIndex, TInt& aWorkAddressIndex) +{ + JELOG2(EPim); + aPlainAddressIndex = KErrNotFound; + aHomeAddressIndex = KErrNotFound; + aWorkAddressIndex = KErrNotFound; + TInt addressCount = aItem.CountValues(EPIMContactAddr); + + // first pass - find zero and single attribute values if exist + TInt i = 0; + for (; i < addressCount; i++) + { + if (aItem.AttributesL(EPIMContactAddr, i) == KPIMAttrNone) + { + aPlainAddressIndex = i; + } + else if (aItem.AttributesL(EPIMContactAddr, i) == EPIMContactAttrHome) + { + aHomeAddressIndex = i; + } + else if (aItem.AttributesL(EPIMContactAddr, i) == EPIMContactAttrWork) + { + aWorkAddressIndex = i; + } + } + + // second pass - fill in the rest + for (i = 0; i < addressCount; i++) + { + if ((aPlainAddressIndex != i) && (aHomeAddressIndex != i) + && (aWorkAddressIndex != i)) + { + // this index has not been used yet + if (KErrNotFound == aWorkAddressIndex) + { + aWorkAddressIndex = i; + } + else if (KErrNotFound == aHomeAddressIndex) + { + aHomeAddressIndex = i; + } + else if (KErrNotFound == aPlainAddressIndex) + { + aPlainAddressIndex = i; + } + else + { + // all indexes are filled + break; // out of the for loop + } + } + } +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::EnsureValidStringValueLengthL +// ----------------------------------------------------------------------------- +void CPIMContactItemAdapter::EnsureValidStringValueLengthL( + TPIMContactField aField, const TDesC& aValue) +{ + JELOG2(EPim); + const TInt* maxLengthArr = NULL; + TInt offset = 0; + TInt arrLen = 0; + + if (aField >= KContactExtStringMaxLengthOffset) + { + maxLengthArr = KContactExtStringMaxLengths; + offset = KContactExtStringMaxLengthOffset; + arrLen = KContactExtStringMaxLengthsLen; + } + else + { + maxLengthArr = KContactStringMaxLengths; + offset = KContactStringMaxLengthsOffset; + arrLen = KContactStringMaxLengthsLen; + } + + TInt index = aField - offset; + + __ASSERT_ALWAYS((index >= 0), User::Invariant()); + __ASSERT_ALWAYS((index < arrLen), User::Invariant()); + + TInt maxLen = maxLengthArr[index]; + if ((maxLen > 0) && (aValue.Length() > maxLen)) + { + User::Leave(KErrTooBig); + } +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::EnsureValidAddrElemLengthL +// ----------------------------------------------------------------------------- +void CPIMContactItemAdapter::EnsureValidAddrElemLengthL( + TPIMContactAddrElement aElemIndex, const TDesC& aElemValue) +{ + JELOG2(EPim); + __ASSERT_DEBUG((aElemIndex >= 0), User::Invariant()); + + __ASSERT_DEBUG((aElemIndex < EPIMContactAddrNumElements), User::Invariant()); + + __ASSERT_DEBUG( + (KContactAddrElemMaxLengths[aElemIndex] != KErrNotSupported), + User::Invariant()); + + if ((KContactAddrElemMaxLengths[aElemIndex] != KErrNotSupported) + && (aElemValue.Length() > KContactAddrElemMaxLengths[aElemIndex])) + { + User::Leave(KErrTooBig); + } +} + +// ----------------------------------------------------------------------------- +// CPIMContactItemAdapter::EnsureValidNameElemLengthL +// ----------------------------------------------------------------------------- +void CPIMContactItemAdapter::EnsureValidNameElemLengthL( + TPIMContactNameElement aElemIndex, const TDesC& aElemValue) +{ + JELOG2(EPim); + __ASSERT_DEBUG((aElemIndex >= 0), User::Invariant()); + + __ASSERT_DEBUG((aElemIndex < EPIMContactNameNumElements), User::Invariant()); + + __ASSERT_DEBUG( + (KContactNameElemMaxLengths[aElemIndex] != KErrNotSupported), + User::Invariant()); + + if ((KContactNameElemMaxLengths[aElemIndex] != KErrNotSupported) + && (aElemValue.Length() > KContactNameElemMaxLengths[aElemIndex])) + { + User::Leave(KErrTooBig); + } +} + +// End of File