quick_recipes (779892), страница 20
Текст из файла (страница 20)
You should definitely familiarize yourself with iCalendar beforedeveloping any kind of value-added application using this API. Thespecification can be found at www.faqs.org/rfcs/rfc2445.html.The Calendar database contains calendar entries, which can beappointments, meetings, anniversaries, to-do notes, and so on. For thepurpose of this text, we are going to refer to any one of these entries asan ‘event’. Each event can belong to one or several categories.Each calendar entry has an identifier during its lifetime in the database.An entry can be repeated. It would then have several calendar instances.CONTACTS AND CALENDAR109Typically, these are calculated dynamically.
A repeat rule defines whenan entry is repeated. Several granularities are available: daily, weekly,monthly. These can be combined.Access to the Calendar database usually requires a calendar serversession and a calendar view. Parts of the view API are asynchronousand it is recommended that any application using the Calendar API usesactive objects to handle events (see Chapter 3 for further details).When dealing with the Calendar APIs, you need to familiarize yourselfwith how time is represented in Symbian OS.
Unless otherwise specified,we use a signed 64-bit integer, which counts the number of microsecondssince midnight, January 1st, 0 AD. For more information, the classes ofinterest are TTime, TDateTime and all the TTimeIntervalXyz, anda good starting point is in the Symbian Developer Library documentation:Symbian OS Guide > Base > Using User Library (E32) > Date and TimeHandling.One of the trickiest issues you will face with the Calendar APIs isdealing with phones moving across time zones, or changes to daylightsaving hours.
Different people and organizations have different requirements about what should happen to the times recorded in your entrieswhen the system time changes. We don’t address this further here, sincethis is an issue every mobile application developer has to deal with inhis or her own way. You can easily end up building several versions ofyour application based purely on this issue and based on the differentrequirements of each of your customers.
The best advice we can offer is tocreate a flexible solution and get your customer’s requirements early on.For testing purposes, the code samples of this book contain \PIM\PopulateAgenda, which makes sure that your development environment contains an Agenda database initialized with a few calendarentries.4.2.3 Easy Recipes4.2.3.1Write Data to a ContactAmount of time required: 40 minutesLocation of example code: \PIM\ContactWriteNewFieldRequired library(s): cntmodel.libRequired header file(s): cntdb.h, cntitem.h, cntfield.h,cntfldst.hRequired platform security capability(s): ReadUserData WriteUserDataProblem: You want to add a text field to an existing contact item.Solution: Modifying a contact data is not difficult in itself.
You couldthink of it as executing an SQL UPDATE statement. Several of the next110SYMBIAN C++ RECIPESrecipes in this section will show you ways of finding a contact to modify.For simplicity’s sake, the code sample shows how to use the result ofCContactDatabase::OwnCardId() as a parameter for the followingAddEmployerL() method:#include#include#include#include#include<cntdb.h> // and link to cntmodel.lib<cntitem.h><cntfield.h><cntdef.h><cntfldst.h>class CContactWrite : public CBase{public:static CContactWrite* NewL();∼CContactWrite(); // to delete iCntDb// The item id for a search.void AddEmployerL(TContactItemId aCntId,const TDesC& aCompany);private:void ConstructL();private:CContactDatabase* iCntDb;};// You need an opened contact database: usually the default// database on the phone. You should always assume that it// may not have been created before.void CContactWrite::ConstructL(){TRAPD(error, iCntDb = CContactDatabase::OpenL());if (KErrNotFound == error){iCntDb = CContactDatabase::CreateL();}else{User::LeaveIfError(error);}}void CContactWrite::AddEmployerL(TContactItemId aCntId,const TDesC& aCompany){// Open the contact item and lock it for exclusive useCContactItem* item = iCntDb->OpenContactLX(aCntId);CleanupStack::PushL(item);// Make a Company Name field to add to the contactCContactItemField* field =CContactItemField::NewLC(KStorageTypeText);field->AddFieldTypeL(KUidContactFieldCompanyName);field->TextStorage()->SetTextL(aCompany);item->AddFieldL(*field); // takes ownership of fieldCleanupStack::Pop(field);// so pop it off the cleanup stackCONTACTS AND CALENDAR111iCntDb->CommitContactL(*item);CleanupStack::PopAndDestroy(item);CleanupStack::PopAndDestroy(); // Release exclusive lock on item}Advanced Tip: What remains on the cleanup stack after a successful call to OpenContactLX is not the item it returns.
It is aTCleanupItem that will release the exclusive lock on the item whendestroyed.What may go wrong when you do this: The field you added may notbe easily accessible to the default Contact application on your phoneif you don’t also specify a vCard mapping for it.4.2.3.2Read Data from a ContactAmount of time required: 40 minutesLocation of example code: \PIM\ContactReadFieldRequired library(s): cntmodel.libRequired header file(s): cntdb.h, cntitem.h, cntfield.h,cntfldst.hRequired platform security capability(s): ReadUserData WriteUserDataProblem: You want to retrieve the value of a text field from an existingcontact item.Solution: We are just going to write some code to extract all the valuesfor a given content type into a descriptor array.
It is very easy to modifythe code so that it returns a descriptor containing only the first value, ifthat is what you require. We don’t show the error handling in the codebelow, but you should remember to handle the case where contacts don’thave the requested field.#include#include#include#include#include#include<cntdb.h> // and link to cntmodel.lib<cntitem.h><cntfield.h><cntdef.h><cntfldst.h><badesca.h> // and link to bafl.lib (descriptor arrays)class CContactRead : public CBase{public:static CContactRead* NewL();112SYMBIAN C++ RECIPES∼CContactRead(); // to delete iCntDbCDesCArray* ReadTextFieldL(TContactItemId aCntId,TFieldType aType);private:void ConstructL();private:CContactDatabase* iCntDb;};// You need an opened contact database: usually the default// database on the phone.
You should always assume that it// may not have been created before.void CContactRead::ConstructL(){TRAPD(error, iCntDb = CContactDatabase::OpenL());if (KErrNotFound == error){iCntDb = CContactDatabase::CreateL();}else{User::LeaveIfError(error);}}CDesCArray* CContactRead::ReadTextFieldL(TContactItemId aCntId,TFieldType aType){// Create descriptor array to store result// Use arbitrary graularityCDesCArray* result = new (ELeave) CDesCArrayFlat(2);CleanupStack::PushL(result);// Use the database engine to read only// the fields we are interested inCContactItemViewDef* viewDef = CContactItemViewDef::NewLC(CContactItemViewDef::EIncludeFields,CContactItemViewDef::EMaskHiddenFields);viewDef->AddL(aType);// Get the contact itemCContactItem* item = iCntDb->ReadContactLC(aCntId, *viewDef);// Get all the fieldsCContactItemFieldSet& fieldSet = item->CardFields();// Go through all of them, add the values to the resultfor(TInt ii = 0 ; ii < fieldSet.Count() ; ++ii){CContactItemField& field = fieldSet[ii];if (KStorageTypeText == field.StorageType()){if (field.TextStorage()->IsFull()){const TPtrC value = field.TextStorage()->Text();CONTACTS AND CALENDAR113result->AppendL(value);}}}CleanupStack::PopAndDestroy(2, viewDef); // item, viewDefCleanupStack::Pop(result);return result; // transfers owernship to caller}Tip: If, instead, you already have a CContactItem loaded with allits fields, you can use CContactItemFieldSet::FindNext() toiterate through the set.4.2.3.3Add a New ContactAmount of time required: 15 minutesLocation of example code: \PIM\ContactAddNewRequired library(s): cntmodel.libRequired header file(s): cntdb.h, cntitem.h, cntfield.h,cntfldst.hRequired platform security capability(s): ReadUserData WriteUserDataProblem: You want to add a brand new contact to the database.Solution: You will probably want to use Recipe 4.2.3.1 to add fields tothe new contact card, once you are done with this.You must first open the database, as you did in Recipe 4.2.3.1:#include#include#include#include#include<cntdb.h> // and link to cntmodel.lib<cntitem.h><cntfield.h><cntdef.h><cntfldst.h>class CContactWrite : public CBase{public:static CContactWrite* NewL();∼CContactWrite(); // to delete iCntDbvoid AddCardL(const TDesC& aFirstName, const TDesC& aLastName,const TDesC& aPhone);private:void ConstructL();private:CContactDatabase* iCntDb;};void CContactWrite::AddCardL(const TDesC& aFirstName,114SYMBIAN C++ RECIPESconst TDesC& aLastName,const TDesC& aPhone){// Create a contact cardCContactCard* contactCard = CContactCard::NewLC();// First nameCContactItemField* firstName =CContactItemField::NewLC(KStorageTypeText);firstName->AddFieldTypeL(KUidContactFieldGivenName);firstName->TextStorage()->SetTextL(aFirstName);contactCard->AddFieldL(*firstName); // takes ownership of fieldCleanupStack::Pop(firstName);// Last nameCContactItemField* lastName =CContactItemField::NewLC(KStorageTypeText);lastName->AddFieldTypeL(KUidContactFieldFamilyName);lastName->TextStorage()->SetTextL(aLastName);contactCard->AddFieldL(*lastName); // takes ownership of fieldCleanupStack::Pop(lastName);// Phone numberCContactItemField* phone =CContactItemField::NewLC(KStorageTypeText);phone->AddFieldTypeL(KUidContactFieldPhoneNumber);phone->TextStorage()->SetTextL(aPhone);contactCard->AddFieldL(*phone); // takes ownership of fieldCleanupStack::Pop(phone);// Add the card to the database, which takes a copyiCntDb->AddNewContactL(*contactCard);CleanupStack::PopAndDestroy(contactCard); // destroy local version}4.2.3.4Remove a ContactAmount of time required: 15 minutesLocation of example code: \PIM\ContactRemoveRequired library(s): cntmodel.libRequired header file(s): cntdb.h, cntitem.h, cntfield.h,cntfldst.hRequired platform security capability(s): ReadUserData WriteUserDataProblem: You want to remove an existing contact from the database.Solution: You must first open the database, just like in Recipe 4.2.3.1:#include#include#include#include<cntdb.h> // and link to cntmodel.lib<cntitem.h><cntfield.h><cntdef.h>class CContactWrite : public CBaseCONTACTS AND CALENDAR115{public:static CContactWrite* NewL();∼CContactWrite(); // to delete iCntDbvoid RemoveContactL(TContactItemId aCntId);private:void ConstructL();private:CContactDatabase* iCntDb;};void CContactWrite::RemoveContactL(TContactItemId aCntId){// just delete itiCntDb->DeleteContactL(aCntId);}Tip: After deleting contacts, it is good practice to call CContactDatabase::CompactL(), which may reduce the contact databasesize.