notepad/notepad1/LibSrc/NpdModel.cpp
author andy simpson <andrews@symbian.org>
Thu, 02 Sep 2010 15:47:07 +0100
branchRCL_3
changeset 67 1539a383d7b6
parent 21 9711e452b5e9
parent 66 bd7edf625bdd
permissions -rw-r--r--
Merge after removal of incorrect RCL_3 drop

/*
* Copyright (c) 2002 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:  Implementation of Notepad engine.
*
*/


// INCLUDE FILES
#include <e32std.h>
#include <gulutil.h>
#include <sysutil.h>
#include <eikenv.h>
#include <barsread.h>
#include "NpdLib.hrh"
#include "NpdModel_platsec.h"
#include "NpdApi.h"
#include "NpdLibPanic.h"
#include "AknUtils.h"

// CONSTANTS
_LIT(KNotepadMceFirstColumnData, "1");
_LIT(KNotepadSqlSelect, 
    "SELECT * FROM Table1 ORDER BY time DESC");
_LIT(KNotepadSqlMceSelect, 
    "SELECT * FROM Table1 ORDER BY memo ASC,key DESC");
_LIT(KNotepadSqlDeleteByKeysAppend, " OR key="); // 8 chars
const TInt KNotepadSqlDeleteByKeysAppendSize(18); // %d costs 10 chars in max
const TInt KNotepadItemArrayGranularity(10);
const TInt KNotepadMaxRunIntervalInMicroSeconds(500000); // 0.5 sec
const TInt KNotepadBuildItemArrayProgressCount(10);
const TInt KNotepadMaxDeleteCountInStep(300);
const TInt KNotepadDiskSpaceNeededForMultipleDeletion(8192);
const TInt KNotepadMaxCharactersForSort(100);

// assert KNotepadListEntryLength >= KNotepadMaxCharactersForSort + length of
//     1st column
const TInt KNotepadListEntryLength( 60 ); 

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

// -----------------------------------------------------------------------------
// CNotepadModel::NewL
// Constructor.
// -----------------------------------------------------------------------------
//
EXPORT_C CNotepadModel* CNotepadModel::NewL(RFs& /*aFs*/, TInt aResId)
    {
    CNotepadModel* self = new(ELeave) CNotepadModel();
    CleanupStack::PushL(self);
    self->ConstructL(aResId);
    CleanupStack::Pop(); //self
    return self;
    }

// -----------------------------------------------------------------------------
// CNotepadModel::~CNotepadModel
// Destructor.
// -----------------------------------------------------------------------------
//
EXPORT_C CNotepadModel::~CNotepadModel()
    {
    delete iDatabaseChangeNotifier;
    delete iExecuter;
    iSavedDeleteKeys.Close();
    iDbUpdate.Close();
    iDbView.Close();
    iKeyArray.Close(); //delete iKeyArray;
    delete iItemArray;
    delete iTimeFormat;
    delete iDateFormat;
    if ( iFixedFirstNote )
    	{
        delete iFixedFirstNote;
    	}    
    }

// -----------------------------------------------------------------------------
// CNotepadModel::AddContentL
// API. CNotepadApi call this.
// -----------------------------------------------------------------------------
//
EXPORT_C void CNotepadModel::AddContentL(const TDesC& aText)
    {
    TInt key(KNotepadPseudoKeyIdForNewNote);
    InsertL(aText, key);
    }

// -----------------------------------------------------------------------------
// CNotepadModel::OpenL
// deprecated. (only for BC).
// -----------------------------------------------------------------------------
//
EXPORT_C void CNotepadModel::OpenL()
    {
    }

// -----------------------------------------------------------------------------
// CNotepadModel::Close
// deprecated. (only for BC).
// -----------------------------------------------------------------------------
//
EXPORT_C void CNotepadModel::Close() 
    {
    }

// -----------------------------------------------------------------------------
// CNotepadModel::IsOpen
// deprecated. (only for BC).
// -----------------------------------------------------------------------------
//
EXPORT_C TBool CNotepadModel::IsOpen() 
    {
    return ETrue;
    } 

// -----------------------------------------------------------------------------
// CNotepadModel::SeekKey
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CNotepadModel::SeekKey(const TInt aKey)
    {
    return iKeyArray.Find(aKey) >= 0 ? // found?
        0 : 1;
    }

// -----------------------------------------------------------------------------
// CNotepadModel::ContentL
// -----------------------------------------------------------------------------
//
HBufC* CNotepadModel::ContentL(TInt aItemIndex)
    {
    return ContentByKeyL(iKeyArray[aItemIndex]);
    }

// -----------------------------------------------------------------------------
// CNotepadModel::IndexOf
// -----------------------------------------------------------------------------
//
TInt CNotepadModel::IndexOf(const TInt aKey) const
    {
    TInt returnIndex(KNotepadModelInvalidIndex);
    if ( aKey != KNotepadPseudoKeyIdForNewNote )
        {
        TInt index(iKeyArray.Find(aKey));
        if ( index >= 0 )
            {
            returnIndex = index;
            }
        }
    return returnIndex;
    }

// -----------------------------------------------------------------------------
// CNotepadModel::HandleDateChangedL
// -----------------------------------------------------------------------------
//
void CNotepadModel::HandleDateChangedL(TBool aSyncNow)
    {
    iFlag |= ENotepadRequireDbViewUpdate | ENotepadRequireItemArrayUpdate;
    if ( aSyncNow )
        {
        SyncL(EFalse);
        }
    }

// -----------------------------------------------------------------------------
// CNotepadModel::DeleteByKeysL
// -----------------------------------------------------------------------------
//
void CNotepadModel::DeleteByKeysL(const RArray<TInt>& aKeys)
    {
    __ASSERT_DEBUG( aKeys.Count() > 0, 
        Panic(ENotepadLibraryPanicInvalidArgument) );
    TRAPD( err, PrepareToDeleteByKeysL(aKeys); ); // execute RDbUpdate
    if ( err != KErrNone )
        {
        AbortDeletionL();
        User::Leave(err);
        }
    iFlag |= ENotepadIsDeleting;
    iFlag &= ~ENotepadIsRemovingLinks;
    iExecuter->Start(TCallBack(DeleteCallBack, this));
    }

// -----------------------------------------------------------------------------
// CNotepadModel::CancelDeletion
// -----------------------------------------------------------------------------
//
void CNotepadModel::CancelDeletion()
    {
    iDbUpdate.Close();
    delete iExecuter;
    iExecuter = NULL;
    iFlag &= ~ENotepadIsDeleting;
    iFlag &= ~ENotepadIsRemovingLinks;
    iFlag |= ENotepadRequireDbViewUpdate;
    if ( iDatabase.IsDamaged() )
        {
        iDatabase.Recover();
        }
    iSavedDeleteKeys.Reset();
	}

// -----------------------------------------------------------------------------
// CNotepadModel::SyncL
// Sync non-updated data.
// -----------------------------------------------------------------------------
//
void CNotepadModel::SyncL( const TBool aForceSync )
    {
    // If iExecuter is creating iDbView, cancel the process and restart 
    // to create iDbView. If iExecuter is deleting items, this method does nothing.
    // (ie. Creating iDbView is postponed until the deleting process 
    // will be finished.
	if ( !aForceSync && (iFlag & ENotepadItemArrayUpdateOnly) )
	    {
	    iFlag |= ENotepadItemArrayUpdateOnly;
    	if ( iModelObserver )
        	{
        	iModelObserver->HandleNotepadModelEventL(
          			MNotepadModelObserver::EStartItemArrayChange );
        	}
	    TInt err(KErrNone);
		TRAP(err,DoUpdateNotepadItemArrayAndKeyArrayL(*iItemArray,
													  iKeyArray,
													  *iTimeFormat));
		if ( err != KErrNone)
			{
			iItemArray->Reset();
			iKeyArray.Reset();
			if ( iModelObserver )
				{
			    iModelObserver->HandleNotepadModelEventL(
			        MNotepadModelObserver::EAbortItemArrayChange ); // not leave
			    }
			User::Leave(err);
		    }
		iFlag &= ~ENotepadItemArrayUpdateOnly; // now iItemArray is up to date
		if ( iModelObserver )
			{
			iModelObserver->HandleNotepadModelEventL(
			        MNotepadModelObserver::ECompleteItemArrayChange );
		    }
	    }
    else if(aForceSync || ( iFlag & ENotepadRequireDbViewUpdate ))
        {
        iFlag |= (ENotepadRequireDbViewUpdate | ENotepadRequireItemArrayUpdate);
        iDbView.Close();
        TDbTextComparison textComparison(EDbCompareCollated);
        User::LeaveIfError( iDbView.Prepare( iDatabase, 
            ( IsTemplates() ? TDbQuery(KNotepadSqlMceSelect, textComparison)
                : TDbQuery(KNotepadSqlSelect, textComparison) ), 
        RDbView::EReadOnly ) );
        User::LeaveIfError( iDbView.EvaluateAll() );
        iFlag &= ~ENotepadRequireDbViewUpdate; // iDbView is now up to date
        BuildItemArrayL(ETrue); // force update
        }
    else 
        {
        BuildItemArrayL(aForceSync);
        }
    return;
    }

// -----------------------------------------------------------------------------
// CNotepadModel::HandleDatabaseChangedL
// -----------------------------------------------------------------------------
//
void CNotepadModel::HandleDatabaseChangedL(TInt aStatus)
    {
    if ( ( ModeOp() == CNotepadCoreModel::ENotepadModelRowDeleted ) ||
    	 ( ModeOp() == CNotepadCoreModel::ENotepadModelRowAdded ) ||
    	 ( ModeOp() == CNotepadCoreModel::ENotepadModelRowUpdated ) )
    	{
 	  	iFlag |=ENotepadItemArrayUpdateOnly;
    	}
    else
    	{
    	iFlag |= ENotepadRequireDbViewUpdate; // delayed sync	
    	}
    if ( iModelObserver 
        && !(IsDeleting() && !(iFlag & ENotepadIsRemovingLinks)) )
        {
        iModelObserver->HandleNotepadModelEventL(
            MNotepadModelObserver::EDatabaseChanged, aStatus );
        }
    }

// -----------------------------------------------------------------------------
// CNotepadModel::SetNotepadModelObserver
// -----------------------------------------------------------------------------
//
void CNotepadModel::SetNotepadModelObserver(
    MNotepadModelObserver* aObserver )
    {
    iModelObserver = aObserver;
    }

// -----------------------------------------------------------------------------
// CNotepadModel::MdcaCount
// from MDesCArray
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CNotepadModel::MdcaCount() const
    {
    return iItemArray->Count();
    }

// -----------------------------------------------------------------------------
// CNotepadModel::MdcaPoint
// from MDesCArray
// -----------------------------------------------------------------------------
//
EXPORT_C TPtrC CNotepadModel::MdcaPoint(TInt aIndex) const
    {
    return (*iItemArray)[aIndex];
    }

// -----------------------------------------------------------------------------
// CNotepadModel::CNotepadModel
// C++ constructor
// -----------------------------------------------------------------------------
//
CNotepadModel::CNotepadModel()
    : CNotepadCoreModel(),
    iListingStyle(ENotepadListingStyleNone)
    {
    }

// -----------------------------------------------------------------------------
// CNotepadModel::ConstructL
// second phase constructor.
// -----------------------------------------------------------------------------
//
void CNotepadModel::ConstructL(TInt aResId)
    {
    TResourceReader rr;
    iEnv->CreateResourceReaderLC(rr, aResId); // Push rr
    CNotepadCoreModel::ConstructL(rr.ReadInt32()); // LLINK data_file
    iListingStyle 
        = rr.ReadInt16(); // WORD  listing_style;
    TInt dateResId(rr.ReadInt32());               // LLINK date_format
    TInt timeResId(rr.ReadInt32());               // LLINK time_format
    TInt firstNoteResId(rr.ReadInt32());          // LLINK first_note;
    CleanupStack::PopAndDestroy(); // rr
    if (dateResId)
        {
        iDateFormat = iEnv->AllocReadResourceL(dateResId);
        }
    if (timeResId)
        {
        iTimeFormat = iEnv->AllocReadResourceL(timeResId);
        }
    if ( firstNoteResId )
    	{
    iFixedFirstNote = iEnv->AllocReadResourceL( firstNoteResId );
    	}
    iItemArray = new(ELeave) CDesCArrayFlat(KNotepadItemArrayGranularity);
    iDatabaseChangeNotifier = 
        CNotepadModel::CDatabaseChangeNotifier::NewL(iDatabase, *this);

    SyncL(ETrue);
    }

// -----------------------------------------------------------------------------
// CNotepadModel::PrepareToDeleteByKeysL
// -----------------------------------------------------------------------------
//
void CNotepadModel::PrepareToDeleteByKeysL(const RArray<TInt>& aKeys)
    {
    CancelDeletion();
    User::LeaveIfError(iFileSession.Connect());
   	CleanupClosePushL(iFileSession);
    iRetval = iFileSession.ReserveDriveSpace( KDefaultDrive, KNotepadDiskSpaceNeededForMultipleDeletion );
    if ( iRetval == KErrNone )
    {
    	iRetval = iFileSession.GetReserveAccess( KDefaultDrive );
    }
    // the priority of iExecuter must be lower than that of CAknProgressDialog
    iExecuter = CIdle::NewL(CActive::EPriorityLow); 
    const TInt count( aKeys.Count() );
    for (TInt i(0); i < count; i++)
        {
        User::LeaveIfError(iSavedDeleteKeys.Append(aKeys[i]));
        }
    iProgressCount = 0;
    ExecuteDeleteStepL();
    iRetval = iFileSession.ReleaseReserveAccess( KDefaultDrive );
    iFileSession.Close();
	CleanupStack::PopAndDestroy();
    }

// -----------------------------------------------------------------------------
// CNotepadModel::ExecuteDeleteStepL
// -----------------------------------------------------------------------------
//
void CNotepadModel::ExecuteDeleteStepL()
    {
    
    iStepCount = iSavedDeleteKeys.Count();
    if ( iStepCount > KNotepadMaxDeleteCountInStep )
        {
        iStepCount = KNotepadMaxDeleteCountInStep;
        }
    HBufC* hbuf = HBufC::NewLC( KNotepadSqlDeleteHeadSize + 
        ( iStepCount - 1 )* KNotepadSqlDeleteByKeysAppendSize);
    TPtr sql = hbuf->Des();
    sql.Append(KNotepadSqlDeleteHead);
    sql.AppendNum(iSavedDeleteKeys[0]);
    if ( IsTemplates() )
        {
        iSavedDeleteKeys.Remove(0);
        }
    else // If Notepad, Remove is postponed until remove link phase
        {
        for (TInt i(1); i < iStepCount; i++)
            {
            sql.Append(KNotepadSqlDeleteByKeysAppend);
            sql.AppendNum(iSavedDeleteKeys[i]);
            }
        }
    User::LeaveIfError(iDbUpdate.Execute(iDatabase, sql));
    CleanupStack::PopAndDestroy(); // hbuf
    }

// -----------------------------------------------------------------------------
// CNotepadModel::AbortDeletionL
// -----------------------------------------------------------------------------
//
void CNotepadModel::AbortDeletionL()
    {
    CancelDeletion();
    if ( iModelObserver )
        {
        iModelObserver->HandleNotepadModelEventL(
            MNotepadModelObserver::EAbortDeletion );
        }
    }

// -----------------------------------------------------------------------------
// CNotepadModel::CompleteDeletionL
// -----------------------------------------------------------------------------
//
void CNotepadModel::CompleteDeletionL()
    {
    CancelDeletion();
    if ( iModelObserver )
        {
        iModelObserver->HandleNotepadModelEventL(
            MNotepadModelObserver::ECompleteDeletion);
        }
    SyncL(ETrue);
    iItemArray->Compress();
    }

// -----------------------------------------------------------------------------
// CNotepadModel::DeleteCallBack
//
// be sure that this function never leave after AbortDeletionL
// because iExecuter is deleted in AbortDeletionL.
// -----------------------------------------------------------------------------
//
TInt CNotepadModel::DeleteCallBack(TAny *aSelf)
    {
    TInt needsRepeat(FALSE);
    CNotepadModel* self = STATIC_CAST(CNotepadModel*, aSelf);
    TRAPD(err, 
        needsRepeat = ( self->iFlag & ENotepadIsRemovingLinks ) ? 
            self->DoRemoveLinkCallBackL() : 
            self->DoDeleteCallBackL(); 
        );
    if ( err != KErrNone )
        {
        self->iEnv->HandleError(err);
        TRAP(err, self->AbortDeletionL(););
        if ( err != KErrNone )
            {
            self->iEnv->HandleError(err);
            }
        }
    return needsRepeat;
    }

// -----------------------------------------------------------------------------
// CNotepadModel::DoDeleteCallBackL
// -----------------------------------------------------------------------------
//
TInt CNotepadModel::DoDeleteCallBackL()
    {
    TInt needsRepeat(TRUE);
    TInt increment(0);
    TBool deleteFinished(EFalse);
    const TInt stat(iDbUpdate.Next());
    if ( stat == 0 ) // current step has completed
        {
        iDbUpdate.Close();
        if ( IsTemplates() )
            {
            if ( iSavedDeleteKeys.Count() == 0 ) // MCE, finish all
                {
                needsRepeat = FALSE;
                CompleteDeletionL();
                deleteFinished = ETrue;
                }
            else // do next step
                {
                increment = iStepCount - iProgressCount;

                iProgressCount += increment;
                if ( iModelObserver )
                    {
                    iModelObserver->HandleNotepadModelEventL(
                            MNotepadModelObserver::EProgressDeletion,
                            1 );
                    }

                ExecuteDeleteStepL();
                }
            }
        else
            {
            // switch to remove link phase
            iFlag |= ENotepadIsRemovingLinks; 
            increment = iStepCount - iProgressCount;
            if ( iSavedDeleteKeys.Count() == iStepCount ) // final step
                {
                deleteFinished = ETrue;
                }
            }
        }
    if ( stat > 0 )
        {
        increment = iDbUpdate.RowCount() - iProgressCount;
        }            
    
    if ( deleteFinished || ( stat == 0 && 
        SysUtil::FFSSpaceBelowCriticalLevelL(&(iEnv->FsSession())) ) )
        {
        User::LeaveIfError(iDatabase.Compact());
        }
    User::LeaveIfError(stat);
    return needsRepeat;
    }

// -----------------------------------------------------------------------------
// CNotepadModel::DoRemoveLinkCallBackL
// -----------------------------------------------------------------------------
//
TInt CNotepadModel::DoRemoveLinkCallBackL()
    {
    TInt needsRepeat(TRUE);
    TBool hasFinished(EFalse);
    TBool timeUp(EFalse);
    TInt count(0);
    TTime beginning;
    TTime now;
    TTimeIntervalMicroSeconds maxInterval(
        KNotepadMaxRunIntervalInMicroSeconds );
    beginning.UniversalTime();
    while ( !hasFinished && !timeUp )
        {
        if ( iStepCount == 0 ) // current step has completed
            {
            hasFinished = ETrue;
            }
        else
            {
            iSavedDeleteKeys.Remove(0);
            count++;
            iStepCount--;
            now.UniversalTime();
            timeUp = ( now.MicroSecondsFrom(beginning) > maxInterval );
            }
        }
    if ( hasFinished ) // current step has finished
        {
        if ( iSavedDeleteKeys.Count() == 0 ) // finish all
            {
            needsRepeat = FALSE;
            CompleteDeletionL();
            }
        else // switch to delete phase again
            {
            iFlag &= ~ENotepadIsRemovingLinks;
            ExecuteDeleteStepL();
            }
        }
    if ( needsRepeat && count > 0 )
        {
        iModelObserver->HandleNotepadModelEventL(
            MNotepadModelObserver::EProgressDeletion, count); 
        }
    return needsRepeat;
    }

// -----------------------------------------------------------------------------
// CNotepadModel::BuildItemArrayL
// -----------------------------------------------------------------------------
//
void CNotepadModel::BuildItemArrayL( const TBool aForceSync )
    {
    if ( !aForceSync && !(iFlag & ENotepadRequireItemArrayUpdate) )
        {
        return;
        }

    iFlag |= ENotepadRequireItemArrayUpdate;
    if ( iModelObserver )
        {
        iModelObserver->HandleNotepadModelEventL(
            MNotepadModelObserver::EStartItemArrayChange );
        }
    iItemArray->Reset();
    iKeyArray.Reset();
    //insert the New note as the firt note
    if ( iFixedFirstNote != NULL )
		{
		TBuf<256> buf;
		_LIT( KBlankSpace, "   " );
		buf.Append( KBlankSpace );	
		buf.Append( KColumnListSeparator );
		buf.Append( *iFixedFirstNote );
		iItemArray->AppendL( buf );
		//default key for New note, -2 is never used for normal keys.
		iKeyArray.Append( -2 );
		}
    
  
    TRAPD( err, DoBuildItemArrayL() );
    if ( err != KErrNone)
        {
        iItemArray->Reset();
        iKeyArray.Reset();
        if ( iModelObserver )
            {
            iModelObserver->HandleNotepadModelEventL(
                MNotepadModelObserver::EAbortItemArrayChange ); // not leave
            }
        User::Leave(err);
        }
    iFlag &= ~ENotepadRequireItemArrayUpdate; // now iItemArray is up to date
    if ( iModelObserver )
        {
        iModelObserver->HandleNotepadModelEventL(
            MNotepadModelObserver::ECompleteItemArrayChange );
        }
    }

// -----------------------------------------------------------------------------
// CNotepadModel::DoBuildItemArrayL
// -----------------------------------------------------------------------------
//
void CNotepadModel::DoBuildItemArrayL()
    {
    HBufC* hbuf = HBufC::NewLC(KNotepadListEntryLength);
    TPtr buf = hbuf->Des();
    if ( IsTemplates() )
        {
        DoBuildTemplateItemArrayL(buf);
        }
    else
        {
        DoBuildNotepadItemArrayL(buf);
        }
    CleanupStack::PopAndDestroy(); // hbuf
    }

// -----------------------------------------------------------------------------
// CNotepadModel::DoBuildNotepadItemArrayL
// -----------------------------------------------------------------------------
//
void CNotepadModel::DoBuildNotepadItemArrayL(
    TPtr& aBuf)
    {
    TTimeIntervalMinutes offset;
    TTime now;
    now.HomeTime();
    TTime gmt;
    gmt.UniversalTime();
    now.MinutesFrom(gmt, offset);
    TInt currentDay(now.DateTime().Day());
    TInt currentMonth(now.DateTime().Month());
    TInt currentYear(now.DateTime().Year());

    RArray<TInt> minutesArrayOfToday;
    CleanupClosePushL(minutesArrayOfToday);
    TInt minutesInToday(0);

    TInt firstIndexOfTheDay(KNotepadModelInvalidIndex);
    TDateTime prevDateTime;

    RArray<TPtrC> textArrayOfTheDay;
    CleanupClosePushL(textArrayOfTheDay);
    iDbView.FirstL();
    while (iDbView.AtRow())
        {
        iDbView.GetL();
        TInt thisKey(iDbView.ColInt(ENotepadKey));
        TTime time = iDbView.ColTime(ENotepadUpdateTime);
        time += offset; // including summertime adjustment
        TDateTime dateTime = time.DateTime(); // cache
        TBool isToday( dateTime.Day() == currentDay
             && dateTime.Month() == currentMonth
             && dateTime.Year() == currentYear );
        if ( isToday )
            {
            minutesInToday = dateTime.Hour() * 60 + dateTime.Minute();
            }
        aBuf.SetLength(0);
        TInt textOffset(0);
        switch (iListingStyle)
            {
            case ENotepadListingStyleNP: // list of memos
                time.FormatL( aBuf, isToday ? *iTimeFormat : *iDateFormat );
                aBuf.Append(KColumnListSeparator);
                textOffset = aBuf.Length();
                // through into next case
            case ENotepadListingStyleFetch: // fetch a memo
                AppendContentAsLabelL(aBuf, iDbView);
                break;
            default:
                break;
            }

        TPtrC thisText = 
            aBuf.Mid(textOffset).Left(KNotepadMaxCharactersForSort);
        if ( (iItemArray->Count() == 0 && iFixedFirstNote == NULL) || (iItemArray->Count() == 1 && iFixedFirstNote != NULL) || 
             dateTime.Day() != prevDateTime.Day() ||
             dateTime.Month() != prevDateTime.Month() ||
             dateTime.Year() != prevDateTime.Year() )
            {
            // first entry or date of the item has changed
            firstIndexOfTheDay = iItemArray->Count();

            textArrayOfTheDay.Reset();
            if ( isToday )
                {
                User::LeaveIfError(minutesArrayOfToday.Append(minutesInToday));
                }
            // INSERT POINT
            AknTextUtils::LanguageSpecificNumberConversion(aBuf);
            iItemArray->AppendL(aBuf);
            User::LeaveIfError( textArrayOfTheDay.Append(
                (*iItemArray)[firstIndexOfTheDay].Mid(textOffset).Left(
                    KNotepadMaxCharactersForSort) ) );
            User::LeaveIfError(iKeyArray.Append(thisKey));
            }
        else
            {
            // calculate an insertion point
            TInt low(0); // this will be result insertion point
            TInt high( textArrayOfTheDay.Count() - 1 );
            TInt mid(0);
            while ( high >= low )
                {
                mid = (high + low) / 2;
                if ( isToday ? ( minutesInToday < minutesArrayOfToday[mid] ||
                    ( minutesInToday == minutesArrayOfToday[mid] &&
                        thisText.CompareC(textArrayOfTheDay[mid]) > 0 ) ) :
                    thisText.CompareC(textArrayOfTheDay[mid]) > 0 )
                    {
                    low = mid + 1;
                    }
                else
                    {
                    high = mid - 1;
                    }
                }
            // low is result
            if ( isToday )
                {
                User::LeaveIfError(minutesArrayOfToday.Insert(
                    minutesInToday, low ) );
                }
            // INSERT POINT
            AknTextUtils::LanguageSpecificNumberConversion(aBuf);
            iItemArray->InsertL(firstIndexOfTheDay + low, aBuf);
            User::LeaveIfError( textArrayOfTheDay.Insert(
                (*iItemArray)[firstIndexOfTheDay + low].Mid(textOffset).Left(
                    KNotepadMaxCharactersForSort), 
                low ) );
            User::LeaveIfError(
                iKeyArray.Insert(thisKey, firstIndexOfTheDay + low) );
            }
        if ( iModelObserver && 
            iItemArray->Count() == KNotepadBuildItemArrayProgressCount )
            {
            iModelObserver->HandleNotepadModelEventL(
                MNotepadModelObserver::EProgressItemArrayChange );
            }
        prevDateTime = dateTime;
        iDbView.NextL();
        }
    CleanupStack::PopAndDestroy(2); // minutesArrayOfToday, textArrayOfTheDay
    }

// -----------------------------------------------------------------------------
// CNotepadModel::DoBuildTemplateItemArrayL
// -----------------------------------------------------------------------------
//
void CNotepadModel::DoBuildTemplateItemArrayL(
    TPtr& aBuf)
    {
    iDbView.FirstL();
    while (iDbView.AtRow())
        {
        iDbView.GetL();
        TInt thisKey(iDbView.ColInt(ENotepadKey));
        aBuf.SetLength(0);
        switch (iListingStyle)
            {
            case ENotepadListingStyleMC:
                aBuf.Append(KNotepadMceFirstColumnData);
                aBuf.Append(KColumnListSeparator);
                // pass through into next case
            case ENotepadListingStyleFetchMC: // fetch template
                AppendContentAsLabelL(aBuf, iDbView);
                break;
            default:
                break;
            }
        // INSERT POINT
        iItemArray->AppendL(aBuf);
        User::LeaveIfError(iKeyArray.Append(thisKey));
        if ( iModelObserver && 
            iItemArray->Count() == KNotepadBuildItemArrayProgressCount )
            {
            iModelObserver->HandleNotepadModelEventL(
                MNotepadModelObserver::EProgressItemArrayChange );
            }
        iDbView.NextL();
        }
    }

// -----------------------------------------------------------------------------
// CNotepadModel::CNotepadModel_Reserved
// -----------------------------------------------------------------------------
//
EXPORT_C void CNotepadModel::CNotepadModel_Reserved()
    {
    }

// -----------------------------------------------------------------------------
// CNotepadModel::SetItemArrayFlags
// -----------------------------------------------------------------------------
//
void CNotepadModel::SetItemArrayFlags()
	{
	if(iFlag&ENotepadItemArrayUpdateOnly)
		{

		iFlag |= ENotepadRequireDbViewUpdate;
		iFlag |= ENotepadRequireItemArrayUpdate;
		}
	}

// -----------------------------------------------------------------------------
// CNotepadModel::ItemArrayFlags
// -----------------------------------------------------------------------------
//
TUint CNotepadModel::ItemArrayFlags()
	{
	return iFlag;
	}

// -----------------------------------------------------------------------------
// CNotepadModel::CDatabaseChangeNotifier::NewL
// -----------------------------------------------------------------------------
//
CNotepadModel::CDatabaseChangeNotifier* 
    CNotepadModel::CDatabaseChangeNotifier::NewL(
    RDbDatabase& aDatabase,
    CNotepadModel& aModel )
    {
    CDatabaseChangeNotifier* self = 
        new(ELeave) CDatabaseChangeNotifier(aModel);
    CleanupStack::PushL(self);
    self->ConstructL(aDatabase);
    CleanupStack::Pop(); // self
    return self; 
    }

// -----------------------------------------------------------------------------
// CNotepadModel::CDatabaseChangeNotifier::~CDatabaseChangeNotifier
// -----------------------------------------------------------------------------
//
CNotepadModel::CDatabaseChangeNotifier::~CDatabaseChangeNotifier()
    {
    Cancel();
    iDbNotifier.Close(); 
    }

// -----------------------------------------------------------------------------
// CNotepadModel::CDatabaseChangeNotifier::CDatabaseChangeNotifier
// -----------------------------------------------------------------------------
//
CNotepadModel::CDatabaseChangeNotifier::CDatabaseChangeNotifier(
    CNotepadModel& aModel )
    :CActive(CActive::EPriorityLow), iModel(aModel)
    {
    CActiveScheduler::Add(this);
    }

// -----------------------------------------------------------------------------
// CNotepadModel::CDatabaseChangeNotifier::ConstructL
// -----------------------------------------------------------------------------
//
void CNotepadModel::CDatabaseChangeNotifier::ConstructL(
    RDbDatabase& aDatabase ) 
    { 
    User::LeaveIfError(iDbNotifier.Open(aDatabase)); 
    iDbNotifier.NotifyChange(iStatus);
    SetActive();
    }

// -----------------------------------------------------------------------------
// CNotepadModel::CDatabaseChangeNotifier::DoCancel
// -----------------------------------------------------------------------------
//
void CNotepadModel::CDatabaseChangeNotifier::DoCancel()
    { 
    iDbNotifier.Cancel(); 
    }

// -----------------------------------------------------------------------------
// CNotepadModel::CDatabaseChangeNotifier::RunL
// -----------------------------------------------------------------------------
//
void CNotepadModel::CDatabaseChangeNotifier::RunL()
    {
    // enum TEvent {EClose,EUnlock,ECommit,ERollback,ERecover};
    TInt status(iStatus.Int());
    TInt err(KErrNone);
    if (status == RDbNotifier::ECommit)
        {
        TRAP(err, iModel.HandleDatabaseChangedL(status););
        }
    // Restart this even if err != KErrNone
    iDbNotifier.NotifyChange(iStatus);
    SetActive();
    User::LeaveIfError(err);
    }

// End of File