imstutils/imconversationview/imcvuiapp/src/cimcvappmessageflowhandler.cpp
author Simon Howkins <simonh@symbian.org>
Mon, 29 Nov 2010 11:18:43 +0000
branchRCL_3
changeset 37 7506649dda4d
parent 0 5e5d6b214f4f
permissions -rw-r--r--
Corrected path to files being exported - not in the same dir as bld.inf

/*
* Copyright (c) 2007-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:  Message flow handler class
*
*/


// INCLUDE FILES
#include    <coemain.h>

#include    "cimcvappmessageflowhandler.h"
#include    "mimcvenginemessagecontainer.h"
#include    "cimcvenginecontextobserver.h"
#include    "mimcvenginemessagesreadinterface.h"
#include 	"imcvlogger.h"
#include	"cimcvappui.h"
#include 	"cimcvengine.h"
#include	"mimcvenginechatinterface.h"


// CONSTANTS
const TInt KMilliToMicro     = 1000;    // multiplier for converting milliseconds to microseconds

const TInt KTimeIntervalSlow = 2000;    // slowest message speed (in milliseconds)
const TInt KTimeIntervalFast =  200;    // fastest message speed (in milliseconds)

const TInt KTimeIntervalOpen =    0;    // message fetching speed when opening the view
const TInt KInitialMessages  =    3;    // fetch n messages at once when opening the view

const TInt KSettingValueMin  =    1;    // minimum value for flow control setting
const TInt KSettingValueMax  =    3;    // maximum value for flow control setting

const TInt KIMFeatBackgroundGroupOpening = 0x00000008;

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

// -----------------------------------------------------------------------------
// CIMCVAppMessageFlowHandler::CIMCVAppMessageFlowHandler
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CIMCVAppMessageFlowHandler::CIMCVAppMessageFlowHandler( MIMCVEngineMessageContainer& aMessageContainer, 
                MIMCVEngineMessageReadInterface& aReadInterface,CIMCVEngine& aActiveEngine )
    : CTimer( EPriorityStandard ), 
      iMessages( aMessageContainer ),
      iReadInterface( aReadInterface ),
      iActiveEngine( aActiveEngine ),
      iFetchMessages( ETrue )
     {
	CActiveScheduler::Add( this );
    }


// -----------------------------------------------------------------------------
// CCAMessageFlowHandler::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CIMCVAppMessageFlowHandler* CIMCVAppMessageFlowHandler::NewL( 
                                    MIMCVEngineMessageContainer& aMessageContainer, 
                                    MIMCVEngineMessageReadInterface& aReadInterface,
                                    CIMCVEngine& aActiveEngine,
                                    TBool aScrollOver )
	{
	CIMCVAppMessageFlowHandler* self = new( ELeave ) CIMCVAppMessageFlowHandler( 
            aMessageContainer,
            aReadInterface ,
            aActiveEngine );

    CleanupStack::PushL( self );
    self->ConstructL( aScrollOver );
    CleanupStack::Pop( self );

    return self;
	}
// -----------------------------------------------------------------------------
// CIMCVAppMessageFlowHandler::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CIMCVAppMessageFlowHandler::ConstructL( TBool aScrollOver )
    {
    // construct base class
    CTimer::ConstructL();
	
    // for getting chat interface from CIMCVAPPAppUi
    iActiveEngine.ChatInterface().RegisterChatListObserver(this);	
	
	// and observe changes
    iReadInterface.SetObserver( this );
    iReadInterface.SetActive(ETrue);
    
    // fetch flow control value from settings
    UpdateTimeIntervalL();        
    
    if ( aScrollOver )
        {
        iBgOpeningMode = EFalse;
        }
    else
        {
    	iBgOpeningMode = 0 & KIMFeatBackgroundGroupOpening;
        }
    
    // start the timer if there are messages
    iInitialMsgCount = iReadInterface.MessageCount();
    if( iInitialMsgCount + iReadInterface.UnreadCount() > 0 )
        {
        // lock the buffer
        iReadInterface.Lock( ETrue );
    
        // use faster timer when constructing
        iTimeInterval = KTimeIntervalOpen * KMilliToMicro;
        After( iTimeInterval );
        }        
  }


// Destructor
CIMCVAppMessageFlowHandler::~CIMCVAppMessageFlowHandler()
    {
    // for getting chat interface from CIMCVAPPAppUi
    iActiveEngine.ChatInterface().UnregisterChatListObserver(this);	
		    
    if ( !iChatDeleted )
        {
        iReadInterface.SetActive(EFalse);
        iReadInterface.SetObserver( NULL );
        iReadInterface.Lock( EFalse );
        }
    Cancel();
	}


// -----------------------------------------------------------------------------
// CIMCVAppMessageFlowHandler::FetchMessages
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CIMCVAppMessageFlowHandler::FetchMessages( TBool aFetch )
    {
    TBool reallyInBg =
        CCoeEnv::Static()->RootWin().OrdinalPosition() == 0 ? EFalse : ETrue;
    
    if ( !reallyInBg && !aFetch )
        {
        // Application is not really in background, this can happen
        // if key lock is activated while application is in foreground
        aFetch = ETrue;
        }
    
    iFetchMessages = aFetch;
    if( iFetchMessages && !iChatDeleted )
        {
        // we're allowed to fetch messages again
        if( iReadInterface.UnreadCount() > 0 && !IsActive() )
            {
            // there are some unread messages
            // => start the timer (if not active already)
            After( iTimeInterval );
            }
        }   
    
    else if( iMsgIndex < iInitialMsgCount )
        {
        Cancel();
        After( iTimeInterval );        
        return;
        }
    else
        {
        // we're not allowed to fetch new messages any more, so cancel the timer
        Cancel();
        }
    }

// -----------------------------------------------------------------------------
// CIMCVAppMessageFlowHandler::HandleMessageEvent
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CIMCVAppMessageFlowHandler::HandleMessageEvent( TMessageEventType aEvent, 
                                                TInt aIndex )
    {
    IM_CV_LOGS(TXT("CIMCVAppMessageFlowHandler::HandleMessageEvent event %d, \
                         index %d"), aEvent, aIndex );
    switch( aEvent )
        {
        case ENewMessage:
            {
            if( !IsActive() && iFetchMessages )
                {
                // if not active, start timer
                After( iTimeInterval );
                }
            
            if ( IsOpening() && iBgOpeningMode )
                {
                // New message during opening phase
                iNewMsgWhileOpening = ETrue;
                }
                
            // otherwise do nothing as timer fetches the messages
            break;
            }
		
        default:
            {            
            break;
            }
        }
    }

// -----------------------------------------------------------------------------
// CIMCVAppMessageFlowHandler::RunL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CIMCVAppMessageFlowHandler::RunL()
    {    
    TBool messages( ETrue );
    TBool opening = IsOpening();
    
    // If we're opening the view, fetch KInitialMessages at a time, otherwise just one
    TInt count( opening ? KInitialMessages : 1 );
    
    while( count-- > 0 && messages )
        {
        if ( iBgOpeningMode && opening )
            {
            // Opening the chat with background message fetching.
            // Perform steps in following order:
            // 1. Add possible new messages that are received during
            //    the opening phase to the end of chat normally
            // 2. Insert unread messages to the beginning of chat

            if ( iNewMsgWhileOpening && iFetchMessages ) 
                {
                // Add the new message now
                iMessages.AddMessageL( iReadInterface.ReadNextUnread() );                						
            	
                iNewMsgWhileOpening = EFalse;
                }
            else if ( iReadInterface.UnreadCount() > 0 && iFetchMessages ) 
                {
                // Insert unread messages, insert in last-to-first order
                iAddedUnreadMsgs++;
                
                iMessages.InsertMessageL(  
                	iReadInterface.ReadUnreadFromIndex(
                    iReadInterface.MessageCount()
                    + iReadInterface.UnreadCount()
                    - iAddedUnreadMsgs )  );
                
                
                }

            else
                {
                // Check if the initial speed was active
                if ( opening )
                    {
                    UpdateTimeIntervalL();
                    }
                messages = EFalse;
                iReadInterface.Lock( EFalse );
                }
            }
        else
            {
            // Functionality in opening in releases 3.1 and earlier
            // and normal functionality when the chat is already fully opened
            // and new messages are received.
            
            //  Add unread messages in first-to-last order
            if ( iReadInterface.UnreadCount() > 0 )
                {
                // Add unread messages
                iMessages.AddMessageL( iReadInterface.ReadNextUnread() );
				
                }
            else
                {
                // Check if the initial speed was active
                if ( opening )
                    {
                    UpdateTimeIntervalL();
                    }
                messages = EFalse;
                iReadInterface.Lock( EFalse );
                }
            }
        }

    // And restart timer if needed    
    if ( messages )        
        {
        Cancel();
        After( iTimeInterval );
        }
    }

// -----------------------------------------------------------------------------
// CIMCVAppMessageFlowHandler::RunError
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CIMCVAppMessageFlowHandler::RunError( TInt aError )
    {
    IM_CV_LOGS(TXT("CIMCVAppMessageFlowHandler::RunError (%d)"), aError );
    
    // Something leaved in RunL
    if( aError == KErrNoMemory )
        {
        // inform user about low memory
        CActiveScheduler::Current()->Error( aError );
        }
    
    if( IsActive() )
        {
        // stop processing messages
        Cancel();
        }
    
    return KErrNone;
    }



// -----------------------------------------------------------------------------
// CIMCVAppMessageFlowHandler::UpdateTimeIntervalL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CIMCVAppMessageFlowHandler::UpdateTimeIntervalL()
    {
    // codescanner warning can be ignored
    TInt flowSetting( 10 );
    
    // flowSetting is from KSettingValueMin to KSettingValueMax
    TInt range( KSettingValueMax - KSettingValueMin );
    TInt newRange( KTimeIntervalFast - KTimeIntervalSlow );
    
    // convert it to a range from KTimeIntervalSlow to KTimeIntervalFast
    TInt flowSpeed( (flowSetting-KSettingValueMin)*newRange / range );
    
    // update the end point
    flowSpeed += KTimeIntervalSlow;
    
    // validate the result
    if( flowSpeed > KTimeIntervalSlow )
        {
        flowSpeed = KTimeIntervalSlow;
        }
        
    if( flowSpeed < KTimeIntervalFast )
        {
        flowSpeed = KTimeIntervalFast;
        }

    // and convert from milliseconds to microseconds            
    iTimeInterval = flowSpeed * KMilliToMicro;
    }

// -----------------------------------------------------------------------------
// CIMCVAppMessageFlowHandler::IsOpening
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CIMCVAppMessageFlowHandler::IsOpening() const
    {
    return iTimeInterval == 
            TTimeIntervalMicroSeconds32( KTimeIntervalOpen * KMilliToMicro );
    }

// -----------------------------------------------------------------------------
// CIMCVAppMessageFlowHandler: HandleChatListEvent
// -----------------------------------------------------------------------------
//
void CIMCVAppMessageFlowHandler::HandleChatListEvent( TInt /*aServiceId*/, TChatListEventType aEvent, 
									MIMCVEngineMessageReadInterface* /*aContainerInfo*/
									) 
	{
		
	switch (aEvent)
		{
		case EChatItemAdded:
			{							
			break;
			}

		case EChatItemDeleted:
			{				
			iChatDeleted = ETrue;
			break;
			}

		default:
			break;
		}
	
	}
    
//  End of File