--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/calendarui/editors/src/CalenEditorDataHandler.cpp Tue Feb 02 10:12:19 2010 +0200
@@ -0,0 +1,3061 @@
+/*
+* Copyright (c) 2006 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: CalenEditorDataHandler implements all logic of checking and
+* validating editor data
+*
+*/
+
+// System includes
+#include <calendateutils.h>
+#include <calenagendautils.h>
+#include <calinstance.h>
+#include <calalarm.h>
+#include <calentry.h>
+#include <calrrule.h>
+#include <centralrepository.h>
+#include <calattachment.h>
+#include <eikenv.h>
+#include <CalenInterimUtils2.h>
+#include <calencontext.h>
+#include <caleninstanceid.h> // TCalenInstanceId
+#include <calenservices.h>
+
+// User includes
+#include "CalenEditorDataHandler.h"
+#include "CalendarPrivateCRKeys.h"
+#include "CalenDefaultEditors.hrh"
+#include "calenentryutil.h"
+#include "CleanupResetAndDestroy.h"
+#include "calenattachmentutils.h"
+#include "calenattachmentinfo.h"
+#include "calenattachmentmodel.h"
+#include "calenunifiededitor.h"
+#include "calendarui_debug.h"
+
+// Constants
+#define KNoOfDaysInWeek 7
+
+// ======== LOCAL FUNCTIONS ========
+
+// -----------------------------------------------------------------------------
+// IsTimed
+// Returns ETrue if the entry is timed (i.e. an appointment or a
+// reminder), EFalse otherwise.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+static TBool IsTimed( CCalEntry::TType aEntryType )
+ {
+ TRACE_ENTRY_POINT;
+
+ TRACE_EXIT_POINT;
+ return aEntryType == CCalEntry::EAppt || aEntryType == CCalEntry::EReminder;
+ }
+
+// -----------------------------------------------------------------------------
+// ForeverDate
+// Returns the date which Calendar presumes to be infinitely far in the future.
+// Used, for example, when setting a repeating meeting to repeat forever.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+static TTime ForeverDate()
+ {
+ TRACE_ENTRY_POINT;
+
+ TTime forever = TTime( TDateTime( ECalenForeverYear, static_cast<TMonth>( ECalenForeverMonth ),
+ ECalenForeverDay, 0, 0, 0, 0) );
+
+ TRACE_EXIT_POINT;
+ return forever;
+ }
+
+// -----------------------------------------------------------------------------
+// IsForeverDate
+// Returns ETrue if the given date is considered by Calendar to be infinitely
+// far in the future.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+static TBool IsForeverDate( const TTime& aDate )
+ {
+ TRACE_ENTRY_POINT;
+
+ TRACE_EXIT_POINT;
+ return CalenDateUtils::OnSameDay( aDate, ForeverDate() );
+ }
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// CCalenEditorDataHandler::CCalenEditorDataHandler
+// Constructor.
+// (other items were commented in a header).
+// ---------------------------------------------------------------------------
+//
+CCalenEditorDataHandler::CCalenEditorDataHandler(
+ CCalEntry& aEntry,
+ const TCalTime& aInstanceDateTime,
+ TBool aIsCreatingNew,
+ TInt aMaxTextEditorLength,
+ MCalenServices& aServices,
+ RArray<TInt>& aCollectionIds)
+ : iEntry( aEntry ),
+ iInstanceDateTime( aInstanceDateTime ),
+ iIsCreatingNew( aIsCreatingNew ),
+ iMaxTextEditorLength( aMaxTextEditorLength ),
+ iServices( aServices ) , iCalendarFieldEdited(EFalse) , iCollectionIds(aCollectionIds)
+ {
+ TRACE_ENTRY_POINT;
+ TRACE_EXIT_POINT;
+ }
+
+// ---------------------------------------------------------------------------
+// CCalenEditorDataHandler::ConstructL
+// Two phase construction.
+// (other items were commented in a header).
+// ---------------------------------------------------------------------------
+//
+void CCalenEditorDataHandler::ConstructL()
+ {
+ TRACE_ENTRY_POINT;
+
+ iEntryType = iEntry.EntryTypeL();
+ iRecurrenceId = iEntry.RecurrenceIdL();
+
+ iOriginal = CCalenEntryUtil::NewL( iEntry, iInstanceDateTime );
+ iEdited = CCalenEntryUtil::NewL( iEntry, iInstanceDateTime );
+ if ( IsCreatingNew() )
+ {
+ SetDefaultNewValuesL( *iOriginal ); // modify iOriginal also
+ SetDefaultNewValuesL( *iEdited );
+ }
+ else
+ {
+ iInstanceId = iServices.Context().InstanceId();
+ }
+
+
+ TRACE_EXIT_POINT;
+ }
+
+// ---------------------------------------------------------------------------
+// CCalenEditorDataHandler::NewL
+// Two-phased constructor.
+// (other items were commented in a header).
+// ---------------------------------------------------------------------------
+//
+CCalenEditorDataHandler* CCalenEditorDataHandler::NewL(
+ CCalEntry& aEntry,
+ const TCalTime& aInstanceDateTime,
+ TBool aIsCreatingNew,
+ TInt aMaxTextEditorLength,
+ MCalenServices& aServices,
+ RArray<TInt>& aCollectionIds)
+ {
+ TRACE_ENTRY_POINT;
+
+ CCalenEditorDataHandler* self = new( ELeave ) CCalenEditorDataHandler(
+ aEntry, aInstanceDateTime, aIsCreatingNew, aMaxTextEditorLength, aServices,aCollectionIds );
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop( self );
+
+ TRACE_EXIT_POINT;
+ return self;
+ }
+
+// ---------------------------------------------------------------------------
+// CCalenEditorDataHandler::~CCalenEditorDataHandler
+// Destructor.
+// (other items were commented in a header).
+// ---------------------------------------------------------------------------
+//
+CCalenEditorDataHandler::~CCalenEditorDataHandler()
+ {
+ TRACE_ENTRY_POINT;
+
+ delete iOriginal;
+ delete iEdited;
+
+ TRACE_EXIT_POINT;
+ }
+
+// ---------------------------------------------------------------------------
+// CCalenEditorDataHandler::Edited
+// Returns the CCalenEditorDataHandler used to represent the entry the
+// user is currently editing.
+// (other items were commented in a header).
+// ---------------------------------------------------------------------------
+//
+CCalenEntryUtil& CCalenEditorDataHandler::Edited()
+ {
+ TRACE_ENTRY_POINT;
+
+ TRACE_EXIT_POINT;
+ return *iEdited;
+ }
+
+// ---------------------------------------------------------------------------
+// CCalenEditorDataHandler::Original
+// Returns the CCalenEditorDataHandler used to represent the entry the
+// user originally opened.
+// (other items were commented in a header).
+// ---------------------------------------------------------------------------
+//
+const CCalenEntryUtil& CCalenEditorDataHandler::Original() const
+ {
+ TRACE_ENTRY_POINT;
+
+ TRACE_EXIT_POINT;
+ return *iOriginal;
+ }
+
+// ---------------------------------------------------------------------------
+// CCalenEditorDataHandler::Entry
+// Returns the entry this object is wrapping round.
+// (other items were commented in a header).
+// ---------------------------------------------------------------------------
+//
+CCalEntry& CCalenEditorDataHandler::Entry()
+ {
+ TRACE_ENTRY_POINT;
+
+ TRACE_EXIT_POINT;
+ return iEntry;
+ }
+
+// ---------------------------------------------------------------------------
+// CCalenEditorDataHandler::InstanceDateTime
+// Returns the instance date/time.
+// (other items were commented in a header).
+// ---------------------------------------------------------------------------
+//
+const TCalTime& CCalenEditorDataHandler::InstanceDateTime() const
+ {
+ TRACE_ENTRY_POINT;
+
+ TRACE_EXIT_POINT;
+ return iInstanceDateTime;
+ }
+
+
+// ---------------------------------------------------------------------------
+// CCalenEditorDataHandler::ShouldSaveOrDeleteOrDoNothingL
+// Works out whether the entry should be deleted, saved,
+// or whether no action should be taken.
+// (other items were commented in a header).
+// ---------------------------------------------------------------------------
+//
+CCalenEditorDataHandler::TAction CCalenEditorDataHandler::ShouldSaveOrDeleteOrDoNothingL()
+ {
+ TRACE_ENTRY_POINT;
+
+ if ( !IsEditedL() )
+ {
+ // Not edited at all OR
+ // Only added space characters to text fields but not
+ // edited the non-text fields
+ // no need to save the note
+ TRACE_EXIT_POINT;
+ return CCalenEditorDataHandler::EActionNothing;
+ }
+
+ // *************** THE NOTE IS EDITED ********************
+ if(IsCreatingNew())
+ {
+ // ************* EDITED NEW NOTE *********
+
+ // Subject && Location && Description are text fields
+ // If text fields as a whole is not empty, we can save the note
+ // If text fields as a whole IS empty, we can STILL save the note
+ // since we edited "non-text" fields
+ if ( !NonTextFieldsEditedL() && AreTextFieldsEmptyL() )
+ {
+ TRACE_EXIT_POINT;
+ return CCalenEditorDataHandler::EActionNothing;
+ }
+ else
+ {
+ TRACE_EXIT_POINT;
+ return CCalenEditorDataHandler::EActionSave;
+ }
+ }
+
+ // **************** EDITED OLD NOTE **********
+
+ if(AreTextFieldsClearedL() && !NonTextFieldsEditedL()) // subject && location && description
+ {
+ // ***** OLD NOTE + TEXT FIELDS EMPTIED + NON-TEXT FIELDS NOT EDITED
+ // Even if user may have edited non-text fields,
+ // delete the note
+ TRACE_EXIT_POINT;
+ return CCalenEditorDataHandler::EActionDelete;
+ }
+
+ // ****** OLD NOTE WITH TEXT FIELDS **********
+ // Save the note, since the text fields contain something
+ TRACE_EXIT_POINT;
+ return CCalenEditorDataHandler::EActionSave;
+ }
+
+// ---------------------------------------------------------------------------
+// CCalenEditorDataHandler::NonTextFieldsEdited
+// Returns ETrue if any of the non-text fields (e.g. time fields) of the entry
+// have been edited, EFalse otherwise.
+// (other items were commented in a header).
+// ---------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::NonTextFieldsEditedL()
+ {
+ TRACE_ENTRY_POINT;
+
+ TRACE_EXIT_POINT;
+
+ return ( IsStartDateTimeEdited() ||
+ IsEndDateTimeEdited() ||
+ IsAlarmEditedL() ||
+ IsRepeatRuleEdited() ||
+ IsPriorityEdited() ||
+ IsCalendarEditedL() ||
+ IsAttachmentExists() ||
+ IsEventTypeEdited() ||
+ AllDayFieldEdited() );
+ }
+
+// ---------------------------------------------------------------------------
+// CCalenEditorDataHandler::TextFieldsEdited
+// Returns ETrue if any of the text fields (e.g. summary) of the entry
+// have been edited, EFalse otherwise.
+// (other items were commented in a header).
+// ---------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::TextFieldsEdited()
+ {
+ TRACE_ENTRY_POINT;
+
+ TRACE_EXIT_POINT;
+
+ return ( IsSummaryEdited() || IsLocationEdited() || IsDescriptionEdited()
+ || IsAttachmentExists() );
+ }
+
+// ---------------------------------------------------------------------------
+// CCalenEditorDataHandler::IsEditedL
+// Returns ETrue if the entry has been modified, EFalse otherwise.
+// (other items were commented in a header).
+// ---------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::IsEditedL()
+ {
+ TRACE_ENTRY_POINT;
+
+ TRACE_EXIT_POINT;
+
+ return ( TextFieldsEdited() || NonTextFieldsEditedL() );
+ }
+
+// ---------------------------------------------------------------------------
+// CCalenEditorDataHandler::WriteChangesToEntryL
+// Read the data from the form and set it to the entry.
+// (other items were commented in a header).
+// ---------------------------------------------------------------------------
+//
+void CCalenEditorDataHandler::WriteChangesToEntryL( CalCommon::TRecurrenceRange aRepeatTarget )
+ {
+ TRACE_ENTRY_POINT;
+
+ // This is only place where we can read data from CCalEntry.
+ // E.g. when we calculate alarm offset, we need to read start time from
+ // entry, not anymore from CCalenEntryUtil.
+ TBool isNew = IsCreatingNew();
+
+ WriteStartAndEndTimesToEntryL( aRepeatTarget );
+
+ if ( isNew || IsSummaryEdited() )
+ {
+ TPtrC summary = Edited().Summary();
+ // If text is considered empty, always store as KNullDesC
+ if ( CalenAgendaUtils::IsEmptyText( summary ) )
+ {
+ summary.Set( KNullDesC );
+ }
+ iEntry.SetSummaryL( summary );
+ }
+
+ if ( isNew || IsLocationEdited() )
+ {
+ TPtrC location = Edited().Location();
+ // If text is considered empty, always store as KNullDesC
+ if ( CalenAgendaUtils::IsEmptyText( location ) )
+ {
+ location.Set(KNullDesC);
+ }
+ iEntry.SetLocationL( location );
+ }
+
+ if ( isNew || IsDescriptionEdited() )
+ {
+ iEntry.SetDescriptionL( Edited().Description() );
+ }
+
+ // Repeat rule has to be modified in both cases
+ if ( isNew || IsStartDateTimeEdited() || IsRepeatRuleEdited() )
+ {
+
+ if ( aRepeatTarget == CalCommon::EThisOnly)
+ {
+ iEntry.ClearRepeatingPropertiesL();
+ }
+ else if ( Edited().IsRepeating() )
+ {
+ // If we're an RDate (with repeat type ERepeatOther), don't try to set an RRule,
+ // but don't clear the repeat properties either.
+ if( Edited().RepeatType() != ERepeatOther )
+ {
+ TCalRRule rrule;
+
+ CalculateRepeatRuleL( Edited().StartDateTime(),
+ Edited().RepeatType(),
+ Edited().RepeatUntilDateTime(),
+ rrule );
+
+ iEntry.SetRRuleL( rrule );
+
+ // As there should not be any rdates, remove any that are
+ // still present
+ RArray<TCalTime> emptyList;
+ CleanupClosePushL( emptyList );
+ iEntry.SetRDatesL( emptyList );
+ CleanupStack::PopAndDestroy(); // emptyList
+ }
+ else
+ {
+ // The repeat type is ERepeatOther, therefore as
+ // it is impossible to create an entry of type
+ // ERepeat other using the editor either the repeat until
+ // date or the start date must have been changed
+
+ // The start date/time has changed, in order for the
+ // series to maintain its pattern, any rDates and if
+ // present rRule are moved by the same offset
+ // The repeat type is ERepeatOther, so check if we have any rdates
+ RArray<TCalTime> rDateList;
+ CleanupClosePushL( rDateList );
+ iEntry.GetRDatesL( rDateList );
+ TInt count = rDateList.Count();
+
+ if ( count == 0 )
+ {
+ // There are no rdates so the new until and start date can be applied
+ // directly.
+ TCalRRule rrule;
+
+ CalculateRepeatRuleL( Edited().StartDateTime(),
+ Edited().RepeatType(),
+ Edited().RepeatUntilDateTime(),
+ rrule );
+
+ iEntry.SetRRuleL( rrule );
+ }
+ else
+ {
+ // There are rDates which need to be checked.
+ if ( IsStartDateTimeEdited() )
+ {
+ // Need to shift any rdates
+ TTime editedStart = iEdited->StartDateTime();
+ TTime origStart = iOriginal->StartDateTime();
+ TTimeIntervalMicroSeconds offSet = editedStart.MicroSecondsFrom( origStart );
+ for ( TInt index = 0; index < count; index++ )
+ {
+ TCalTime& rDateTime = rDateList[ index ];
+ TTime shiftedTime = rDateTime.TimeUtcL();
+ TDateTime before = shiftedTime.DateTime();
+ shiftedTime += offSet;
+ TDateTime after = shiftedTime.DateTime();
+ rDateTime.SetTimeUtcL( shiftedTime );
+ }
+ }
+
+ // Check and fix the rDates and rRules match the
+ // repeat until date and time.
+ TTime untilTime = Edited().RepeatUntilDateTime();
+
+ // Remove any rdates that are after the the repeat until date
+ TInt count = rDateList.Count();
+ if ( count > 0 )
+ {
+ TInt index = count - 1;
+ do
+ {
+ TTime lastRDate = CalenDateUtils::BeginningOfDay( rDateList[ index ].TimeLocalL() );
+ TDateTime before = lastRDate.DateTime();
+ if ( lastRDate > untilTime )
+ {
+ rDateList.Remove( index-- );
+ }
+ else
+ {
+ index = KErrNotFound;
+ }
+ } while ( index != KErrNotFound );
+ }
+
+ // Need to check if the end date of the
+ // rrule needs adjusting if it exists.
+ TCalRRule rRule;
+ if ( iEntry.GetRRuleL( rRule ) )
+ {
+ count = rDateList.Count();
+ if ( count > 0 )
+ {
+ // There still exists some rdates, so only need to trim
+ // the rrule if it exists
+ TTime lastRDate = CalenDateUtils::BeginningOfDay( rDateList[ count - 1 ].TimeLocalL() );
+ const TTime& origUntilDate = Original().RepeatUntilDateTime();
+ TTime startDT = rRule.DtStart().TimeLocalL();
+
+ if ( lastRDate <= origUntilDate && startDT > lastRDate )
+ {
+ if ( startDT < untilTime)
+ {
+ if( origUntilDate != untilTime)
+ {
+ ApplyUntilDateToRRuleL( rRule, untilTime);
+ iEntry.SetRRuleL( rRule );
+ }
+ }
+ else
+ {
+ // The repeat start is after the until date
+ // so remove any repeat information.
+ iEntry.ClearRepeatingPropertiesL();
+
+ // If the entry date has been moved past the until
+ // date, need to swap the an rDate for the entry.
+ TTime startTime = iEntry.StartTimeL().TimeLocalL();
+
+ if ( startTime > untilTime )
+ {
+ // Find the duration of the entry
+ TTime endTime = iEntry.EndTimeL().TimeLocalL();
+ TTimeIntervalMinutes duration;
+ //startTime.MinutesFrom( endTime, duration );// for bug: CMCA-745CZ4
+ endTime.MinutesFrom( startTime, duration );
+
+ // Choose the first rDate as the new start time
+ TCalTime newStartTime = rDateList[ 0 ];
+ endTime = newStartTime.TimeLocalL() + duration;
+
+ // FIXME.
+ // If there is only one rDate left, the agenda model
+ // will crash if it is deleted.
+ if ( count != 0 )
+ {
+ rDateList.Remove( 0 );
+ }
+
+ TCalTime newEndTime;
+ if ( UseFloatingTimeL() )
+ {
+ newEndTime.SetTimeLocalFloatingL( endTime );
+ }
+ else
+ {
+ newEndTime.SetTimeLocalL( endTime );
+ }
+
+ iEntry.SetStartAndEndTimeL( newStartTime, newEndTime );
+ }
+ }
+ }
+ }
+ }
+
+ iEntry.SetRDatesL( rDateList );
+ }
+
+ CleanupStack::PopAndDestroy(); // rDateList
+ }
+ }
+ else
+ {
+ iEntry.ClearRepeatingPropertiesL();
+
+ // FIXME As the entry is supposedly not repeating
+ // any rDates should be removed. Unforunately this
+ // is not possible at the moment because removing the
+ // rdates will cause the agenda model to panic
+ //
+ // RArray<TCalTime> emptyList;
+ // CleanupClosePushL( emptyList );
+ // iEntry.SetRDatesL( emptyList );
+ // CleanupStack::PopAndDestroy(); // emptyList
+ }
+ }
+
+ if ( isNew || IsAlarmEditedL() && ( iEntry.StatusL() != CCalEntry::ETodoCompleted ) )
+ {
+ if ( Edited().IsAlarmActivated() )
+ {
+ CCalAlarm* alarm = iEntry.AlarmL();
+ if ( ! alarm )
+ {
+ alarm = CCalAlarm::NewL();
+ }
+ CleanupStack::PushL( alarm );
+
+ TTime startTime;
+ // ToDos don't have start time!
+ // If we have undated todo with alarm that was taken care earlier
+ if (iEntry.EntryTypeL()==CCalEntry::ETodo)
+ {
+ startTime = iEntry.EndTimeL().TimeLocalL();
+ }
+
+ // if this is not todo we use starttime normal way
+ else
+ {
+ startTime = iEntry.StartTimeL().TimeLocalL();
+ }
+ TCalRRule ignore;
+ TBool isRepeating = iEntry.GetRRuleL( ignore );
+
+ // If edit alarm of repeating entry, we have to nudge start
+ // time to instance date
+ if ( isRepeating && aRepeatTarget == CalCommon::EThisAndAll )
+ {
+ // nudge to instance date;
+ TTime instanceDate = iInstanceDateTime.TimeLocalL();
+ if ( IsStartDateTimeEdited() )
+ {
+ instanceDate = Edited().EventDateTime();
+ }
+
+ TDateTime insDt = instanceDate.DateTime();
+ TDateTime startDt = startTime.DateTime();
+ // Don't use individual setters (SetMonth, SetDay ...), because
+ // they break if month doesn't contain old date
+ // or date to be set.
+ startDt.Set( insDt.Year(), insDt.Month(), insDt.Day(),
+ startDt.Hour(), startDt.Minute(),
+ startDt.Second(), startDt.MicroSecond() );
+ startTime = TTime( startDt );
+ }
+
+ TTime alarmTime = Edited().AlarmDateTime();
+
+ TTimeIntervalMinutes offset;
+ startTime.MinutesFrom( alarmTime, offset );
+ alarm->SetTimeOffset( offset );
+
+ iEntry.SetAlarmL( alarm );
+ CleanupStack::PopAndDestroy( alarm );
+ }
+ else
+ {
+ iEntry.SetAlarmL( NULL );
+ }
+ }
+
+ if ( isNew || IsPriorityEdited() )
+ {
+ // map priority here
+ TUint priority = 0;
+ switch ( Edited().Priority() )
+ {
+ case CCalenEntryUtil::ETodoPriorityHigh:
+ priority = 1;
+ break;
+ case CCalenEntryUtil::ETodoPriorityNormal:
+ priority = 2;
+ break;
+ case CCalenEntryUtil::ETodoPriorityLow:
+ priority = 3;
+ break;
+ default:
+ ASSERT( EFalse );
+ break;
+ }
+ iEntry.SetPriorityL( priority );
+ }
+
+ if ( isNew )
+ {
+ CCalEntry::TReplicationStatus status = CCalEntry::EOpen;
+ switch ( Edited().SynchType() )
+ {
+ case CCalenEntryUtil::ESynchPrivate:
+ status = CCalEntry::EPrivate;
+ break;
+ case CCalenEntryUtil::ESynchPublic:
+ status = CCalEntry::EOpen;
+ break;
+ case CCalenEntryUtil::ESynchNoSync:
+ status = CCalEntry::ERestricted;
+ break;
+ default:
+ ASSERT( EFalse );
+ break;
+ }
+ iEntry.SetReplicationStatusL( status );
+ }
+
+ /**
+ * S60 settings for new entries
+ */
+ if ( IsCreatingNew() )
+ {
+ if ( Edited().EntryType() == CCalEntry::EAnniv )
+ {
+ TCalRRule rrule( TCalRRule::EYearly );
+ rrule.SetDtStart( iEntry.StartTimeL() );
+ rrule.SetInterval( 1 );
+ rrule.SetCount( 0 );
+ iEntry.SetRRuleL( rrule );
+ }
+ }
+
+ // check for attachments
+ if( isNew || IsAttachmentExists() )
+ {
+ // TODO: Uncomment this when enabling attachment support
+ AddAttachementsToEntryL();
+ }
+ TRACE_EXIT_POINT;
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::ApplyUntilDateToRRuleL
+// Applies an new until date to a rrule
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCalenEditorDataHandler::ApplyUntilDateToRRuleL( TCalRRule& aRRule, const TTime& aRepeatUntil ) const
+ {
+ TRACE_ENTRY_POINT;
+ // note repeat is set to forever.
+ if ( ! CalenDateUtils::IsValidDay( aRepeatUntil ) || IsForeverDate( aRepeatUntil ) )
+ {
+ // Set repeat to forever:
+ aRRule.SetCount( 0 );
+ }
+ else
+ {
+ // Change repeatuntil so that hours, minutes, ... are same as in start date
+ TDateTime dtUntil = aRepeatUntil.DateTime();
+ TDateTime dtStart= iEntry.StartTimeL().TimeLocalL().DateTime();
+
+ dtUntil.Set( dtUntil.Year(), dtUntil.Month(), dtUntil.Day(),
+ dtStart.Hour(), dtStart.Minute(), dtStart.Second(), dtStart.MicroSecond() );
+
+ TCalTime calRepeatUntil;
+ if ( UseFloatingTimeL() )
+ {
+ calRepeatUntil.SetTimeLocalFloatingL( TTime( dtUntil ) );
+ }
+ else
+ {
+ calRepeatUntil.SetTimeLocalL( TTime( dtUntil ) );
+ }
+ aRRule.SetUntil( calRepeatUntil );
+ }
+ TRACE_EXIT_POINT;
+ }
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::DurationGreaterThanRepeatIntervalError
+// Returns ETrue if the duration of instances of the meeting is greater than
+// the repeat period of the series, EFalse otherwise.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::DurationGreaterThanRepeatIntervalError()
+ {
+ TRACE_ENTRY_POINT;
+ TBool isError = EFalse;
+ switch( Edited().RepeatType() )
+ {
+ case ERepeatDaily:
+ case ERepeatWorkdays:
+ {
+ TTimeIntervalDays durDays = Edited().EndDateTime().DaysFrom( Edited().StartDateTime() );
+ isError = durDays >= TTimeIntervalDays(1);
+ break;
+ }
+ case ERepeatWeekly:
+ {
+ TTimeIntervalDays durDays = Edited().EndDateTime().DaysFrom( Edited().StartDateTime() );
+ isError = durDays >= TTimeIntervalDays(7);
+ break;
+ }
+ case ERepeatBiWeekly:
+ {
+ TTimeIntervalDays durDays = Edited().EndDateTime().DaysFrom( Edited().StartDateTime() );
+ isError = durDays >= TTimeIntervalDays(14);
+ break;
+ }
+ case ERepeatMonthly:
+ {
+ TTimeIntervalMonths durMonths = Edited().EndDateTime().MonthsFrom( Edited().StartDateTime() );
+ isError = durMonths >= TTimeIntervalMonths(1);
+ break;
+ }
+ case ERepeatYearly:
+ {
+ TTimeIntervalYears durYears = Edited().EndDateTime().YearsFrom( Edited().StartDateTime() );
+ isError = durYears >= TTimeIntervalYears(1);
+ break;
+ }
+ case ERepeatOther:
+ {
+ isError = EFalse;
+ break;
+ }
+ default:
+ // Not repeating, no error
+ isError = EFalse;
+ break;
+ }
+ TRACE_EXIT_POINT;
+ return isError;
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::CheckErrorsForThisAndAllL
+// Check for errors in the form. This function should only be called when the
+// user has decided they want to edit "This and all" from a prompt, or when the
+// entry is not repeating.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+CCalenEditorDataHandler::TError CCalenEditorDataHandler::CheckErrorsForThisAndAllL()
+ {
+ TRACE_ENTRY_POINT;
+
+ // From UI spec:
+ // 5 checks is specified, only one not needed in this phase is 2.1
+
+ const TTime start = Edited().StartDateTime();
+ const TTime end = Edited().EndDateTime();
+
+ // 1) Check that entry doesn't end earlier than it starts
+ if ( end < start )
+ {
+ TRACE_EXIT_POINT;
+ return CCalenEditorDataHandler::EFormErrStopTimeEarlierThanStartTime;
+ }
+
+ // 2) Repeating entry checks:
+ if ( Edited().IsRepeating() )
+ {
+ // 2.1) Check that repeat until date is a) later than start date (for new notes)
+ // b) not before start date (for existing notes)
+ TTime repeatUntilDay = CalenDateUtils::BeginningOfDay(
+ Edited().RepeatUntilDateTime() );
+
+ TTime repeatStartDay;
+
+ // if new note or old note isnt repeating
+ // edited.repeatUntil date must be greater than edited.start date
+ // else
+ // if IsRepeatRuleEdited or IsStartDateTimeEdited
+ // //(either one above will make a new rule in which edited.startdate is the start date)
+ // edited.repeatUntil must be greater than edited.start date
+ // else
+ // edited.repeatUntil must be greater than start date on disk
+
+ TCalRRule rrule;
+ if( IsCreatingNew() ||
+ !Entry().GetRRuleL(rrule) ||
+ IsRepeatRuleEdited() ||
+ IsStartDateTimeEdited() )
+ {
+ // We don't have an rrule so we can't get the rrule start date,
+ // or user has edited a field that will cause new start date to be used in the new rule.
+ // Use the edited entry's start date.
+ repeatStartDay = CalenDateUtils::BeginningOfDay( start );
+ }
+ else
+ {
+ // original rrule is valid and new rule will not be created
+ repeatStartDay = CalenDateUtils::BeginningOfDay( rrule.DtStart().TimeLocalL() );
+ }
+
+ if ( repeatUntilDay <= repeatStartDay )
+ {
+ TRACE_EXIT_POINT;
+ return CCalenEditorDataHandler::EFormErrRepeatUntilEarlierThanNote;
+ }
+
+ if( DurationGreaterThanRepeatIntervalError() )
+ {
+ TRACE_EXIT_POINT;
+ return CCalenEditorDataHandler::EFormErrDurationGreaterThanRepeatInterval;
+ }
+ // 3) Alarm field checks:
+ TRACE_EXIT_POINT;
+ return CheckAlarmFieldsForErrorsL(ETrue); // user editing the series
+ }
+
+ // 3) Alarm field checks:
+ TRACE_EXIT_POINT;
+ return CheckAlarmFieldsForErrorsL(); // user editing the series
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::CheckErrorsForThisOnlyL
+// Check for errors in the form. This function should only be called when the
+// user has decided they want to edit "This only" from a prompt, or when the
+// entry is an exception.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+CCalenEditorDataHandler::TError CCalenEditorDataHandler::CheckErrorsForThisOnlyL( CCalEntry& /*aParentEntry*/,
+ CCalInstanceView& /*aInstanceView*/ )
+ {
+ TRACE_ENTRY_POINT;
+
+ const TTime start = Edited().StartDateTime();
+ const TTime end = Edited().EndDateTime();
+
+ // Check that entry doesn't end earlier than it starts
+ if ( end < start )
+ {
+ TRACE_EXIT_POINT;
+ return CCalenEditorDataHandler::EFormErrStopTimeEarlierThanStartTime;
+ }
+
+ TError error = CheckForOutOfSequenceL();
+
+ if( error != EFormErrNone )
+ {
+ return error;
+ }
+
+ // Alarm field checks:
+ TRACE_EXIT_POINT;
+ return CheckAlarmFieldsForErrorsL(); // user creating/editing an exception
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::CheckForOutOfSequenceL
+// Checks to see if the instance is being moved out of sequence, relative to
+// the rest of the series.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+CCalenEditorDataHandler::TError CCalenEditorDataHandler::CheckForOutOfSequenceL()
+ {
+ TRACE_ENTRY_POINT;
+ // Only perform the checks when we change the start or end time of the meeting.
+ if( !IsStartDateTimeEdited() && !IsEndDateTimeEdited() )
+ {
+ TRACE_EXIT_POINT;
+ return EFormErrNone;
+ }
+
+ TCalTime prevStart, prevEnd;
+
+ GetPreviousInstanceTimeL( prevStart, prevEnd );
+
+ if( prevStart.TimeLocalL() != Time::NullTTime() )
+ {
+ // Does the exception end on/after prevEnd?
+ if( Edited().StartDateTime() < prevEnd.TimeLocalL() )
+ {
+ // Does the exception start after prevStart?
+ if( Edited().StartDateTime() > prevStart.TimeLocalL() )
+ {
+ TRACE_EXIT_POINT;
+ return EFormErrOverlapsExistingInstance;
+ }
+ else
+ {
+ // Does the exception finish after prevStart?
+ if( Edited().EndDateTime() > prevStart.TimeLocalL() )
+ {
+ TRACE_EXIT_POINT;
+ return EFormErrOverlapsExistingInstance;
+ }
+ else
+ {
+ TRACE_EXIT_POINT;
+ return EFormErrOutOfSequence;
+ }
+ }
+ }
+
+ // Does the exception start on the same day as prevStart?
+ if( CalenDateUtils::OnSameDay( Edited().StartDateTime(), prevStart.TimeLocalL() ) )
+ {
+ TRACE_EXIT_POINT;
+ return EFormErrInstanceAlreadyExistsOnThisDay;
+ }
+ }
+
+ TCalTime nextStart, nextEnd;
+
+ GetNextInstanceTimeL( nextStart, nextEnd );
+
+ if( nextStart.TimeLocalL() != Time::NullTTime() )
+ {
+ // Does the exception finish on/before nextStart?
+ if( Edited().EndDateTime() > nextStart.TimeLocalL() )
+ {
+ // Does the exception finish before nextFinish?
+ if( Edited().EndDateTime() < nextEnd.TimeLocalL() )
+ {
+ TRACE_EXIT_POINT;
+ return EFormErrOverlapsExistingInstance;
+ }
+ else
+ {
+ // Does the exception start before nextFinish?
+ if( Edited().StartDateTime() < nextEnd.TimeLocalL() )
+ {
+ TRACE_EXIT_POINT;
+ return EFormErrOverlapsExistingInstance;
+ }
+ else
+ {
+ TRACE_EXIT_POINT;
+ return EFormErrOutOfSequence;
+ }
+ }
+ }
+
+ // Does the exception start on the same day as nextStart?
+ if( CalenDateUtils::OnSameDay( Edited().StartDateTime(), nextStart.TimeLocalL() ) )
+ {
+ TRACE_EXIT_POINT;
+ return EFormErrInstanceAlreadyExistsOnThisDay;
+ }
+ }
+
+ // Does the series have any rdates
+ RArray<TCalTime> rDateArray;
+ CleanupClosePushL( rDateArray );
+ Entry().GetRDatesL( rDateArray );
+ TInt rDateCount = rDateArray.Count();
+
+ if ( rDateCount > 0 )
+ {
+ // If the series has rdates, check that the exception
+ // does not overlap or start on the same day
+ const TTime& startDateTime = Edited().StartDateTime();
+ const TTime& endDateTime = Edited().EndDateTime();
+ TTimeIntervalMinutes duration;
+ startDateTime.MinutesFrom( endDateTime, duration );
+
+ for ( TInt index = 0; index < rDateCount; index++ )
+ {
+ const TTime& rDate = rDateArray[ index ].TimeLocalL();
+
+ if ( !CalenDateUtils::OnSameDay( Original().StartDateTime(), rDate ) )
+ {
+ // Does the exception start or end on the same day as a rdate.
+ if ( CalenDateUtils::OnSameDay( startDateTime, rDate ) )
+ {
+ CleanupStack::PopAndDestroy(); // rDateArray
+ TRACE_EXIT_POINT;
+ return EFormErrInstanceAlreadyExistsOnThisDay;
+ }
+
+ // Does the exception overlap an rdate?
+ TTime rDateEnd = rDate + duration;
+ if ( endDateTime > rDateEnd && startDateTime < rDate )
+ {
+ CleanupStack::PopAndDestroy(); // rDateArray
+ TRACE_EXIT_POINT;
+ return EFormErrOverlapsExistingInstance;
+ }
+ }
+ }
+ }
+
+ CleanupStack::PopAndDestroy(); // rDateArray
+ TRACE_EXIT_POINT;
+ return EFormErrNone;
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::GetPreviousInstanceTimeL
+// Gets the start and end times of the previous instance. Sets both to a null
+// time if there is no instance before the current one
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCalenEditorDataHandler::GetPreviousInstanceTimeL( TCalTime& aPreviousStartTime,
+ TCalTime& aPreviousEndTime )
+ {
+ TRACE_ENTRY_POINT;
+
+ aPreviousStartTime.SetTimeLocalL( Time::NullTTime() );
+ aPreviousEndTime.SetTimeLocalL( Time::NullTTime() );
+
+ RPointerArray<CCalEntry> entries;
+ CleanupResetAndDestroyPushL(entries);
+
+ EntryViewL().FetchL( Entry().UidL(), entries );
+
+ TCalTime currentInstanceDate = Entry().RecurrenceIdL();
+ if( currentInstanceDate.TimeUtcL() == Time::NullTTime() )
+ {
+ // We must be creating a new exception. Calculate the recurrence id.
+ TTimeIntervalMinutes timeOfDay = CalenDateUtils::TimeOfDay( entries[0]->StartTimeL().TimeLocalL() );
+ TTime beginningOfDay = CalenDateUtils::BeginningOfDay( InstanceDateTime().TimeLocalL() );
+ currentInstanceDate.SetTimeLocalL( beginningOfDay + timeOfDay );
+ }
+
+ TCalRRule rrule;
+ if( entries[0]->GetRRuleL(rrule) )
+ {
+ TCalenRepeatIndex repeatIndex = CalenNoteDataUtil::RepeatIndexL( *entries[0] );
+ TBool keepLooking = ETrue;
+ RArray<TCalTime> exdates;
+ CleanupClosePushL( exdates );
+ entries[0]->GetExceptionDatesL(exdates);
+
+ // Needed for case ERepeatOther
+ TCalRRule::TType type( rrule.Type() );
+ TInt repeatInterval( rrule.Interval() );
+ TCalTime start, end;
+ TTime previousInstanceTime = Time::NullTTime();
+
+ while( keepLooking )
+ {
+ // Subtract the repeat interval of the parent.
+ switch( repeatIndex )
+ {
+ case ERepeatDaily:
+ currentInstanceDate.SetTimeLocalL( currentInstanceDate.TimeLocalL()-TTimeIntervalDays(1) );
+ break;
+ case ERepeatWeekly:
+ currentInstanceDate.SetTimeLocalL( currentInstanceDate.TimeLocalL()-TTimeIntervalDays(7) );
+ break;
+ case ERepeatBiWeekly:
+ currentInstanceDate.SetTimeLocalL( currentInstanceDate.TimeLocalL()-TTimeIntervalDays(14) );
+ break;
+ case ERepeatMonthly:
+ currentInstanceDate.SetTimeLocalL( currentInstanceDate.TimeLocalL()-TTimeIntervalMonths(1) );
+ break;
+ case ERepeatYearly:
+ currentInstanceDate.SetTimeLocalL( currentInstanceDate.TimeLocalL()-TTimeIntervalYears(1) );
+ break;
+ case ERepeatWorkdays:
+ currentInstanceDate.SetTimeLocalL(currentInstanceDate.TimeLocalL()-TTimeIntervalDays(7) );
+ case ERepeatOther:
+ /* This case includes repeating events like: 3 days every week, 3rd weekday of everymonth
+ that does not fall in any cases above but still have repeating rule*/
+
+ // Check if the current entry being edited is child entry
+ // If yes, then put back the child entry time to currentInstanceDate
+ if(Entry().RecurrenceIdL().TimeUtcL() != Time::NullTTime() )
+ {
+ TTimeIntervalMinutes timeOfDay = CalenDateUtils::TimeOfDay( Entry().StartTimeL().TimeLocalL() );
+ TTime beginningOfDay = CalenDateUtils::BeginningOfDay( InstanceDateTime().TimeLocalL() );
+ currentInstanceDate.SetTimeLocalL( beginningOfDay + timeOfDay );
+ }
+
+ switch( type )
+ {
+ case TCalRRule::EDaily:
+ start.SetTimeLocalL( currentInstanceDate.TimeLocalL()-TTimeIntervalDays(1 * repeatInterval));
+ break;
+ case TCalRRule::EWeekly:
+ start.SetTimeLocalL( currentInstanceDate.TimeLocalL()-TTimeIntervalDays(7 * repeatInterval));
+ break;
+ case TCalRRule::EMonthly:
+ // Add 7 days of buffer to cover the cases were gap b/w two instances of the event
+ // can go beuong 30 days. Ex: Every third wednesday of every month
+ start.SetTimeLocalL( currentInstanceDate.TimeLocalL()-TTimeIntervalMonths(repeatInterval)-TTimeIntervalDays(7 * repeatInterval));
+ break;
+ case TCalRRule::EYearly:
+ // Add 7 days of buffer to cover the cases were gap b/w two instances of the event
+ // can go beuong 365 days. Ex: Every third wednesday of September of every year
+ start.SetTimeLocalL( currentInstanceDate.TimeLocalL()-TTimeIntervalYears(repeatInterval)-TTimeIntervalDays(7 * repeatInterval));
+ break;
+ }
+
+ end.SetTimeLocalL(CalenDateUtils::BeginningOfDay(currentInstanceDate.TimeLocalL()));
+ previousInstanceTime = GetPreviousInstanceForRepeatOtherL(*entries[0], CalCommon::TCalTimeRange( start, end));
+ currentInstanceDate.SetTimeLocalL( previousInstanceTime);
+ break;
+ default:
+ case ERepeatNotRepeated:
+ keepLooking = EFalse;
+ break;
+ }
+
+ // Is currentInstanceDate before parent dt start?
+ if( currentInstanceDate.TimeLocalL() < entries[0]->StartTimeL().TimeLocalL() )
+ {
+ // There are no instances before the exception
+ keepLooking = EFalse;
+ }
+ else
+ {
+ // Is there an exdate on currentInstanceDate?
+ TBool isExdateOnDay = EFalse;
+ for(TInt i=0; i<exdates.Count(); ++i)
+ {
+ if( exdates[i].TimeLocalL() == currentInstanceDate.TimeLocalL() )
+ {
+ isExdateOnDay = ETrue;
+ // There is an exdate - is there a child associated with the exdate?
+ for(TInt j=1; j<entries.Count(); ++j)
+ {
+ if( entries[j]->RecurrenceIdL().TimeLocalL() == currentInstanceDate.TimeLocalL() )
+ {
+ // This child is the previous instance.
+ aPreviousStartTime = entries[j]->StartTimeL();
+ aPreviousEndTime = entries[j]->EndTimeL();
+ keepLooking = EFalse;
+ }
+ }
+ break;
+ }
+ }
+
+ if( !isExdateOnDay )
+ {
+ // The instance exists and hasn't been deleted or made into an exception.
+ // Use information from the parent to set the start/end times.
+ aPreviousStartTime = currentInstanceDate;
+
+ TTimeIntervalMinutes duration;
+ TTime start = entries[0]->StartTimeL().TimeLocalL();
+ TTime end = entries[0]->EndTimeL().TimeLocalL();
+ end.MinutesFrom( start, duration );
+ aPreviousEndTime.SetTimeLocalL( currentInstanceDate.TimeLocalL() + duration );
+ keepLooking = EFalse;
+ }
+ }
+ }
+ CleanupStack::PopAndDestroy( &exdates );
+ }
+
+ CleanupStack::PopAndDestroy(&entries);
+
+ TRACE_EXIT_POINT;
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::GetNextInstanceTimeL
+// Gets the start and end times of the next instance. Sets both to a null
+// time if there is no instance after the current one.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCalenEditorDataHandler::GetNextInstanceTimeL( TCalTime& aNextStartTime,
+ TCalTime& aNextEndTime )
+ {
+ TRACE_ENTRY_POINT;
+
+ aNextStartTime.SetTimeLocalL( Time::NullTTime() );
+ aNextEndTime.SetTimeLocalL( Time::NullTTime() );
+
+ RPointerArray<CCalEntry> entries;
+ CleanupResetAndDestroyPushL(entries);
+
+ EntryViewL().FetchL( Entry().UidL(), entries );
+
+ TCalTime currentInstanceDate = Entry().RecurrenceIdL();
+ if( currentInstanceDate.TimeUtcL() == Time::NullTTime() )
+ {
+ // We must be creating a new exception. Calculate the recurrence id.
+ TTimeIntervalMinutes timeOfDay = CalenDateUtils::TimeOfDay( entries[0]->StartTimeL().TimeLocalL() );
+ TTime beginningOfDay = CalenDateUtils::BeginningOfDay( InstanceDateTime().TimeLocalL() );
+ currentInstanceDate.SetTimeLocalL( beginningOfDay + timeOfDay );
+ }
+
+ TCalRRule rrule;
+ if( entries[0]->GetRRuleL(rrule) )
+ {
+ TCalenRepeatIndex repeatIndex = CalenNoteDataUtil::RepeatIndexL( *entries[0] );
+ TBool keepLooking = ETrue;
+ RArray<TCalTime> exdates;
+ CleanupClosePushL( exdates );
+ entries[0]->GetExceptionDatesL(exdates);
+
+ // Needed for case ERepeatOther
+ TCalRRule::TType type( rrule.Type() );
+ TInt repeatInterval( rrule.Interval() );
+ TCalTime start, end;
+ TTime nextInstanceTime = Time::NullTTime();
+
+ while( keepLooking )
+ {
+ // Subtract the repeat interval of the parent.
+ switch( repeatIndex )
+ {
+ case ERepeatDaily:
+ currentInstanceDate.SetTimeLocalL( currentInstanceDate.TimeLocalL()+TTimeIntervalDays(1) );
+ break;
+ case ERepeatWeekly:
+ currentInstanceDate.SetTimeLocalL( currentInstanceDate.TimeLocalL()+TTimeIntervalDays(7) );
+ break;
+ case ERepeatBiWeekly:
+ currentInstanceDate.SetTimeLocalL( currentInstanceDate.TimeLocalL()+TTimeIntervalDays(14) );
+ break;
+ case ERepeatMonthly:
+ currentInstanceDate.SetTimeLocalL( currentInstanceDate.TimeLocalL()+TTimeIntervalMonths(1) );
+ break;
+ case ERepeatYearly:
+ currentInstanceDate.SetTimeLocalL( currentInstanceDate.TimeLocalL()+TTimeIntervalYears(1) );
+ break;
+ case ERepeatWorkdays:
+ currentInstanceDate.SetTimeLocalL(currentInstanceDate.TimeLocalL()+TTimeIntervalDays(7) );
+ break;
+ case ERepeatOther:
+ {
+ /* This case includes repeating events like: 3 days every week, 3rd weekday of everymonth
+ that does not fall in any cases above but still have repeating rule*/
+
+ // Check if the current entry being edited is child entry
+ // If yes, then put back the child entry time to currentInstanceDate
+ if(Entry().RecurrenceIdL().TimeUtcL() != Time::NullTTime())
+ {
+ TTimeIntervalMinutes timeOfDay = CalenDateUtils::TimeOfDay( Entry().StartTimeL().TimeLocalL() );
+ TTime beginningOfDay = CalenDateUtils::BeginningOfDay( InstanceDateTime().TimeLocalL() );
+ currentInstanceDate.SetTimeLocalL( beginningOfDay + timeOfDay );
+ }
+ switch( type )
+ {
+ case TCalRRule::EDaily:
+ end.SetTimeLocalL( currentInstanceDate.TimeLocalL()+TTimeIntervalDays(1 * repeatInterval));
+ break;
+ case TCalRRule::EWeekly:
+ end.SetTimeLocalL( currentInstanceDate.TimeLocalL()+TTimeIntervalDays(7 * repeatInterval));
+ break;
+ case TCalRRule::EMonthly:
+ // Add 7 days of buffer to cover the cases were gap b/w two instances of the event
+ // can go beuong 30 days. Ex: Every third wednesday of every month
+ end.SetTimeLocalL( currentInstanceDate.TimeLocalL()+TTimeIntervalMonths(repeatInterval)+TTimeIntervalDays(7 * repeatInterval));
+ break;
+ case TCalRRule::EYearly:
+ // Add 7 days of buffer to cover the cases were gap b/w two instances of the event
+ // can go beuong 365 days. Ex: Every third wednesday of September of every year
+ end.SetTimeLocalL( currentInstanceDate.TimeLocalL()+TTimeIntervalYears(repeatInterval)+TTimeIntervalDays(7 * repeatInterval));
+ break;
+ }
+
+ start.SetTimeLocalL(CalenDateUtils::BeginningOfDay(currentInstanceDate.TimeLocalL()+TTimeIntervalDays(1)));
+
+ nextInstanceTime = GetNextInstanceForRepeatOtherL(*entries[0], CalCommon::TCalTimeRange( start, end));
+ currentInstanceDate.SetTimeLocalL( nextInstanceTime);
+ break;
+ }
+ case ERepeatNotRepeated:
+ keepLooking = EFalse;
+ break;
+ default:
+ break;
+ }
+
+ // Is currentInstanceDate after parent dt end?
+ if( currentInstanceDate.TimeLocalL() > rrule.Until().TimeLocalL() )
+ {
+ // There are no instances before the exception
+ keepLooking = EFalse;
+ }
+ else
+ {
+ // Is there an exdate on currentInstanceDate?
+ TBool isExdateOnDay = EFalse;
+ for(TInt i=0; i<exdates.Count(); ++i)
+ {
+ if( exdates[i].TimeLocalL() == currentInstanceDate.TimeLocalL() )
+ {
+ isExdateOnDay = ETrue;
+ // There is an exdate - is there a child associated with the exdate?
+ for(TInt j=1; j<entries.Count(); ++j)
+ {
+ if( entries[j]->RecurrenceIdL().TimeLocalL() == currentInstanceDate.TimeLocalL() )
+ {
+ // This child is the previous instance.
+ aNextStartTime = entries[j]->StartTimeL();
+ aNextEndTime = entries[j]->EndTimeL();
+ keepLooking = EFalse;
+ }
+ }
+ break;
+ }
+ }
+
+ if( !isExdateOnDay )
+ {
+ // The instance exists and hasn't been deleted or made into an exception.
+ // Use information from the parent to set the start/end times.
+ aNextStartTime = currentInstanceDate;
+
+ TTimeIntervalMinutes duration;
+ TTime start = entries[0]->StartTimeL().TimeLocalL();
+ TTime end = entries[0]->EndTimeL().TimeLocalL();
+ end.MinutesFrom( start, duration );
+ aNextEndTime.SetTimeLocalL( currentInstanceDate.TimeLocalL() + duration );
+ keepLooking = EFalse;
+ }
+ }
+ }
+ CleanupStack::PopAndDestroy( &exdates );
+ }
+
+ CleanupStack::PopAndDestroy(&entries);
+
+ TRACE_EXIT_POINT;
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::CheckAlarmFieldsForErrorsL
+// Check the alarm fields for errors. Returns the error if found, or
+// EFormErrNone if no error found.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+CCalenEditorDataHandler::TError CCalenEditorDataHandler::CheckAlarmFieldsForErrorsL(TBool aSeries)
+ {
+ TRACE_ENTRY_POINT;
+
+ TError error = EFormErrNone;
+ // If alarm not active, no check
+ if ( Edited().IsAlarmActivated() )
+ {
+ TTime alarm = Edited().AlarmDateTime();
+ TTime startTime = Edited().StartDateTime();
+ TTime now(Time::NullTTime());
+ now.HomeTime();
+
+ if(IsAlarmInAcceptablePeriod(error, alarm, startTime))
+ {
+ // ask form (not iEntry) if it is repeating
+ // if we launched an old exception, then form has no repeat field
+ // if creating a new exception, then form has repeat field
+ TBool EventIsInFuture = (IsTimedEntry() && (startTime > now)) ||
+ (!IsTimedEntry() && (startTime.DaysFrom(now) >= TTimeIntervalDays(0)));
+ if( !aSeries && (alarm < now) && ( iEdited->EntryType()!=CCalEntry::EAnniv ) )
+ {
+ // dont let non-repeating future entries have alarms in past
+ error = EFormErrAlarmTimePast;
+ }
+ /* otherwise, save alarm to past:
+ * new/old non-repeating & in past
+ * repeating new/old repeating in past/future
+ */
+ }
+ }
+
+ TRACE_EXIT_POINT;
+ return error;
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::IsAlarmInAcceptablePeriod
+// Check alarm time validity
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::IsAlarmInAcceptablePeriod(TError& aError,
+const TTime& aAlarmTime, const TTime& aStartTime) const
+ {
+ TRACE_ENTRY_POINT;
+
+ TTime upperLimit = IsTimedEntry() ?
+ aStartTime :
+ CalenDateUtils::BeginningOfDay(aStartTime) + TTimeIntervalDays(1);
+ TTime lowerLimit = aStartTime - TTimeIntervalDays(31);
+ TBool acceptable = ETrue;
+ if(aAlarmTime < lowerLimit)
+ {
+ acceptable = EFalse;
+ aError = EFormErrAlarmDateTooManyDaysBeforeNote;
+ }
+ else if(aAlarmTime > upperLimit)
+ {
+ acceptable = EFalse;
+ aError = EFormErrAlarmTimeLaterThanNote;
+ }
+
+ TRACE_EXIT_POINT;
+ return acceptable;
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::ForceValidValuesL
+// Force the form to use valid values. This function gets called when the user
+// forces the application to exit, for example by pressing the off button.
+// We attempt to save as much data as possible from the form.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCalenEditorDataHandler::ForceValidValuesL( CalCommon::TRecurrenceRange aRepeatTarget )
+ {
+ TRACE_ENTRY_POINT;
+
+ // Checks and valid values are
+ // from S60 Calendar UI spec, chapter 4.6.4.1 Exiting Note Editor:
+
+ // We modify values as we go, thus we can't pre-read fields.
+ // E.g. when start time is needed in check, it should be always read
+ // from model, because previous check might have modified it.
+
+ // 2) if ends earlier than starts
+ if ( Edited().EndDateTime() < Edited().StartDateTime() )
+ {
+ // a) (for new entry) set end time equal to start time
+ if ( IsCreatingNew() )
+ {
+ Edited().SetEndDateTimeL( Edited().StartDateTime() );
+ }
+ // b) (for existing entries) replace with original end time
+ else
+ {
+ Edited().SetEndDateTimeL( Original().EndDateTime() );
+ // if still wrong, replace start time also
+ Edited().SetStartDateTimeL( Original().StartDateTime() );
+ }
+ } // END end < start check
+
+ // 1) Alarm validation
+ if ( Edited().IsAlarmActivated() )
+ {
+ TTime now;
+ now.HomeTime();
+
+ // Note: all three checks are done for each alarm.
+ // Alarm time is read always again, because modifications are done after each check
+
+ // 1.1) a) if alarm more than 31 days before start, alarm is set 31 days before start
+ // b) (for todos) - "" - before due date
+ TTime maxAlarmBeforeStart = Edited().StartDateTime() - TTimeIntervalDays( 31 );
+ if ( Edited().AlarmDateTime() < maxAlarmBeforeStart )
+ {
+ Edited().SetAlarmDateTimeL( maxAlarmBeforeStart );
+ }
+
+ // 1.2) a) (meetings) if alarm later than start, set it to default alarm time
+ // b) (for todos & annivs) - "" - later than due date
+ TTime atLatest = Edited().StartDateTime();
+ if(!IsTimedEntry())
+ {
+ atLatest += TTimeIntervalDays(1);
+ atLatest -= TTimeIntervalSeconds(1);
+ // at Latest for ToDo/Anniv would be DD @ 23:59:59
+ }
+ if( Edited().AlarmDateTime() > atLatest )
+ {
+ SetDefaultAlarmDateTimeL();
+ }
+
+ // 1.3) if alarm is set to passed time,
+ if ( Edited().AlarmDateTime() < now )
+ {
+ // a) it is set off for
+ // - new/old NON-REPEATING entries
+ if (!Edited().IsRepeating() && Edited().EntryType() != CCalEntry::EAnniv )
+ {
+ Edited().SetAlarmOffL();
+ }
+ // b) (for existing entries) it is saved, unless it has failed 1.1 or 1.2
+ else
+ {
+ // keep, if it is repeating entry, since repeating entries
+ // can have alarms in past
+ }
+ }
+ } // END alarm checks
+
+ // 3) Repeat rule checks
+ if ( Edited().IsRepeating() )
+ {
+ // if repeating note's repeat until date
+ // a) (for new entries) isn't one day later than start date
+ // b) (for existing entries) is before start date
+ // set it to one year later from start date
+ TTime repeatUntilDay = CalenDateUtils::BeginningOfDay(
+ Edited().RepeatUntilDateTime() );
+ TTime startDay = CalenDateUtils::BeginningOfDay( Edited().StartDateTime() );
+ if ( ( IsCreatingNew() && repeatUntilDay <= startDay) ||
+ (! IsCreatingNew() && repeatUntilDay < startDay) )
+ {
+ Edited().SetRepeatUntilDateTimeL( startDay + TTimeIntervalYears(1) );
+ }
+ }
+
+ // 4) if due date of todo is passed or invalid, save it with entered date
+ // no operation (this is just clarification in UI spec
+
+
+ // 5) Check for out of sequence for exceptions
+ // 6) Check for duration > rpt interval for series
+
+ if( aRepeatTarget == CalCommon::EThisOnly )
+ {
+ TError error = CheckForOutOfSequenceL();
+
+ if( error != EFormErrNone )
+ {
+ // Revert start/end times
+ Edited().SetStartDateTimeL( Original().StartDateTime() );
+ Edited().SetEndDateTimeL( Original().EndDateTime() );
+ }
+ }
+ else if( aRepeatTarget == CalCommon::EThisAndAll )
+ {
+ if( DurationGreaterThanRepeatIntervalError() )
+ {
+ // Revert start/end times
+ Edited().SetStartDateTimeL( Original().StartDateTime() );
+ Edited().SetEndDateTimeL( Original().EndDateTime() );
+ }
+ }
+
+ TRACE_EXIT_POINT;
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::IsOldEntry
+// Returns ETrue if the entry was already created previously so that
+// we are now editing it, returns EFalse otherwise.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::IsOldEntry()
+ {
+ TRACE_ENTRY_POINT;
+
+ TRACE_EXIT_POINT;
+ return !IsCreatingNew();
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::AreTextFieldsEmptyL
+// Returns ETrue if summary && location && description text fields are all empty
+// Returns EFalse otherwise.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::AreTextFieldsEmptyL()
+ {
+ TRACE_ENTRY_POINT;
+
+ // We have to consider texts empty, if only summary is empty, in case
+ // location is not supported, because location can still exists in database.
+ TBool summaryAndDescriptionEmpty = CalenAgendaUtils::IsEmptyText( iEdited->Summary() ) &&
+ CalenAgendaUtils::IsEmptyText( iEdited->Description() );
+
+ if(LocationEnabledInUiL())
+ {
+ TRACE_EXIT_POINT;
+ return summaryAndDescriptionEmpty && CalenAgendaUtils::IsEmptyText( iEdited->Location() );
+ }
+
+ TRACE_EXIT_POINT;
+
+ return summaryAndDescriptionEmpty; // and location is empty implicitly
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::AreTextFieldsClearedL
+// Returns ETrue if the user cleared the text in the location and summary fields.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::AreTextFieldsClearedL()
+ {
+ TRACE_ENTRY_POINT;
+
+ if ( CalenAgendaUtils::IsEmptyText( iEdited->Summary() ) &&
+ CalenAgendaUtils::IsEmptyText( iEdited->Description() ) )
+ {
+ if ( LocationEnabledInUiL() )
+ {
+ if ( CalenAgendaUtils::IsEmptyText( iEdited->Location() ) )
+ {
+ if ( IsSummaryEmptied() || IsDescriptionEmptied() || IsLocationEmptied() )
+ {
+ TRACE_EXIT_POINT;
+ return ETrue;
+ }
+ }
+ }
+
+ else if ( IsSummaryEmptied() || IsDescriptionEmptied() )
+ {
+ TRACE_EXIT_POINT;
+ return ETrue;
+ }
+ }
+
+ TRACE_EXIT_POINT;
+
+ return EFalse;
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::IsDescriptionEmptied
+// Returns ETrue, the description was not empty in original && is empty
+// in the edited note
+// Returns EFalse, otherwise
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+TBool CCalenEditorDataHandler::IsDescriptionEmptied()
+ {
+ TRACE_ENTRY_POINT;
+
+ if( !CalenAgendaUtils::IsEmptyText( iOriginal->Description() ) &&
+ CalenAgendaUtils::IsEmptyText( iEdited->Description() ) )
+ {
+ TRACE_EXIT_POINT;
+ return ETrue;
+ }
+
+ TRACE_EXIT_POINT;
+
+ return EFalse;
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::IsSummaryEmptied
+// Returns ETrue, the summary was not empty in original && is empty
+// in the edited note
+// Returns EFalse, otherwise
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+TBool CCalenEditorDataHandler::IsSummaryEmptied()
+ {
+ TRACE_ENTRY_POINT;
+
+ if( !CalenAgendaUtils::IsEmptyText( iOriginal->Summary() ) &&
+ CalenAgendaUtils::IsEmptyText( iEdited->Summary() ) )
+ {
+ TRACE_EXIT_POINT;
+ return ETrue;
+ }
+
+ TRACE_EXIT_POINT;
+ return EFalse;
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::IsLocationEmptied
+// Returns ETrue, the summary was not empty in original && is empty
+// in the edited note
+// Returns EFalse, otherwise
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+TBool CCalenEditorDataHandler::IsLocationEmptied()
+ {
+ TRACE_ENTRY_POINT;
+
+ if( !CalenAgendaUtils::IsEmptyText( iOriginal->Location() ) &&
+ CalenAgendaUtils::IsEmptyText( iEdited->Location() ) )
+ {
+ TRACE_EXIT_POINT;
+ return ETrue;
+ }
+
+ TRACE_EXIT_POINT;
+ return EFalse;
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::IsEntryTypeEdited
+// Returns ETrue if the 'Entry Type' is edited, EFalse otherwise.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::IsEntryTypeEdited()
+ {
+ TRACE_ENTRY_POINT;
+
+ TRACE_EXIT_POINT;
+ return iOriginal->EntryType() != iEdited->EntryType();
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::IsStartDateTimeEdited
+// Returns ETrue if the start date/time has been edited, EFalse otherwise.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::IsStartDateTimeEdited()
+ {
+ TRACE_ENTRY_POINT;
+
+ TBool isEdited = EFalse;
+
+ TTime orgTTime = iOriginal->StartDateTime();
+ TTime editedTTime = iEdited->StartDateTime();
+
+ // Get TDateTime of Original & Edited entries.
+ TDateTime orgDT = orgTTime.DateTime();
+ TDateTime editedDT = editedTTime.DateTime();
+
+ if( !IsTimedEntry() && IsCreatingNew() )
+ {
+ // For non-timed event,on while creating new entry.
+ // check for only Date field change only.
+ if( orgDT.Day() != editedDT.Day() ||
+ orgDT.Month() != editedDT.Month() ||
+ orgDT.Year() != editedDT.Year() )
+ {
+ isEdited = ETrue;
+ }
+ }
+ else
+ {
+
+ // For timed entry, check for Entry Date/Time Changes
+ if( orgTTime != editedTTime )
+ {
+ isEdited = ETrue;
+ }
+ }
+
+ TRACE_EXIT_POINT;
+ return isEdited;
+
+ //return iOriginal->StartDateTime() != iEdited->StartDateTime();
+
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::IsEndDateTimeEdited
+// Returns ETrue if the end date/time has been edited, EFalse otherwise.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::IsEndDateTimeEdited()
+ {
+ TRACE_ENTRY_POINT;
+ TBool isEdited = EFalse;
+
+ TTime orgTTime = iOriginal->EndDateTime();
+ TTime editedTTime = iEdited->EndDateTime();
+
+ // Get TDateTime of Original & Edited entries.
+ TDateTime orgDT = orgTTime.DateTime();
+ TDateTime editedDT = editedTTime.DateTime();
+
+ if( !IsTimedEntry() && IsCreatingNew() )
+ {
+
+ // For non-timed event, check for only Date field change.
+ // No need to check for Entry time change.
+ if( orgDT.Day() != editedDT.Day() ||
+ orgDT.Month() != editedDT.Month() ||
+ orgDT.Year() != editedDT.Year() )
+ {
+ isEdited = ETrue;
+ }
+ }
+ else
+ {
+ // For timed entry, check for Entry Date/Time Changes
+ if( orgTTime != editedTTime )
+ {
+ isEdited = ETrue;
+ }
+ }
+
+ TRACE_EXIT_POINT;
+ return isEdited;
+
+ //return iOriginal->EndDateTime() != iEdited->EndDateTime();
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::IsDescriptionEdited
+// Returns ETrue if the description has been modified, EFalse otherwise.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::IsDescriptionEdited()
+ {
+ TRACE_ENTRY_POINT;
+
+ TRACE_EXIT_POINT;
+ return iOriginal->Description() != iEdited->Description();
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::IsPriorityEdited
+// Returns ETrue if the priotity has been modified, EFalse otherwise.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::IsPriorityEdited()
+ {
+ TRACE_ENTRY_POINT;
+
+ TRACE_EXIT_POINT;
+ return iOriginal->Priority() != iEdited->Priority();
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::IsCalendarEditedL
+// Returns ETrue if the calendar filed has been edited, EFalse otherwise.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::IsCalendarEditedL()
+ {
+ TRACE_ENTRY_POINT;
+
+ TRACE_EXIT_POINT;
+ return iCalendarFieldEdited;
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::IsSummaryEdited
+// Returns ETrue if the summary has been edited, EFalse otherwise.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::IsSummaryEdited()
+ {
+ TRACE_ENTRY_POINT;
+
+ // For summary and location, we compare only that part of text
+ // that fits to editor. If it's equal, then we don't go and unnecessarily
+ // truncate existing data.
+ TRACE_EXIT_POINT;
+ return ( iOriginal->Summary().Left( iMaxTextEditorLength )
+ != iEdited->Summary().Left( iMaxTextEditorLength ) );
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::IsLocationEdited
+// Returns ETrue if the location has been edited, EFalse otherwise.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::IsLocationEdited()
+ {
+ TRACE_ENTRY_POINT;
+
+ // For summary and location, we compare only that part of text
+ // that fits to editor. If it's equal, then we don't go and unnecessarily
+ // truncate existing data.
+ TRACE_EXIT_POINT;
+ return ( iOriginal->Location().Left( iMaxTextEditorLength )
+ != iEdited->Location().Left( iMaxTextEditorLength ) );
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::IsAlarmEditedL
+// Returns ETrue if the alarm has been edited, EFalse otherwise.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::IsAlarmEditedL()
+ {
+ TRACE_ENTRY_POINT;
+
+ if ( iOriginal->IsAlarmActivated() && iEdited->IsAlarmActivated() )
+ {
+ // The alarm must be flagged as changed if the interval between the entry start
+ // and the alarm is different. (We can't just compare alarm times directly because
+ // the start date of the entry may have changed.)
+ TTimeIntervalMinutes origOffset, editedOffset;
+
+ User::LeaveIfError( iOriginal->AlarmDateTime().MinutesFrom( iOriginal->StartDateTime(), origOffset ) );
+ User::LeaveIfError( iEdited->AlarmDateTime().MinutesFrom( iEdited->StartDateTime(), editedOffset ) );
+
+ TBool alarmTimeChanged = origOffset != editedOffset;
+
+ TRACE_EXIT_POINT;
+ return alarmTimeChanged;
+ }
+ else
+ {
+ TBool statusChanged = iOriginal->IsAlarmActivated() != iEdited->IsAlarmActivated();
+
+ TRACE_EXIT_POINT;
+ return statusChanged;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::IsRepeatRuleEdited
+// Returns ETrue if the repeat rule has been edited, EFalse otherwise.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::IsRepeatRuleEdited()
+ {
+ TRACE_ENTRY_POINT;
+
+ if ( iOriginal->IsRepeating() && iEdited->IsRepeating() )
+ {
+ TBool repeatTypeChanged = iOriginal->RepeatType() != iEdited->RepeatType();
+ TBool untilDateChanged = iOriginal->RepeatUntilDateTime() != iEdited->RepeatUntilDateTime();
+
+ TRACE_EXIT_POINT;
+ return repeatTypeChanged || untilDateChanged;
+ }
+ else
+ {
+ TBool statusChanged = iOriginal->IsRepeating() != iEdited->IsRepeating();
+
+ TRACE_EXIT_POINT;
+ return statusChanged;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::LocationEnabledInUiL
+// Returns ETrue if the location is a valid field for this type of entry
+// (i.e. meetings & reminders only), EFalse otherwise.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::LocationEnabledInUiL()
+ {
+ TRACE_ENTRY_POINT;
+
+ // Location is enabled for timed entries (i.e. an appointment or a
+ // reminder)
+ TRACE_EXIT_POINT;
+ return IsTimedEntry();
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::IsTimedEntry
+// Returns ETrue if this is a timed entry, EFalse otherwise.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::IsTimedEntry() const
+ {
+ TRACE_ENTRY_POINT;
+
+ TRACE_EXIT_POINT;
+ return IsTimed( iEdited->EntryType() );
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::IsCreatingNew
+// Returns ETrue if the user is creating a new entry, EFalse if the user is
+// editing an existing entry.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::IsCreatingNew() const
+ {
+ TRACE_ENTRY_POINT;
+
+ TRACE_EXIT_POINT;
+ return iIsCreatingNew;
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::IsStartDateChanged
+// Returns ETrue if the start date of the entry has been changed,
+// EFalse otherwise. Note that this function only checks the date,
+// and not the time of day, of the entry.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::IsStartDateChanged()
+ {
+ TRACE_ENTRY_POINT;
+
+ TRACE_EXIT_POINT;
+ return ! CalenDateUtils::OnSameDay( iOriginal->StartDateTime(),
+ iEdited->StartDateTime() );
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::IsAttachmentExists
+// Returns ETrue calendar entry is having attachments
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::IsAttachmentExists()
+ {
+ TRACE_ENTRY_POINT;
+ TBool attachmentExits(EFalse);
+
+ // TODO: Uncomment this when enabling attachment support
+
+ if( (iOriginal->AttachmentCount() != iEdited->AttachmentCount())
+ || iServices.GetAttachmentData()->NumberOfItems() )
+ {
+ attachmentExits = ETrue;
+ }
+
+ TRACE_EXIT_POINT;
+ return attachmentExits;
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::IsEventTypeEdited
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::IsEventTypeEdited()
+ {
+ TRACE_ENTRY_POINT;
+ TBool fieldModified = EFalse;
+
+ // Check EventType field is edited for already saved Entry
+ // For Newly created entry, ignore the EventTypeChange
+ if( (iOriginal->EntryType() != iEdited->EntryType()) && !IsCreatingNew() )
+ {
+ fieldModified = ETrue;
+ }
+
+ TRACE_EXIT_POINT;
+ return fieldModified;
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::AllDayFieldEdited
+// Returns ETrue if `All day event' line has been modified.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::AllDayFieldEdited()
+ {
+ TRACE_ENTRY_POINT;
+ TBool fieldModified = EFalse;
+
+ if( iOriginal->IsAllDayEvent() != iEdited->IsAllDayEvent() )
+ {
+ fieldModified = ETrue;
+ }
+
+ TRACE_EXIT_POINT;
+ return fieldModified;
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::SetDefaultAlarmDateTimeL
+// Sets the alarm to the default value. This function is called after the user
+// forces an exit, e.g. when pressing the power off button.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCalenEditorDataHandler::SetDefaultAlarmDateTimeL()
+ {
+ TRACE_ENTRY_POINT;
+
+ /**
+ * Default alarm time is UI spec logic.
+ * It is important that this is here, because there shouldn't be UI spec logic in CCalenEntryUtil,
+ * only in CCalenEditorDataHandler.
+ *
+ * It is still a bit odd, that other set methods are in CCalenEntryUtil but not here.
+ * Maybe I add wrapper set methods for edited data also in *Handler.
+ * e.g. void SetAlarmOffL() { Edited().SetAlarmOffL(); }
+ *
+ */
+ TTime defaultAlarm;
+
+ if ( IsTimedEntry() )
+ {
+ TTimeIntervalMinutes defaultOffsetM( 15 ); // FIXME: should be read from central repository
+ defaultAlarm = Edited().StartDateTime() - defaultOffsetM;
+ }
+ else
+ {
+ TTimeIntervalHours defaultOffsetH( -8 );
+ defaultAlarm = CalenDateUtils::BeginningOfDay( Edited().EventDateTime() ) - defaultOffsetH;
+ }
+
+ Edited().SetAlarmOnL( defaultAlarm );
+
+ TRACE_EXIT_POINT;
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::CalculateRepeatRuleL
+// Calculates the repeat rule for a given entry.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCalenEditorDataHandler::CalculateRepeatRuleL(
+ const TTime& aStartDateTime,
+ TCalenRepeatIndex aNewRepeatType,
+ const TTime& aRepeatUntil,
+ TCalRRule& aRRule)
+ {
+ TRACE_ENTRY_POINT;
+
+ // FIXME: This is copy-pasted from old implementation.
+ // This should be rewritten with care.
+ //If it ain't broke...?
+ TTime startDateTime = aStartDateTime;
+ TTime repeatUntil = aRepeatUntil;
+
+ TCalRRule origRRule;
+ TBool hasOrigRRule = iEntry.GetRRuleL( origRRule );
+
+ TBool isStartDateSame = CalenDateUtils::OnSameDay(
+ Original().StartDateTime(), Edited().StartDateTime() );
+
+ //
+ // If repeat type is changed, repeat start date
+ // is replaced to the date of "Start date" field.
+ //
+ if ( hasOrigRRule &&
+ isStartDateSame &&
+ aNewRepeatType == Original().RepeatType() )
+ {
+ aRRule = origRRule; // keep the original setting...
+ // until date changed?
+ }
+ else if (aNewRepeatType == ERepeatOther)
+ {
+ // prevRptDef is ALWAYS non-NULL in this block,
+ // because previous note's repeat ALWAYS exists.
+ aRRule = origRRule;
+ TCalTime repeatStart;
+ if ( UseFloatingTimeL() )
+ {
+ repeatStart.SetTimeLocalFloatingL( startDateTime );
+ }
+ else
+ {
+ repeatStart.SetTimeLocalL( startDateTime );
+ }
+ aRRule.SetDtStart( repeatStart );
+ }
+ else
+ {
+ TCalTime repeatSt;
+ if ( UseFloatingTimeL() )
+ {
+ repeatSt.SetTimeLocalFloatingL( startDateTime );
+ }
+ else
+ {
+ repeatSt.SetTimeLocalL( startDateTime );
+ }
+ aRRule.SetDtStart( repeatSt );
+ aRRule.SetInterval( 1 );
+
+ TInt interval(1);
+
+ switch ( aNewRepeatType )
+ {
+ case (ERepeatDaily): // Daily
+ {
+ aRRule.SetType( TCalRRule::EDaily );
+ break;
+ }
+ case (ERepeatWeekly): // Weekly
+ {
+ if (hasOrigRRule && origRRule.Type() == TCalRRule::EDaily &&
+ origRRule.Interval() == 7)
+ {
+ // If old note's repeat is every 7 days,
+ // set repeat to every 7 days to Agenda, NOT every week.
+ //
+ aRRule.SetType( TCalRRule::EDaily );
+ interval = 7;
+ }
+ else
+ {
+ aRRule.SetType( TCalRRule::EWeekly );
+
+ RArray<TDay> dayArray;
+ CleanupClosePushL( dayArray );
+ dayArray.Append( aRRule.DtStart().TimeLocalL().DayNoInWeek() );
+ aRRule.SetByDay( dayArray );
+ CleanupStack::PopAndDestroy( &dayArray );
+ }
+ break;
+ }
+ case (ERepeatBiWeekly): // Bi-weekly
+ {
+ if ( hasOrigRRule && origRRule.Type() == TCalRRule::EDaily &&
+ origRRule.Interval() == 14)
+ {
+ // If old note's repeat is every 14 days,
+ // set repeat to every 14 days to Agenda, NOT every 2 weeks.
+ //
+ aRRule.SetType( TCalRRule::EDaily );
+ interval = 14;
+ }
+ else
+ {
+ aRRule.SetType( TCalRRule::EWeekly );
+ interval = 2;
+
+ RArray<TDay> dayArray;
+ CleanupClosePushL( dayArray );
+ dayArray.Append( aRRule.DtStart().TimeLocalL().DayNoInWeek() );
+ aRRule.SetByDay( dayArray );
+ CleanupStack::PopAndDestroy( &dayArray );
+ }
+ break;
+ }
+ case ERepeatWorkdays:// Weekly
+ {
+ TLocale iLocale;
+ TUint iWorkDays = iLocale.WorkDays();
+ if (hasOrigRRule && origRRule.Type() == TCalRRule::EDaily
+ && origRRule.Interval() == 7)
+ {
+ // If old note's repeat is every 7 days,
+ // set repeat to every 7 days to Agenda, NOT every week.
+ //
+ aRRule.SetType(TCalRRule::EDaily);
+ interval = 7;
+ }
+ else
+ {
+ aRRule.SetType(TCalRRule::EWeekly);
+ RArray<TDay> dayArray;
+ CleanupClosePushL(dayArray);
+ TInt fixedNum = 1;
+ TInt ruleday = 0;
+ for (TInt i =0 ; i < KNoOfDaysInWeek ; i++)
+ {
+ ruleday = fixedNum << i;
+ if(iWorkDays & ruleday)
+ {
+ dayArray.Append((TDay)i);
+ aRRule.SetByDay(dayArray);
+ }
+ }
+ CleanupStack::PopAndDestroy(&dayArray);
+ }
+ break;
+
+ }
+ case (ERepeatMonthly):
+ // Monthly By Position
+ {
+ aRRule.SetType( TCalRRule::EMonthly );
+
+ RArray<TInt> dateArray;
+ CleanupClosePushL( dateArray );
+ dateArray.Append( aRRule.DtStart().TimeLocalL().DayNoInMonth() );
+ aRRule.SetByMonthDay( dateArray );
+ CleanupStack::PopAndDestroy( &dateArray );
+
+ break;
+ }
+ case (ERepeatYearly): // Yearly
+ {
+ // If old note's repeat is every 12 months,
+ // set repeat to every 12 months to Agenda, NOT every year.
+ //
+ if ( hasOrigRRule && origRRule.Type() == TCalRRule::EMonthly &&
+ origRRule.Interval() == 12)
+ {
+ aRRule.SetType( TCalRRule::EMonthly );
+ interval = 12;
+ }
+ else
+ {
+ aRRule.SetType( TCalRRule::EYearly );
+ }
+ break;
+ }
+ default: // Repeat item is "Other"
+ {
+ interval = aRRule.Interval(); // To copy previous note's interval
+ break;
+ }
+ }
+
+ aRRule.SetInterval( interval );
+ }
+
+ // If repeat until is max date of Calendar,
+ // note repeat is set to forever.
+ if ( ! CalenDateUtils::IsValidDay(repeatUntil) || IsForeverDate( repeatUntil ) )
+ {
+ // Set repeat to forever:
+ aRRule.SetCount( 0 );
+ }
+ else
+ {
+ // Change repeatuntil so that hours, minutes, ... are same as in start date
+ TDateTime dtUntil = repeatUntil.DateTime();
+ TDateTime dtStart= iEntry.StartTimeL().TimeLocalL().DateTime();
+
+ dtUntil.Set( dtUntil.Year(), dtUntil.Month(), dtUntil.Day(),
+ dtStart.Hour(), dtStart.Minute(), dtStart.Second(), dtStart.MicroSecond());
+
+ TCalTime calRepeatUntil;
+ if ( UseFloatingTimeL() )
+ {
+ calRepeatUntil.SetTimeLocalFloatingL( TTime( dtUntil ) );
+ }
+ else
+ {
+ calRepeatUntil.SetTimeLocalL( TTime( dtUntil ) );
+ }
+ aRRule.SetUntil( calRepeatUntil );
+ }
+
+ TRACE_EXIT_POINT;
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::SetDefaultNewValuesL
+// Sets the default values when creating a new entry.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCalenEditorDataHandler::SetDefaultNewValuesL(CCalenEntryUtil& aData)
+ {
+ TRACE_ENTRY_POINT;
+
+ // FIXME: I don't know if this method should be needed or not.
+ // It's a bit unclear that if pass entry that is new,
+ // should we set default data in caller (application) or
+ // here.
+ // But to replicate old editor functionality, we set in editor
+ // side
+
+ ASSERT( IsCreatingNew() );
+ // start time and end time are taken from passed entry.
+ // They have to be initialized outside of editors
+
+ // subject, location, description are by default empty
+
+ // repeat rule is by default off
+
+ // alarm is by default off
+
+ // synch value
+ aData.SetSynchTypeL( CCalenEntryUtil::ESynchPrivate );
+
+ // priority
+ aData.SetPriorityL( CCalenEntryUtil::ETodoPriorityNormal );
+
+ TRACE_EXIT_POINT;
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::IsChildL
+// Returns ETrue if the entry is a child, EFalse otherwise.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::IsChildL() const
+ {
+ TRACE_ENTRY_POINT;
+
+ TRACE_EXIT_POINT;
+ return iRecurrenceId.TimeUtcL() != Time::NullTTime();
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::UseFloatingTimeL
+// Returns ETrue if the entry should use floating time, EFalse otherwise.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CCalenEditorDataHandler::UseFloatingTimeL() const
+ {
+ TRACE_ENTRY_POINT;
+
+ // Use floating time based on type
+ // This way we ensure that entries _created_ with Calendar Editors
+ // are consistent regarding time mode.
+ //
+ TRACE_EXIT_POINT;
+ return (! IsTimedEntry()); // use floating time for non-timed entries
+
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::WriteStartAndEndTimesToEntryL
+// Writes the start and end times from the form to the CCalEntry.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CCalenEditorDataHandler::WriteStartAndEndTimesToEntryL( CalCommon::TRecurrenceRange aRepeatTarget )
+ {
+ TRACE_ENTRY_POINT;
+
+ const TBool unDatedTodo=(iEntry.EntryTypeL()==CCalEntry::ETodo) && (iEntry.EndTimeL().TimeLocalL()==Time::NullTTime());
+ const TBool unDatedTodoWithAlarm=unDatedTodo && (Edited().IsAlarmActivated());
+
+ TBool shouldWriteBothTimes =
+ // For new entries
+ IsCreatingNew() ||
+ // When creating exception entry (exception entry's time are read from editors)
+ ( aRepeatTarget != CalCommon::EThisAndAll ) ||
+ // when repeating entry is modified to be non-repeating (entry's times are read from editors)
+ ( Original().IsRepeating() && ! Edited().IsRepeating() );
+
+ if ( shouldWriteBothTimes || IsStartDateTimeEdited() || IsEndDateTimeEdited() || unDatedTodoWithAlarm )
+ {
+
+ TCalTime entryStart;
+ TCalTime entryEnd;
+
+ // 1) Initialize entryStart and entryEnd with original times.
+ // But for todos we need to be careful, because there might not be them originally
+ // In S60 UI, todos don't have starttime, so we use same for both start and end time.
+ if (iEntry.EntryTypeL()==CCalEntry::ETodo)
+ {
+ // if undated todo and it has alarm activated
+ if ((iEntry.EndTimeL().TimeLocalL()==Time::NullTTime()) && (Edited().IsAlarmActivated()))
+ {
+ entryStart.SetTimeLocalL(Edited().EventDateTime());
+ entryEnd.SetTimeLocalL(Edited().EventDateTime());
+ shouldWriteBothTimes=ETrue; // Ensures that times are written later
+ }
+ else
+ {
+ entryStart = iEntry.EndTimeL();
+ entryEnd = iEntry.EndTimeL();
+ }
+ }
+ else
+ {
+ entryStart = iEntry.StartTimeL();
+ entryEnd = iEntry.EndTimeL();
+ }
+
+ // 2) Decide start time
+ if ( shouldWriteBothTimes || IsStartDateTimeEdited() )
+ {
+ TTime newStart = Edited().StartDateTime();
+ TDateTime newStartDT = newStart.DateTime();
+ // Special case:
+ // In case c) only start time (hh:mm) of d) existing a) repeating b) series is edited,
+ // we need to preserve start date (dd.mm.yyy), because start date in editors
+ // is instance's start date.
+ // (Example of problematic cases that brings up, when UI represents
+ // two different concepts in same start date field)
+ // a) repeating b) series is edited c) only start time is edited d) existing
+ if ( Edited().IsRepeating() && aRepeatTarget == CalCommon::EThisAndAll && ! IsStartDateChanged() && ! IsCreatingNew() )
+ {
+ TDateTime oldDt = iEntry.StartTimeL().TimeLocalL().DateTime();
+ TDateTime editDt = newStart.DateTime();
+ newStart = TTime( TDateTime( oldDt.Year(), oldDt.Month(), oldDt.Day(),
+ editDt.Hour(), editDt.Minute(),
+ oldDt.Second(), oldDt.MicroSecond() ) );
+ }
+ else if ( ( Edited().RepeatType() == ERepeatOther ) && IsStartDateChanged() )
+ {
+ // The start time might have been disguised because the entry
+ // consists of an rRule and rDates. The actual start time
+ // needs to be extracted
+ RArray<TCalTime> rDates;
+ CleanupClosePushL( rDates );
+
+ iEntry.GetRDatesL( rDates );
+ if ( rDates.Count() > 0 )
+ {
+ // As we have rDates, check to see if there is an
+ // rRule
+ TCalRRule rRule;
+ if ( iEntry.GetRRuleL( rRule ) )
+ {
+ TTime firstRDate = rDates[ 0 ].TimeLocalL();
+ TTime rRuleStart = iEntry.StartTimeL().TimeLocalL();
+ TTime lastRDate = rDates[ rDates.Count() - 1 ].TimeLocalL();
+ TTimeIntervalMinutes startDateShiftInterval = 0;
+ if ( firstRDate < rRuleStart )
+ {
+ // The first rDate is before the start of the rRule
+ // So adjust the start date accordingly
+
+ User::LeaveIfError( newStart.MinutesFrom( firstRDate, startDateShiftInterval ) );
+ }
+ else
+ {
+ // The start of the rRule comes first
+ User::LeaveIfError( newStart.MinutesFrom( rRuleStart, startDateShiftInterval ) );
+ }
+
+ newStart = rRuleStart + startDateShiftInterval;
+
+ TInt rRuleCount = rRule.Count();
+ rRule.SetCount( rRuleCount );
+
+ TCalTime rRuleDT;
+ if ( UseFloatingTimeL() )
+ {
+ rRuleDT.SetTimeLocalFloatingL( newStart );
+ }
+ else
+ {
+ rRuleDT.SetTimeLocalL( newStart );
+ }
+
+ rRule.SetDtStart( rRuleDT );
+
+ // For rearranging the recurrence pattern for an
+ // entry having rdates
+
+ TInt repeatType = rRule.Type();
+ switch ( repeatType )
+ {
+ case ( TCalRRule::EWeekly ): //For Weekly repeating event
+ {
+ RArray<TDay> dayArray;
+ CleanupClosePushL( dayArray );
+ dayArray.Append( rRule.DtStart().TimeLocalL().DayNoInWeek() );
+ rRule.SetByDay( dayArray );
+ CleanupStack::PopAndDestroy( &dayArray );
+
+ // Adjust the RepeatUntil date
+ ApplyUntilDateToRRuleL( rRule, Edited().RepeatUntilDateTime() );
+ break;
+ }
+ case ( TCalRRule::EMonthly ):// For Monthly repeating event
+ {
+ RArray<TInt> dateArray;
+ CleanupClosePushL( dateArray );
+ dateArray.Append( rRule.DtStart().TimeLocalL().DayNoInMonth() );
+ rRule.SetByMonthDay( dateArray );
+ CleanupStack::PopAndDestroy( &dateArray );
+
+ // Adjust the RepeatUntil date
+ ApplyUntilDateToRRuleL( rRule, Edited().RepeatUntilDateTime() );
+ break;
+ }
+
+ case ( TCalRRule::EDaily ):// For Daily repeating event
+ {
+ TCalRRule curRule;
+ iEntry.GetRRuleL( curRule );
+
+ // Adjust the RepeatUntil date
+ if(lastRDate < curRule.Until().TimeLocalL() )
+ {
+ ApplyUntilDateToRRuleL( rRule, Edited().RepeatUntilDateTime() );
+ }
+
+
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+
+ iEntry.SetRRuleL( rRule );
+ }
+ }
+
+ CleanupStack::PopAndDestroy(); // rDates
+ }
+
+ if ( UseFloatingTimeL() )
+ {
+ entryStart.SetTimeLocalFloatingL( newStart );
+ }
+ else
+ {
+ entryStart.SetTimeLocalL( newStart );
+ }
+ }
+
+ // 3) Decide end time
+ if ( shouldWriteBothTimes || IsEndDateTimeEdited() )
+ {
+ TTime start = Edited().StartDateTime();
+ TTime end = Edited().EndDateTime();
+
+ // For all-day events, we add 24 hours to end date
+ // to make it full day long
+ /*if ( iEntryType == CCalEntry::EEvent)
+ {
+ end += TTimeIntervalDays(1);
+ }*/
+
+ TTimeIntervalMinutes duration;
+ TInt err = end.MinutesFrom( start, duration );
+ ASSERT( err == KErrNone );
+ ASSERT( duration >= TTimeIntervalMinutes(0) );
+
+ if ( UseFloatingTimeL() )
+ {
+ entryEnd.SetTimeLocalFloatingL( entryStart.TimeLocalL() + duration );
+ }
+ else
+ {
+ entryEnd.SetTimeLocalL( entryStart.TimeLocalL() + duration );
+ }
+ }
+
+ // If EntryType is changed as Non-timed/Timed entry, along with StartTime(AND/OR)EndTime,
+ // Both Start/End time TimeMode should be changed accordingly.
+ if ( UseFloatingTimeL() )
+ {
+ entryStart.SetTimeLocalFloatingL( entryStart.TimeLocalL() );
+ entryEnd.SetTimeLocalFloatingL( entryEnd.TimeLocalL() );
+ }
+ else
+ {
+ entryStart.SetTimeLocalL( entryStart.TimeLocalL() );
+ entryEnd.SetTimeLocalL( entryEnd.TimeLocalL() );
+ }
+
+ // Write times to entry
+ iEntry.SetStartAndEndTimeL( entryStart, entryEnd );
+ }
+
+ TRACE_EXIT_POINT;
+ }
+
+//----------------------------------------------------------------------
+// CCalenEditorDataHandler::ResetOriginalDataL
+// Reset original editor data
+// (other items were commented in a header).
+//----------------------------------------------------------------------
+void CCalenEditorDataHandler::ResetOriginalDataL()
+ {
+ TRACE_ENTRY_POINT;
+
+ if(iOriginal)
+ {
+ delete iOriginal;
+ iOriginal=NULL;
+ }
+ iOriginal = CCalenEntryUtil::NewL( iEntry, iInstanceDateTime );
+
+ TRACE_EXIT_POINT;
+ }
+
+//----------------------------------------------------------------------
+// CCalenEditorDataHandler::EntryViewL
+// Temp function to get to work
+// (other items were commented in a header).
+//----------------------------------------------------------------------
+CCalEntryView& CCalenEditorDataHandler::EntryViewL()
+ {
+ TRACE_ENTRY_POINT;
+
+ CCalEntryView* entryView = iServices.EntryViewL(CurrentDbCollectionId());
+
+ TRACE_EXIT_POINT;
+ return *entryView;
+ }
+
+//----------------------------------------------------------------------
+// CCalenEditorDataHandler::InstanceViewL
+// Temp function to get to work
+// (other items were commented in a header).
+//----------------------------------------------------------------------
+CCalInstanceView& CCalenEditorDataHandler::InstanceViewL()
+ {
+ TRACE_ENTRY_POINT;
+
+ CCalInstanceView* instanceView = iServices.InstanceViewL(iCollectionIds);
+
+ TRACE_EXIT_POINT;
+ return *instanceView;
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::GetPreviousInstanceForRepeatOtherL()
+// Returns the time of the previous instance of a particular repeating entry
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TTime CCalenEditorDataHandler::GetPreviousInstanceForRepeatOtherL(CCalEntry& aEntry, const CalCommon::TCalTimeRange& timeRange)
+ {
+ RPointerArray<CCalInstance> allInstances;
+ CleanupResetAndDestroyPushL( allInstances );
+
+ TInt filter;
+ // Get the entry type to be filtered
+ switch(aEntry.EntryTypeL())
+ {
+ case CCalEntry::EAppt:
+ filter = CalCommon::EIncludeAppts;
+ break;
+ case CCalEntry::ETodo:
+ filter = CalCommon::EIncludeCompletedTodos | CalCommon::EIncludeIncompletedTodos;
+ break;
+ case CCalEntry::EEvent:
+ filter = CalCommon::EIncludeEvents;
+ break;
+ case CCalEntry::EReminder:
+ filter = CalCommon::EIncludeReminder;
+ break;
+ case CCalEntry::EAnniv:
+ filter = CalCommon::EIncludeAnnivs;
+ break;
+ default:
+ filter = CalCommon::EIncludeAll;
+ break;
+ };
+
+ iServices.InstanceViewL()->FindInstanceL( allInstances,
+ (CalCommon::TCalViewFilterFlags)filter,
+ timeRange);
+
+ TTime previousTime = Time::NullTTime();
+
+ for( TInt i = allInstances.Count() - 1; i >= 0; i-- )
+ {
+ if( allInstances[i]->Entry().UidL() == aEntry.UidL() )
+ {
+ TRACE_EXIT_POINT;
+ previousTime = allInstances[i]->Time().TimeLocalL();
+ break;
+ }
+ }
+
+ CleanupStack::PopAndDestroy( &allInstances );
+ return previousTime;
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::GetNextInstanceForRepeatOtherL()
+// Returns the time of the next instance of a particular repeating entry
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TTime CCalenEditorDataHandler::GetNextInstanceForRepeatOtherL( CCalEntry& aEntry, const CalCommon::TCalTimeRange& timeRange )
+ {
+ RPointerArray<CCalInstance> allInstances;
+ CleanupResetAndDestroyPushL( allInstances );
+
+ TInt filter;
+ // Get the entry type to be filtered
+ switch( aEntry.EntryTypeL() )
+ {
+ case CCalEntry::EAppt:
+ filter = CalCommon::EIncludeAppts;
+ break;
+ case CCalEntry::ETodo:
+ filter = CalCommon::EIncludeCompletedTodos | CalCommon::EIncludeIncompletedTodos;
+ break;
+ case CCalEntry::EEvent:
+ filter = CalCommon::EIncludeEvents;
+ break;
+ case CCalEntry::EReminder:
+ filter = CalCommon::EIncludeReminder;
+ break;
+ case CCalEntry::EAnniv:
+ filter = CalCommon::EIncludeAnnivs;
+ break;
+ default:
+ filter = CalCommon::EIncludeAll;
+ break;
+ };
+
+ iServices.InstanceViewL()->FindInstanceL( allInstances,
+ ( CalCommon::TCalViewFilterFlags )filter,
+ timeRange);
+
+ TTime nextTime = Time::NullTTime();
+
+ TInt i( 0 );
+ for( ; i < allInstances.Count(); i++ )
+ {
+ if( allInstances[i]->Entry().UidL() == aEntry.UidL() )
+ {
+ TRACE_EXIT_POINT;
+ nextTime = allInstances[i]->Time().TimeLocalL();
+ break;
+ }
+ }
+
+ CleanupStack::PopAndDestroy( &allInstances );
+ return nextTime;
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::SetEntryType
+// add attachments to the entry as ccalattachments
+// -----------------------------------------------------------------------------
+//
+void CCalenEditorDataHandler::SetEntryType( CCalEntry::TType aNewEntryType )
+ {
+ iEntryType = aNewEntryType;
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::AddAttachementsToEntryL
+// add attachments to the entry as ccalattachments
+// -----------------------------------------------------------------------------
+//
+void CCalenEditorDataHandler::AddAttachementsToEntryL()
+ {
+ TRACE_ENTRY_POINT;
+
+ // Get the list of attachments from model and add them to entry
+ RPointerArray<CCalenAttachmentInfo> attachmentInfoList;
+ iServices.GetAttachmentData()->GetAttachmentListL( attachmentInfoList );
+ TInt attachmentCount = iEntry.AttachmentCountL();
+ TInt modelCount = attachmentInfoList.Count();
+
+ if( attachmentCount > 0 && modelCount == 0 )
+ {
+ // This means that all the attachments in the entry have been deleted
+ // by the user. So remove all attchments from the entry
+ for( int index = 0 ; index < attachmentCount ; index++ )
+ {
+ iEntry.DeleteAttachmentL( *iEntry.AttachmentL( 0 ) );
+ }
+
+ // No attachments need to be added at this point, we can simply return.
+ attachmentInfoList.Close();
+ TRACE_EXIT_POINT;
+ return;
+ }
+
+ // Delete all the attachmenst of the entry which are not present in the model
+ TInt currentIndex = 0;
+ for( TInt index=0; index < attachmentCount; index++ )
+ {
+ CCalAttachment* attachment = iEntry.AttachmentL( currentIndex );
+ TBool matchFound = EFalse;
+ for( int modelIndex = 0 ; modelIndex < modelCount ; modelIndex++ )
+ {
+ CCalenAttachmentInfo* attachmentInfo = attachmentInfoList[ modelIndex ];
+ if( attachmentInfo->StoreType() ==
+ CCalenAttachmentInfo::ECalenAttachmentFetchedFromEntry )
+ {
+ // We are only interested in those attachments which have been
+ // fetched from the entry because any newly added attachments
+ // will not yet be updated in the entry
+ RFile attachmentHandle;
+ CleanupClosePushL( attachmentHandle );
+ attachment->FileAttachment()->FetchFileHandleL( attachmentHandle );
+
+ TFileName systemFileName;
+ attachmentHandle.FullName( systemFileName );
+
+ if( systemFileName == attachmentInfo->SystemFileName() )
+ {
+ // There is an attachment in the model which matches the
+ // attachment in the entry. So do not delete it
+ matchFound = ETrue;
+ CleanupStack::PopAndDestroy( &attachmentHandle );
+ break;
+ }
+ CleanupStack::PopAndDestroy( &attachmentHandle );
+ }
+ }
+ if( !matchFound )
+ {
+ // There is no matching attachment in the model. Delete it from entry
+ // This will compress the attachment array. Hence do not increment the currentIndex
+ iEntry.DeleteAttachmentL( *iEntry.AttachmentL( currentIndex ) );
+ }
+ else
+ {
+ // Move to the next attachment
+ currentIndex++;
+ }
+ }
+
+ // Now add the remaining newly added attachments to the entry
+ for( TInt index=0 ; index< modelCount ; index++ )
+ {
+ CCalenAttachmentInfo* attachmentInfo = attachmentInfoList[ index ];
+ if( attachmentInfo->StoreType() == CCalenAttachmentInfo::ECalenNewAttachment )
+ {
+ TParsePtrC fileNameParser(attachmentInfo->FileName());
+ RFile fileHandle;
+ CEikonEnv* eikonEnv = CEikonEnv::Static();
+ RFs& fs = eikonEnv->FsSession();
+ User::LeaveIfError(fs.ShareProtected());
+
+ TInt err = fileHandle.Open( fs, attachmentInfo->FileName(), EFileWrite );
+ if( KErrNone != err )
+ {
+ attachmentInfoList.Close();
+ TRACE_EXIT_POINT;
+ return;
+ }
+ CleanupClosePushL(fileHandle);
+
+ CCalAttachment* attachment = CCalAttachment::NewFileL(fileHandle);
+ CleanupStack::PopAndDestroy(&fileHandle);
+
+ CleanupStack::PushL( attachment );
+ // Sets the label for the attachment
+ attachment->SetLabelL( fileNameParser.NameAndExt() );
+ // Sets mime type for the attachment
+ attachment->SetMimeTypeL( attachmentInfo->DataType().Des8() );
+ attachment->SetAttribute(CCalAttachment::EExportInline);
+ iEntry.AddAttachmentL( *attachment );
+ CleanupStack::Pop( attachment );
+ }
+ }
+ attachmentInfoList.Close();
+
+ TRACE_EXIT_POINT;
+ }
+
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::SetCalendarFieldEditedL
+// Set if calendar is been edited or not with previous and current collection id
+// -----------------------------------------------------------------------------
+//
+void CCalenEditorDataHandler::SetCalendarFieldEditedL(TBool aEdited ,
+ TCalCollectionId aPreviousDbColId,
+ TCalCollectionId aCurrentDbColId)
+ {
+ TRACE_ENTRY_POINT
+ iCalendarFieldEdited = aEdited;
+ iPreviousDbColId = aPreviousDbColId;
+ iCurrentDbColId = aCurrentDbColId;
+ TRACE_EXIT_POINT
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::PreviousDbCollectionId
+// Get previous collection id
+// -----------------------------------------------------------------------------
+//
+TCalCollectionId CCalenEditorDataHandler::PreviousDbCollectionId()
+ {
+ TRACE_ENTRY_POINT
+ TRACE_EXIT_POINT
+ return iPreviousDbColId;
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::CurrentDbCollectionId
+// Get current collection id
+// -----------------------------------------------------------------------------
+//
+TCalCollectionId CCalenEditorDataHandler::CurrentDbCollectionId()
+ {
+ TRACE_ENTRY_POINT
+ TRACE_EXIT_POINT
+ return iCurrentDbColId;
+ }
+
+// -----------------------------------------------------------------------------
+// CCalenEditorDataHandler::CalenInstanceId
+// Returns the instance id.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+const TCalenInstanceId CCalenEditorDataHandler::CalenInstanceId()
+ {
+ TRACE_ENTRY_POINT;
+
+ TRACE_EXIT_POINT;
+
+ return iInstanceId;
+ }
+
+// End of file --Don't remove this.