calendarui/globaldata/src/calendbchangenotifier.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 25 May 2010 12:41:10 +0300
branchRCL_3
changeset 30 d68a4b5d5885
parent 20 21239b3bcd78
child 59 aba12c885d83
permissions -rw-r--r--
Revision: 201019 Kit: 2010121

/*
* 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:   Notifies observers of external changes to the calendar database
*
*/



//debug
#include "calendarui_debug.h"

// INCLUDE FILES
#include "CleanupResetAndDestroy.h"
#include "calendbchangenotifier.h"    // CCalenDbChangeNotifier
#include "calenglobaldata.h"            // Calendar global data
#include <calsession.h>                 // CalSession
#include <missedalarm.h>
#include <missedalarmstore.h>
#include <missedalarmstorecrkeys.h>
#include <calcalendarinfo.h>

// -----------------------------------------------------------------------------
// KTimerResolution limits the number of notifications sent to registered
// MCalenDBChangeObserver instances.  Notifications may come from 
// MCalChangeCallBack2 at a very high rate which could impact performance, 
// for example by causing constant view refreshes.
// CCalenDbChangeNotifier notifies observers when KTimerResolution has elapsed
// since the last notification was received from MCalChangeCallBack2
// -----------------------------------------------------------------------------
const TInt KTimerResolution = 1000000;  // 1 Second

// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CCalenDbChangeNotifier::CCalenDbChangeNotifier
// C++ default constructor can NOT contain any code, that might leave.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
CCalenDbChangeNotifier::CCalenDbChangeNotifier( CCalSession& aSession ) 
    : CActive( EPriorityNormal ),
      iSession( aSession )
    {
    TRACE_ENTRY_POINT;

    iRestartTimer = EFalse;

    TRACE_EXIT_POINT;
    }

// -----------------------------------------------------------------------------
// CCalenDbChangeNotifier::NewL
// Two-phased constructor.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
CCalenDbChangeNotifier* CCalenDbChangeNotifier::NewL( CCalSession& aSession )
    {
    TRACE_ENTRY_POINT;

    CCalenDbChangeNotifier* self = new( ELeave ) CCalenDbChangeNotifier( aSession );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );

    TRACE_EXIT_POINT;
    return self;
    }

// -----------------------------------------------------------------------------
// CCalenDbChangeNotifier::ConstructL
// Symbian 2nd phase constructor can leave.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
void CCalenDbChangeNotifier::ConstructL()
    {
    TRACE_ENTRY_POINT;

    // We want to receive notifications for the full agenda date range
    TCalTime start, end;
    start.SetTimeUtcL( TCalTime::MinTime() );
    end.SetTimeUtcL( TCalTime::MaxTime() );
    CalCommon::TCalTimeRange range( start, end ); 

    // Create a notification filter
    iCalChangeFilter = CCalChangeNotificationFilter::NewL(
                                                        MCalChangeCallBack2::EChangeEntryAll, 
                                                        ETrue, 
                                                        range );

    // Enable database change notifications on current global data session
    iSession.StartChangeNotification( *this, *iCalChangeFilter );

    // Create a timer to limit the number of notifications broadcast
    iNotificationTimer.CreateLocal();

    // Active object, add to active scheduler
    CActiveScheduler::Add( this );

    TRACE_EXIT_POINT;
    }

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

    Cancel();
    // Reset the observer array.  Array contents are NOT owned by this class
    iDBObservers.Reset();

    iNotificationTimer.Close();

    // Disable database change notifications on current global data session   
    PIM_TRAPD_HANDLE( iSession.StopChangeNotification() );

    // Destroy the notification filter
    delete iCalChangeFilter;
    
    TRACE_EXIT_POINT;    
    }

// -----------------------------------------------------------------------------
// CCalenDbChangeNotifier::LastDBModificationTime
// Returns the time of the last database change notification.  This may not be
// the time of the last notification sent to MCalenDBChangeObservers.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
TTime CCalenDbChangeNotifier::LastDBModificationTime() const
    {
    TRACE_ENTRY_POINT;

    TRACE_EXIT_POINT;
    return iLastDbChangeNotification;
    }

// -----------------------------------------------------------------------------
// CCalenDbChangeNotifier::CalChangeNotification
// Called when a change to the agenda database occurs from a different session
// to the one we are currently using.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
void CCalenDbChangeNotifier::CalChangeNotification( RArray<TCalChangeEntry>& aChangeItems )
    {
    TRACE_ENTRY_POINT;

    TRAP_IGNORE(HandleMissedAlarmsL(aChangeItems));
    // Always update the last notification time, even if we don't notify 
    // our observers
    iLastDbChangeNotification.UniversalTime();
    if( !IsActive() )
        {
        iNotificationTimer.After( iStatus, KTimerResolution );
        SetActive();
        }
    else
        {
        iRestartTimer = ETrue;
        iNotificationTimer.Cancel();
        }

    TRACE_EXIT_POINT;
    }
void CCalenDbChangeNotifier::HandleMissedAlarmsL(const RArray<TCalChangeEntry>& aChangeItems)
    {
    TRACE_ENTRY_POINT
    CRepository* missedAlarmStoreRepository = CRepository::NewL(
            KCRUidMissedAlarmStore);
    // Create missed alarm store
    CMissedAlarmStore* missedAlarmStore = CMissedAlarmStore::NewL(
            *missedAlarmStoreRepository);
    CleanupStack::PushL(missedAlarmStore);
    RPointerArray<CMissedAlarm> missedAlarmStorelist;
    CleanupResetAndDestroyPushL(missedAlarmStorelist);
    missedAlarmStore->GetL(missedAlarmStorelist);
    CCalCalendarInfo* calendarInfo = iSession.CalendarInfoL();
    CleanupStack::PushL(calendarInfo);
    CCalenDbChangeNotifier::TCalLuidFilename calLuidFilename;
    calLuidFilename.iFilename = calendarInfo->FileNameL();
    if (missedAlarmStorelist.Count())
        {
        for (TInt idx = 0; idx < aChangeItems.Count(); idx++)
            {
            if (aChangeItems[idx].iChangeType == EChangeDelete)
                {
                calLuidFilename.iLuid = aChangeItems[idx].iEntryId;
                TInt index = missedAlarmStorelist.Find(
                        calLuidFilename,CCalenDbChangeNotifier::DoFindEntryByLuid);
                if(index != KErrNotFound)
                    {
                    CMissedAlarm* missedAlarm = missedAlarmStorelist[index];
                    missedAlarmStore->RemoveL(*missedAlarm);
                    }
                }
            }
        }
    CleanupStack::PopAndDestroy(calendarInfo);
    CleanupStack::PopAndDestroy(&missedAlarmStorelist);
    CleanupStack::PopAndDestroy(missedAlarmStore);
    TRACE_EXIT_POINT    
    }
TBool CCalenDbChangeNotifier::DoFindEntryByLuid(
                const TCalLuidFilename* aLuidFilename,const CMissedAlarm& aMissedAlarm)
    {
    TRACE_ENTRY_POINT
    TRACE_EXIT_POINT
    return (aLuidFilename->iLuid == aMissedAlarm.iLuid 
            && !aLuidFilename->iFilename.CompareF(aMissedAlarm.iCalFileName));
    }

// -----------------------------------------------------------------------------
// CCalenDbChangeNotifier::RegisterObserverL
// Adds the passed observer to the observer array.  All observers in the array 
// will be notified of changes to the agenda database.
// (other items were commented in a header).
// -----------------------------------------------------------------------------    
 void CCalenDbChangeNotifier::RegisterObserverL( MCalenDBChangeObserver& aDBObserver )
    {
    TRACE_ENTRY_POINT;

    iDBObservers.Append( &aDBObserver );

    TRACE_EXIT_POINT;
    }

// -----------------------------------------------------------------------------
// CCalenDbChangeNotifier::DeRegisterObserverL
// Removes the passed observer to the observer array.  All observers in the array 
// will be notified of changes to the agenda database.
// -----------------------------------------------------------------------------       
void CCalenDbChangeNotifier::DeRegisterObserverL( MCalenDBChangeObserver& aDBObserver )
    {
    TRACE_ENTRY_POINT;

    for( TInt x = 0; x < iDBObservers.Count(); ++x )
        {
        if( iDBObservers[x] == &aDBObserver )
            {
            iDBObservers.Remove( x );
            return;
            }
        }
    User::Leave( KErrNotFound );

    TRACE_EXIT_POINT;
    }

// -----------------------------------------------------------------------------       
// CCalenDbChangeNotifier::RunL
// From CActive::RunL
// Called when notification timer expires
// (other items were commented in a header).
// -----------------------------------------------------------------------------       
void CCalenDbChangeNotifier::RunL()
    {
    TRACE_ENTRY_POINT;

    switch( iStatus.Int() )
        {
        case KErrCancel:
            {
            // The normal reason for the timer being cancelled is another
            // database change.  Restart the timer.
            if( iRestartTimer )
                {
                iRestartTimer = EFalse;
                iNotificationTimer.After( iStatus, KTimerResolution );
                SetActive();
                }        
            }
        break;

        case KErrNone:
            {
            //Timer completion, notify observers
            for( TInt x = 0; x < iDBObservers.Count(); ++x )
                {
                iDBObservers[x]->HandleDBChangeL();
                }
            }
        break;

        default:
            {
            User::Leave( KErrArgument );
            }
        break;
        }

    TRACE_EXIT_POINT;
    }

// -----------------------------------------------------------------------------       
// CCalenDbChangeNotifier::RunError
// From CActive::RunError
// (other items were commented in a header).
// -----------------------------------------------------------------------------
TInt CCalenDbChangeNotifier::RunError( TInt aError )
    {
    TRACE_ENTRY_POINT;

    //RunL leaving means that the view could not be refreshed.
    //Theres not much we can do except be ready for the next database event.
    iRestartTimer = EFalse;

    TRACE_EXIT_POINT;
    return aError;
    }

// -----------------------------------------------------------------------------       
// CCalenDbChangeNotifier::DoCancel
// From CActive::DoCancel
// (other items were commented in a header).
// -----------------------------------------------------------------------------
void CCalenDbChangeNotifier::DoCancel()
    {
    TRACE_ENTRY_POINT;

    // Stop the notification timer
    iRestartTimer = EFalse;
    iNotificationTimer.Cancel();

    TRACE_EXIT_POINT;
    }

// End of File