uifw/AvKon/src/AknPhedModel.cpp
changeset 0 2f259fa3e83a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uifw/AvKon/src/AknPhedModel.cpp	Tue Feb 02 01:00:49 2010 +0200
@@ -0,0 +1,507 @@
+/*
+* Copyright (c) 2002-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: 
+*
+*/
+
+#include "AknPhedModel.h"
+#include "NumberGrouping.h"
+
+#include <e32svr.h>
+#include <AknUtils.h>
+
+const TInt KExtraSpaceForGroupedNumber = 6;
+
+//
+// CAknPhedBuffer
+//
+CAknPhedScratchBuffer::CAknPhedScratchBuffer() :iPtr(0,0)
+	{
+	}
+
+CAknPhedScratchBuffer::~CAknPhedScratchBuffer()
+	{
+	delete iBuf;
+	}
+
+void CAknPhedScratchBuffer::ConstructL(TInt aMaxLen)
+	{
+	iBuf = HBufC::NewL(aMaxLen + KExtraSpaceForGroupedNumber);
+	iPtr.Set(iBuf->Des());
+	}
+
+
+
+//
+// CAknPhedModel
+//
+CAknPhedModel* CAknPhedModel::NewL( TInt aMaxLen )
+    {
+    CAknPhedModel* self = new( ELeave ) CAknPhedModel;
+    CleanupStack::PushL( self );
+    self->ConstructL( aMaxLen );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+CAknPhedModel::~CAknPhedModel()
+    {
+    delete iNumberGroupingBuffer;
+	delete iBuf;
+    }
+
+void CAknPhedModel::SetText( const TDesC& aText )
+    {
+    StartEvent();
+
+    // delete all existing text
+    TInt len = iRealLength;
+    DeleteLeft( len, len );
+
+    // insert the new text
+    SetRealCursorPosition( 0 );
+    Insert( aText );
+
+    ReportEvent(MPhedDataObserver::TAknPhedDataEvent(
+                MPhedDataObserver::TAknPhedDataEvent::EText, 
+                0,
+                iNumberGroupingBuffer->Length() ) );
+    }
+
+void CAknPhedModel::Insert( TText aChar )
+    {
+    StartEvent();
+    ClearAnySelection();
+
+    TInt nOldCursorPos = CursorPosition();
+
+    // buffer full rule: Text overflows off the left hand side of the buffer
+    TInt maxLength = MaxDisplayLength();
+    if ( iRealLength == maxLength )
+        {
+        if (nOldCursorPos == 0)
+            {
+            ReportEvent( MPhedDataObserver::TAknPhedDataEvent() );
+            return;
+            }
+        else
+            {
+            DeleteLeft( 1 );
+            SetRealCursorPosition( iRealCursor - 1 );
+            }
+        }
+        
+    iNumberGroupingBuffer->Insert( iRealCursor, aChar );
+    ++iRealLength;
+    iNumberGroupingBuffer->FormattedNumber();
+    SetRealCursorPosition( iRealCursor + 1 );
+    if ( Length() > maxLength )
+        {
+        DeleteLeft( 1 );
+        SetRealCursorPosition( iRealCursor - 1 );
+        ReportEvent(MPhedDataObserver::TAknPhedDataEvent(
+        MPhedDataObserver::TAknPhedDataEvent::EText, 
+        CursorPosition(),                                  
+        CursorPosition() ) );
+        }
+    else 
+        {
+        ReportEvent( MPhedDataObserver::TAknPhedDataEvent(
+                MPhedDataObserver::TAknPhedDataEvent::EText, 
+                nOldCursorPos,                                  
+                CursorPosition() ) );
+        }                
+    
+    }
+
+void CAknPhedModel::DeleteLeft()
+    {
+    if( !ClearAnySelection() && iRealCursor > 0 )
+        {
+        StartEvent();
+
+        TInt nOldCursorPos = CursorPosition();
+
+        DeleteLeft(iRealCursor);
+        
+        SetRealCursorPosition( iRealCursor - 1 );
+        ReportEvent( MPhedDataObserver::TAknPhedDataEvent(
+                MPhedDataObserver::TAknPhedDataEvent::EText, 
+                CursorPosition(),                               
+                CursorPosition() ) );
+        }
+        
+    }
+
+void CAknPhedModel::DeleteLeft( TInt aIndex, TInt aCount )
+    {
+    aIndex--;   // delete char to the left
+
+    for ( TInt ii = 0; ii < aCount; ++ii )
+        {
+        iNumberGroupingBuffer->Delete( aIndex - ii );
+        --iRealLength;
+        }
+    }   
+
+TPtrC CAknPhedModel::Selection() const
+    { 
+    TInt nFrom = LeftMark();
+    TInt nTo = nFrom + SelectionWidth();
+
+    if(!nTo) nTo = iRealLength;
+    
+    return iNumberGroupingBuffer->Selection( nFrom, nTo );
+    }
+
+void CAknPhedModel::Cut( TDes& aCutText )
+    {
+    aCutText = Selection();
+    ClearAnySelection();
+    }
+
+void CAknPhedModel::Copy( TDes& aCopiedText ) const
+    {
+    aCopiedText = Selection();
+    }
+
+void CAknPhedModel::Paste( const TDesC& aText )
+    {
+    ClearAnySelection();
+    Insert( aText );
+    }
+
+TInt CAknPhedModel::Language()  const   
+    {
+    TInt language = iNumberGroupingBuffer->Language();
+    language &= KAknLanguageMask;  
+    TInt forceLanguage = iNumberGroupingBuffer->iForceLanguage;
+    forceLanguage &= KAknLanguageMask; 
+    
+    return ( ELangAmerican == language || 
+             ELangAmerican == forceLanguage)
+            ? ELangAmerican : ELangTest;
+    }
+
+TInt CAknPhedModel::Compensate( TInt aRealPosition ) const
+{
+    TInt nCompensated = 0;
+    if ( Language() )
+    	{
+    if( iCursorDirection == EUp )
+        nCompensated = aRealPosition + Spaces( 0, aRealPosition );
+    else if( iCursorDirection == EDown )
+        nCompensated = aRealPosition + Spaces( 0, aRealPosition + 1 );    
+    	}
+    else
+    	{
+    	nCompensated = aRealPosition;
+    	}
+    return nCompensated;
+}
+
+TInt CAknPhedModel::Uncompensate( TInt aCompensatedPosition ) const
+{
+    TInt nUncompensated = 0;
+    if ( Language() )
+    	{
+    if( iCursorDirection == EUp )
+        nUncompensated = aCompensatedPosition - Spaces( aCompensatedPosition - 1 );
+    else if( iCursorDirection == EDown )
+        nUncompensated = aCompensatedPosition - Spaces( aCompensatedPosition );    
+    	}
+    else
+    	{
+    	nUncompensated = aCompensatedPosition;
+    	}
+    return nUncompensated;
+}
+
+TInt CAknPhedModel::SetRealCursorPosition( TInt aCursorPos )
+    {
+    StartEvent();
+    if ( SelectionExists() )
+        {
+        // selection is lost, so report a selection change event
+        StartEvent();
+        ReportEvent( MPhedDataObserver::TAknPhedDataEvent(
+                     MPhedDataObserver::TAknPhedDataEvent::ESelection ) );
+        }
+
+    iRealCursor = iRealAnchor = aCursorPos;
+
+    ReportEvent( MPhedDataObserver::TAknPhedDataEvent(
+                 MPhedDataObserver::TAknPhedDataEvent::ECursor ) );
+    
+    return iRealCursor;
+    }
+
+TInt CAknPhedModel::SetCompensatedCursorPosition( TInt aCursorPos )
+    {
+    StartEvent();
+    if ( SelectionExists() )
+        {
+        // selection is lost, so report a selection change event
+        StartEvent();
+        ReportEvent( MPhedDataObserver::TAknPhedDataEvent(
+                     MPhedDataObserver::TAknPhedDataEvent::ESelection ) );
+        }
+
+    iRealCursor = iRealAnchor = Uncompensate( aCursorPos );
+
+    ReportEvent( MPhedDataObserver::TAknPhedDataEvent(
+                 MPhedDataObserver::TAknPhedDataEvent::ECursor ) );
+    
+    return iRealCursor;
+    }
+
+TInt CAknPhedModel::SetAnchorPosition(TInt aAnchorPos)
+    { 
+    StartEvent();
+
+    iRealAnchor = aAnchorPos;
+
+    ReportEvent( MPhedDataObserver::TAknPhedDataEvent(
+                 MPhedDataObserver::TAknPhedDataEvent::ESelection ) );
+
+    return iRealAnchor;
+    }
+
+
+TInt CAknPhedModel::CursorLeft()
+    {
+     // cursor rule: cursor left -> left of selection or left with wrap to RHS
+    if ( SelectionExists() )
+        return SetRealCursorPosition( LeftMark() );
+    else if (iRealCursor > 0)
+        {
+        return SetRealCursorPosition( iRealCursor - 1 );
+        }
+    else
+        return SetRealCursorPosition( iRealLength );
+    }
+
+TInt CAknPhedModel::CursorRight()
+    {
+    // cursor rule: cursor right -> right of selection or right with wrap to LHS
+    if ( SelectionExists() )
+        return SetRealCursorPosition( RightMark() );
+    else if ( iRealCursor < iRealLength )
+        return SetRealCursorPosition( iRealCursor + 1 );
+    else
+        return SetRealCursorPosition( 0 );
+    }
+
+void CAknPhedModel::ConstructL( TInt aMaxLen )
+    {
+    iBuf = new(ELeave) CAknPhedScratchBuffer;
+   	iBuf->ConstructL(aMaxLen);
+
+    // Construct the number grouping engine with the reversed buffer support turned on
+    iNumberGroupingBuffer = CPNGNumberGrouping::NewL( aMaxLen, ETrue );
+    
+    iSelection.Set( KNullDesC );
+    iCursorDirection = EUp;
+
+    iCount = 0;
+    }
+
+void CAknPhedModel::Insert( const TDesC& aText )
+    {
+    StartEvent();
+    TInt len = aText.Length();
+    for ( TInt ii=0; ii<len; ii++ )
+        {
+        Insert( aText[ii] );
+        }
+
+    if ( len && iRealCursor > 0 )
+        {
+        // report a text event if anything actually got inserted
+        ReportEvent( MPhedDataObserver::TAknPhedDataEvent(
+                     MPhedDataObserver::TAknPhedDataEvent::EText, 
+                     Max( 0, CursorPosition() - len ),             
+                     CursorPosition() ) );         
+        }
+    else
+        {
+        // otherwise report nothing
+        ReportEvent( MPhedDataObserver::TAknPhedDataEvent() );
+        }
+    }
+
+TBool CAknPhedModel::ClearAnySelection()
+    {
+    if ( SelectionExists() )
+        {
+        StartEvent();
+        TInt left = LeftMark(); 
+        TInt right = RightMark();
+
+        DeleteLeft( right, SelectionWidth() );
+        iNumberGroupingBuffer->FormattedNumber();
+        
+        SetRealCursorPosition( left );
+                
+        ReportEvent( MPhedDataObserver::TAknPhedDataEvent(
+                     MPhedDataObserver::TAknPhedDataEvent::EText, 
+                     CursorPosition(), 
+                     left ) );
+        
+        return ETrue;
+        }
+    return EFalse;
+    }
+
+void CAknPhedModel::StartEvent()
+    {
+    // Events can be nested, so that one combined event is reported for each external operation
+    if (iEventDepth == 0)
+        iEvent.Reset();
+    
+    iEventDepth++;
+    }
+
+void CAknPhedModel::ReportEvent( const MPhedDataObserver::TAknPhedDataEvent& aEvent )
+    {
+    // Combine this event with any other nested event and report the lot if the
+    // nesting is finished
+    iEvent.Add( aEvent ); 
+    iEventDepth--;
+    
+    if ( iEventDepth == 0 && iObserver && 
+         ( iEvent.TextChanged() || iEvent.CursorChanged() || iEvent.SelectionChanged() ) )
+        {
+        // safety subtlty: event is reported as the very last thing in case the caller
+        // does something stupid, like leave.
+        iObserver->HandlePhedDataEvent( iEvent, this );
+        }
+    }
+
+void CAknPhedModel::SelectMove( TInt aInc )
+    {
+    // selection rule: selection cursor wraps LHS <-> RHS
+    iRealCursor = iRealCursor + aInc;
+
+    if ( iRealCursor < 0 )
+        iRealCursor = iRealLength;
+    else if ( iRealCursor > iRealLength )
+        iRealCursor =  0;
+    
+    StartEvent();
+    ReportEvent( MPhedDataObserver::TAknPhedDataEvent(
+                 MPhedDataObserver::TAknPhedDataEvent::ESelection | 
+                 MPhedDataObserver::TAknPhedDataEvent::ECursor ) );
+    }
+
+TBool CAknPhedModel::CursorPositionIsSpace()
+{
+    TInt nCursorPosition = CursorPosition();
+
+    if( nCursorPosition != Length() )
+        return iNumberGroupingBuffer->IsSpace( nCursorPosition );
+    else
+        return EFalse;
+}
+
+TInt CAknPhedModel::Spaces( TInt aFromPos, TInt aToPos ) const
+{
+    TInt spacesCount = 0;
+    TInt toPos = aToPos;
+    
+    for( TInt i = aFromPos; i <= toPos; ++i )
+    {
+        if( iNumberGroupingBuffer->IsSpace( i ) )
+        {
+            ++spacesCount;
+            ++toPos;            
+        }
+    }   
+    
+    return spacesCount;
+}
+
+TInt CAknPhedModel::Spaces( TInt aToPos ) const
+{
+    TInt spacesCount = 0;
+    TInt toPos = aToPos;
+    
+    for( TInt i = 0; i <= toPos; ++i )
+    {
+        if( iNumberGroupingBuffer->IsSpace( i ) )
+        {
+            ++spacesCount;            
+        }
+    }   
+    
+    return spacesCount;
+}
+//
+// MPhedDataObserver::TAknPhedDataEvent
+//
+void MPhedDataObserver::TAknPhedDataEvent::Add( const TAknPhedDataEvent& aEvent )
+    {
+    if ( aEvent.TextChanged() )
+        {
+        if ( TextChanged() )
+            {
+            if ( iStart > aEvent.iStart )
+                iStart = aEvent.iStart;
+            if ( iEnd < aEvent.iEnd )
+                iEnd = aEvent.iEnd;
+            }
+        else
+            {
+            iStart = aEvent.iStart;
+            iEnd = aEvent.iEnd;
+            }
+        }
+
+    iType |= aEvent.iType;
+    }
+
+
+//
+// TAknPhedDataMirror
+//
+void TAknPhedDataMirror::HandlePhedDataEvent( const TAknPhedDataEvent& aEvent, 
+                                              CAknPhedModel* aPhedData )
+    {
+    // The mirror reverses event positioning from the model
+    if ( iObserver )
+        {
+        TInt start;
+        TInt end;
+        aEvent.TextChangeRange( start, end );
+        TAknPhedDataEvent event( aEvent.Type(), Mirror( end ), Mirror( start ) );
+        iObserver->HandlePhedDataEvent( event, aPhedData );
+        }
+    }
+
+TInt TAknPhedDataMirror::Compensate( TInt aMirrorPosition ) const
+    { 
+    TInt Compensated ;
+    if ( iPhed->Language() )
+    	{
+        Compensated = aMirrorPosition - iPhed->Spaces( 0, iPhed->iRealCursor );
+    	}
+    else
+    	{
+    	Compensated = aMirrorPosition;
+    	}
+    return Compensated; 
+    }
+
+// End of File
+