calendarui/editors/src/CalenEntryUpdater.cpp
author Simon Howkins <simonh@symbian.org>
Mon, 22 Nov 2010 16:01:09 +0000
branchRCL_3
changeset 93 d216ae5a8733
parent 66 bd7edf625bdd
child 67 1539a383d7b6
permissions -rw-r--r--
Adjusted to avoid exports, etc, from a top-level bld.inf

/*
* Copyright (c) 2002-2004 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:  ?Description
*
*/

// user includes
#include "CalenEntryUpdater.h"
#include "CleanupResetAndDestroy.h"
#include "calenglobaldata.h"        // CCalenGlobalData
//debug
#include "calendarui_debug.h"

// system includes
#include <calcommon.h>
#include <CalenInterimUtils2.h>
#include <calenagendautils.h>
#include <calendateutils.h>
#include <calentry.h>
#include <calentryview.h>
#include <calinstance.h>
#include <calinstanceview.h>
#include <calrrule.h> 
#include <vwsdef.h>
#include <calencommands.hrh>            // Calendar commands
#include <calencontext.h>
#include <caleninstanceid.h>            // TCalenInstanceId
#include <calenservices.h>
#include <calenactionuiutils.h>

// -----------------------------------------------------------------------------
// CCalenEntryUpdater::NewL()
// Two-phased constructor.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CCalenEntryUpdater* CCalenEntryUpdater::NewL( MCalenServices& aServices ,RArray<TInt>& aCollectionIds )
    {
    TRACE_ENTRY_POINT;

    CCalenEntryUpdater* self = new (ELeave) CCalenEntryUpdater( aServices, aCollectionIds );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );

    TRACE_EXIT_POINT;
    return self;
    }

// -----------------------------------------------------------------------------
// CCalenEntryUpdater::~CCalenEntryUpdater()
// Destructor
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CCalenEntryUpdater::~CCalenEntryUpdater()
    {
    TRACE_ENTRY_POINT;
    TRACE_EXIT_POINT;
    }

// -----------------------------------------------------------------------------
// CCalenEntryUpdater::CCalenEntryUpdater()
// Constructor.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CCalenEntryUpdater::CCalenEntryUpdater( MCalenServices& aServices , RArray<TInt>& aCollectionIds)
: iServices( aServices ) , iCollectionIds(aCollectionIds)
    {
    TRACE_ENTRY_POINT;
    TRACE_EXIT_POINT;
    }

// -----------------------------------------------------------------------------
// CCalenEntryUpdater::ConstructL()
// Leaving construction.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCalenEntryUpdater::ConstructL()
    {
    TRACE_ENTRY_POINT;
    TRACE_EXIT_POINT;
    }

// -----------------------------------------------------------------------------
// CCalenEntryUpdater::DeleteEntryL()
// Delete the given entry from agenda.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCalenEntryUpdater::DeleteEntryL( CCalEntry& aEntry, TCalenInstanceId aInstanceId )
    {
    TRACE_ENTRY_POINT;    

    EntryViewL(aInstanceId.iColId).DeleteL( aEntry );

    TRACE_EXIT_POINT;
    }

// -----------------------------------------------------------------------------
// CCalenEntryUpdater::TryDeleteInstanceWithUiL()
// Attempt to delete the entry, using CCalenCommonUI. Only delete the entry
// using the repeat type defined in aRepeatType.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCalenEntryUpdater::TryDeleteInstanceWithUiL( CCalEntry& aEntry,
                                                    const TCalTime& aInstanceDate,
                                                    CalCommon::TRecurrenceRange aRepeatType,
                                                    MCalenServices& aServices )
    {
    TRACE_ENTRY_POINT;
    DoTryDeleteInstanceWithUiL( aEntry, aInstanceDate, ETrue, aRepeatType, aServices );
    TRACE_EXIT_POINT;
    }

// -----------------------------------------------------------------------------
// CCalenEntryUpdater::TryDeleteInstanceWithUiL()
// Attempt to delete the entry, using CCalenCommonUI to prompt the user whether to
// delete the entire series or just the instance.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCalenEntryUpdater::TryDeleteInstanceWithUiL( CCalEntry& aEntry,
                                                    const TCalTime& aInstanceDate,
                                                    MCalenServices& aServices )
    {
    TRACE_ENTRY_POINT;
    
    DoTryDeleteInstanceWithUiL( aEntry, 
                                            aInstanceDate, 
                                            EFalse, 
                                            CalCommon::EThisAndAll, 
                                            aServices );
    TRACE_EXIT_POINT;
    }

// -----------------------------------------------------------------------------
// CCalenEntryUpdater::DoTryDeleteInstanceWithUiL()
// If aHasRepeatType is ETrue, use aRepeatType to determine whether to delete the
// entire series or just the instance. If aHasRepeatType is EFalse, aRepeatType is
// ignored and the user is prompted to choose.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCalenEntryUpdater::DoTryDeleteInstanceWithUiL( CCalEntry& /*aEntry*/,
                                                      const TCalTime& /*aInstanceDate*/,
                                                      TBool aHasRepeatType,
                                                      CalCommon::TRecurrenceRange aRepeatType,
                                                      MCalenServices& aServices )
    {
    TRACE_ENTRY_POINT;

    if( aHasRepeatType )
        {
        switch( aRepeatType )
            {
            case CalCommon::EThisOnly:
                aServices.IssueCommandL( ECalenDeleteCurrentOccurrence );
                break;
            case CalCommon::EThisAndAll:
                aServices.IssueCommandL( ECalenDeleteSeries );
                break;
            default:
                ASSERT( 0 );
            }
        }
    else
        {
        aServices.IssueCommandL( ECalenDeleteCurrentEntry );
        }
        
    TRACE_EXIT_POINT;
    }

// -----------------------------------------------------------------------------
// CCalenEntryUpdater::UpdateRDatesL()
// Updates the RDates and Exception dates of the given entry.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCalenEntryUpdater::UpdateRDatesL( CCalEntry& aEditedEntry,
                                        CCalEntry& aOrigEntry,
                                        const TCalTime& aOrigInstanceDate )
    {
    TRACE_ENTRY_POINT;

    RArray<TCalTime> rdates;
    CleanupClosePushL( rdates );
    aEditedEntry.GetRDatesL( rdates );

    TBool hasRdates = rdates.Count() > 0;

    // If we've changed the RRule but we already have RDates, get rid of the RDates.
    if( hasRdates )
        {
        TCalRRule editedRule;
        TBool editedHasRule = aEditedEntry.GetRRuleL( editedRule ) 
                                   && editedRule.Type() != TCalRRule::EInvalid;

        TCalRRule origRule;
        TBool origHasRule = aOrigEntry.GetRRuleL( origRule ) 
                                   && origRule.Type() != TCalRRule::EInvalid;

        TBool repeatRuleHasChanged = EFalse;
        if ( editedHasRule && origHasRule )
            {
            repeatRuleHasChanged = TypeOrIntervalChangedL( editedRule, origRule );
            }
        else
            {
            repeatRuleHasChanged = editedHasRule || origHasRule;
            }

        if( repeatRuleHasChanged && ! hasRdates )
            {
            // Clear any RDates, Exception dates etc.
            aEditedEntry.ClearRepeatingPropertiesL();
            aEditedEntry.SetRRuleL( editedRule );
            }
        else
            {
            // If the start time of the entry has been modified,
            // and we have RDates, update the RDates to the new time.
            if( aEditedEntry.StartTimeL().TimeLocalL() != aOrigEntry.StartTimeL().TimeLocalL() )
                {
                // The original time is that of the RDate which the user opened up,
                // not the start time of the entry. First iteration through the rates
                // is to get the time of day of the rdate on the instance day.

                TTimeIntervalMinutes origTime = -1;
                TTimeIntervalMinutes newTime = CalenDateUtils::TimeOfDay( aEditedEntry.StartTimeL().TimeLocalL() );

                for( TInt i=0; i<rdates.Count(); ++i )
                    {
                    if( CalenDateUtils::OnSameDay( aOrigInstanceDate.TimeLocalL(), rdates[i].TimeLocalL() ) )
                        {
                        origTime = CalenDateUtils::TimeOfDay( rdates[i].TimeLocalL() );
                        }
                    }

                // Alternatively, the entry opened up could have been the main parent entry.
                if( origTime.Int() == -1 )
                    {
                    if( CalenDateUtils::OnSameDay( aOrigInstanceDate.TimeLocalL(), aOrigEntry.StartTimeL().TimeLocalL() ) )
                        {
                        origTime = CalenDateUtils::TimeOfDay( aOrigEntry.StartTimeL().TimeLocalL() );
                        }
                    }

                ASSERT( origTime.Int() != -1 );

                RArray<TCalTime> exdates;
                CleanupClosePushL( exdates );
                aOrigEntry.GetExceptionDatesL( exdates );

                for( TInt i=0; i<rdates.Count(); ++i )
                    {
                    TBool ignore = EFalse;

                    for( TInt j=0; j<exdates.Count(); ++j )
                        {
                        if( rdates[i].TimeUtcL() == exdates[j].TimeLocalL() )
                            {
                            ignore = ETrue;
                            break;
                            }
                        }

                    if( !ignore && CalenDateUtils::TimeOfDay( rdates[ i ].TimeLocalL() ) == origTime )
                        {
                        TTime beginningOfDay = CalenDateUtils::BeginningOfDay( rdates[ i ].TimeLocalL() );
                        
                        
                        // Use floating time for non-timed entries 
                        if ( !CalenAgendaUtils::IsTimedEntryL(aEditedEntry.EntryTypeL()))
                            {
                            rdates[ i ].SetTimeLocalFloatingL( beginningOfDay + newTime );
                            }
                        else
                            {
                            rdates[ i ].SetTimeLocalL( beginningOfDay + newTime );
                            }
                        }
                    }

                aEditedEntry.SetRDatesL( rdates );
                // SetExceptionDatesL doesn't remove any existing exception dates.
                // As as result we have to clear the repeating properties then repopulate
                // the entry's repeating properties by restoring the RRule, each child
                // entry, the RDates, and any unduplicated exception dates.
                aEditedEntry.SetExceptionDatesL( exdates );
                CleanupStack::PopAndDestroy( &exdates );
                }
            }
        }

    CleanupStack::PopAndDestroy(&rdates);

    TRACE_EXIT_POINT;
    }

// -----------------------------------------------------------------------------
// CCalenEntryUpdater::TypeOrIntervalChangedL
// Compares two rrules for differences
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CCalenEntryUpdater::TypeOrIntervalChangedL( const TCalRRule& aEditedRule,
                                                  const TCalRRule& aOrigRule ) const
    {
    TRACE_ENTRY_POINT;

    TBool repeatTypeChanged = aEditedRule.Type() != aOrigRule.Type();
    TBool intervalChanged = aEditedRule.Interval() != aOrigRule.Interval();

    TRACE_EXIT_POINT;
    return ( repeatTypeChanged || intervalChanged );
    }

// -----------------------------------------------------------------------------
// CCalenEntryUpdater::UpdateInstanceL()
// Stores the given entry using CCalenInterimUtils2.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCalenEntryUpdater::UpdateInstanceL( CCalEntry& aEditedEntry,
                                          CCalEntry& aOrigEntry,
                                          const TCalTime& aOrigInstanceDate,
                                          CalCommon::TRecurrenceRange aWhichInstances,
                                          const TCalTime& aNewInstanceStartDate,
                                          const TCalTime& aNewInstanceEndDate,
                                          const TDesC& aFileName )
    {
    TRACE_ENTRY_POINT;
    
    TInt colId = iServices.SessionL(aFileName).CollectionIdL();
    
    //Set the collection id here for temp instanceId and set it to context
    TCalenInstanceId instanceIdTemp = iServices.Context().InstanceId();
    instanceIdTemp.iColId = colId;
    instanceIdTemp.iType = aEditedEntry.EntryTypeL();
    
    if (aNewInstanceStartDate.TimeLocalL() != aOrigInstanceDate.TimeLocalL()
            || instanceIdTemp.iInstanceTime <= 0)
        {
        instanceIdTemp.iInstanceTime = aNewInstanceStartDate.TimeLocalL();
        }
    iServices.Context().SetInstanceIdL(instanceIdTemp,iServices.Context().ViewId());
    TBool isChild( aOrigEntry.RecurrenceIdL().TimeUtcL() != Time::NullTTime() );

    if(isChild)
        {
        CCalenInterimUtils2::StoreL( EntryViewL(colId), aEditedEntry, ETrue );
        }
    else if( aWhichInstances == CalCommon::EThisAndAll )
        {
        UpdateRDatesL( aEditedEntry, aOrigEntry, aOrigInstanceDate );
        CCalenInterimUtils2::StoreL( EntryViewL(colId), aEditedEntry, ETrue );
        }
    else if( aWhichInstances == CalCommon::EThisOnly )
        {
        // copy global UID from the original entry
        HBufC8* guid = aOrigEntry.UidL().AllocLC();
 
        // create new (child) entry
        // Use original instance time for recurrenceID as this entry hasn't got one.
        CCalEntry* newEntry = CCalEntry::NewL( aOrigEntry.EntryTypeL(), 
                                               guid,
                                               aOrigEntry.MethodL(),
                                               aOrigEntry.SequenceNumberL(),
                                               aOrigInstanceDate,
                                               aWhichInstances );

        CleanupStack::Pop( guid ); // ownership transferred        
        CleanupStack::PushL( newEntry );

        // copy all the data from edited entry
        newEntry->CopyFromL( aEditedEntry );

        // Workround for Symbian "features":
        // The summary is not automatically copied when it is very large.
        newEntry->SetSummaryL( aEditedEntry.SummaryL() );
        // Calling SetStartAndEndTimeL on an entry with an RRule with TDays
        // completely ignores the date you pass in.
        if( ! CalenDateUtils::OnSameDay( aNewInstanceStartDate.TimeUtcL(), newEntry->StartTimeL().TimeUtcL() ) )
            {
            TCalTime newStart, newEnd;
            TTime beginningOfDay = CalenDateUtils::BeginningOfDay( aNewInstanceStartDate.TimeUtcL() );
            TTimeIntervalMinutes timeOfDay = CalenDateUtils::TimeOfDay( newEntry->StartTimeL().TimeUtcL() );
            newStart.SetTimeUtcL( beginningOfDay + timeOfDay );
            beginningOfDay = CalenDateUtils::BeginningOfDay( aNewInstanceEndDate.TimeUtcL() );
            timeOfDay = CalenDateUtils::TimeOfDay( newEntry->EndTimeL().TimeUtcL() );
            newEnd.SetTimeUtcL( beginningOfDay + timeOfDay );
            newEntry->SetStartAndEndTimeL( newStart, newEnd );
            }

        // reset local UID
        newEntry->SetLocalUidL( TCalLocalUid( 0 ) );

        // clear repeat rule properties
        newEntry->ClearRepeatingPropertiesL();
		
		// Set the geocoordinates
		CCalGeoValue* geoValue = aEditedEntry.GeoValueL();
		if( geoValue )
            {
            newEntry->SetGeoValueL( *geoValue );
            delete geoValue;
            }
		
        CCalenInterimUtils2::StoreL( EntryViewL(colId), *newEntry, ETrue );
        
        MCalenContext &context = iServices.Context();
        TCalenInstanceId id = TCalenInstanceId::CreateL( *newEntry,  aNewInstanceStartDate , colId );
        context.SetFocusDateAndTimeAndInstanceL( aNewInstanceStartDate, id, context.ViewId() );

        aEditedEntry.SetLocalUidL( newEntry->LocalUidL() );

        CleanupStack::PopAndDestroy( newEntry );
        }
    else
        {
        // not supported in UI level
        __ASSERT_ALWAYS( EFalse, User::Invariant() );
        }

    TRACE_EXIT_POINT;
    }

// -----------------------------------------------------------------------------
// CCalenEntryUpdater::FindInstanceL()
// Returns the index into aInstances of the instance with the same UID as
// aEntry, at the same date/time as aInstanceDate, or return KErrNotFound if
// no match found.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CCalenEntryUpdater::FindInstanceL( CCalEntry& aEntry,
                                        const TCalTime& aInstanceDate, 
                                        RPointerArray<CCalInstance>& aInstances)
    {
    TRACE_ENTRY_POINT;

    InstanceViewL().FindInstanceL( aInstances, 
                                                CalCommon::EIncludeAll,
                                                CalCommon::TCalTimeRange(aInstanceDate, aInstanceDate) );

    for( TInt i( 0 ); i < aInstances.Count(); i++ )
        {
        if( aInstances[i]->Entry().UidL() == aEntry.UidL() )
            {
            TRACE_EXIT_POINT;
            return i;
            }
        }

    TRACE_EXIT_POINT;
    return -1;
    }

// -----------------------------------------------------------------------------
// CCalenEntryUpdater::EntryViewL()
// Get CalEntryView from services
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CCalEntryView&  CCalenEntryUpdater::EntryViewL(TInt ColId)
    {
    TRACE_ENTRY_POINT;

    CCalEntryView* entryView = iServices.EntryViewL(ColId);

    TRACE_EXIT_POINT;
    return *entryView;
    }

// -----------------------------------------------------------------------------
// CCalenEntryUpdater::InstanceViewL()
// Get CalInstanceView from services 
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CCalInstanceView&  CCalenEntryUpdater::InstanceViewL()
    {
    TRACE_ENTRY_POINT;
    
    CCalInstanceView* instanceView = iServices.InstanceViewL(iCollectionIds);

    TRACE_EXIT_POINT;
    return *instanceView;
    }

// -----------------------------------------------------------------------------
// CCalenEntryUpdater::DeleteInstanceL()
// Delete the given instance from agenda.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCalenEntryUpdater::DeleteInstanceL( CCalEntry& /*aEntry*/, TCalenInstanceId aInstanceId )
    {
    TRACE_ENTRY_POINT;    
    
    CCalInstance* instance = CalenActionUiUtils::FindPossibleInstanceL( aInstanceId, InstanceViewL() );
    if( instance )
        {
        CleanupStack::PushL( instance );
        InstanceViewL().DeleteL(instance , CalCommon::EThisOnly);
        CleanupStack::Pop( instance );
        }
   
    TRACE_EXIT_POINT;
    }
// End of File