imstutils/imconversationview/imcvuiapp/src/cimcvappmessageflowhandler.cpp
changeset 0 5e5d6b214f4f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/imstutils/imconversationview/imcvuiapp/src/cimcvappmessageflowhandler.cpp	Tue Feb 02 10:12:18 2010 +0200
@@ -0,0 +1,416 @@
+/*
+* 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