Categories: Symbian C++ | How To | Code Examples | PIM
This page was last modified 23:01, 30 April 2008.
CalInterimAPI
From Forum Nokia Wiki
The new CalInterim API has been introduced with the Symbian 9.1 releases to replace the old Agenda Model API.
Connecting
The CCalSession is the interface to the Calendar file. The instantiation of CCalSession will result in a connection to the Calendar Server:
h:
#include <calsession.h> #include <calprogresscallback.h> #include <caliterator.h> #include <calentry.h> #include <calentryview.h> #include <caltime.h> #include <calalarm.h> #include <calcategory.h> #include <caluser.h> #include <calrrule.h> #include <calinstance.h> #include <calinstanceview.h> class CCalendar : public MCalProgressCallBack { CCalendar(); void ConstructL(); ~CCalendar(); [...] private: void OpenCalendarL(); [...] CCalSession* iCalSession; CCalIter* iCalIter; CCalEntryView* iCalEntryView; HBufC8* iNext; TBool iReady; [...] }
cpp:
#include "Calendar.h" CCalendar::CCalendar() { } CCalendar::~CCalendar() { if(iCalIter) { delete iCalIter; } if(iCalEntryView) { delete iCalEntryView; } if(iCalSession) { delete iCalSession; } if( iNext ) { delete iNext; iNext = NULL; } } void CCalendar::ConstructL() { iReady=EFalse; iNext = HBufC8::NewL(50); OpenCalendarL(); } void CCalendar::OpenCalendarL() { // allocate and construct server // Check that calendar exists, and if not, create it. // Calendar does not exist until it is created by calendar app - or by us. iCalSession = CCalSession::NewL(); //Open the default calendar file TRAPD(aErr, iCalSession->OpenL(KNullDesC)); if(aErr == KErrNotFound) { TRAPD(err, iCalSession->CreateCalFileL(iCalSession->DefaultFileNameL()) ); TRAPD(aErr2, iCalSession->OpenL(KNullDesC)); } iCalEntryView = CCalEntryView::NewL(*iCalSession, *this); iCalIter = CCalIter::NewL(*iCalSession); //Reset to the begin of the Calendar entries TPtr8 aAddress( iNext->Des() ); aAddress = iCalIter->FirstL(); }
Do not forget implement other functions!
// Called during calendar entry view creation void CCalendar::Progress(TInt aPercentageCompleted) { } void CCalendar::Completed(TInt aError) { if(aError==KErrNone) iReady=ETrue; } // Returns whether or not progress notification is required TBool CCalendar::NotifyProgress() { // Progress notification is required return ETrue; } // Utility function to handle CCalEntry insert // Destroy the RPointerArray void DestroyRPointerArray(TAny* aPtr) { RPointerArray<CCalEntry>* self = static_cast<RPointerArray<CCalEntry>*> (aPtr); self->ResetAndDestroy(); }
Insert new Appointment
To insert new item with a given ID you should create a CCalEntry item and fill out with the desidered data.
void CCalendar::NewApptL(TInt aID) { if(!iReady) //if this function is called too soon then return. Calendar opening //must finish first. return; //Create entry with the given new GUid HBufC8* guidBuf; TBuf8<30> tmpGuid; tmpGuid.Num( aID ); guidBuf = tmpGuid.AllocL(); CCalEntry* appt = CCalEntry::NewL(CCalEntry::EAppt, guidBuf, CCalEntry::EMethodNone, 0); CleanupStack::PushL(appt); //Some data appt->SetSummaryL( _L("Summary") ); appt->SetLocationL( _L("Location") ); appt->SetDescriptionL( _L("Description") ); //Start / end date TTime start; start.UniversalTime(); TTime end; end.UniversalTime(); TCalTime startCalTime; startCalTime.SetTimeUtcL(start); TCalTime endCalTime; //NullTTime() //Comment out the next line if you do not want to set end time endCalTime.SetTimeUtcL(end); //Set it appt->SetStartAndEndTimeL(startCalTime, endCalTime); //Store this new Entry RPointerArray<CCalEntry> entryArray; CleanupStack::PushL(TCleanupItem(DestroyRPointerArray, &entryArray)); entryArray.AppendL(appt); TInt success(0); iCalEntryView->StoreL(entryArray, success); entryArray.Reset(); CleanupStack::PopAndDestroy(&entryArray); CleanupStack::PopAndDestroy(appt); }
Insert new Todo
To insert new item with a given ID you should create a CCalEntry item and fill out with the desidered data.
void CCalendar::NewTodoL(TInt aID) { //Create an antry with the given GUid HBufC8* guidBuf; TBuf8<30> tmpGuid; tmpGuid.Num( aID ); guidBuf = tmpGuid.AllocL(); CCalEntry* todo = CCalEntry::NewL(CCalEntry::ETodo, guidBuf, CCalEntry::EMethodNone, 0); CleanupStack::PushL(todo); todo->SetSummaryL( _L("Summary") ); //Priority TInt priority = 1; todo->SetPriorityL(priority); //Completed TCalTime calTime; TTime time; time.UniversalTime(); calTime.SetTimeUtcL(time); todo->SetCompletedL(ETrue, calTime); //End date TTime end; end.UniversalTime(); TCalTime calEndDate; calEndDate.SetTimeUtcL(end); todo->SetStartAndEndTimeL(calStartDate, calEndDate); //Store New Entry RPointerArray<CCalEntry> entryArray; CleanupStack::PushL(TCleanupItem(DestroyRPointerArray, &entryArray)); entryArray.AppendL(aTask); TInt success(0); iCalEntryView->StoreL(entryArray, success); entryArray.Reset(); CleanupStack::PopAndDestroy(&entryArray); CleanupStack::PopAndDestroy(todo); }
Add old AgendaModel Alarm data to the new CCalEntry Appointment item
This code sample is useful if you port your application from the previous agenda model. In the old model you should use the SetAlarm(TTimeIntervalDays aDaysWarning,TTimeIntervalMinutes aTime). In the new API you can set the alarm only by giving the offset time according to the start date of the entry.
//Get old alarm data TTimeIntervalDays aDays = ...; TTimeIntervalMinutes aMinutes= ...; //tmp variables TInt oneDayInMin = 1440; TInt64 oneDayInMicroSec = 86400000000LL; TInt64 oneMinInMicroSec = 60000000; TCalTime startCalTime; //Set the start time startCalTime.SetTimeUtcL(start); TInt offSet = ((startCalTime.TimeLocalL().Int64() % oneDayInMicroSec) / oneMinInMicroSec) - aMinutes.Int(); if( offSet < 0 ) offSet = oneDayInMin - Abs(offSet); TTimeIntervalMinutes tmp( offSet + aDays.Int() * oneDayInMin); CCalAlarm* alarm = CCalAlarm::NewL(); if(alarm) { alarm->SetTimeOffset(tmp); appt->SetAlarmL(alarm); delete alarm; }
Add old AgendaModel Alarm data to the new CCalEntry Todo item
This lines are similar to the appointment code, but now the alarm offset is calculated from the end date (due date).
//Get old alarm data TTimeIntervalDays aDays = ...; TTimeIntervalMinutes aMinutes= ...; //tmp variables TInt oneDayInMin = 1440; TInt64 oneDayInMicroSec = 86400000000LL; TInt64 oneMinInMicroSec = 60000000; TCalTime endCalTime; //Set end date endCalTime.SetTimeUtcL(dueDate); TInt offSet = ((endCalTime.TimeLocalL().Int64() % oneDayInMicroSec) / oneMinInMicroSec) - aMinutes.Int(); TTimeIntervalMinutes tmp( offSet + aDays.Int() * oneDayInMin); CCalAlarm* alarm = CCalAlarm::NewL(); if( alarm ) { alarm->SetTimeOffset(tmp); todo->SetAlarmL(alarm); delete alarm; }
Delete entry
void CCalendar::DeleteItemL(TInt aID) { CCalEntry* aEntry = NULL; TBuf8<30> tmpGuid; tmpGuid.Num( aID ); HBufC8* guidBuf = tmpGuid.AllocL(); RPointerArray<CCalEntry> tmpArray; CleanupStack::PushL(TCleanupItem(DestroyRPointerArray, &tmpArray)); iCalEntryView->FetchL( guidBuf->Des(), tmpArray ); delete guidBuf; if( tmpArray.Count() == 0 ) { CleanupStack::PopAndDestroy(&tmpArray); return; } aEntry = tmpArray[0]; iCalEntryView->DeleteL(*aEntry); CleanupStack::PopAndDestroy(&tmpArray); }
Update Appointment entry
Because the CCalEntryView->UpdateL() can't update all the attributes of an entry i use a tmpEntry to store the copied data to store the new modified entry, there are some entry swapping to avoid the data loss if a break occour. You can also implement this function using the CopyCalEntryL() function, described at the end of this document.
void CCalendar::UpdateApptL(TInt aID) { CCalEntry* aAppt = NULL; CCalEntry* tmpEntry = NULL; TInt aID = GetInt(*aIDText); TBuf8<30> tmpGuid; tmpGuid.Num(aID); HBufC8* guidBuf = tmpGuid.AllocL(); HBufC8* guidTmp; TBool aFound = EFalse; RPointerArray<CCalEntry> array; CleanupStack::PushL(TCleanupItem(DestroyRPointerArray, &array)); TRAPD(aErr, iCalEntryView->FetchL(guidBuf->Des(), array) ); if (!aErr && array.Count() > 0 ) { aAppt = array[0]; if( aAppt->EntryTypeL() != CCalEntry::EAppt ) aAppt = NULL; aFound = ETrue; } if (aFound) { //This will create new unique UID HBufC8* guidTmp = CalenInterimUtils::GlobalUidL(); /* //Check the existence of the newly created tmp guid TInt itemCount = 0; do { TInt guidNum = Math::Random(); TBuf8<30> tmpGuid; tmpGuid.Num( Abs(guidNum) ); guidTmp = tmpGuid.AllocL(); RPointerArray<CCalEntry> tmparray; CleanupStack::PushL(TCleanupItem(DestroyRPointerArray, &tmparray)); iCalEntryView->FetchL(guidTmp->Des(), tmparray); itemCount = tmparray.Count(); CleanupStack::PopAndDestroy(&tmparray); if( itemCount > 0 ) delete guidTmp; } while( itemCount > 0 ); */ tmpEntry = CCalEntry::NewL(CCalEntry::EAppt, guidTmp, CCalEntry::EMethodNone, 0); CleanupStack::PushL(tmpEntry); CopyCalEntryL(aAppt, tmpEntry); CleanupStack::Pop(tmpEntry); } CleanupStack::PopAndDestroy(&array); if( tmpEntry ) CleanupStack::PushL(tmpEntry); //Set new data: tmpEntry->SetSummaryL(_L("Summary")); // [...] //Store it if( tmpEntry ) CleanupStack::Pop(tmpEntry); if (aFound) { HBufC8* guidUpdate = guidBuf->AllocL(); CCalEntry* updateEntry = CCalEntry::NewL(CCalEntry::EAppt, guidUpdate, CCalEntry::EMethodNone, 0); CleanupStack::PushL(updateEntry); CopyCalEntryL(tmpEntry, updateEntry); CleanupStack::Pop(updateEntry); HBufC8* deleteGuidTmp = guidTmp->AllocL(); //Insert the tmp entry RPointerArray<CCalEntry> insertArray; CleanupStack::PushL(TCleanupItem(DestroyRPointerArray, &insertArray)); insertArray.AppendL(tmpEntry); TInt success(0); iCalEntryView->StoreL(insertArray, success); insertArray.Reset(); CleanupStack::PopAndDestroy(&insertArray); delete tmpEntry; //Delete old RPointerArray<CCalEntry> deleteArray; CleanupStack::PushL(TCleanupItem(DestroyRPointerArray, &deleteArray)); iCalEntryView->FetchL(guidBuf->Des(), deleteArray); CCalEntry* deleteEntry = deleteArray[0]; iCalEntryView->DeleteL(*deleteEntry); CleanupStack::PopAndDestroy(&deleteArray); //insert new update Entry RPointerArray<CCalEntry> updateArray; CleanupStack::PushL(TCleanupItem(DestroyRPointerArray, &updateArray)); updateArray.AppendL(updateEntry); success = 0; iCalEntryView->StoreL(updateArray, success); updateArray.Reset(); CleanupStack::PopAndDestroy(&updateArray); delete updateEntry; //Delete tmp Entry RPointerArray<CCalEntry> deleteTmpArray; CleanupStack::PushL(TCleanupItem(DestroyRPointerArray, &deleteTmpArray)); iCalEntryView->FetchL(deleteGuidTmp->Des(), deleteTmpArray); CCalEntry* deleteTmpEntry = deleteTmpArray[0]; iCalEntryView->DeleteL(*deleteTmpEntry); CleanupStack::PopAndDestroy(&deleteTmpArray); delete deleteGuidTmp; } delete guidBuf; }
Update Todo item
The Todo entry update can be made in similar mode than the Appointment entry.
Convert item CCalEntry IDs to old AgendaModel entry IDs
If you are porting your application from the old Agenda API to the new CalInterim API, presumably you have head-ache how to convert the new alphanumeric IDs to the old integer ID-s. Here is an example:
///////////////////////////////////////////////////////////////////// /* Because the Global Uid(22 char length &HBufC8) of an entry is out of range of TInt32... This function must be called after the & CCalIter creation and before any other functions. */ // Update the Global uids to be in the range of TInt32 void CCalendar::ConvertL() { HBufC8* next = HBufC8::NewL(50); TPtr8 aAddress( next->Des() ); aAddress = iCalIter->FirstL(); while( next->Des() != KNullDesC8 ) { //Checking if the ( UID is string) || (bigger then 2147483646) TBool toConvert = EFalse; TBuf8<100> des8 = _L8(""); TRAPD(err_fetch, des8.Copy( next->Des() ) ); if( err_fetch == KErrNone ) { TLex8 lex8 = TLex8(des8); TInt id = 0; TInt err_lex = lex8.Val(id); if( err_lex != KErrNone ) toConvert = ETrue; } //Update if( toConvert != EFalse ) { RPointerArray<CCalEntry> fetchArray; CleanupStack::PushL(TCleanupItem(DestroyRPointerArray, &fetchArray)); iCalEntryView->FetchL(next->Des(), fetchArray); CCalEntry* aEntry = fetchArray[0]; /////////////////////////////////////////////////// //Convert only the Appontment & Todo if( aEntry->EntryTypeL() == CCalEntry::EAppt || aEntry->EntryTypeL() == CCalEntry::ETodo ) { //Check the existence of an entry with the new GUid HBufC8* guidBuf; TInt itemCount = 0; do { TInt guidNum = Math::Random(); TBuf8<30> tmpGuid; tmpGuid.Num( Abs(guidNum) ); guidBuf = tmpGuid.AllocL(); RPointerArray<CCalEntry> tmparray; CleanupStack::PushL(TCleanupItem(DestroyRPointerArray, &tmparray)); iCalEntryView->FetchL(guidBuf->Des(), tmparray); itemCount = tmparray.Count(); CleanupStack::PopAndDestroy(&tmparray); if( itemCount > 0 ) delete guidBuf; } while( itemCount > 0 ); CCalEntry* updateEntry; if( aEntry->EntryTypeL() == CCalEntry::EAppt ) { updateEntry = CCalEntry::NewL(CCalEntry::EAppt, guidBuf, CCalEntry::EMethodNone, 0); } else { updateEntry = CCalEntry::NewL(CCalEntry::ETodo, guidBuf, CCalEntry::EMethodNone, 0); } //Copy: because updateEntry->CopyFromL( *aEntry, EDontCopyId ); //doesn't work :( CopyCalEntryL(aEntry, updateEntry); RPointerArray<CCalEntry> modifyingArray; CleanupStack::PushL(TCleanupItem(DestroyRPointerArray, &modifyingArray)); modifyingArray.AppendL(updateEntry); TInt numberOfEntries(0); iCalEntryView->StoreL(modifyingArray, numberOfEntries); CleanupStack::PopAndDestroy(&modifyingArray); //Delete old RPointerArray<CCalEntry> deleteArray; CleanupStack::PushL(TCleanupItem(DestroyRPointerArray, &deleteArray)); iCalEntryView->FetchL(aEntry->UidL(), deleteArray); CCalEntry* deleteEntry = deleteArray[0]; iCalEntryView->DeleteL(*deleteEntry); CleanupStack::PopAndDestroy(&deleteArray); } CleanupStack::PopAndDestroy(&fetchArray); } aAddress = iCalIter->NextL(); } delete next; next = NULL; }
Copy entry to an other one without Global ID
This function is usefull if CCalEntry CopyFromL( *aEntry, EDontCopyId ) doesn't work. aSource and aTarget should exist before calling this function. All 2 entries should be the same type!
void CCalendar::CopyCalEntryL(CCalEntry* aSource, CCalEntry* aTarget) { aTarget->SetSummaryL( aSource->SummaryL() ); aTarget->SetDescriptionL( aSource->DescriptionL() ); aTarget->SetLastModifiedDateL(); aTarget->SetDTStampL( aSource->DTStampL() ); aTarget->SetLocationL( aSource->LocationL() ); aTarget->SetStatusL( aSource->StatusL() ); aTarget->SetReplicationStatusL( aSource->ReplicationStatusL() ); aTarget->SetPriorityL( aSource->PriorityL() ); //On Nokia E60 - sometimes at Todo entries, getting startTime/endTime Leaves! //In this case create a new NullTTime Enty TCalTime startCalTime; TRAPD(err, startCalTime = aSource->StartTimeL()); if( err != KErrNone ) { TTime time = Time::NullTTime(); startCalTime.SetTimeUtcL(time); } TCalTime endCalTime; TRAPD(err1, endCalTime = aSource->EndTimeL()); if( err1 != KErrNone ) { TTime time = Time::NullTTime(); endCalTime.SetTimeUtcL(time); } aTarget->SetStartAndEndTimeL(startCalTime, aSource->EndTimeL()); if( aSource->EntryTypeL() == CCalEntry::ETodo ) { TCalTime time = aSource->CompletedTimeL(); if( time.TimeUtcL() != Time::NullTTime() ) aTarget->SetCompletedL (ETrue time); aSource->CompletedTimeL().TimeUtcL(), ETrue, 3); } TCalRRule rule; if( aSource->GetRRuleL( rule ) != EFalse ) aTarget->SetRRuleL( rule ); RArray<TCalTime> array; aSource->GetRDatesL( array ); if( array.Count() > 0 ) aTarget->SetRDatesL( array ); array.Reset(); aSource->GetExceptionDatesL( array ); if( array.Count() > 0 ) aTarget->SetExceptionDatesL( array ); array.Close(); CCalAlarm* alarm = aSource->AlarmL(); aTarget->SetAlarmL( alarm ); if( alarm ) { aSource->AlarmL()->TimeOffset().Int(), 3); delete alarm; } //If, //Category, Attendee, Organizer, PhoneOwner, Method, //SequenceNumber, RecurrenceID, TzRules, LocalUid are not needed }
--Egeri 09:51, 8 June 2007 (UTC)
| Related Discussions | ||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| exe missing in emulator | Symbian_Neil | General Symbian C++ | 7 | 2007-03-15 07:48 |
| CalInterim API problem | egeri | General Symbian C++ | 0 | 2006-07-21 07:14 |
| CalChangeNotification and PC Suite synchronization S60 | ValentinK | General Symbian C++ | 0 | 2008-03-21 19:10 |
| How to make the calendar | de_fong | General Symbian C++ | 18 | 2008-03-22 16:11 |
| Problem in calendar APIs | swetha_s | General Symbian C++ | 7 | 2008-03-11 20:25 |
