cbs/cbsui/UiSrc/CCbsUiMsgView.cpp
branchRCL_3
changeset 20 987c9837762f
parent 0 ff3b6d0fd310
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cbs/cbsui/UiSrc/CCbsUiMsgView.cpp	Wed Sep 01 12:15:03 2010 +0100
@@ -0,0 +1,1030 @@
+/*
+* Copyright (c) 2008 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 CCbsUiMsgView.
+*
+*
+*/
+
+
+
+// INCLUDES
+#include <AknUtils.h>        //AknTextUtils
+#include <bldvariant.hrh>    // for feature flags
+#include <featmgr.h>  	     // for feature manager
+#include <aknappui.h>
+#include <aknViewAppUi.h>
+#include <eikmenup.h>
+#include <avkon.hrh>
+#include <aknnavide.h>
+#include <txtrich.h>         // CRichText
+#include <AknProgressDialog.h>
+#include <eikmenub.h>
+#include <hlplch.h>
+#include <avkon.rsg>
+#include <StringLoader.h>
+#include <cbsuiApp.rsg>
+#include <barsread.h>
+#include <AknQueryDialog.h>
+#include <eikmop.h>
+#include <FindItemmenu.rsg>
+#include <finditemmenu.h>
+#include <finditemdialog.h>
+#include <akntitle.h>
+#include "CCbsUIMsgView.h"
+#include "Cbsuiapp.hrh"
+#include "CCbsUIMsgViewContainer.h"
+#include "CbsUiPanic.h"
+#include "CbsUiConstants.h"
+#include "CbsUiUtility.h"
+#include "CbsUiDebug.h"
+#include "MCbs.h"
+#include "CbsUiId.h"  //KUidCbsUiappDef
+
+ 
+
+// CONSTANTS
+
+static const TUid KUidCbsUiappApp = { KUidCbsUiappDef };
+const TInt KCbsImmediateMessageIdInt = 313;
+const TInt KMaxAssumedDateTimeLength = 30;
+
+_LIT(KSpace, " ");
+_LIT(KLineBreak, "\n");
+const TInt KMaxSeparatorLenght = 5;
+const TInt KOneHotMarkedMessage = 1;
+
+
+
+
+
+// ================= MEMBER FUNCTIONS =======================
+
+// C++ default constructor can NOT contain any code, that
+// might leave.
+
+CCbsUiMsgView::CCbsUiMsgView( MCbs& aServer )
+: 
+iServer( aServer )
+    {
+    }
+
+// Symbian OS default constructor can leave.
+void CCbsUiMsgView::ConstructL()
+    {
+    BaseConstructL( R_CBSUI_MSGVIEW );   
+    iFindItemMenu = CFindItemMenu::NewL( ECbsUiCmdFindItem );
+    iFromOtherApplication = EFalse;
+
+    CEikStatusPane* statusPane = StatusPane();
+        
+    iNaviContainer = 
+    STATIC_CAST( CAknNavigationControlContainer*, statusPane->
+    		ControlL( TUid::Uid( EEikStatusPaneUidNavi ) ) );    
+    
+    }
+
+// Two-phased constructor.
+CCbsUiMsgView* CCbsUiMsgView::NewL( MCbs& aServer )
+    {
+    CCbsUiMsgView* self = new (ELeave) CCbsUiMsgView( aServer );
+    
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop();
+    return self;
+    }
+
+// Destructor
+CCbsUiMsgView::~CCbsUiMsgView()
+    {
+    CloseContextMenu();
+    
+    if ( iContainer )
+        {
+        AppUi()->RemoveFromViewStack( *this, iContainer );
+        }
+    
+    delete iContainer;
+    delete iFindItemMenu;
+
+    if ( iNaviContainer && iDecoratedLabel )
+    	{
+    	iNaviContainer->Pop ( iDecoratedLabel );
+    	delete iDecoratedLabel;
+    	}
+	iDecoratedLabel = NULL;
+
+	if ( iNaviContainer && iPreviousDecoratedLabel )
+		{
+		iNaviContainer->Pop ( iPreviousDecoratedLabel );
+		delete iPreviousDecoratedLabel;
+		}
+	iPreviousDecoratedLabel = NULL;
+
+    delete iMessage;
+    }
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::HandleNaviDecoratorEventL
+// 
+// 
+// ---------------------------------------------------------
+//
+void CCbsUiMsgView::HandleNaviDecoratorEventL( TInt aEventID )
+	{
+	
+    switch ( aEventID )
+    	{
+		// Left arrow tapped from the navi pane
+    	case MAknNaviDecoratorObserver::EAknNaviDecoratorEventLeftTabArrow:
+		    {
+		    if( AknLayoutUtils::LayoutMirrored() )
+		    	{
+		        MoveToNextMessageL();
+		        }
+		    else
+		        {
+		        MoveToPreviousMessageL();
+		        }
+		    break;
+		    }               
+		// Right arrow tapped from the navi pane
+    	case MAknNaviDecoratorObserver::EAknNaviDecoratorEventRightTabArrow:
+		    {
+		    if( AknLayoutUtils::LayoutMirrored() )
+		    	{
+		        MoveToPreviousMessageL();
+		        }
+		    else
+		        {
+		        MoveToNextMessageL();
+		        }
+		    break;
+		    }
+		default:
+		    {
+		    break;
+		    }
+    	}
+
+	}
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::DynInitMenuPaneL
+// 
+// 
+// ---------------------------------------------------------
+//
+void CCbsUiMsgView::DynInitMenuPaneL( TInt aResourceId,
+                                     CEikMenuPane* aMenuPane )
+    {
+    __ASSERT_DEBUG( aMenuPane, CbsUiPanic( EMenuPaneNullError ) );
+    __ASSERT_DEBUG( iFindItemMenu, CbsUiPanic( EFindItemNullError ) );
+    
+    switch ( aResourceId )
+        {
+        case R_CBSUI_MSGVIEW_MENU:
+            {
+            iFindItemMenu->DisplayFindItemMenuItemL( 
+                *aMenuPane, 
+                ECbsUiappCmdMsgMenuDelete );
+            
+            if ( CbsUiUtility::IsSavedL(iCurrentHandle, iServer) )
+                {
+                aMenuPane->DeleteMenuItem( ECbsUiappCmdMsgMenuKeep );
+                } 
+            if( !FeatureManager::FeatureSupported( KFeatureIdHelp ) )
+                {
+                aMenuPane->DeleteMenuItem( EAknCmdHelp );
+                }
+            break;
+            }                           
+        case R_FINDITEMMENU_MENU:
+            {
+            iFindItemMenu->DisplayFindItemCascadeMenuL( *aMenuPane );
+            break;
+            }
+        default:
+            break;
+        }
+    }    
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::ProcessCommandL
+// 
+// 
+// ---------------------------------------------------------
+//
+void CCbsUiMsgView::ProcessCommandL( TInt aCommand )
+    {            
+    if ( iContextMenu )
+        {
+        iContextMenu->StopDisplayingMenuBar();
+        CloseContextMenu();
+        }            
+
+    // Context sensitive menu should be opened when MSK pressed
+    switch ( aCommand )
+        {    
+        case EAknSoftkeyContextOptions:
+            HandleCommandL( EAknSoftkeyContextOptions );
+            break;            
+        default:
+            break;
+        }
+    // Call base class
+    CAknView::ProcessCommandL( aCommand );
+    }
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::Id
+// 
+// 
+// ---------------------------------------------------------
+//
+TUid CCbsUiMsgView::Id() const
+    {
+    return TUid::Uid( ECbsUiMsgViewId );
+    }
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::MoveToNextMessage
+// 
+// 
+// ---------------------------------------------------------
+//
+void CCbsUiMsgView::MoveToNextMessageL()
+    {   
+    // if a message is class 0, then changing the message
+    // content is not allowed.
+    if ( iIsClass0 )
+        {
+        return;
+        }
+    
+    if ( SetHandleTo(iCurrentHandle, EToNext) )
+        {
+        DoLoadMessageL();
+        }
+    
+    }
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::MoveToPreviousMessage
+// 
+//
+// ---------------------------------------------------------
+//
+void CCbsUiMsgView::MoveToPreviousMessageL()
+    {
+    // if a message is class 0, then changing the message
+    // content is not allowed.
+    if ( iIsClass0 )
+        {
+        return;
+        }
+    
+    if ( SetHandleTo(iCurrentHandle, EToPrevious) )
+        {
+        DoLoadMessageL();
+        }
+    }
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::HandleCommandL
+// 
+// 
+// ---------------------------------------------------------
+//
+void CCbsUiMsgView::HandleCommandL( TInt aCommand )
+    {
+    if ( iFindItemMenu && iFindItemMenu->CommandIsValidL( aCommand ) )
+        {
+        DoSearchL( aCommand );
+        }
+    
+    TBool exit(EFalse); // program exits if true
+    
+    switch ( aCommand )
+        {
+        case EAknSoftkeyBack:
+            {
+            ActivateTopicViewL( CurrentTopicNumber(), iCurrentHandle );
+            break;
+            }
+        case ECbsUiappCmdMsgMenuKeep:
+            {            
+            if ( CbsUiUtility::SaveCurrentMessageL(iCurrentHandle, *this) ==
+                KErrNone && iIsClass0 )
+                {
+                exit = ETrue;
+                
+                // show modal note
+                CbsUiUtility::ShowConfirmationNoteL(
+                    R_TEXT_NOTE_MSG_KEPT, ETrue);
+                }
+            break;
+            }
+        case ECbsUiCmdCopyToClipboard:
+            {
+            iContainer->CopyToClipboardL();   
+            CbsUiUtility::ShowConfirmationNoteL(R_TEXT_NOTE_MSG_TO_CLIP);
+            break;
+            }
+        case ECbsUiappCmdMsgMenuDelete:
+            {            
+            if ( DeleteMessageL(iCurrentHandle) && iIsClass0 )
+                {
+                exit = ETrue;
+                }
+            break;
+            }
+        case EAknSoftkeyContextOptions:
+        case ECbsUiappCmdOkKey:
+            {
+            LaunchContextMenuL();
+            break;
+            }
+        case EAknCmdHelp:
+            AppUi()->HandleCommandL(aCommand);
+            break;
+        case EAknSoftkeyExit: // let it run through
+        case EAknCmdExit:
+            {
+            if ( !iFromOtherApplication )
+                {
+                // if it has been CBSUI then do this
+                ActivateTopicListViewL();
+                }
+            else
+                {
+                exit = ETrue;
+                }
+            iFromOtherApplication = EFalse;
+            break;
+            }         					   		    
+        default:
+            break;
+        }
+    
+    if ( exit )
+        {
+        STATIC_CAST(
+            MEikCommandObserver*, AppUi() )->ProcessCommandL(EAknCmdExit);
+        }
+    }
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::DoActivateL
+// 
+// 
+// ---------------------------------------------------------
+//
+void CCbsUiMsgView::DoActivateL( const TVwsViewId& aPrevViewId,
+                                TUid aCustomMessageId,
+                                const TDesC8& aCustomMessage )
+    {   
+    iIsClass0 = EFalse;
+    TBool topicListViewActivated(EFalse);
+    
+    switch ( aCustomMessageId.iUid )
+        {
+        case KCbsUiCustomMessageIdInt:
+            iFromOtherApplication = EFalse;
+            Cba()->SetCommandSetL(R_AVKON_SOFTKEYS_OPTIONS_BACK);
+            SetCurrentMessageHandle(aCustomMessage);
+            break;
+        case KCbsImmediateMessageIdInt:
+            if ( aPrevViewId.iAppUid != KUidCbsUiappApp )
+                {
+                iFromOtherApplication = ETrue;
+                }
+            SetCurrentMessageHandle(aCustomMessage);
+            Cba()->SetCommandSetL(R_AVKON_SOFTKEYS_OPTIONS_EXIT);
+            Cba()->DrawDeferred();
+            iIsClass0 = ETrue;
+            break;
+        default: // this should be soft notification
+            iFromOtherApplication = EFalse;
+            Cba()->SetCommandSetL(R_AVKON_SOFTKEYS_OPTIONS_BACK);
+            topicListViewActivated = HandleSoftNotificationL();
+            break;
+        }
+    
+    if ( !topicListViewActivated )
+        {
+        if ( !iContainer )
+            {
+            iContainer = CCbsUiMsgViewContainer::NewL(*this, ClientRect());
+            AppUi()->AddToViewStackL(*this, iContainer);
+            }
+        
+        TInt err( DoLoadMessageL() );
+        
+        // if it is class 0 message and some error occurs
+        if ( err != KErrNone && iIsClass0 )
+            {
+            User::Leave(err);
+            }
+        
+        if ( iMessage )
+            {
+            iContainer->ActivateL();
+            }
+        else
+            {
+            // some error occured
+            ActivateTopicViewL( CurrentTopicNumber(), iCurrentHandle );
+            }
+        }
+    }
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::DoDeactivate()
+// 
+// 
+// ---------------------------------------------------------
+//
+void CCbsUiMsgView::DoDeactivate()
+    {
+    iServer.LockMessage(NULL);
+    
+    CloseContextMenu();
+    if ( iContainer )
+        {
+        AppUi()->RemoveFromViewStack( *this, iContainer );
+        delete iContainer;
+        iContainer = NULL;
+        }
+    
+    delete iDecoratedLabel;
+    iDecoratedLabel = NULL;
+    
+    DeleteOldMessage();
+    }
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::UpdateNaviPaneL
+// 
+//  
+// ---------------------------------------------------------
+//
+void CCbsUiMsgView::UpdateNaviPaneL()
+    {
+    
+    TInt currentPosition( KCbsErrValue );
+    TInt totalMessages( KCbsErrValue );
+    
+    TInt err (
+        GetMessagePosition( iCurrentHandle, currentPosition, totalMessages ) );
+
+    TBool prev( currentPosition != 0 );
+    TBool next( ( currentPosition + 1 ) < totalMessages );
+    
+    // If a message is class 0, then the navipane is empty
+    if ( iIsClass0 || err != KErrNone )
+        {
+        // Delete the existed label before creating a new one 
+        // in case of memory leak
+        CAknNavigationDecorator* oldLabel = iDecoratedLabel;
+        iDecoratedLabel = CbsUiUtility::CreateEmptyNavigationPaneL();
+        delete oldLabel;
+        return;
+        }
+    
+    // Create a new decorator    
+    CArrayFixFlat<TInt>* array = new( ELeave ) CArrayFixFlat<TInt>( 2 );
+    CleanupStack::PushL( array );
+    array->AppendL( currentPosition + 1 );
+    array->AppendL( totalMessages );
+    HBufC* messageLocationInTopic = StringLoader::LoadL( R_MESSAGE_LOCATION_IN_TOPIC, *array, iCoeEnv );
+    CleanupStack::PopAndDestroy(); // array
+    CleanupStack::PushL( messageLocationInTopic );
+
+    CAknNavigationDecorator* newDecoratedLabel = iNaviContainer->CreateNavigationLabelL( *messageLocationInTopic );
+    CleanupStack::PopAndDestroy(); // messageLocationInTopic
+
+    CleanupStack::PushL( newDecoratedLabel );
+    
+    // Set new decorator on top of navi pane's decorator stack
+    // ( topmost decorator is the one to show )
+    iNaviContainer->PushL( *newDecoratedLabel );
+
+    // Remove previous decorator from decorator stack and delete it
+    if ( iPreviousDecoratedLabel )
+    	{
+    	iNaviContainer->Pop( iPreviousDecoratedLabel );        
+    	delete iPreviousDecoratedLabel;
+    	iPreviousDecoratedLabel = NULL;
+    	}
+
+    // Update decorator pointers to new ones
+    iPreviousDecoratedLabel = iDecoratedLabel;
+    iDecoratedLabel = newDecoratedLabel;
+    
+    __ASSERT_DEBUG( iDecoratedLabel, CbsUiPanic( EErrNullPointer ) );
+   
+    // Set observer for navi pane
+    iDecoratedLabel->SetNaviDecoratorObserver( this );
+
+    CleanupStack::Pop( newDecoratedLabel );
+    
+    iDecoratedLabel->MakeScrollButtonVisible( ETrue );
+
+    if( AknLayoutUtils::LayoutMirrored() )
+        {
+        iDecoratedLabel->SetScrollButtonDimmed( CAknNavigationDecorator::ELeftButton, !next );
+        iDecoratedLabel->SetScrollButtonDimmed( CAknNavigationDecorator::ERightButton, !prev );
+        }
+    else
+        {
+    	iDecoratedLabel->SetScrollButtonDimmed( CAknNavigationDecorator::ELeftButton, !prev );
+    	iDecoratedLabel->SetScrollButtonDimmed( CAknNavigationDecorator::ERightButton, !next );
+        }
+
+    }
+
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::SaveMessage
+// 
+//  
+// ---------------------------------------------------------
+//
+TInt CCbsUiMsgView::SaveMessage( const TCbsMessageHandle& aHandle )
+    {
+    return iServer.SaveMessage(aHandle);
+    }
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::DoSearchL
+// 
+//  
+// ---------------------------------------------------------
+//
+void CCbsUiMsgView::DoSearchL( TInt aCommand )
+    {
+    CFindItemDialog* dialog =  CFindItemDialog::NewL( 
+        iContainer->GetEditor()->Read(0), 
+        iFindItemMenu->SearchCase(aCommand) );
+    dialog->ExecuteLD();
+    }
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::TopicListChangedL
+// 
+// 
+// ---------------------------------------------------------
+//
+void CCbsUiMsgView::TopicListChangedL( TCbsTopicListEvent /*aEvent*/, TCbsTopicNumber aTopicNumber )
+    {
+    if ( iContainer && (CurrentTopicNumber() == aTopicNumber) )
+        {
+        UpdateNaviPaneL();
+        }
+    }
+
+
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::HandleRectChangeInContainerL
+// 
+// 
+// ---------------------------------------------------------
+//
+void CCbsUiMsgView::HandleRectChangeInContainerL()
+    {
+    if ( iContainer )
+        {
+        iContainer->SetRect( ClientRect() );
+        iContainer->UpdateMessageL( *iMessage );
+        }
+    
+    }
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::CloseContextMenu
+// 
+//  
+// ---------------------------------------------------------
+//
+void CCbsUiMsgView::CloseContextMenu()
+    {
+    if ( iContextMenu )
+        {
+        AppUi()->RemoveFromViewStack(*this, iContextMenu);
+        delete iContextMenu;
+        iContextMenu = NULL;
+        }
+    }
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::LaunchContextMenuL
+// 
+//  
+// ---------------------------------------------------------
+//
+void CCbsUiMsgView::LaunchContextMenuL()
+    {        
+    TInt rssName = R_CBSUI_MSG_KEEP_AND_DELETE_CONTEXT_MENUBAR;
+    
+    if ( CbsUiUtility::IsSavedL(iCurrentHandle, iServer) )
+        {                        
+        rssName = R_CBSUI_MSG_DELETE_CONTEXT_MENUBAR;
+        }   
+    
+    CloseContextMenu();
+    
+    __ASSERT_DEBUG( !iContextMenu, CbsUiPanic(EErrAllreadyExists) );
+    
+    iContextMenu = new (ELeave) CEikMenuBar;    
+    iContextMenu->ConstructL(
+        this,
+        0,
+        rssName );
+    
+    // Set type to context sensitive
+    iContextMenu->SetMenuType( CEikMenuBar::EMenuContext );
+    
+    AppUi()->AddToViewStackL( 
+        *this, 
+        iContextMenu, 
+        ECoeStackPriorityMenu, 
+        ECoeStackFlagRefusesFocus );
+    
+    iContextMenu->TryDisplayMenuBarL();
+    }
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::DeleteOldMessage
+// 
+//
+// ---------------------------------------------------------
+//
+void CCbsUiMsgView::DeleteOldMessage()
+    {
+    delete iMessage;
+    iMessage = NULL;    
+    }
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::DoLoadMessageL
+// 
+//
+// ---------------------------------------------------------
+//
+TInt CCbsUiMsgView::DoLoadMessageL()
+    {
+    TRAPD( err, LoadMessageL() );
+    
+    switch ( err ) 
+        {
+        case KErrNotFound:
+            {
+            // If the message cannot be found
+            // it is not necessary to do anything.
+            // It is just showing some other message (current).
+            break;
+            }
+        case KErrNone:
+            {
+            // normal case
+            __ASSERT_DEBUG( iMessage, CbsUiPanic(EErrNullPointer) );
+            iContainer->UpdateMessageL(*iMessage);
+            // navi pane has to be updated in all cases; expect when leave
+            UpdateNaviPaneL();
+            Cba()->SetCommandSetL( R_CBS_SOFTKEYS_OPTIONS_BACK__CONTEXTOPTIONS );
+            break;
+            }
+        default:
+            User::Leave( err );
+            break;
+        }
+    
+    return err;
+    }
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::ActivateTopicViewL
+// 
+//
+// ---------------------------------------------------------
+//
+void CCbsUiMsgView::ActivateTopicViewL( TCbsTopicNumber aTopicNumber, TCbsMessageHandle aHandle )
+    {  
+    TPckgBuf<TCbsUiTopicActivationPckg> message;
+    message().iTopicNumber = aTopicNumber;
+    message().iMessageHandle = aHandle;
+    
+    AppUi()->ActivateLocalViewL( 
+        TUid::Uid(ECbsUiTopicViewId), KSetFocusToId, message );
+    }
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::SetCurrentMessageHandle
+// 
+//
+// ---------------------------------------------------------
+//
+void CCbsUiMsgView::SetCurrentMessageHandle( const TDesC8& aMessageHandle )
+    {
+    TPckgBuf<TCbsMessageHandle> pckgMessageHandle;
+    pckgMessageHandle.Copy(aMessageHandle);
+    iCurrentHandle = pckgMessageHandle();
+    }
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::LoadMessageL
+// 
+//
+// ---------------------------------------------------------
+//
+void CCbsUiMsgView::LoadMessageL()
+    {      
+    User::LeaveIfError( iServer.LockMessage(iCurrentHandle) );
+    
+    TCbsMessage message;
+    TInt err( iServer.FindMessageByHandle(iCurrentHandle, message) );
+    __CBSUI_ASSERT( err == KErrNone, CbsUiPanic(EErrMsgHandleNotFound) );
+    User::LeaveIfError(err);
+    
+    // mark the message as read 
+    err = iServer.ReadMessage(iCurrentHandle);
+    User::LeaveIfError(err);
+    
+    DeleteOldMessage();
+    iMessage = HBufC::NewMaxL(message.iLength);
+    TPtr messageContent = iMessage->Des();
+    
+    err = iServer.GetMessageContents(iCurrentHandle, messageContent);
+    
+    __CBSUI_ASSERT( err == KErrNone, 
+        CbsUiPanic(EMessageContentsError) );
+    
+    if ( err != KErrNone )
+        {
+        DeleteOldMessage();
+        User::Leave(err);
+        }
+    
+    AddDateAndTimeL( 
+        message.iDateTime,
+        &iMessage, // address of pointer variable
+        R_CBS_DATE_FORMAT_ARRAY );
+    }
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::AddDateAndTime
+// 
+// 
+// ---------------------------------------------------------
+//
+void CCbsUiMsgView::AddDateAndTimeL( const TInt64 aTime, HBufC** aMessage, TUint aResourceArrayId ) const
+    {
+    __ASSERT_DEBUG( aTime >= 0, CbsUiPanic(EErrInvalidValue) );
+    __ASSERT_DEBUG( *aMessage, CbsUiPanic(EErrNullPointer) );
+    __ASSERT_DEBUG( (*aMessage)->Length() > 0, CbsUiPanic(EErrEmptyDesc) );
+    __ASSERT_DEBUG( aResourceArrayId > 0, CbsUiPanic(EErrInvalidValue) );
+    
+    HBufC* timeBuffer = HBufC::NewMaxLC( KMaxAssumedDateTimeLength );
+    TInt bufLen( 0 );
+    TTime time( aTime );
+    
+    // change universal time to local time
+    TLocale locale;
+    time += locale.UniversalTimeOffset();
+    
+    TPtr des = timeBuffer->Des();    
+    TInt length( ( *aMessage )->Length() );
+    
+    // for adding date and time to message
+    TResourceReader reader;
+    iCoeEnv->CreateResourceReaderLC( reader, aResourceArrayId );
+    TInt count( reader.ReadInt16() );
+    
+    TBuf<KMaxSeparatorLenght> separator( KLineBreak );
+    TInt separatorsLength( KLineBreak().Length() + KSpace().Length() );
+    
+    for ( TInt i( 0 ); i < count; i++ )
+        {
+        TUint resourceId( reader.ReadUint32() );
+        
+        HBufC* format = iCoeEnv->AllocReadResourceLC( resourceId );
+        
+        time.FormatL( des, *format );
+        AknTextUtils::DisplayTextLanguageSpecificNumberConversion( des );
+        
+        if ( i > 0 )
+            {
+            separator = KSpace;
+            }
+        
+        bufLen += timeBuffer->Length();
+        (*aMessage) = (*aMessage)->ReAllocL( 
+            length + bufLen +  separatorsLength );
+        
+        // have to get a new pointer after reallocation
+        TPtr ptr2 = ( *aMessage )->Des();
+        ptr2.Append( separator );
+        ptr2.Append( *timeBuffer );
+        
+        CleanupStack::PopAndDestroy(); // format
+        }
+    
+    CleanupStack::PopAndDestroy( 2 ); // timeBuffer, reader
+    }
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::CurrentTopicNumber
+// 
+// 
+// ---------------------------------------------------------
+//
+TCbsTopicNumber CCbsUiMsgView::CurrentTopicNumber() const
+    {
+    return STATIC_CAST( TCbsTopicNumber, (iCurrentHandle >> 16) & 0xFFFF );
+    }
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::GetMessagePosition
+// 
+// 
+// ---------------------------------------------------------
+//
+TInt CCbsUiMsgView::GetMessagePosition( TCbsMessageHandle aHandle, TInt& aPosition, TInt& aTotal )
+    {
+    TInt err( iServer.GetMessageIndexByHandle(aHandle, aPosition) );
+    
+    __CBSUI_ASSERT( err == KErrNone, CbsUiPanic(EErrMsgHandleNotFound) );
+    __CBSUI_ASSERT( aPosition != KCbsErrValue, CbsUiPanic(EErrInvalidValue) );
+    
+    if ( err == KErrNone )
+        {
+        err = iServer.GetMessageCount( CurrentTopicNumber(), aTotal );
+        }
+    
+    __CBSUI_ASSERT( err == KErrNone, CbsUiPanic(EErrMsgHandleNotFound) );
+    __CBSUI_ASSERT( aPosition + 1 <= aTotal, CbsUiPanic(EErrMsgImbalance) );
+    
+    return err;
+    }
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::SetHandleTo
+// 
+// 
+// ---------------------------------------------------------
+//
+TBool CCbsUiMsgView::SetHandleTo( TCbsMessageHandle& aHandle, TMsgViewSetHandle aTo )
+    {
+    TCbsMessageHandle prev;
+    TCbsMessageHandle next;
+    TInt position(KCbsErrValue);
+    TBool result(EFalse);
+    
+    TInt err( iServer.GetNextAndPrevMessageHandle(
+        aHandle, prev, next, position) );
+    
+    if ( err == KErrNone )
+        {
+        __ASSERT_DEBUG( 
+            position >= 0 && position <= (ECbsTail | ECbsHead), 
+            CbsUiPanic(EErrInvalidValue) );           
+        
+        switch ( aTo )
+            {
+            case EToPrevious:
+                // if position is head it cannot go thru
+                if ( (position & ECbsHead) == 0 )
+                    {
+                    aHandle = prev;
+                    result = ETrue;
+                    }
+                break;
+            case EToNext:
+                // if position is tail it cannot go thru
+                if ( (position & ECbsTail) == 0 )
+                    {
+                    aHandle = next;
+                    result = ETrue;
+                    }
+                break;
+            default:
+                __ASSERT_DEBUG(0, CbsUiPanic(EErrInvalidValue));
+                break;
+            }
+        }        
+    
+    return result;
+    }
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::DeleteMessageL
+// 
+// 
+// ---------------------------------------------------------
+//
+TBool CCbsUiMsgView::DeleteMessageL( TCbsMessageHandle aHandle )
+    {
+    TBool result(EFalse);
+    
+    CAknQueryDialog* dlg = CAknQueryDialog::NewL();    
+    
+    if ( dlg->ExecuteLD(R_DELETE_MSG_CONFIRMATION_QUERY) )
+        {
+        TCbsMessageHandle handleToBeFocused(aHandle);        
+        
+        if ( !SetHandleTo(handleToBeFocused, EToNext) )
+            {
+            if ( !SetHandleTo(handleToBeFocused, EToPrevious) )
+                {
+                // next or previous could not be set, 0 will unlock message
+                handleToBeFocused = 0;
+                }
+            }
+        
+        // Unlock message to be deleted and lock next message before delete
+        __ASSERT_DEBUG(handleToBeFocused != aHandle, 
+            CbsUiPanic(EErrInvalidValue));
+        
+        iServer.LockMessage(handleToBeFocused);
+        iServer.DeleteMessage(aHandle);
+        
+        // free handleToBeFocused message
+        if ( handleToBeFocused != 0)
+            {
+            iServer.LockMessage(NULL);
+            }
+        
+        // Topic number is still the same even if the message is
+        // deleted.
+        ActivateTopicViewL( CurrentTopicNumber(), handleToBeFocused );
+        result = ETrue;
+        }
+    
+    return result;
+    }
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::ActivateTopicListViewL
+// 
+// 
+// ---------------------------------------------------------
+//
+void CCbsUiMsgView::ActivateTopicListViewL() const
+    {
+    AppUi()->ActivateLocalViewL( TUid::Uid(ECbsUiTopicListViewId) );
+    }
+
+// ---------------------------------------------------------
+// CCbsUiMsgView::HandleSoftNotification
+// 
+// 
+// ---------------------------------------------------------
+//
+TBool CCbsUiMsgView::HandleSoftNotificationL()
+    {
+    TCbsTopic topic;
+    TInt err;
+    TBool result( EFalse );
+    TInt count( iServer.NumberOfUnreadHotmarkedMessages() );
+    __ASSERT_DEBUG( 
+        count >= KOneHotMarkedMessage, CbsUiPanic(EErrInvalidValue) );
+    
+    switch ( count )
+        {
+        case KOneHotMarkedMessage:
+            iServer.GetHotmarkedMessageHandle( iCurrentHandle );
+            err = iServer.FindTopicByNumber( CurrentTopicNumber(), topic );
+            if ( err == KErrNone )
+                {
+                //Update Title pane
+                CEikStatusPane* sp = StatusPane();
+                CAknTitlePane* title = 
+                    STATIC_CAST(CAknTitlePane*, sp->ControlL( TUid::Uid( EEikStatusPaneUidTitle) ) );
+                title->SetTextL( topic.iName );
+                }
+            break;
+        default: // Many hot marked messages
+            ActivateTopicListViewL();
+            result = ETrue;
+            break;
+        }
+    
+    return result;
+    }
+
+
+//  End of File