calendarui/editors/src/CalenEditorDataHandler.cpp
author andy simpson <andrews@symbian.org>
Thu, 02 Sep 2010 15:47:07 +0100
branchRCL_3
changeset 67 1539a383d7b6
parent 27 55d60436f00b
parent 66 bd7edf625bdd
permissions -rw-r--r--
Merge after removal of incorrect RCL_3 drop

/*
* 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:
            {
            TTime startDate = Edited().StartDateTime();
            TTime endDate = Edited().EndDateTime();
            // In case AllDay event end at "12:00am" 24/06/2009. 
            // editor should display EndDate as 23/06/2009.
            if(Edited().IsAllDayEvent())
                {
                if( endDate > startDate )
                    {
                    endDate -= TTimeIntervalDays( 1 );
                    if( endDate < startDate )
                        {
                        endDate = startDate;
                        }
                    }
                }
            TTimeIntervalDays durDays = endDate.DaysFrom( startDate);
            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.