messagingappbase/msgeditor/appuisrc/MsgEditorAppUi.cpp
changeset 0 72b543305e3a
child 2 0bf1d54f37d9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingappbase/msgeditor/appuisrc/MsgEditorAppUi.cpp	Thu Dec 17 08:44:11 2009 +0200
@@ -0,0 +1,1801 @@
+/*
+* Copyright (c) 2002-2009 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:  MsgEditorAppUi implementation
+*
+*/
+
+
+
+// ========== INCLUDE FILES ================================
+
+#include <featmgr.h>                // for feature manager
+
+#include <eikenv.h>                 // Eikon Enviroment
+#include <txtrich.h>                // Rich Text
+#include <eikrted.h>                // CEikRichTextEditor
+#include <eikmenub.h>               // CEikMenuBar
+#include <eikspane.h>               // status panel
+
+#include <eikapp.h>                 // CEikApplication
+#include <eikserverapp.h>
+#include <bautils.h>                // NearestLanguageFile
+#include <eikdialg.h>               // CEikDialog
+#include <data_caging_path_literals.hrh>
+
+#include <msvapi.h>                 //
+#include <mtmuibas.h>               // MTM UI
+#include <mtmuidef.hrh>             // Preferences
+#include <mtmdef.h>                 // TMsvPartList
+
+#include <MuiuMsgEmbeddedEditorWatchingOperation.h>
+#include <MuiuMsgEditorLauncher.h>  // for TEditorParameters
+#include <MuiuMessageIterator.h>    // for CMessageIterator
+#include <MuiuOperationWait.h>      // for CMuiuOperationWait
+#include <muiu.mbg>
+
+#include <aknenv.h>
+#include <aknnavi.h>                // CAknNavigationControlContainer
+#include <aknnavide.h>              // CAknNavigationDecorator
+#include <akntabgrp.h>              // CAknTabGroup
+#include <akninputblock.h>          // CAknInputBlock
+#include <aknnotewrappers.h>
+#include <AknIndicatorContainer.h>
+#include <akncontext.h>             // For message store in MMC -indication
+#include <AknsUtils.h>
+#include <AknsConstants.h>
+#include <commonphoneparser.h>      // Common phone number validity checker
+#include <apgicnfl.h>               // apamasked bitmaps
+#include <ErrorUI.h>				// CErrorUI - to show global error notes
+#include <StringLoader.h>           // StringLoader
+#include <NpdApi.h>                 // Notepad API
+#include <avkon.hrh>
+#include <AknStatuspaneUtils.h>
+#include <AknSettingCache.h>
+#include <messaginginternalcrkeys.h>
+#include <MessagingSDKCRKeys.h>
+#include "MsgEditorAppUiExtension.h"
+
+#include <aknlayoutscalable_avkon.cdl.h>
+
+#include "MsgEditorShutter.h"
+
+#include "MsgEditorCommon.h"
+#include "MsgEditorAppUi.h"         // class header
+#include "MsgEditorView.h"          // View
+#include "MsgBodyControl.h"         // Body Control
+#include "MsgSendKeyAcceptingQuery.h"
+#include "MsgEditorAppUiPanic.h"    // Panics
+#include "MsgEditorFlags.h"         // EditorFlags
+#include "MsgAttachmentUtils.h"
+#include <MsgEditorAppUi.rsg>       // resource identifiers
+#include "MsgNaviPaneControl.h"
+
+#ifdef RD_MSG_FAST_PREV_NEXT
+#include <messaginginternalpskeys.h>
+#endif
+
+#include "MsgEditorLogging.h"
+
+// ========== EXTERNAL DATA STRUCTURES =====================
+
+// ========== EXTERNAL FUNCTION PROTOTYPES =================
+
+// ========== CONSTANTS ====================================
+
+const TInt KMsgDiskSpaceForDelete = ( 5 * 1024 ); // minimum disk space needed when deleting messages
+
+// ========== MACROS =======================================
+
+_LIT( KMsgEditorAppUiResourceFileName, "msgeditorappui.rsc" );
+_LIT( KMuiuBitmapFileName, "muiu.mbm" );
+_LIT( KMsgEditorAppUiFilterRe, "RE:" );
+_LIT( KMsgEditorAppUiFilterFw, "FW:" );
+_LIT( KMsgEditorAppUiFilterFwd, "FWD:" );
+
+// ========== LOCAL CONSTANTS AND MACROS ===================
+
+// ========== MODULE DATA STRUCTURES =======================
+
+// ========== LOCAL FUNCTION PROTOTYPES ====================
+
+// ========== LOCAL FUNCTIONS ==============================
+
+// ========== MEMBER FUNCTIONS =============================
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::CMsgEditorAppUi
+//
+// Constructor.
+// ---------------------------------------------------------
+//
+EXPORT_C CMsgEditorAppUi::CMsgEditorAppUi() : 
+    iExitMode( MApaEmbeddedDocObserver::EKeepChanges ),
+    iCloseWithEndKey( ETrue )
+    {
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::ConstructL
+//
+// 2nd phase constructor.
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::ConstructL()
+    {
+    CMsgEditorBaseUi::ConstructL();
+    
+    iMsgNaviDirection = KErrNotFound; 
+
+    // initialize feature manager to check supported features
+    FeatureManager::InitializeLibL();
+    iMmcFeatureSupported = FeatureManager::FeatureSupported( KFeatureIdMmc );
+
+    TParse parse;
+    parse.Set( KMsgEditorAppUiResourceFileName, &KDC_RESOURCE_FILES_DIR, NULL );
+    TFileName fileName( parse.FullName() );
+
+    BaflUtils::NearestLanguageFile( iCoeEnv->FsSession(), fileName );
+    iResourceFileOffset = iEikonEnv->AddResourceFileL( fileName );
+
+    Document()->SetEditorModelObserver( this );
+
+    iFileMan = CFileMan::NewL( iEikonEnv->FsSession() );
+
+    // create msgeditor temp directory.
+    TFileName temppath;
+    MsgAttachmentUtils::GetMsgEditorTempPath( temppath );
+
+    RFs& fs = iEikonEnv->FsSession();
+    fs.MkDir( temppath );
+
+    CEikStatusPane* sp = StatusPane();
+    if ( iMmcFeatureSupported && 
+        TInt( Document()->Session().CurrentDriveL() ) == EDriveE )
+        {
+        CAknContextPane* contextPane = static_cast<CAknContextPane*>
+            ( sp->ControlL( TUid::Uid( EEikStatusPaneUidContext ) ) );
+        TParse fileParse;
+        fileParse.Set( KMuiuBitmapFileName, &KDC_APP_BITMAP_DIR, NULL );
+        CFbsBitmap* bmp = NULL;
+        CFbsBitmap* mask = NULL;
+#ifdef __SCALABLE_ICONS
+        AknsUtils::CreateIconL(
+            AknsUtils::SkinInstance(),
+            KAknsIIDQgnMenuMceMmcCxt,
+            bmp,
+            mask,
+            fileParse.FullName(),
+            EMbmMuiuQgn_menu_mce_mmc,
+            EMbmMuiuQgn_menu_mce_mmc_mask );
+#else
+        AknsUtils::CreateIconL(
+            AknsUtils::SkinInstance(),
+            KAknsIIDQgnMenuMceMmcCxt,
+            bmp,
+            mask,
+            fileParse.FullName(),
+            EMbmMuiuQgn_menu_mce_mmc_cxt,
+            EMbmMuiuQgn_menu_mce_mmc_cxt_mask );
+#endif  //__SCALABLE_ICONS
+        contextPane->SetPicture( bmp, mask );
+        }
+    iOwnNaviPane = static_cast<CAknNavigationControlContainer*>
+        ( sp->ControlL( TUid::Uid( EEikStatusPaneUidNavi ) ) );
+    iCoeEnv->FsSession().ReserveDriveSpace(
+        TInt( Document()->Session().CurrentDriveL() ),
+        KMsgDiskSpaceForDelete );
+  
+    CMsgEditorDocument* doc = Document();
+    iEditorShutter = CMsgEditorShutter::NewL(*doc);
+  
+    iMsgEditorAppUiExtension = new(ELeave) CMsgEditorAppUiExtension( this );
+    CAknEnv* env = iAvkonEnv;
+    CAknSettingCache& cache = env->SettingCache();
+    cache.RegisterPluginL( &( iMsgEditorAppUiExtension->iSettingCachePlugin ) );    
+    
+    iStatusPaneRes = StatusPane()->CurrentLayoutResId();
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::~CMsgEditorAppUi
+//
+// Destructor.
+// ---------------------------------------------------------
+//
+EXPORT_C CMsgEditorAppUi::~CMsgEditorAppUi()
+    {
+    delete iEditorShutter;
+
+    Document()->SetEditorModelObserver( NULL );
+
+    // remove resource file from CONE-maintained resource file list.
+    if ( iResourceFileOffset )
+        {
+        iEikonEnv->DeleteResourceFile( iResourceFileOffset );
+        }
+
+    // call NotifyExit on completion of editing of an embedded document.
+    if ( iDoorObserver )
+        {
+        MEBLOGGER_WRITEF( _L( "MEB: CMsgEditorAppUi: Closing with exit mode %d" ), iExitMode );
+        iDoorObserver->NotifyExit( iExitMode );
+        }
+
+    delete iView;
+    delete iLock;
+    delete iNaviDecorator;
+
+    delete iIterator;
+
+    // delete files from our temp directory.
+    if ( iFileMan )
+        {
+        TFileName temppath;
+        MsgAttachmentUtils::GetMsgEditorTempPath( temppath );
+
+        /*TInt err =*/ iFileMan->Delete( temppath /*, CFileMan::ERecurse*/ );
+        //TInt err2 = iFileMan->RmDir(temppath); // remove directory
+        }
+
+    delete iFileMan;
+
+    // Uninitialize FeatureManager and members
+    FeatureManager::UnInitializeLib();
+    if( iMsgEditorAppUiExtension )
+        {
+        CAknEnv* env = iAvkonEnv;
+        CAknSettingCache& cache = env->SettingCache();
+        cache.DeRegisterPlugin( &( iMsgEditorAppUiExtension->iSettingCachePlugin ) );
+        delete iMsgEditorAppUiExtension;
+        }    
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::HandleKeyEventL
+//
+// Route key events to view.
+// ---------------------------------------------------------
+//
+EXPORT_C TKeyResponse CMsgEditorAppUi::HandleKeyEventL(
+    const TKeyEvent& aKeyEvent, TEventCode aType )
+    {
+    if ( iView )
+        {
+        return iView->OfferKeyEventL( aKeyEvent, aType );
+        }
+    return EKeyWasNotConsumed;
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::HandleWsEventL
+//
+//
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::HandleWsEventL( const TWsEvent& aEvent,CCoeControl* aDestination )
+    {
+    TInt type = aEvent.Type();
+
+    if ( type == EEventKey )
+        {
+        TKeyEvent* key = aEvent.Key();
+        if ( ( key->iModifiers & EModifierShift ) &&
+            ( key->iCode == EKeyBackspace ) )
+            {
+            if ( iView )
+                {
+                CMsgBodyControl* body = 
+                        static_cast<CMsgBodyControl*>( iView->ControlById( EMsgComponentIdBody ) );
+
+                if ( body && body->IsReadOnly() )
+                    {
+                    TRAP_IGNORE( SaveBodyL( body ) );
+                    }
+                }
+
+            key->iModifiers &= ~EModifierShift;
+            key->iCode = EKeyDelete;
+            }
+        }
+        
+    if ( type != KAknUidValueEndKeyCloseEvent ||
+         iCloseWithEndKey )
+        {
+        CAknAppUi::HandleWsEventL( aEvent, aDestination );
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::NextMessageL
+//
+// Set a specific exit code for opening next or previous message. Codes are
+// defined in MuiuMsgEmbeddedEditorWatchingOperation.h 
+// and handled by MCE after msg viewer has been closed.
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::NextMessageL( TBool aForward )
+    {
+    // Next is ETrue if layout is EAknLayoutIdABRW,
+    // EFalse if EAknLayoutIdELAF or EAknLayoutIdAPAC
+    if ( AknLayoutUtils::LayoutMirrored() )
+        {
+        aForward = !aForward;
+        }
+
+    iMsgNaviDirection = aForward;
+#ifdef RD_MSG_FAST_PREV_NEXT
+    // Check if next/previous message can be fast opened by viewer
+    __ASSERT_DEBUG( iIterator != NULL, Panic( ENullPointer1 ) );
+    if ( aForward )
+        {
+        iIterator->SetNextMessage();
+        }
+    else
+        {
+        iIterator->SetPreviousMessage();
+        }
+
+    if ( CanFastOpenL( *iIterator) )
+        {
+        // Load next/previous message
+        TRAPD( err, Document()->SetEntryL( iIterator->CurrentMessage().Id() ) );
+        // If fast open fails, view is incompletely constructed
+        // Drop back to mce
+        if( err == KErrCancel )
+            {
+            /* It is a known-valid failure(quick lauch cancelled in viewers due to heterogenous messages)
+             * In that case, reset the current entry to original and exit with correct code so that message
+             * will be launched completely from MCE.
+             */
+            if ( iMsgNaviDirection )
+                {
+                iIterator->SetPreviousMessage();
+                }
+            else
+                {
+                iIterator->SetNextMessage();
+                }
+            Document()->SetEntryWithoutNotificationL( iIterator->CurrentMessage().Id() );
+            iExitMode = iMsgNaviDirection ?
+                MApaEmbeddedDocObserver::TExitMode(
+                    CMsgEmbeddedEditorWatchingOperation::EMsgExitNext) :
+                MApaEmbeddedDocObserver::TExitMode(
+                    CMsgEmbeddedEditorWatchingOperation::EMsgExitPrevious);
+            Exit( iExitMode );
+            }
+        else if ( err != KErrNone )
+            {
+            // Unknown error during quick launch.
+            iCoeEnv->HandleError( err );
+            iExitMode = MApaEmbeddedDocObserver::ENoChanges;
+            Exit( EAknSoftkeyClose );
+            }
+        }
+    else
+#endif // RD_MSG_FAST_PREV_NEXT
+        {
+        iExitMode = aForward ?
+            MApaEmbeddedDocObserver::TExitMode(
+                CMsgEmbeddedEditorWatchingOperation::EMsgExitNext) :
+            MApaEmbeddedDocObserver::TExitMode(
+                CMsgEmbeddedEditorWatchingOperation::EMsgExitPrevious);
+        Exit( iExitMode );
+        }
+    iMsgNaviDirection = KErrNotFound;
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::IsNextMessageAvailableL
+//
+// Check if next or previous msg is available.
+// ---------------------------------------------------------
+//
+EXPORT_C TBool CMsgEditorAppUi::IsNextMessageAvailableL( TBool aForward )
+    {
+    TBool ret = EFalse;
+    
+    if ( iEikonEnv->StartedAsServerApp() )
+        {
+        CMsgEditorDocument* doc = Document();
+
+        if ( iIterator == NULL )
+            {
+            iIterator = CMessageIterator::NewL( doc->Session(), doc->Entry() );
+            iIterator->SetMessageIteratorObserver( this );
+            }
+
+        // Next is ETrue if layout is EAknLayoutIdABRW,
+        // EFalse if EAknLayoutIdELAF or EAknLayoutIdAPAC
+        if ( AknLayoutUtils::LayoutMirrored() )
+            {
+            aForward = !aForward;
+            }
+
+        if ( aForward )
+            {
+            if ( iIterator->NextMessageExists() )
+                {
+                ret = ETrue;
+                }
+            }
+        else
+            {
+            if ( iIterator->PreviousMessageExists() )
+                {
+                ret = ETrue;
+                }
+            }
+        }
+        
+    return ret;
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::MessageIndexInFolderL
+//
+// Returns index of current msg and also total number of msgs in folder.
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::MessageIndexInFolderL( TInt& aCurrentIndex, 
+                                                      TInt& aMsgsInFolder )
+    {
+    if ( iEikonEnv->StartedAsServerApp() )
+        {
+        CMsgEditorDocument* doc = Document();
+
+        if ( iIterator == NULL )
+            {
+            iIterator = CMessageIterator::NewL( doc->Session(), doc->Entry() );
+            iIterator->SetMessageIteratorObserver( this );
+            }
+
+        aCurrentIndex = iIterator->CurrentMessageIndex();
+        aMsgsInFolder = iIterator->MessagesInFolder();
+        }
+    else
+        {
+        aCurrentIndex = 0;
+        aMsgsInFolder = 0;
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::MoveMessageEntryL
+//
+// Moves an entry to another location.
+// ---------------------------------------------------------
+//
+EXPORT_C TMsvId CMsgEditorAppUi::MoveMessageEntryL( TMsvId aTarget ) const
+    {
+    TMsvEntry msvEntry = Document()->Entry();
+    TMsvId id = KMsvNullIndexEntryId;
+
+    if ( msvEntry.Parent() != aTarget )
+        {
+        CAknInputBlock::NewLC();
+
+        CMsvEntry* parentEntry = Document()->Session().GetEntryL( msvEntry.Parent() );
+        CleanupStack::PushL( parentEntry );
+
+        // -- Change sort parameters so that parentEntry->MoveL does not leave as the child is invisible.
+        TMsvSelectionOrdering sort = parentEntry->SortType();
+        sort.SetShowInvisibleEntries( ETrue );
+        parentEntry->SetSortTypeL( sort );
+
+        // Copy original from the parent to the new location.
+        CMuiuOperationWait* wait = CMuiuOperationWait::NewLC();
+
+        CMsvOperation* op = parentEntry->MoveL(
+            msvEntry.Id(), aTarget, wait->iStatus );
+        CleanupStack::PushL( op );
+        wait->Start(); // wait for asynch operation
+
+        TMsvLocalOperationProgress prog = McliUtils::GetLocalProgressL( *op );
+        User::LeaveIfError( prog.iError );
+        id = prog.iId;
+
+        CleanupStack::PopAndDestroy( 4 );  // op, wait, parentEntry, absorber
+        }
+
+    return id;
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::DeleteAndExitL
+//
+// Deletes current entry and then exits.
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::DeleteAndExitL()
+    {
+    DeleteCurrentEntryL();
+    Exit( EAknSoftkeyBack );
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::DeleteCurrentEntryL
+//
+// Deletes current entry.
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::DeleteCurrentEntryL()
+    {
+    CMsgEditorDocument* doc = Document();
+    UnlockEntry();
+
+    TInt msgStoreDrive = TInt( doc->Session().CurrentDriveL() );
+    iCoeEnv->FsSession().GetReserveAccess( msgStoreDrive );
+
+    if ( doc->CurrentEntry().OwningService() == KMsvLocalServiceIndexEntryId )
+        {
+        const TMsvId id = doc->Entry().Id();
+        //doc->CurrentEntry().SetEntryL( doc->Entry().Parent() );
+        TRAPD( 
+                err, 
+                {
+                doc->CurrentEntry().SetEntryL( doc->Entry().Parent() ); 
+                doc->CurrentEntry().DeleteL( id ); 
+                }
+            );
+        if ( err != KErrNone )
+            {
+            doc->Session().RemoveEntry( id );
+            }
+        }
+    else
+        {
+        CMsvEntrySelection* sel = new ( ELeave ) CMsvEntrySelection;
+        CleanupStack::PushL( sel );
+        TMsvId id = doc->Entry().Id();
+        sel->AppendL( id );
+        doc->Mtm().SwitchCurrentEntryL( doc->Entry().Parent() );
+
+        CMuiuOperationWait* wait = CMuiuOperationWait::NewLC();
+
+        CMsvOperation* op = doc->MtmUi().DeleteFromL( *sel, wait->iStatus );
+        CleanupStack::PushL( op );
+
+        wait->Start();
+
+        const TInt err = doc->MtmUi().DisplayProgressSummary( op->ProgressL() );
+        CleanupStack::PopAndDestroy( 3, sel );  // sel, wait, op
+        if ( err == KErrCancel )
+            {
+            doc->Mtm().SwitchCurrentEntryL( id );
+            LockEntryL();
+            return ;
+            }
+        User::LeaveIfError( err );
+        }
+
+    iCoeEnv->FsSession().ReleaseReserveAccess( msgStoreDrive );
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::PrepareToExit
+//
+//
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::PrepareToExit()
+    {
+    CMsgEditorDocument* doc = Document();
+
+    if ( doc->HasModel() )
+        {
+        if ( doc->Entry().InPreparation() )
+            {
+            doc->Session().RemoveEntry( doc->Entry().Id() );
+            }
+        }
+
+    CEikAppUi::PrepareToExit();
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::ReplyL
+//
+// Asynchronous Mtm reply command.
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::ReplyL(
+    TMsvId aTarget, TBool aIncludeOriginal /*= ETrue*/ )
+    {
+    TMsvPartList parts =
+        KMsvMessagePartDescription |
+        KMsvMessagePartOriginator;
+
+    if ( aIncludeOriginal )
+        {
+        parts |= KMsvMessagePartBody;
+        }
+
+    CBaseMtmUi& mtmUi = Document()->MtmUi();
+
+    // to by-pass scanner warning about member variable being stored into
+    // cleanup stack blocker is first stored into temporary variable. Storing
+    // is allowed here as it is not owned.
+    CAknInputBlock* blocker = CAknInputBlock::NewCancelHandlerLC( this );
+    iInputBlocker = blocker;
+
+    CMuiuOperationWait* wait =
+        CMuiuOperationWait::NewLC( EActivePriorityWsEvents + 10 );
+
+    mtmUi.SetPreferences( mtmUi.Preferences() | EMtmUiFlagEditorPreferEmbedded );
+    CMsvOperation* oper = mtmUi.ReplyL( aTarget, parts, wait->iStatus );
+    CleanupStack::PushL( oper );
+
+    wait->Start();
+    
+    CleanupStack::PopAndDestroy( 3, iInputBlocker );  // absorber, wait, oper
+    iInputBlocker = NULL;
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::ReplyToAllL
+//
+// Asynchronous Mtm reply all command.
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::ReplyToAllL(
+    TMsvId aTarget, TBool aIncludeOriginal /*= ETrue*/ )
+    {
+    TMsvPartList parts =
+        KMsvMessagePartDescription |
+        KMsvMessagePartRecipient |
+        KMsvMessagePartOriginator ;
+
+    if ( aIncludeOriginal )
+        {
+        parts |= KMsvMessagePartBody;
+        }
+
+    CBaseMtmUi& mtmUi = Document()->MtmUi();
+    
+    // to by-pass scanner warning about member variable being stored into
+    // cleanup stack blocker is first stored into temporary variable. Storing
+    // is allowed here as it is not owned.
+    CAknInputBlock* blocker = CAknInputBlock::NewCancelHandlerLC( this );
+    iInputBlocker = blocker;
+
+    CMuiuOperationWait* wait =
+        CMuiuOperationWait::NewLC( EActivePriorityWsEvents + 10 );
+
+    mtmUi.SetPreferences( mtmUi.Preferences() | EMtmUiFlagEditorPreferEmbedded );
+    CMsvOperation* oper = mtmUi.ReplyL( aTarget, parts, wait->iStatus );
+    CleanupStack::PushL( oper );
+
+    wait->Start();
+    
+    CleanupStack::PopAndDestroy( 3, iInputBlocker );  // absorber, wait, oper
+    iInputBlocker = NULL;
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::ForwardL
+//
+// Asynchronous Mtm forward command.
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::ForwardL( TMsvId aTarget )
+    {
+    TMsvPartList parts =
+        KMsvMessagePartBody |
+        KMsvMessagePartDescription |
+        KMsvMessagePartAttachments;
+
+    CBaseMtmUi& mtmUi = Document()->MtmUi();
+    mtmUi.SetPreferences( mtmUi.Preferences() | EMtmUiFlagEditorPreferEmbedded );
+    
+    // to by-pass scanner warning about member variable being stored into
+    // cleanup stack blocker is first stored into temporary variable. Storing
+    // is allowed here as it is not owned.
+    CAknInputBlock* blocker = CAknInputBlock::NewCancelHandlerLC( this );
+    iInputBlocker = blocker;
+    
+    CMuiuOperationWait* wait = CMuiuOperationWait::NewLC( EActivePriorityWsEvents + 10 );
+    
+    CMsvOperation* oper = mtmUi.ForwardL( aTarget, parts, wait->iStatus );
+    CleanupStack::PushL( oper );
+
+    wait->Start();
+
+    CleanupStack::PopAndDestroy( 3, iInputBlocker );  // absorber, wait, oper
+    iInputBlocker = NULL;
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::InsertTemplate
+//
+//
+// ---------------------------------------------------------
+//
+EXPORT_C TInt CMsgEditorAppUi::InsertTemplateL( TInt aMaxChars /*= -1*/ )
+    {
+    __ASSERT_DEBUG( iView != NULL, Panic( ENullPointer1 ) );
+
+    // get memo content from notepad to buffer.
+    HBufC* title = iEikonEnv->AllocReadResourceLC( R_QTN_MAIL_POPUP_TEXT_SEL_TEMP );
+
+    HBufC* buf = CNotepadApi::FetchTemplateL( title );
+    CleanupStack::PushL( buf );
+
+    TInt err = DoInsertTextL( buf, aMaxChars );
+
+    CleanupStack::PopAndDestroy( 2, title ); // buf, title
+    return err;
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::InsertTextMemoL
+//
+//
+// ---------------------------------------------------------
+//
+EXPORT_C TInt CMsgEditorAppUi::InsertTextMemoL( TInt aMaxChars )
+    {
+    __ASSERT_DEBUG( iView != NULL, Panic( ENullPointer1 ) );
+
+    // get memo content from notepad to buffer.
+    HBufC* title = iEikonEnv->AllocReadResourceLC( R_QTN_NMAKE_FETCH_MEMO_PRMPT );
+
+    HBufC* buf = CNotepadApi::FetchMemoL( title );
+    CleanupStack::PushL( buf );
+
+    TInt err = DoInsertTextL( buf, aMaxChars );
+    
+    CleanupStack::PopAndDestroy( 2, title ); // buf, title
+    return err;
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::DoInsertTextL
+//
+//
+// ---------------------------------------------------------
+//
+TInt CMsgEditorAppUi::DoInsertTextL( HBufC* aBuffer, TInt aMaxChars )
+    {
+    TInt err( KErrNone );
+    if ( aBuffer )
+        {
+        TInt buflen = aBuffer->Length();
+
+        if ( aMaxChars == -1 || buflen <= aMaxChars )
+            {
+            CMsgBodyControl* body = 
+                    static_cast<CMsgBodyControl*>( iView->ControlById( EMsgComponentIdBody ) );
+
+            if ( body )
+                {
+                CEikRichTextEditor& editor = body->Editor();
+
+                if ( body != iView->FocusedControl() )
+                    {
+                    editor.SetCursorPosL( editor.TextLength(), EFalse );
+                    }
+
+                body->InsertTextL( *aBuffer );
+
+                iView->SetFocus( EMsgComponentIdBody );
+
+                Document()->SetChanged( ETrue );
+                }
+            }
+        else
+            {
+            err = KErrOverflow;
+            }
+        }
+    else
+        {
+        err = KErrCancel;
+        }
+        
+    return err;
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::UpdateNaviPaneL
+//
+// Updates navi pane.
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::UpdateNaviPaneL(
+    const CFbsBitmap* aBitmap     /*= NULL*/,
+    const CFbsBitmap* aBitmapMask /*= NULL*/ )
+    {
+    UpdateNaviPaneL( EFalse, aBitmap, aBitmapMask );
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::UpdateNaviPaneL
+//
+// Updates navi pane.
+// ---------------------------------------------------------
+//
+void CMsgEditorAppUi::UpdateNaviPaneL(
+    TBool             aUpdateExisting,
+    const CFbsBitmap* aBitmap     /*= NULL*/,
+    const CFbsBitmap* aBitmapMask /*= NULL*/ )
+    {
+    if ( !iOwnNaviPane )
+        {
+        return;
+        }
+    TInt index = 0;
+    TInt msgs = 0;
+    HBufC* buf;
+
+    MessageIndexInFolderL( index, msgs );
+
+    TBool prevAvailable = IsNextMessageAvailableL( EFalse );
+    TBool nextAvailable = IsNextMessageAvailableL( ETrue );
+
+    CArrayFixFlat<TInt>* array = new( ELeave ) CArrayFixFlat<TInt>( 2 );
+    CleanupStack::PushL( array );
+
+    if ( msgs )
+        {
+        array->AppendL( index + 1 );
+        array->AppendL( msgs );
+        buf = StringLoader::LoadLC( R_QTN_STAT_MSG_NUMBER, *array, iCoeEnv );
+        }
+    else
+        {
+        // if no messages make empty message label.
+        buf = HBufC::NewLC( 0 );
+        prevAvailable = nextAvailable = 0;
+        }
+
+    if ( aUpdateExisting )
+        {
+        if ( iNaviDecorator )
+            {
+            CAknTabGroup* tabGroup =
+                static_cast<CAknTabGroup*>( iNaviDecorator->DecoratedControl() );
+            tabGroup->ReplaceTabTextL( 0, *buf );
+
+            iNaviDecorator->MakeScrollButtonVisible( ETrue );
+            iNaviDecorator->SetScrollButtonDimmed(
+                CAknNavigationDecorator::ELeftButton,
+                !prevAvailable );
+            iNaviDecorator->SetScrollButtonDimmed(
+                CAknNavigationDecorator::ERightButton,
+                !nextAvailable );
+
+            iOwnNaviPane->PushL( *iNaviDecorator );
+            }
+        }
+    else
+        {
+        delete iNaviDecorator;
+        iNaviDecorator = NULL;
+        iNaviDecorator = iOwnNaviPane->CreateTabGroupL();
+        
+        CAknTabGroup* tabGroup =
+            static_cast<CAknTabGroup*>( iNaviDecorator->DecoratedControl() );
+        tabGroup->AddTabL( 0, *buf );            
+        tabGroup->SetActiveTabById( 0 );
+        // does not leave with one tab.
+        tabGroup->SetTabFixedWidthL( KTabWidthWithOneTab );
+
+        iNaviDecorator->MakeScrollButtonVisible( ETrue );
+        iNaviDecorator->SetScrollButtonDimmed(
+            CAknNavigationDecorator::ELeftButton,
+            !prevAvailable );
+        iNaviDecorator->SetScrollButtonDimmed(
+            CAknNavigationDecorator::ERightButton,
+            !nextAvailable );
+
+        iOwnNaviPane->PushL( *iNaviDecorator );
+
+        if ( aBitmap && aBitmapMask )
+            {
+            // replace tab with new one containing text and bitmaps.
+            // this must be done after PushL because this transfers
+            // ownership of caller's bitmaps to tab group.
+            tabGroup->ReplaceTabL( 0, *buf, aBitmap, aBitmapMask );
+            }
+        }
+    CleanupStack::PopAndDestroy( 2, array ); // buf, array
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::HandleIteratorEventL
+//
+//
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::HandleIteratorEventL(
+    TMessageIteratorEvent aEvent )
+    {
+    if ( aEvent == EFolderCountChanged )
+        {
+        UpdateNaviPaneL( ETrue );
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::CallToSenderQueryL
+//
+//
+// ---------------------------------------------------------
+//
+EXPORT_C TBool CMsgEditorAppUi::CallToSenderQueryL(
+    const TDesC& aNumber, const TDesC& aAlias )
+    {
+    CDesCArrayFlat* strings = new ( ELeave ) CDesCArrayFlat( 2 );
+    CleanupStack::PushL( strings );
+
+    strings->AppendL( aAlias );  // %0U
+    strings->AppendL( aNumber ); // %1U
+
+    HBufC* prompt = StringLoader::LoadLC(
+        R_QTN_SMS_QUEST_CALL, *strings, iCoeEnv );
+
+    CMsgSendKeyAcceptingQuery* dlg = CMsgSendKeyAcceptingQuery::NewL( *prompt );
+    TInt ret = dlg->ExecuteLD( R_MEB_CALLBACK_QUERY );
+
+    CleanupStack::PopAndDestroy( 2, strings ); // strings, prompt
+
+    return ( ret != 0 ); // No = EFalse, others = ETrue.
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::ProcessCommandParametersL
+//
+// Parses command line parameter and launch model accoring to them.
+// ---------------------------------------------------------
+//
+EXPORT_C TBool CMsgEditorAppUi::ProcessCommandParametersL(
+    TApaCommand /*aCommand*/,
+    TFileName& /*aDocumentName*/,
+    const TDesC8& aTail )
+    {
+    CMsgEditorDocument& doc = *Document();
+
+    if ( aTail.Length() > 0 )
+        {
+        // Get the parameters passed by the launching MTMUI.
+        TPckgBuf<TEditorParameters> paramPack;
+        const TInt paramSize = sizeof( TEditorParameters );
+
+        __ASSERT_ALWAYS( aTail.Length() == paramSize, Panic( EInvalidArgument ) );
+
+        paramPack.Copy( aTail );
+        const TEditorParameters& params = paramPack();
+        
+        // to by-pass scanner warning about member variable being stored into
+        // cleanup stack blocker is first stored into temporary variable. Storing
+        // is allowed here as it is not owned.
+        CAknInputBlock* blocker = CAknInputBlock::NewCancelHandlerLC( this );
+        iInputBlocker = blocker;
+
+        doc.LaunchParametersL( params );
+        doc.EntryChangedL();  // notified after is unique (and unlocked).
+        doc.PrepareToLaunchL( this );
+
+        CleanupStack::PopAndDestroy( iInputBlocker );
+        iInputBlocker = NULL;
+        }
+    else
+        {
+        // no parameters enable TestEditor launching...
+        doc.PrepareToLaunchL( this );
+        }
+
+    return EFalse;
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::MenuBar
+//
+// Returns application menubar.
+// ---------------------------------------------------------
+//
+EXPORT_C CEikMenuBar* CMsgEditorAppUi::MenuBar() const
+    {
+    return iEikonEnv->AppUiFactory()->MenuBar();
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::SetEmphasis
+//
+// From MEikMenuObserver (called when menu is opened).
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::SetEmphasis(
+    CCoeControl* aMenuControl, TBool aEmphasis )
+    {
+    if ( iView )
+        {
+        UpdateStackedControlFlags(
+            iView,
+            aEmphasis ? ECoeStackFlagRefusesFocus : 0,
+            ECoeStackFlagRefusesFocus );
+        }
+
+    UpdateStackedControlFlags(
+        aMenuControl,
+        aEmphasis ? 0 : ECoeStackFlagRefusesFocus,
+        ECoeStackFlagRefusesFocus );
+
+    HandleStackChanged();
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::HandleEntryChangeL
+//
+// Default error handling for all messaging editors and viewers.
+// HandleEntryChangeL is called when the currently open message
+// has been modified by some other messaging client. The default
+// action is "do nothing", but editors can define their own event
+// processing by overriding this function.
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::HandleEntryChangeL()
+    {
+    // no action
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::HandleEntryDeletedL
+//
+// Default error handling for all messaging editors and viewers.
+// HandleEntryDeletedL is called when the currently open message
+// has been deleted by some other messaging client.
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::HandleEntryDeletedL()
+    {
+    // TODO: get error code from errorres.
+    ViewErrorL(-7005);
+
+    // close the application (and possible chain of viewers, editors and mce etc.).
+    ProcessCommandL( EAknCmdExit );
+    //Exit();
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::HandleEntryMovedL
+//
+// Default error handling for all messaging editors and viewers.
+// HandleEntryMovedL is called when the currently open message
+// has been moved to some other folder, by some other messaging
+// client.
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::HandleEntryMovedL(
+    TMsvId /*aOldParent*/, TMsvId /*aNewParent*/ )
+    {
+    // refresh model content.
+    Document()->SetEntryWithoutNotificationL( Document()->Entry().Id() );
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::HandleMtmGroupDeinstalledL
+//
+// Default error handling for all messaging editors and viewers.
+// HandleMtmGroupDeinstalledL is called when the MTM Group used
+// by the currently open message has been removed from the device.
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::HandleMtmGroupDeinstalledL()
+    {
+    // TODO: get error code from errorres.
+    ViewErrorL( -7006 );
+
+    // close the application (and possible chain of viewers, editors and mce etc.).
+    ProcessCommandL( EAknCmdExit );
+    //Exit();
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::HandleGeneralErrorL
+//
+// Default error handling for all messaging editors and viewers.
+// HandleGeneralErrorL is called when some unknown error has
+// happened. The aErrorCode parameter contains the error code.
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::HandleGeneralErrorL( TInt /*aErrorCode*/ )
+    {
+    // TODO: show note?
+
+    // close the application (and possible chain of viewers, editors and mce etc.).
+    ProcessCommandL( EAknCmdExit );
+    //Exit();
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::HandleCloseSessionL
+//
+// Default error handling for all messaging editors and viewers.
+// HandleCloseSessionL is called when the messaging server wants
+// to close the session (e.g. because it's closing down and wants
+// to get rid of all messaging clients).
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::HandleCloseSessionL()
+    {
+    // save changes and close the application.
+    DoMsgSaveExitL();
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::HandleServerFailedToStartL
+//
+// Default error handling for all messaging editors and viewers.
+// HandleServerFailedToStartL is called when the message server
+// start-up was not successful.
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::HandleServerFailedToStartL()
+    {
+    // TODO: get error code from errorres.
+    ViewErrorL( -7007 );
+
+    // close the application (and possible chain of viewers, editors and mce etc.).
+    ProcessCommandL( EAknCmdExit );
+    //Exit();
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::HandleServerTerminatedL
+//
+// Default error handling for all messaging editors and viewers.
+// HandleServerTerminatedL is called when the messaging server has
+// died. Application cannot use the message server session any more.
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::HandleServerTerminatedL()
+    {
+    // TODO: get error code from errorres.
+    ViewErrorL( -7008 );
+
+    // close the application (and possible chain of viewers, editors and mce etc.).
+    ProcessCommandL( EAknCmdExit );
+    //Exit();
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::HandleMediaChangedL
+//
+// Default error handling for all messaging editors and viewers.
+// HandleMediaChangedL is called when the messaging storage has
+// been moved into another disk, This means that the current
+// message entry is not valid any more. This function creates
+// new entry in the new messaging store, in order to enable saving
+// the message. The new entry is left in InPreparation state, so
+// that it will be deleted if the application (e.g. viewer) does
+// not save anything in it.
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::HandleMediaChangedL()
+    {
+    if( iMmcFeatureSupported )
+        {
+        // create new InPreparation entry in the new messaging store.
+        CMsgEditorDocument* doc = Document();
+        doc->CreateNewL( doc->DefaultMsgService(), doc->DefaultMsgFolder() );
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::HandleMediaUnavailableL
+//
+// Default error handling for all messaging editors and viewers.
+// The media state is recorded in model and default action in AppUi
+// is to display warning message to the user.
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::HandleMediaUnavailableL()
+    {
+    if( iMmcFeatureSupported )
+        {
+        ProcessCommandL( EAknCmdExit );
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::HandleMediaAvailableL
+//
+// Default error handling for all messaging editors and viewers.
+// No action made by default, the media state is recorded in model.
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::HandleMediaAvailableL()
+    {
+    // no action
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::HandleMediaIncorrectL
+//
+// Default error handling for all messaging editors and viewers.
+// The media state is recorded in model, and warning note is displayed
+// to the user here.
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::HandleMediaIncorrectL()
+    {
+    if( iMmcFeatureSupported )
+        {
+        ViewErrorL( KMsvMediaIncorrect );
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::HandleCorruptedIndexRebuildingL
+//
+// Default error handling for all messaging editors and viewers.
+// The default action is to put busy note on the screen. The busy
+// note will be displayed while the index is being rebuilt - until
+// we get "index rebuilt" event in HandleCorruptedIndexRebuiltL().
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::HandleCorruptedIndexRebuildingL()
+    {
+    HBufC* line = iEikonEnv->AllocReadResourceLC( R_MEB_N_IN_REBUILDING_INDEX );
+    iEikonEnv->BusyMsgL( *line );
+    CleanupStack::PopAndDestroy( line );  // line
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::HandleCorruptedIndexRebuiltL
+//
+// Default error handling for all messaging editors and viewers.
+// The default action is to remove the busy note displayed when
+// the index rebuilding event was received.
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::HandleCorruptedIndexRebuiltL()
+    {
+    iEikonEnv->BusyMsgCancel();
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::CreateCustomControlL
+//
+// Default implementation is NULL since viewers do not need this.
+// ---------------------------------------------------------
+//
+EXPORT_C CMsgBaseControl* CMsgEditorAppUi::CreateCustomControlL( TInt /*aControlType*/ )
+    {
+    return NULL;
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::IsLaunchedL
+//
+// Checks if document has finished launching.
+// ---------------------------------------------------------
+//
+EXPORT_C TBool CMsgEditorAppUi::IsLaunchedL() const
+    {
+    return Document()->IsLaunched();
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::EditorObserver
+//
+// Default implementation.
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::EditorObserver(
+    TMsgEditorObserverFunc aFunc,
+    TAny* /*aArg1*/,
+    TAny* aArg2,
+    TAny* /*aArg3*/ )
+    {
+    switch (aFunc)
+        {
+        case EMsgDenyClipboardOperation:
+            {
+            TInt* ret = static_cast<TInt*>( aArg2 );
+            *ret = 0;
+            }
+            break;
+
+        case EMsgHandleFocusChange:
+        default:
+            break;
+        }
+    }
+
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::DoMtmCmdL
+//
+// Get services from mtm's and offers them to APP UI.
+// ---------------------------------------------------------
+//
+void CMsgEditorAppUi::DoMtmCmdL( const TUid& /*aQuery*/, TInt aCmd ) const
+    {
+    CMsvEntrySelection* selection = new ( ELeave ) CMsvEntrySelection;
+    CleanupStack::PushL( selection );
+    selection->AppendL( Document()->Entry().Id() );
+    TBuf8<1> null;
+    TMsvId origMessageId = Document()->Entry().Id();
+    Document()->MtmUi().InvokeSyncFunctionL( aCmd, *selection, null );
+    CleanupStack::PopAndDestroy( selection );  // selection
+    Document()->SetEntryL( origMessageId );
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::ViewErrorL
+//
+// Helper function for Handle... methods.
+// ---------------------------------------------------------
+//
+void CMsgEditorAppUi::ViewErrorL( TInt aTitle )
+    {
+    // TODO: check if app in foreground and show error note only then.
+    CErrorUI* errorUI = CErrorUI::NewLC( *iCoeEnv );
+    errorUI->ShowGlobalErrorNoteL( aTitle );
+    CleanupStack::PopAndDestroy( errorUI ); // errorUI
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::HandleResourceChangeL
+//
+//
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::HandleResourceChangeL(TInt aType)
+    {
+    CAknAppUi::HandleResourceChangeL( aType );
+    if ( iView )
+        {
+        iView->HandleResourceChange( aType );
+        }
+    
+    if ( aType == KEikDynamicLayoutVariantSwitch )
+        {
+        iStatusPaneRes = StatusPane()->CurrentLayoutResId();
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::SaveBodyL
+//
+//
+// ---------------------------------------------------------
+//
+void CMsgEditorAppUi::SaveBodyL( CMsgBodyControl* aBody )
+    {
+    CEikRichTextEditor* bodyEditor = &aBody->Editor();
+    if ( bodyEditor )
+        {
+        CRichText* richText = bodyEditor->RichText();
+        if ( richText )
+            {
+            TInt len = richText->DocumentLength();
+            if ( len )
+                {
+                HBufC* buf = HBufC::NewLC( len );
+                TPtr ptr = buf->Des();
+                richText->Extract( ptr, 0 );
+                CNotepadApi::AddContentL( ptr );
+                CleanupStack::PopAndDestroy( buf );
+                }
+            }
+        } 
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::ShowCloseQueryL
+// ---------------------------------------------------------
+//
+EXPORT_C TInt CMsgEditorAppUi::ShowCloseQueryL()
+    {
+    TInt selectedIndex( 0 );
+    CAknListQueryDialog* dlg = new ( ELeave ) CAknListQueryDialog( &selectedIndex );
+    dlg->PrepareLC( R_MEB_CLOSE_QUERY );
+    if ( dlg->RunLD() )
+        {
+        return ( selectedIndex == 0 )
+            ? EMsgCloseSave
+            : EMsgCloseDelete;
+        }
+    else
+        {
+        return EMsgCloseCancel;
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::CreateSubjectPrefixStringL
+// ---------------------------------------------------------
+//
+EXPORT_C HBufC* CMsgEditorAppUi::CreateSubjectPrefixStringL(
+        const TDesC& aSubject,
+        TBool aReply )
+    {
+    HBufC* newSubject = NULL;
+    TInt subjectLength = aSubject.Length();
+    if ( subjectLength >= 0 )
+        {
+        TInt formatResource = aReply
+            ? R_MSG_REPLY_PREFIX
+            : R_MSG_FORWARD_PREFIX;
+
+        HBufC* subjectFormat = StringLoader::LoadLC(
+            formatResource,
+            iCoeEnv );
+        
+        HBufC* filteredSubject = RemovePrefixesL( aSubject );    
+        CleanupStack::PushL( filteredSubject );
+        
+        if ( filteredSubject->Length() > 0 )
+        	{
+	        // Create a buffer large enough to hold the re-formated subject
+	        newSubject = HBufC::NewL( subjectLength + subjectFormat->Length());
+	        
+	        TPtr ptr( newSubject->Des() );            
+	        ptr.Append( *subjectFormat );
+	        ptr.Append( *filteredSubject );	        
+        	}
+        else
+        	{
+        	newSubject = HBufC::NewL( 0 );
+        	}
+        
+        CleanupStack::PopAndDestroy( filteredSubject );
+        CleanupStack::PopAndDestroy( subjectFormat );
+        }
+    return newSubject;
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::RemovePrefixesL
+// ---------------------------------------------------------
+//
+HBufC* CMsgEditorAppUi::RemovePrefixesL( const TDesC& aSubject )
+    {
+    // filter setup
+    RPointerArray<TDesC> prefixArray;
+    CleanupClosePushL( prefixArray );
+    
+    // add prefixes to remove
+    TPtrC filterRe( KMsgEditorAppUiFilterRe );
+    prefixArray.AppendL( &filterRe );  
+    
+    TPtrC filterFw( KMsgEditorAppUiFilterFw );
+    prefixArray.AppendL( &filterFw );
+    
+    TPtrC filterFwd( KMsgEditorAppUiFilterFwd );
+    prefixArray.AppendL( &filterFwd ); 
+    
+    // corresponding prefixes for the current language variant
+    HBufC* prefixReply = StringLoader::LoadLC( R_MSG_REPLY_PREFIX, iCoeEnv );
+    TPtr prefixReplyPtr = prefixReply->Des();
+    prefixReplyPtr.Trim();        
+    prefixArray.AppendL( &prefixReplyPtr );
+    
+    HBufC* prefixForward = StringLoader::LoadLC( R_MSG_FORWARD_PREFIX, iCoeEnv );
+    TPtr prefixForwardPtr = prefixForward->Des();
+    prefixForwardPtr.Trim();
+    prefixArray.AppendL( &prefixForwardPtr );
+    
+    // Remove prefixes 
+    HBufC* subject = aSubject.AllocL();
+    TPtr ptr( subject->Des() );
+    TBool prefixFound;
+    // Search until no prefixes found
+    do
+        {
+        // Loop all prefixes
+        prefixFound = EFalse;
+        ptr.TrimLeft();
+        for ( TInt i = 0; i < prefixArray.Count(); i++ )  
+            {
+            TPtrC prefix( *prefixArray[i] );
+            
+            // Remove prefixes while same prefix found at begining of subject    
+            while ( ptr.FindC( prefix ) == 0 )
+                {
+                ptr.Delete( 0, prefix.Length() ); 
+                prefixFound = ETrue;
+                ptr.TrimLeft();
+                }
+            }
+        } while ( prefixFound );
+    
+    CleanupStack::PopAndDestroy(3, &prefixArray ); 
+    
+    return subject;        
+    }    
+// ---------------------------------------------------------
+// CMsgEditorAppUi::LockEntryL
+//
+//
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::LockEntryL()
+    {
+    if ( iLock == NULL )
+        {
+        iLock = CLock::LockL( *Document() );
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::UnlockEntry
+//
+//
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::UnlockEntry()
+    {
+    delete iLock;
+    iLock = NULL;
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::IsLockedEntry
+//
+//
+// ---------------------------------------------------------
+//
+EXPORT_C TBool CMsgEditorAppUi::IsLockedEntry() const
+    {
+    return iLock != NULL;
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::Exit
+//
+//
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::Exit( TInt aReason /*= EEikCmdExit*/ )
+	{
+#ifdef RD_MSG_FAST_PREV_NEXT
+    // Communicate message id via publish and subscribe to MCE
+    RProperty::Set( KPSUidMuiu, KMuiuKeyCurrentMsg,
+        Document()->Entry().Id() );
+#endif // RD_MSG_FAST_PREV_NEXT
+
+	CEikAppServer* server = iEikonEnv->AppServer();
+	if ( server )
+        {
+		server->NotifyServerExit( aReason );
+        }
+	CEikAppUi::Exit();
+	}
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::HandleLocalZoomChangeL
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::HandleLocalZoomChangeL( TMsgCommonCommands aNewZoom )
+    {
+    TInt localZoom = 0;
+    TInt oldLocalZoom = EAknUiZoomAutomatic;
+    CRepository* repository = CRepository::NewL( KCRUidMessagingUiSettings );
+    TInt ret = repository->Get( KMessagingEditorLocalUiZoom, oldLocalZoom );
+    if ( ret == KErrNone )
+        {
+        switch( aNewZoom )
+            {
+            case EMsgDispSizeAutomatic:
+                {
+                localZoom = EAknUiZoomAutomatic;
+                break;
+                }
+            case EMsgDispSizeLarge:
+                {
+                localZoom = EAknUiZoomLarge;
+                break;
+                }
+            case EMsgDispSizeNormal:
+                {
+                localZoom = EAknUiZoomNormal;
+                break;
+                }
+            case EMsgDispSizeSmall:
+                {
+                localZoom = EAknUiZoomSmall;
+                break;
+                }
+            default:
+                break; 
+            }
+        if( oldLocalZoom != localZoom )
+            {
+            ret = repository->Set( KMessagingEditorLocalUiZoom, localZoom );
+            __ASSERT_DEBUG( !ret, Panic( EMsgRepositorySettingFailure ) );
+            TWsEvent event; 
+            event.SetType( KAknLocalZoomLayoutSwitch ); 
+            ret = iEikonEnv->WsSession().SendEventToAllWindowGroups( event );
+            }
+        }
+
+    delete repository;          
+    }
+    
+// ---------------------------------------------------------
+// CMsgEditorAppUi::CreateViewerNaviPaneL
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::CreateViewerNaviPaneL( TTime aTime, 
+                                                      TMsgEditorMsgPriority aPriority,
+                                                      TBool aUtcTime )
+    {
+    CAknNavigationControlContainer* naviContainer = 
+        static_cast<CAknNavigationControlContainer*>( StatusPane()->ControlL( 
+                                                            TUid::Uid( EEikStatusPaneUidNavi ) ) );
+    if ( !iNaviDecorator )
+        {
+        CMsgNaviPaneControl* naviPaneControl = CMsgNaviPaneControl::NewL( naviContainer );
+        naviPaneControl->SetNavigationControlObserver( this );
+        
+        // naviPaneControl ownership transferred to iNaviDecorator.
+        iNaviDecorator = CAknNavigationDecorator::NewL( naviContainer, naviPaneControl );
+        
+        naviPaneControl->SetTimeIndicatorL( aTime, aUtcTime );
+        naviPaneControl->SetPriorityIndicatorL( aPriority );
+        
+        CMsgEditorDocument* doc = Document();
+        naviPaneControl->SetNavigationIndicatorL( doc->Session(), doc->Entry() );
+        
+        iNaviDecorator->SetContainerWindowL( *naviContainer );
+        iNaviDecorator->MakeScrollButtonVisible( EFalse );
+        iNaviDecorator->SetComponentsToInheritVisibility( ETrue );
+        iOwnNaviPane = NULL;
+        }
+    else
+        {
+        User::Leave( KErrAlreadyExists );
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::HandleNavigationControlEventL
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::HandleNavigationControlEventL( TMsgNaviControlEventId aEvent )
+    {
+    if ( aEvent ==  MMsgNaviPaneControlObserver::EMsgNaviLeftArrowPressed ||
+         aEvent == MMsgNaviPaneControlObserver::EMsgNaviRightArrowPressed )
+        {
+        if ( IsNextMessageAvailableL( aEvent == MMsgNaviPaneControlObserver::EMsgNaviRightArrowPressed ) )
+            {
+            /* no need for separate checks for right and left arrows
+            because IsNextMessageAvailableL() and NextMessageL
+            are called with the truth-value of the same comparison */
+            NextMessageL( aEvent == MMsgNaviPaneControlObserver::EMsgNaviRightArrowPressed );
+            } 
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::CLock::LockL
+//
+//
+// ---------------------------------------------------------
+//
+CMsgEditorAppUi::CLock* CMsgEditorAppUi::CLock::LockL(
+    const CMsgEditorDocument& aDoc)
+    {
+    CLock* lock = new ( ELeave ) CLock();
+    CleanupStack::PushL( lock );
+    
+    lock->iStore = aDoc.CurrentEntry().EditStoreL();
+    lock->iStream.AssignL( *( lock->iStore ), KMsvEntryRichTextBody );
+    
+    CleanupStack::Pop( lock );
+    return lock;
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::CLock::CLock
+//
+//
+// ---------------------------------------------------------
+//
+CMsgEditorAppUi::CLock::CLock()
+    {
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::CLock::~CLock
+//
+//
+// ---------------------------------------------------------
+//
+CMsgEditorAppUi::CLock::~CLock()
+    {
+    if ( iStore != NULL )
+        {
+        iStream.Release();
+        iStream.Close();
+        iStore->Revert();
+        delete iStore;
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::CanFastOpenL
+// ---------------------------------------------------------
+//
+EXPORT_C TBool CMsgEditorAppUi::CanFastOpenL( const CMessageIterator& /*aIterator*/ )
+    {
+    return EFalse;
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::AknInputBlockCancel
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::AknInputBlockCancel()
+    {
+    if ( iInputBlocker )
+        {
+        iInputBlocker->MakeVisible( EFalse );
+        iInputBlocker->ControlEnv()->AppUi()->RemoveFromStack( iInputBlocker );
+        }
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::SetTitleIconSizeL
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::SetTitleIconSizeL( CFbsBitmap* aTitleBitmap )
+    {
+    TRect mainPane;
+    AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::ETitlePane, mainPane );
+    TAknLayoutRect titleIconPaneLayoutRect;
+    
+    if ( AknStatuspaneUtils::StaconPaneActive() )
+        {
+        titleIconPaneLayoutRect.LayoutRect( mainPane,
+                                            AknLayoutScalable_Avkon::title_pane_stacon_g1( 0 ).LayoutLine() );
+        }
+    else
+        {
+        titleIconPaneLayoutRect.LayoutRect( mainPane,
+                                            AknLayoutScalable_Avkon::title_pane_g2( 0 ).LayoutLine() );
+        }
+    
+    TSize iconSize = titleIconPaneLayoutRect.Rect().Size();
+
+    User::LeaveIfError( AknIconUtils::SetSize( aTitleBitmap, iconSize, EAspectRatioPreserved ) );
+    }
+
+// ---------------------------------------------------------
+// CMsgEditorAppUi::HandleStatusPaneSizeChange
+//
+// Performs layout switch on view area if statuspane is changed to 
+// same statuspane that is used by CMsgEditorAppUi. This is for
+// correcting the layout if layout switch was performed when 
+// SMIL player or SMIL editor that use different statuspane
+// were displayed. Without this the layout would be shown as if
+// statuspane that SMIL components use would be used.
+// ---------------------------------------------------------
+//
+EXPORT_C void CMsgEditorAppUi::HandleStatusPaneSizeChange()
+    {
+    CAknAppUi::HandleStatusPaneSizeChange();
+    
+    if ( iView &&
+         iStatusPaneRes == StatusPane()->CurrentLayoutResId() )
+        {
+        iView->HandleResourceChange( KEikDynamicLayoutVariantSwitch );
+        }
+    }
+
+//  End of File