notepad/notepad1/LibSrc/NpdModel.cpp
changeset 0 f979ecb2b13e
child 20 21239b3bcd78
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/notepad/notepad1/LibSrc/NpdModel.cpp	Tue Feb 02 10:12:19 2010 +0200
@@ -0,0 +1,935 @@
+/*
+* 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;
+    }
+
+// -----------------------------------------------------------------------------
+// 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
+    CleanupStack::PopAndDestroy(); // rr
+    if (dateResId)
+        {
+        iDateFormat = iEnv->AllocReadResourceL(dateResId);
+        }
+    if (timeResId)
+        {
+        iTimeFormat = iEnv->AllocReadResourceL(timeResId);
+        }
+    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]));
+        }
+    ExecuteDeleteStepL();
+    iRetval = iFileSession.ReleaseReserveAccess( KDefaultDrive );
+    iFileSession.Close();
+	CleanupStack::PopAndDestroy();
+    }
+
+// -----------------------------------------------------------------------------
+// CNotepadModel::ExecuteDeleteStepL
+// -----------------------------------------------------------------------------
+//
+void CNotepadModel::ExecuteDeleteStepL()
+    {
+    iProgressCount = 0;
+    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);
+        for (TInt i(0); i < iStepCount - 1; i++)
+            {
+            sql.Append(KNotepadSqlDeleteByKeysAppend);
+            sql.AppendNum(iSavedDeleteKeys[0]);
+            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;
+                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 ( increment > 0 )
+        {
+        iProgressCount += increment;
+        if ( iModelObserver )
+            {
+            iModelObserver->HandleNotepadModelEventL(
+                MNotepadModelObserver::EProgressDeletion, increment);
+            }
+        }
+    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();
+    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 || 
+             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