quick_recipes (779892), страница 22
Текст из файла (страница 22)
Once returned, thecollection can be used to retrieve data from each element individually.Remember to use a CContactItemViewDef, like in Recipe 4.2.3.2.The Contact database supports several layers of sorting folded into oneoperation. This means that you can set up the sort on one field first. Ifseveral items have the same order for that sort, a second field is used toorder these items amongst themselves. You can specify as many fields asyou want to refine how the items will be sorted.We are going to sort all contacts by their last name.
Those with thesame last name will then be further sorted by first name.You could imagine the same kind of sorting by country first, then bycity or by more than two parameters.Open the database as you did in Recipe 4.2.3.1:#include#include#include#include<cntdb.h> // and link to cntmodel.lib<cntitem.h><cntfield.h><cntdef.h>class CContactRead : public CBase{public:static CContactRead* NewL();∼CContactRead(); // to delete iCntDbCContactIdArray* SortByNameL();private:void ConstructL();private:CContactDatabase* iCntDb;};CContactIdArray* CContactRead::SortByNameL(){CArrayFix<CContactDatabase::TSortPref>* sortOrder=new(ELeave)CArrayFixSeg<CContactDatabase::TSortPref>(2);122SYMBIAN C++ RECIPESCleanupStack::PushL(sortOrder);CContactDatabase::TSortPref lastNameSort(KUidContactFieldFamilyName);CContactDatabase::TSortPref firstNameSort(KUidContactFieldGivenName);sortOrder->AppendL(lastNameSort);sortOrder->AppendL(firstNameSort);iCntDb->SortL(sortOrder); // takes ownership of sortOrderCleanupStack::Pop(sortOrder);return CContactIdArray::NewL(iCntDb->SortedItemsL());}Tip: The Contact database is the most optimized to deal with this particular type of sorting.
Even with several hundred contacts, it will not takemore than a couple of seconds on your phone. There is an additionalasynchronous overload that can be used inside an active schedulerusing CContactDatabase::SortAsynchL(), which is the oneyou should use inside a GUI application. For an example of how todo so, please see the code sample in \PIM\ContactAsynchSort.What may go wrong when you do this: On UIQ, you may get strangeresults using the synchronous sort, because a contact with an emptyfield of the right type will be considered first in alphabetical order. Theasynchronous sort seems to filter these out, and both return correctresults on S60.4.2.4.2Use the vCard FormatAmount of time required: 40 minutesLocation of example code: \PIM\ContactStandardRequired library(s): cntmodel.libRequired header file(s): cntdb.h, cntitem.h, cntfield.h,cntdef.hRequired platform security capability(s): ReadUserData WriteUserDataProblem: You want to send and receive contacts between differentdevices.Solution: The vCard standard is supported by many devices, mobile ornot, regardless of their operating system.
The vCard specification canbe found at www.imc.org/pdi/vcard-21.txt (Symbian OS v9.1 supportsvCard 2.1).CONTACTS AND CALENDAR123Our aim is to convert text data into a contact in the Contacts database,and then convert it back again. The actual data transfer between devicesis outside the scope of this book. Section 4.3 on Networking and Section4.9 on Connectivity should be a useful reference however.Symbian OS streams have the advantage of exposing the same API,regardless of where the data is actually stored (file, descriptor, database,etc.), so they are perfect for our purpose here.
You will find furtherdiscussion of streams in the file handling recipes given in Section 4.1.Remember to 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><s32strm.h> // and link to estor.libclass CContactWrite : public CBase{public:static CContactWrite* NewL();∼CContactWrite(); // to delete iCntDbvoid ExportContactL(TContactItemId aCntId,RWriteStream& aOutput);void ImportContactL(RReadStream& aInput);private:void ConstructL();private:CContactDatabase* iCntDb;};void CContactWrite::ExportContactL(TContactItemId aCntId,RWriteStream& aOutput){// this only works with a collection of contact ids.CContactIdArray* array = CContactIdArray::NewLC();array->AddL(aCntId);TUid uid;uid.iUid = KVersitEntityUidVCard;iCntDb->ExportSelectedContactsL(uid, *array, aOutput,CContactDatabase::EDefault);CleanupStack::PopAndDestroy(array);}void CContactWrite::ImportContactL(RReadStream& aInput){TBool success;CArrayPtr<CContactItem>* importedContacts =iCntDb->ImportContactsL(TUid::Uid(KVersitEntityUidVCard),aInput,success,CContactDatabase::EImportSingleContact |CContactDatabase::EIncludeX |CContactDatabase::ETTFormat);124SYMBIAN C++ RECIPESif (success){// use the cleanupstack if you intend to commit// the imported contact to the database.delete importedContacts->At(0);// because CArrayPtr::Reset() isn’t enoughdelete importedContacts;}else{delete importedContacts; // just in caseUser::Leave(KErrGeneral);}}Tip: Using EImportSingleContact is important here so success ismeaningful.
Otherwise, you risk reading more of the stream than youmeant to or missing an error report. You should also have a look at theCParserVCard API.What may go wrong when you do this: The Symbian OS contactengine allows developers to create contact items that cannot be fullyconverted into vCard data. The pitfalls of this are too numerous toenumerate here, so experimentation will be required if you start usingadvanced contact functionalities. Field mappings and CContactDatabase::EIncludeXyz are here to help.What may go wrong when you do this: If you have gone throughthis section in order and run each set of sample code, the test contactdatabase may be without an own card, because you removed it inRecipe 4.2.3.4.
Just run the \PIM\PopulateContact sample codeagain to add it back to the database.4.2.4.3Use the vCal FormatAmount of time required: 40 minutesLocation of example code: \PIM\AgendaStandardRequired library(s): calinterimapi.libRequired header file(s): calsession.h, calentryview.h,calprogresscallback.h, caldataexchange.hRequired platform security capability(s): ReadUserData WriteUserDataProblem: You want to send and receive calendar entries across differentdevices.CONTACTS AND CALENDAR125Solution: The vCal standard is supported by many devices, mobileor not, regardless of their operating system.
The vCal specificationcan be found at www.imc.org/pdi/vcal-10.txt (Symbian OS v9.1 supports vCal 1.0). However, from Symbian OS v9.1, there has beena clear push toward the iCalendar standard, which is specified atwww.faqs.org/rfcs/rfc2445.html.In effect, we need to convert text data into an event in the Calendardatabase, and then convert it back again.Symbian OS streams have the advantage of exposing the same API,regardless of where the data is actually stored (file, descriptor, DBMS,etc.), so they are perfect for our purpose here. You will find furtherdiscussion of streams in the file handling recipes given in Section 4.1.You must first open the Calendar database as you did in Recipe 4.2.3.1:#include <calsession.h> // and link to calinterimapi.lib#include <calentryview.h>#include <calprogresscallback.h>#include <caldataexchange.h>#include <CalDataFormat.h>#include <s32strm.h> // and link to estor.lib#include <mmf\common\mmfcontrollerpluginresolver.h>// this last one is for the ResetAndDestroy TCleanupItemclass CCalWrite : public CBase, public MCalProgressCallBack{public:static CCalWrite* NewL();∼CCalWrite(); // to delete iCalSes and iCalViewvoid ExportEventL(TCalLocalUid aEventId,RWriteStream& aOutput);void ImportEventL(RReadStream& aInput);public: // from MCalProgressCallBackvoid Progress(TInt){};void Completed(TInt){};TBool NotifyProgress(){return EFalse;};private:void ConstructL();private:CCalSession* iCalSes;CCalEntryView* iCalView;};void CCalWrite::ExportEventL(TCalLocalUid aEventId,RWriteStream& aOutput){CCalEntry* entry = iCalView->FetchL(aEventId);if (NULL == entry){User::Leave(KErrNotFound);}else{CleanupStack::PushL(entry);126SYMBIAN C++ RECIPESCCalDataExchange* exch =CCalDataExchange::NewL(*iCalSes);CleanupStack::PushL(exch);RPointerArray<CCalEntry> array;CleanupClosePushL(array);array.AppendL(entry);// as in [1.5.], we don’t transfer ownership of entry// to array.exch->ExportL(KUidVCalendar, aOutput, array);// Clean up array, exch, entryCleanupStack::PopAndDestroy(3, entry);}}void CCalWrite::ImportEventL(RReadStream& aInput){RPointerArray<CCalEntry> array;CleanupResetAndDestroyPushL(array);CCalDataExchange* exch = CCalDataExchange::NewL(*iCalSes);CleanupStack::PushL(exch);exch->ImportL(KUidVCalendar, aInput, array, 0, 1);CleanupStack::PopAndDestroy(exch);// do something with the imported event here (code omitted)...CleanupStack::PopAndDestroy(&array);}What may go wrong when you do this: The Symbian OS CalendarAPIs allow developers to create calendar entries that cannot be fullyconverted into vCal data.
The pitfalls of this are too numerous toenumerate here, so experimentation may be required.Tip: You should also have a look at the CParserVCal API.4.2.4.4Create a Repeating Calendar EventAmount of time required: 45 minutesLocation of example code: \PIM\AgendaRepeatRequired library(s): calinterimapi.libRequired header file(s): calsession.h, calentryview.h,calrrule.h, calprogresscallback.hRequired platform security capability(s): ReadUserData WriteUserDataProblem: You want to create a new calendar event that repeats daily andevery other week.CONTACTS AND CALENDAR127Solution: Much of this example repeats what we described in Recipe4.2.3.6 (for example, the GUID generator, which we won’t discuss againhere).First of all, open the database as described in Recipe 4.2.3.1:#include#include#include#include#include<calsession.h> // and link to calinterimapi.lib<calentryview.h><calrrule.h><calprogresscallback.h><e32const.h>class CCalWrite : public CBase, public MCalProgressCallBack{public:static CCalWrite* NewL();∼CCalWrite(); // to delete iCalSes and iCalViewvoid AddRepeatL(const TDesC& aDescription,TInt aWeeklyInterval);public: // from MCalProgressCallBackvoid Progress(TInt){};void Completed(TInt){};TBool NotifyProgress(){return EFalse;};private:void ConstructL();HBufC8* MakeGuidLC();private:CCalSession* iCalSes;CCalEntryView* iCalView;};void CCalWrite:: AddRepeatL(const TDesC& aDescription,TInt aWeeklyInterval){// create a new entryHBufC8* guid = MakeGuidLC();CCalEntry* entry = CCalEntry::NewL(CCalEntry::EAppt, guid,CCalEntry::EMethodNone, 0);CleanupStack::Pop(guid);CleanupStack::PushL(entry);// set some valuesTTime now;now.UniversalTime();now += TTimeIntervalHours(1); // start in an hourTCalTime start;start.SetTimeUtcL(now);now += TTimeIntervalHours(1); // lasts an hourTCalTime end;end.SetTimeUtcL(now);entry->SetStartAndEndTimeL(start, end);entry->SetDescriptionL(aDescription);// make the repeat ruleTCalRRule rule(TCalRRule::EWeekly);rule.SetDtStart(start);rule.SetCount(52/aWeeklyInterval); // for a yearrule.SetInterval(aWeeklyInterval);128SYMBIAN C++ RECIPESRArray<TDay> days;CleanupClosePushL(days);days.AppendL(EMonday);days.AppendL(ETuesday);days.AppendL(EWednesday);days.AppendL(EThursday);days.AppendL(EFriday);rule.SetByDay(days); // every weekdayCleanupStack::PopAndDestroy(&days);entry->SetRRuleL(rule);// add the entry to the databaseRPointerArray<CCalEntry> array;CleanupClosePushL(array);array.AppendL(entry);// Don’t transfer ownership of entry to arrayTInt success = 0;iCalView->StoreL(array, success);if (success < 1){User::Leave(KErrGeneral);}CleanupStack::PopAndDestroy(2, entry); // array, entry}4.2.5 Advanced Recipes4.2.5.1Find a ContactAmount of time required: 1 hourLocation of example code: \PIM\ContactFindRequired library(s): cntmodel.libRequired header file(s): cntdb.h, cntitem.h, cntfield.h,cntdef.hRequired platform security capability(s): ReadUserData WriteUserDataProblem: You want to find all the contacts that match a given searchcriterion.Solution: What you want is a collection of TContactItemId objects.All the elements it contains will match your search criterion, but they areadded to the collection in no particular order.Once returned, the collection can be used to retrieve data from eachelement individually.