calendarui/controller/src/calendeleteui.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 19 Aug 2010 09:53:43 +0300
branchRCL_3
changeset 28 96907930389d
parent 15 9711e452b5e9
child 29 12af337248b1
permissions -rw-r--r--
Revision: 201031 Kit: 201033

/*
* Copyright (c) 2007 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:  Handles deletion
*
*/


// INCLUDES
#include <Calendar.rsg>
#include <calendateutils.h>
#include <calenagendautils.h>
#include <aknnotewrappers.h>
#include <AknWaitDialog.h>
#include <calcommon.h>
#include <calentryview.h>
#include <calinstance.h>
#include <calinstanceview.h>
#include <caltime.h>
#include <centralrepository.h>
#include <eikenv.h>
#include <StringLoader.h>
#include <sysutil.h>
#include <calenglobaldata.h>
#include <calrrule.h>
#include <calsession.h>
#include <calencommands.hrh>            // Calendar commands
#include <calencontext.h>
#include <caleninstanceid.h>            // TCalenInstanceId
#include <calenactionuiutils.h>
#include <calcalendarinfo.h>
#include <calentoolbar.h>
#include <akntoolbar.h>
#include <calenattachmentmodel.h>

#include "calendarui_debug.h"           // Debug
#include "calendeleteui.h"
#include "calencontroller.h"
#include "CleanupResetAndDestroy.h"
#include "CalenInterimUtils2.h"
#include "CalendarPrivateCRKeys.h"      // For CalendarInternalCRKeys.h
#include "calenmultipledbmanager.h"

// Local constants
const TInt KEntriesToDelete = 1;

// ----------------------------------------------------------------------------
// CCalenDeleteUi::NewL
// Two phased constructor
// (other items were commented in a header).
// ----------------------------------------------------------------------------
//
CCalenDeleteUi* CCalenDeleteUi::NewL( CCalenController& aController )
    {
    TRACE_ENTRY_POINT;

    CCalenDeleteUi* self = new( ELeave ) CCalenDeleteUi( aController );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );

    TRACE_EXIT_POINT;
    return self;
    }

// ----------------------------------------------------------------------------
// CCalenDeleteUi::CCalenDeleteUi
// ?implementation_description
// (other items were commented in a header).
// ----------------------------------------------------------------------------
//
CCalenDeleteUi::CCalenDeleteUi( CCalenController& aController )
    : iEikEnv( CEikonEnv::Static() ), iController( aController )
    {
    TRACE_ENTRY_POINT;
    TRACE_EXIT_POINT;
    }

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

    if( iWaitDialog )
        {
        delete iWaitDialog;
        iWaitDialog = NULL;
        }

    if( iGlobalData )
        {
        iGlobalData->Release();
        }

    if( iDelAllRange )
        delete iDelAllRange;

    iDeleteColIds.Reset();
    
    TRACE_EXIT_POINT;
    }

// ----------------------------------------------------------------------------
// CCalenDeleteUi::ConstructL
// Second phase of construction
// (other items were commented in a header).
// ----------------------------------------------------------------------------
//
void CCalenDeleteUi::ConstructL()
    {
    TRACE_ENTRY_POINT;

    iGlobalData = CCalenGlobalData::InstanceL();

    // Both the entry view and instance views are needed
    // by the deleteUi commands, there queue the construction of both
    RArray<TInt> colArray;
    iController.GetActiveCollectionidsL(colArray);
    
    CCalInstanceView* instanceView = iGlobalData->InstanceViewL(colArray);
    colArray.Reset();
    if( !instanceView )
        {
        iController.RegisterForNotificationsL( this, ECalenNotifyEntryInstanceViewCreated );
        }
    iController.RegisterForNotificationsL( this, ECalenNotifyCancelDelete );
    iMoreEntriesToDelete = EFalse;
    iDisplayQuery = EFalse;
    iEntriesToDelete = KEntriesToDelete;
    iDelAllRange = NULL;
    TRACE_EXIT_POINT;
    }

// ----------------------------------------------------------------------------
// CCalenDeleteUi::HandleECalenNotifyViewCreatedL
// Handles ECalenNotifyViewCreated.
// (other items were commented in a header).
// ----------------------------------------------------------------------------
//
void CCalenDeleteUi::HandleECalenNotifyViewCreatedL()
    {
    TRACE_ENTRY_POINT;
    RArray<TInt> colArray;
    iController.GetActiveCollectionidsL(colArray);
    
    if( iGlobalData->InstanceViewL(colArray) )
        {
        // Handle the outstanding command
        HandleCommandL( iStoredCommand );

        // Cancel the notify as the entry view is now
        // constructed.
        iController.CancelNotifications( this );
        }
    colArray.Reset();
    TRACE_EXIT_POINT;
    }

// ----------------------------------------------------------------------------
// CCalenDeleteUi::HandleNotification
// Handles notifications.
// (other items were commented in a header).
// ----------------------------------------------------------------------------
//
void CCalenDeleteUi::HandleNotification(const TCalenNotification aNotification )
    {
    TRACE_ENTRY_POINT;

    if ( aNotification == ECalenNotifyEntryInstanceViewCreated )
        {
        PIM_TRAPD_HANDLE( HandleECalenNotifyViewCreatedL() );
        }
    if( aNotification == ECalenNotifyCancelDelete)
        {
        if(iMutlipleContextIdsCount)
            {
            // get the context
            MCalenContext& context = iGlobalData->Context();
            // reset the multiple contexts
            context.ResetMultipleContextIds();
            
            // dismiss the waitdialog
            if(iWaitDialog)
                {
                TRAP_IGNORE(iWaitDialog->ProcessFinishedL());
                }
            }
        }
    TRACE_EXIT_POINT;
    }

// ----------------------------------------------------------------------------
// CCalenDeleteUi::HandleCommandL
// Handles action ui commands
// (other items were commented in a header).
// ----------------------------------------------------------------------------
//
TBool CCalenDeleteUi::HandleCommandL( const TCalenCommand& aCommand )
    {
    TRACE_ENTRY_POINT;
    TBool continueCommand(EFalse);
    
    RArray<TInt> colArray;
    iController.GetActiveCollectionidsL(colArray);
    
    if( colArray.Count() && !( iGlobalData->InstanceViewL(colArray) ) )
        {
        iStoredCommand = aCommand;
        }
    else
        {
        switch( aCommand.Command() )
            {
            case ECalenDeleteCurrentEntry:
                DeleteCurrentEntryL(); // Entry & instance
                break;

            case ECalenDeleteSeries:
                DeleteThisOrAllL( CalCommon::EThisAndAll );
                break;
                
            case ECalenDeleteCurrentOccurrence:
                DeleteThisOrAllL( CalCommon::EThisOnly );
                break;
                
            case ECalenDeleteEntryWithoutQuery:
                continueCommand = DeleteEntryWithoutQueryL();
                break;

            case ECalenDeleteAllEntries:
                HandleDeleteAllEntriesL();
                break;

            case ECalenDeleteEntriesBeforeDate:
                DeleteEntriesBeforeDateL(); // EntryView & instance
                break;

            default:
                // Controller decided this class was the place to handle this
                // command but it wasn't in our list; something has gone wrong.
                //ASSERT( EFalse );
                break;
            }
        }
    colArray.Reset();
    TRACE_EXIT_POINT;
    return continueCommand;
    }

// ----------------------------------------------------------------------------
// CCalenDeleteUi::CalenCommandHandlerExtensionL
// Dummy implementation.
// (other items were commented in a header).
// ----------------------------------------------------------------------------
//
TAny* CCalenDeleteUi::CalenCommandHandlerExtensionL( TUid /*aExtensionUid*/ )
    {
    TRACE_ENTRY_POINT;
    TRACE_EXIT_POINT;
    return NULL;
    }

// ----------------------------------------------------------------------------
// CCalenDeleteUi::DeleteThisOrAllL
// Deletes series repeating entry
// (other items were commented in a header).
// ----------------------------------------------------------------------------
//
void CCalenDeleteUi::DeleteThisOrAllL( CalCommon::TRecurrenceRange aRepeatType )
    {
    TRACE_ENTRY_POINT;
    
    TBool isDeleted( EFalse );
    
    RArray<TInt> colIdArray;
    colIdArray.AppendL(iGlobalData->Context().InstanceId().iColId);
    
    if( iGlobalData->Context().InstanceId().iEntryLocalUid )
        {
        CCalInstance* instance = 
            CalenActionUiUtils::FindPossibleInstanceL( 
                                           iGlobalData->Context().InstanceId(),
                                           *iGlobalData->InstanceViewL(colIdArray) );
            if( instance )
            {
            CleanupStack::PushL( instance );
            isDeleted = DeleteSingleInstanceL( instance, aRepeatType );
            
            if( isDeleted )
                {
                CleanupStack::Pop( instance );
                }
            else
                {
                CleanupStack::PopAndDestroy( instance );
                }
            }
        }
    colIdArray.Reset();
    
    iController.BroadcastNotification( isDeleted? ECalenNotifyEntryDeleted :
                                                               ECalenNotifyDeleteFailed );
    
    TRACE_EXIT_POINT;
    }

// ----------------------------------------------------------------------------
// CCalenDeleteUi::DeleteEntryWithoutQueryL()
// Deletes the current entry
// (other items were commented in a header).
// ----------------------------------------------------------------------------
//
TBool CCalenDeleteUi::DeleteEntryWithoutQueryL()
    {
    TRACE_ENTRY_POINT;
	TBool continueCommand(EFalse);
    
	// get the context
	MCalenContext& context = iGlobalData->Context();
	
	// get the multliple context ids count
	iMutlipleContextIdsCount = context.MutlipleContextIdsCount();
	
	ASSERT( iMutlipleContextIdsCount );

	    if(!iMoreEntriesToDelete)
		    {
		    iDisplayQuery = ShowMultipleEntriesDeleteQueryL(iMutlipleContextIdsCount);
		    }
		
		if(iDisplayQuery)
			{
			if(!iMoreEntriesToDelete)	
			    {
			    DisplayWaitDialogL();
			    }
			// get the multiple context instance ids
			RArray<TCalenInstanceId>& multipleContextIds = context.GetMutlipleContextIds();
			
			if(iMutlipleContextIdsCount <= iEntriesToDelete )
			    {
			    iMoreEntriesToDelete = EFalse; 
			    iEntriesToDelete = iMutlipleContextIdsCount;
			    }
			else
			    {
			    iMoreEntriesToDelete = ETrue;
	            // set the continue command flag if more entries are there to delete
			    continueCommand = ETrue;
			    }
			    
			TInt index(0);
			while(index<iEntriesToDelete)
			    {
			    // get the local uid of the entry through multiple context list
			    TCalLocalUid entryLocalUid = multipleContextIds[0].iEntryLocalUid;			    
			    if(entryLocalUid)
			        {
			        DeleteEntryL(entryLocalUid, multipleContextIds[0].iColId);
			        }
			    // remove mutliple context based on the instanceid
			    context.RemoveMultipleContextId(multipleContextIds[0]);
			    index++;
			   }

			if(!iMoreEntriesToDelete)
			    {
			    MarkedEntriesDeletedL();    
			    }
			MCalenToolbar* toolbarImpl = iController.Services().ToolbarOrNull(); 
            if (toolbarImpl)
                {
                CAknToolbar& toolbar = toolbarImpl->Toolbar();
    
                // dim clear and clear all toolbar buttons
                toolbar.SetItemDimmed(ECalenNewMeeting, EFalse, ETrue);
                }
			}
        else
            {
            context.ResetMultipleContextIds();
            // notify delete failed
            iController.BroadcastNotification(ECalenNotifyDeleteFailed);    
            }
	
    TRACE_EXIT_POINT;
    return continueCommand;
    }

// ----------------------------------------------------------------------------
// CCalenDeleteUi::DeleteCurrentEntryL
// Deletes the current entry
// (other items were commented in a header).
// ----------------------------------------------------------------------------
//
void CCalenDeleteUi::DeleteCurrentEntryL()
    {
    TRACE_ENTRY_POINT;

    TBool deleted( EFalse );
    TCalenNotification notification = ECalenNotifyDeleteFailed;
    
    // Make sure we're focused on an entry.
    if( iGlobalData->Context().InstanceId().iEntryLocalUid )
        {
        //If todo, use the LUid.
        //Todos returns the current time if start or end time has not been saved.
        if( CCalEntry::ETodo == iGlobalData->Context().InstanceId().iType )
            {
            CCalEntry* entry = iGlobalData->EntryViewL(iGlobalData->Context().InstanceId().iColId)->FetchL(
                                    iGlobalData->Context().InstanceId().iEntryLocalUid );

            if( entry )
                {
                CleanupStack::PushL( entry );
                deleted = DeleteEntryL( iGlobalData->EntryViewL(iGlobalData->Context().InstanceId().iColId), entry );

                if( deleted )
                    {
                    CleanupStack::Pop( entry );
                    notification = ECalenNotifyEntryDeleted;
                    }
                else
                    {
                    CleanupStack::PopAndDestroy( entry );
                    }
                }
            }
        else // Not todo
            {
            RArray<TInt> colIdArray;
            colIdArray.AppendL(iGlobalData->Context().InstanceId().iColId);
                
            CCalInstance* instance = CalenActionUiUtils::FindPossibleInstanceL( 
                                                            iGlobalData->Context().InstanceId(),
                                                            *iGlobalData->InstanceViewL(colIdArray) );
            // if we have instance we will do delete other wise just return
            if( instance )
                {
                // Note: ownership handling of instance is dirty in this case, 
                // because DeleteSingleInstanceLtakes ownership, if it's deletes 
                // instance (property of CalInterimApi), otherwise not.
                CleanupStack::PushL( instance );
                deleted = DeleteSingleInstanceL( instance );

                if( deleted )
                    {
                    CleanupStack::Pop( instance );
                    notification = ECalenNotifyEntryDeleted;
                    }
                else
                    {
                    CleanupStack::PopAndDestroy( instance );
                    }
                }
            colIdArray.Reset();
            }
        }
    else
        {
         TBool doDelete( ETrue );
         
         doDelete = CalenActionUiUtils::ShowDeleteConfirmationQueryL( 
                                                                   iGlobalData->Context().InstanceId().iType == CCalEntry::ETodo ?
                                                                   CalenActionUiUtils::EDeleteToDo :
                                                                   CalenActionUiUtils::EDeleteEntry );
		if ( doDelete )
			{
			notification = ECalenNotifyEntryDeleted;	
			}
        }
        
    iController.BroadcastNotification( notification );

    TRACE_EXIT_POINT;
    }

// ----------------------------------------------------------------------------
// CCalenDeleteUi::DeleteAllEntriesL
// Deletes all entries
// (other items were commented in a header).
// ----------------------------------------------------------------------------
//
void CCalenDeleteUi::DeleteAllEntriesL()
    {
    TRACE_ENTRY_POINT;

    ASSERT( !iIsDeleting );

    const TInt buttonId = CalenActionUiUtils::ShowDeleteConfirmationQueryL( 
                                           CalenActionUiUtils::EDeleteAll );

    if( buttonId )
        {
        HandleDeleteMultipleEventsL( TCalTime::MinTime(), TCalTime::MaxTime(),
                                 R_QTN_CALE_CONF_ALL_NOTES_DELETED );
        }
    else
        {
        // notify delete failed
        iController.BroadcastNotification(ECalenNotifyDeleteFailed); 
        }

    TRACE_EXIT_POINT;
    }

// ----------------------------------------------------------------------------
// CCalenDeleteUi::DeleteEntriesBeforeDateL
// Deletes all entries before a set date.
// (other items were commented in a header).
// ----------------------------------------------------------------------------
//
void CCalenDeleteUi::DeleteEntriesBeforeDateL()
    {
    TRACE_ENTRY_POINT;

    ASSERT( !iIsDeleting );
    TTime date;
    date.HomeTime();
    TTime today = date;

    TBool execute( EFalse );
    TBool exit( ETrue );
    do{
        exit = ETrue;
        execute = EFalse;

        TInt buttonId = CalenActionUiUtils::DateQueryL(date, R_CALEN_DEL_BEFORE_DATE_PROMPT);

        if( buttonId == EAknSoftkeyOk || buttonId == EEikBidOk )
            {
            execute = ETrue;
            if( today < date )
                {
                CAknNoteDialog* dialog = new( ELeave ) CAknNoteDialog( 
                                                            CAknNoteDialog::EConfirmationTone,
                                                            CAknNoteDialog::ELongTimeout );
                dialog->ExecuteLD( R_CALEN_DELETEERROR_NOTE );
                execute = EFalse;
                exit = EFalse;
                }
            }
        }while( !exit );

    // Do delete only if inputted day is after beginning of range
    if( execute && date > TCalTime::MinTime() )
        {
        // Two pass delete:
        // 1. pass
        // To prevent destroying entries starting and ending midnight
        // subtract one microsecond and do delete on that range.
        date -= TTimeIntervalMicroSeconds32( 1 );
        date = Max( date, TCalTime::MinTime() );

        HandleDeleteMultipleEventsL( TCalTime::MinTime(),
                                                date,
                                               R_QTN_CALE_CONF_PAST_NOTE_DELETED );
        }
    else
        {
        iController.BroadcastNotification( ECalenNotifyDeleteFailed );
        }
    
    TRACE_EXIT_POINT;
    }

// ----------------------------------------------------------------------------
// CCalenDeleteUi::HandleDeleteMultipleEventsL
// Handles multiple delete events
// (other items were commented in a header).
// ----------------------------------------------------------------------------
//
void CCalenDeleteUi::HandleDeleteMultipleEventsL( const TTime& aFirstDay,
                                                                     const TTime& aLastDay,
                                                                     TInt /*aConfNoteId */)
    {
    TRACE_ENTRY_POINT;

    ASSERT( !iWaitDialog );
    ASSERT( !iIsDeleting );
    //iConfirmationNoteId = aConfNoteId;

    iWaitDialog = new( ELeave ) CAknWaitDialog( REINTERPRET_CAST( CEikDialog**, 
                                                                  &iWaitDialog ) );
    iWaitDialog->ExecuteLD( R_CALEN_DELETE_WAIT_NOTE );

    DeleteDayRangeL( aFirstDay, aLastDay );

    TRACE_EXIT_POINT;
    }

// ----------------------------------------------------------------------------
// CCalenDeleteUi::DeleteDayRangeL
// Deletes all entries in a given range.
// (other items were commented in a header).
// ----------------------------------------------------------------------------
//
void CCalenDeleteUi::DeleteDayRangeL( const TTime& aStart,
                                                      const TTime& aEnd )
    {
    TRACE_ENTRY_POINT;

    iStartTime = aStart;
    iEndTime = aEnd;

    TCalTime start, end;
    start.SetTimeLocalL( iStartTime );
    end.SetTimeLocalL( iEndTime );

    if( iDelAllRange )
        {
        delete iDelAllRange;
        iDelAllRange = NULL;
        }
    
    iDelAllRange = new(ELeave) CalCommon::TCalTimeRange( start, end );
    iDeleteColIds.Reset();

    iIsDeleting = ETrue;   

    iController.GetActiveCollectionidsL(iDeleteColIds);
    
    //remember the calenders, delete entries in each calendar one by one by calling DeleteL(...) after completed()
    iNumberOfCalendars = iDeleteColIds.Count();
    iToShowDeleteNote = 0;
    iGlobalData->EntryViewL(iDeleteColIds[iToShowDeleteNote])->DeleteL( *iDelAllRange, CalCommon::EIncludeAll, *this );
        
    TRACE_EXIT_POINT;
    }

// ----------------------------------------------------------------------------
// CCalenDeleteUi::Completed
// Completed callback
// (other items were commented in a header).
// ----------------------------------------------------------------------------
//
void CCalenDeleteUi::Completed( TInt aFirstPassError )
    {
    TRACE_ENTRY_POINT;

    PIM_TRAPD_HANDLE( DoCompletedL( aFirstPassError ) );

    TRACE_EXIT_POINT;
    }

// ----------------------------------------------------------------------------
// CCalenDeleteUi::DoCompletedL
// Handles delete callback
// (other items were commented in a header).
// ----------------------------------------------------------------------------
//
void CCalenDeleteUi::DoCompletedL( TInt aFirstPassError )
    {
    TRACE_ENTRY_POINT;
    iToShowDeleteNote++;
    if(iNumberOfCalendars == iToShowDeleteNote)
        {
	    if( aFirstPassError == KErrNone )
	        {
	        // 2: Second pass, delete notes that end 00:00 of next day of iEndTime
	        // We didn't delete them in first pass
	        TTime nextMidnight = CalenDateUtils::BeginningOfDay( iEndTime + TTimeIntervalDays( 1 ) );
	        nextMidnight = Min( nextMidnight, TCalTime::MaxTime() );
	        PIM_TRAPD_HANDLE( DeleteEntriesEndingAtMidnightL( nextMidnight ) );
	        }
	        
		// 3. End deleting, close wait dialog, and show confirmation or error note
		iIsDeleting = EFalse;
		iToShowDeleteNote = 0;
		// dismiss the waitdialog
		if(iWaitDialog)
			{
			TRAP_IGNORE(iWaitDialog->ProcessFinishedL());
			}

		if( aFirstPassError == KErrNone )
			{
			// Show confirmation note
//			HBufC* buf = StringLoader::LoadLC( iConfirmationNoteId, iEikEnv );
//			CAknConfirmationNote* dialog = new( ELeave ) CAknConfirmationNote();
//			dialog->ExecuteLD(*buf);
//			CleanupStack::PopAndDestroy( buf );
			}
		else
			{
			// Show error note
			if(iEikEnv)
			   {
			   iEikEnv->ResolveError( aFirstPassError );
			   }
			}
		iDeleteColIds.Reset();
		delete iDelAllRange;
		iDelAllRange = NULL;
		
	    iController.BroadcastNotification( ECalenNotifyMultipleEntriesDeleted );
        }
    else
        {
        //delete entries in next calendar...
        iGlobalData->EntryViewL(iDeleteColIds[iToShowDeleteNote])->DeleteL( *iDelAllRange, CalCommon::EIncludeAll, *this );
        }

    TRACE_EXIT_POINT;
    }

// ----------------------------------------------------------------------------
// CCalenDeleteUi::NotifyProgress
// Delete progress notification
// (other items were commented in a header).
// ----------------------------------------------------------------------------
//
TBool CCalenDeleteUi::NotifyProgress()
    {
    TRACE_ENTRY_POINT;
    // Tell framework that we are not intrested in Progress notifications.
    TRACE_EXIT_POINT;
    return EFalse;
    }

// ----------------------------------------------------------------------------
// CCalenDeleteUi::Progress
// Delete progress notification
// (other items were commented in a header).
// ----------------------------------------------------------------------------
//
void CCalenDeleteUi::Progress( TInt /*aPercentageCompleted*/ )
    {
    TRACE_ENTRY_POINT;
    // do nothing, we are not intrested in Progress notifications
    TRACE_EXIT_POINT;
    }

// ----------------------------------------------------------------------------
// CCalenDeleteUi::DeleteEntriesEndingAtMidnightL
// Deletes entries ending at midnight on the given day
// (other items were commented in a header).
// ----------------------------------------------------------------------------
//
void CCalenDeleteUi::DeleteEntriesEndingAtMidnightL( TTime aMidnight )
    {
    TRACE_ENTRY_POINT;

    TCalTime start, end;
    start.SetTimeLocalL( aMidnight - TTimeIntervalMinutes(1) );
    end.SetTimeLocalL( aMidnight );
    CalCommon::TCalTimeRange midnightRange( start, end );
    
    RArray<TInt> colIdArray;
    iController.GetActiveCollectionidsL(colIdArray);
    
    // 1: Find instances falling on midnight moment
    RPointerArray< CCalInstance > instances;
    CleanupResetAndDestroyPushL( instances );
    iGlobalData->InstanceViewL(colIdArray)->FindInstanceL( instances,
                                                 CalCommon::EIncludeAll, 
                                                 midnightRange );
    
    colIdArray.Reset();

    // 2. loop through them and delete those entries that end at midnight
    for( TInt i=0; i < instances.Count(); ++i )
        {
        CCalInstance* item = instances[i];
        RArray<TInt> colIdArray;
        colIdArray.AppendL(item->InstanceIdL().iCollectionId);
        
        // Checking that if entry ends at midnight, is quite clumsy, but here goes:
        // EndsAtStartOfDay takes only CCalInstance, but here we mimic EndsAtStartOfDay
        // for CCalEntry type.

        // First check that if _instance_ ends at midnight, but starts earlier
        if( CalenAgendaUtils::EndsAtStartOfDayL( item, aMidnight ) )
            {
            // Second, check that _entry's_ endtime is exactly the midnight
            // This prevents us from destroying repeating entries, that has one
            // instance falling on given midnight.
            if( item->Entry().EndTimeL().TimeLocalL() == aMidnight )
                {
                iGlobalData->InstanceViewL(colIdArray)->DeleteL( item, CalCommon::EThisOnly );
                // Ownership was transferred to DeleteL.
                // Put null to array to prevent double-deletion
                instances[i] = NULL;                
                }
            }
        colIdArray.Reset();
        }
    CleanupStack::PopAndDestroy( &instances );

    TRACE_EXIT_POINT;
    }

// -----------------------------------------------------------------------------
// CCalenDeleteUi::DeleteSingleInstanceL
// Delete the given instance. Ask the user whether to delete the series or the instance.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CCalenDeleteUi::DeleteSingleInstanceL( CCalInstance* aInstance )
    {
    TRACE_ENTRY_POINT;
    TRACE_EXIT_POINT;
    return DoDeleteSingleInstanceL( aInstance, EFalse, CalCommon::EThisAndAll );
    }

// -----------------------------------------------------------------------------
// CCalenDeleteUi::DeleteSingleInstanceL
// Delete the given instance. Delete the entry range given by aRepeatType.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CCalenDeleteUi::DeleteSingleInstanceL( CCalInstance* aInstance, 
                                                            CalCommon::TRecurrenceRange aRepeatType )
    {
    TRACE_ENTRY_POINT;
    TRACE_EXIT_POINT;
    return DoDeleteSingleInstanceL( aInstance, ETrue, aRepeatType );
    }

// -----------------------------------------------------------------------------
// CCalenDeleteUi::DoDeleteSingleInstanceL
// Performs the deletion of the instance. If aHasRepeatType is EFalse, the user
// is prompted to delete either the instance or the entire series. In this case,
// aRepeatType is ignored. If aHasRepeatType is ETrue, aRepeatType determines
// whether to delete the instance or the entire series.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CCalenDeleteUi::DoDeleteSingleInstanceL( CCalInstance* aInstance,
                                                           TBool aHasRepeatType,
                                                           CalCommon::TRecurrenceRange aRepeatType )
    {
    TRACE_ENTRY_POINT;

    CCalEntry& entry = aInstance->Entry();
    const CCalEntry::TType entryType = entry.EntryTypeL(); 
    RArray<TInt> colIdArray;
    colIdArray.AppendL(aInstance->InstanceIdL().iCollectionId);
    

    TCalRRule rrule;

    TBool repeating = entry.GetRRuleL( rrule );

    if( !repeating )
        {
        // Even though there is no RRule, the entry might
        // have a list of rdates.
        RArray< TCalTime > rDateArray;
        CleanupClosePushL( rDateArray );
        entry.GetRDatesL( rDateArray );
        repeating = ( rDateArray.Count() > 0 );
        CleanupStack::PopAndDestroy(); // rDateArray
        }

    const TBool child = entry.RecurrenceIdL().TimeUtcL() != Time::NullTTime();

    if( !aHasRepeatType )
        {
        aRepeatType = CalCommon::EThisAndAll;
        }

    TBool doDelete( ETrue );

    if( !aHasRepeatType && ( child || repeating ) && ( entryType != CCalEntry::EAnniv ) )
        {
        doDelete = CalenActionUiUtils::ShowRepeatTypeQueryL( aRepeatType,
                                                           CalenActionUiUtils::EDelete );
        }
    else
        {
        doDelete = CalenActionUiUtils::ShowDeleteConfirmationQueryL( 
                                                                   entryType == CCalEntry::ETodo ?
                                                                   CalenActionUiUtils::EDeleteToDo :
                                                                   CalenActionUiUtils::EDeleteEntry );
        }
        
    if( doDelete )
        {
        //Before deleteing the entry reset the attachment model
        if(iController.Services().GetAttachmentData()->NumberOfItems())
            {
            iController.Services().GetAttachmentData()->Reset();
            }
        
        if( !TryDeleteWithMrUtilsL( aInstance, aRepeatType ) )
            {
            if( !child || aRepeatType == CalCommon::EThisOnly )
                {
                iGlobalData->InstanceViewL(colIdArray)->DeleteL( aInstance, aRepeatType );
                }
            else if( aRepeatType == CalCommon::EThisAndAll )
                {
                // Unfortunately we can't pass the existing child instance through to the
                // InstanceView DeleteL function because even if we pass in EThisAndAll, it
                // only ever deletes the exception. We'll have to fetch the parent then
                // delete it via the entry view.
                RPointerArray<CCalEntry> entries;
                CleanupResetAndDestroyPushL( entries );
                iGlobalData->EntryViewL(aInstance->InstanceIdL().iCollectionId)->FetchL( aInstance->Entry().UidL(), entries );
                iGlobalData->EntryViewL(aInstance->InstanceIdL().iCollectionId)->DeleteL( *entries[0] );
                CleanupStack::PopAndDestroy( &entries );
                if( aInstance )
                    {
                    delete aInstance;
                    aInstance = NULL;
                    }
                }
            else
                {
                User::Leave( KErrNotSupported );
                }
            }
        }

    colIdArray.Reset();
    TRACE_EXIT_POINT;
    return doDelete;
    }

// -----------------------------------------------------------------------------
// CCalenDeleteUi::DeleteEntryL
// Deletes an entry from the database
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CCalenDeleteUi::DeleteEntryL( CCalEntryView* aEntryView, CCalEntry* aEntry )
    {
    TRACE_ENTRY_POINT;
    const CCalEntry::TType entryType = aEntry->EntryTypeL();

    TBool doDelete = CalenActionUiUtils::ShowDeleteConfirmationQueryL( 
                                                                    entryType == CCalEntry::ETodo ?
                                                                    CalenActionUiUtils::EDeleteToDo :
                                                                    CalenActionUiUtils::EDeleteEntry );
    if( doDelete )
        {
        //Before deleteing the attachment, reset the attachment model
        if(iController.Services().GetAttachmentData()->NumberOfItems())
            {
            iController.Services().GetAttachmentData()->Reset();
            }
        aEntryView->DeleteL( *aEntry );

        if( aEntry )
            {
            delete aEntry;
            aEntry = NULL;
            }
        }

    TRACE_EXIT_POINT;
    return doDelete;
    }

// -----------------------------------------------------------------------------
// CCalenDeleteUi::TryDeleteWithMrUtilsL
// Attempt to delete the instance using the Meeting Request utilities,
// if MR viewers is enabled.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CCalenDeleteUi::TryDeleteWithMrUtilsL( CCalInstance* aInstance, 
                                                              CalCommon::TRecurrenceRange aRepeatType )
    {
    TRACE_ENTRY_POINT;
    
    TBool doDelete = ETrue;

	if( iGlobalData->InterimUtilsL().MRViewersEnabledL() && 
        iGlobalData->InterimUtilsL().IsMeetingRequestL(aInstance->Entry()))

        {
        CMRMailboxUtils::TMailboxInfo info;
        if( iGlobalData->AttemptToRetrieveDefaultMailboxL( info ) )
            {
            if(aRepeatType == CalCommon::EThisAndAll )
                {
                iGlobalData->MeetingRequestUtilsL().DeleteWithUiL( aInstance->Entry(),
                                                                                      info.iEntryId );
                if( aInstance )
                    {
                    delete aInstance;
                    aInstance = NULL;
                    }
                }
            else if( aRepeatType == CalCommon::EThisOnly )
                {
                iGlobalData->MeetingRequestUtilsL().DeleteWithUiL( aInstance, info.iEntryId );
                }
            else
                {
                User::Leave( KErrNotSupported );
                }
            }
        else
            {
            doDelete = EFalse;
            }
        }
    else
        {
        doDelete = EFalse;
        }

    TRACE_EXIT_POINT;
    return doDelete;
    }

// -----------------------------------------------------------------------------
// CCalenDeleteUi::ShowMultipleEntriesDeleteQueryL
// For displaying multiple entries deletion confirmation query
// -----------------------------------------------------------------------------
//
TInt CCalenDeleteUi::ShowMultipleEntriesDeleteQueryL(TInt aCount)
	{
    TRACE_ENTRY_POINT;

    CAknQueryDialog *dialog = CAknQueryDialog::NewL( );
    CleanupStack::PushL( dialog );
    TInt resID;
    HBufC* prompt;
    if( aCount > 1 )
        {
        resID = R_CALEN_QTN_TODO_QUEST_DELETE_MARKED_NOTES;
        prompt = StringLoader::LoadLC( resID, aCount );
        }
    else if( aCount ==  1 )
        {
        resID = R_CALEN_QTN_TODO_QUEST_DELETE_MARKED_NOTE;
        prompt = StringLoader::LoadLC( resID );
        }
    else
        {
        CleanupStack::PopAndDestroy( dialog );
        TRACE_EXIT_POINT;
        return 0;   //return 0 for other invalid aCount value ( < 0 )
        }
    dialog->SetPromptL( *prompt );
    CleanupStack::PopAndDestroy( prompt );

    CleanupStack::Pop( dialog );

    TRACE_EXIT_POINT;
    return dialog->ExecuteLD( R_CALEN_ERASEQUERY_NOTE );

	}

// -----------------------------------------------------------------------------
// CCalenDeleteUi::DialogDismissedL
// From MProgressDialogCallback
// Callback method
// called when a dialog is dismissed.
// -----------------------------------------------------------------------------
//
void CCalenDeleteUi::DialogDismissedL( const TInt /*aButtonId*/ )
    {
    TRACE_ENTRY_POINT;
    // dismiss the wait dialog
    if(iWaitDialog)
        {
        iWaitDialog->ProcessFinishedL();
        }
    
    // no more entries to delete
    iMoreEntriesToDelete = EFalse;
    iDisplayQuery = EFalse;
    
    // issue notification cancel delete
    iController.BroadcastNotification(ECalenNotifyCancelDelete);
    TRACE_EXIT_POINT;
    }

// -----------------------------------------------------------------------------
// CCalenDeleteUi::DeleteEntryL
// Delete entry using entry local uid
// -----------------------------------------------------------------------------
//
void CCalenDeleteUi::DeleteEntryL(TCalLocalUid& aEntryLocalUid, TInt aColId)
    {
    TRACE_ENTRY_POINT;
    
    // fetch the entry
    CCalEntry* entry = iGlobalData->EntryViewL(aColId)->FetchL(aEntryLocalUid);
    if( entry )
        {
        CleanupStack::PushL( entry );
        iGlobalData->EntryViewL(aColId)->DeleteL( *entry );
        CleanupStack::Pop( entry );
        delete entry;
        entry = NULL;
        }   
    
    TRACE_EXIT_POINT;
    }

// -----------------------------------------------------------------------------
// CCalenDeleteUi::DisplayWaitDialogL
// Display wait dialog
// -----------------------------------------------------------------------------
//
void CCalenDeleteUi::DisplayWaitDialogL()
    {
    TRACE_ENTRY_POINT;
    
    delete iWaitDialog;
    iWaitDialog = NULL;
    iWaitDialog = new( ELeave )CAknWaitDialog( REINTERPRET_CAST( CEikDialog**, &iWaitDialog ), ETrue );
    iWaitDialog->ExecuteLD( R_TODO_VIEW_DELETE_WAIT_NOTE );
    iWaitDialog->SetCallback(this);
    
    TRACE_EXIT_POINT;
    }

// -----------------------------------------------------------------------------
// CCalenDeleteUi::MarkedEntriesDeletedL
// Dismiss wait dialog and show information note
// -----------------------------------------------------------------------------
//
void CCalenDeleteUi::MarkedEntriesDeletedL()
    {
    TRACE_ENTRY_POINT;
    
    // dismiss the waitdialog
    if(iWaitDialog)
        {
        iWaitDialog->ProcessFinishedL();
        }
    
    // Show confirmation note
    //HBufC* buf = StringLoader::LoadLC( R_QTN_CALE_CONF_ALL_NOTES_DELETED, iEikEnv );
    //CAknConfirmationNote* dialog = new( ELeave ) CAknConfirmationNote();
    //dialog->ExecuteLD(*buf);
    //CleanupStack::PopAndDestroy( buf );

    // notify marked entries deleted
    iController.BroadcastNotification( ECalenNotifyMarkedEntryDeleted );
    
    TRACE_EXIT_POINT;
    }

// -----------------------------------------------------------------------------
// CCalenDeleteUi::HandleDeleteAllEntriesL
// Handles launching of the delete all entries list query
// -----------------------------------------------------------------------------
//
void CCalenDeleteUi::HandleDeleteAllEntriesL()
    {
    TRACE_ENTRY_POINT;
    RPointerArray<CCalCalendarInfo> calendarInfoList;
    CleanupClosePushL(calendarInfoList);
	iController.Services().GetAllCalendarInfoL(calendarInfoList);
    TInt visibleCalendarsCount(0);
    for(TInt index=0;index<calendarInfoList.Count();index++)
        {
        if(calendarInfoList[index]->Enabled())
            {
            visibleCalendarsCount++;
            }
        if(visibleCalendarsCount>1)
            {
            break;
            }
        }
    CleanupStack::PopAndDestroy();
    
    TInt headingTextResourceId(0);
    if(visibleCalendarsCount==1)
        {
        headingTextResourceId = R_CALE_SINGLE_CALENDAR_DELETE_ENTRIES;
        }
    else
        {
        headingTextResourceId = R_CALE_MULTI_CALENDAR_DELETE_ENTRIES;
        }

    TInt selectedIndex(0);
    CAknListQueryDialog* deleteEntriesListDialog = new(ELeave) CAknListQueryDialog(&selectedIndex);
    deleteEntriesListDialog->PrepareLC(R_DELETE_ENTRIES_LIST_QUERY);
    HBufC* buf = StringLoader::LoadLC( headingTextResourceId, iEikEnv );
    deleteEntriesListDialog->QueryHeading()->SetTextL(buf->Des());
    CleanupStack::PopAndDestroy( buf );
    
    if(deleteEntriesListDialog->RunLD())
        {
        if(selectedIndex)
            {
            DeleteAllEntriesL();
            }
        else
            {
            DeleteEntriesBeforeDateL();
            }
        }
    else
        {
        iController.BroadcastNotification(ECalenNotifyDeleteFailed);
        }
    
    TRACE_EXIT_POINT
    }
	
// End of File