srsf/vcommandhandler/src/tagnameset.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:29:17 +0100
branchRCL_3
changeset 23 e36f3802f733
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201033 Kit: 201035

/*
* Copyright (c) 2006 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:  Array of tags and corresponding spoken texts
*
*/


#include "rubydebug.h"
#include "tagnameset.h"
#include <nssvasmspeechitem.h>
#include <nssvasmtag.h>
#include <nssvasmtagmgr.h>

_LIT( KTagNameSetPanic, "TNS" );

CTagNameSet* CTagNameSet::NewLC()
    {
    CTagNameSet* self = new (ELeave) CTagNameSet;
    CleanupStack::PushL( self );
    return self;
    }
    
CTagNameSet::~CTagNameSet()
    {
    iTags.ResetAndDestroy();
    iTexts.ResetAndDestroy();
    }
    
        
/**
* Adds a tag-text pair to be trained
* @param aTag tag to be trained and saved. This objects takes ownership
*        on the aTag
* @param aTrainingText text to be recognized. This object doesn't
*        take ownership on aTrainingText, but makes an own copy
*/
void CTagNameSet::AppendL( const MNssTag* aTag, const TDesC& aTrainingText )
    {
    HBufC* text = aTrainingText.AllocL();
    iTexts.Append( text );
    iTags.Append( aTag );    
    }

/**
* Train and save to VAS all the stored tags. It is not specified what happens
* to VAS if this method leaves
* @param aParams
* @param aTagMgr
* @param aIgnoreErrors If ETrue, doesn't fail the whole operation if some
*        individual trainings/savings failed. Trains and saves as much as
*        possible
*/
void CTagNameSet::TrainAndSaveL( const CNssTrainingParameters& aParams, 
                                 MNssTagMgr& aTagMgr, TBool aIgnoreErrors )
    {
    RUBY_DEBUG_BLOCK( "CTrainingPack::TrainAndSaveL" );
    iIgnoreErrors = aIgnoreErrors;
    RUBY_DEBUG1( "CTrainingPack::TrainAndSaveL Processing [%d] pairs", iTags.Count() );
    
    TrainTagsL( aParams );
    SaveTagsL( aTagMgr );
    }
    
/**
* Remove all the stored tags from VAS. It is not specified what happens
* to VAS if this method leaves
* @param aTagMgr
* @param aIgnoreErrors If ETrue, doesn't fail the whole operation if some
*        individual removals failed. Removes as many tags as
*        possible
*/                            
void CTagNameSet::UntrainL( MNssTagMgr& aTagMgr, TBool aIgnoreErrors )
    {
    RUBY_DEBUG_BLOCK("");
    iIgnoreErrors = aIgnoreErrors;
    RUBY_DEBUG1( "Removing [%d] tags from VAS", iTags.Count() );
    SetCallbacksExpected( iTags.Count() );
    
    if( iCallbacksExpected > 0 )
        {
       	for( TInt i = 0; i < iTags.Count(); i++ )
        	{
            DeleteTagL( aTagMgr, *iTags[i] );
    	    }  // for
        WaitUntilOperationsAreCompletedL();
        }
    }

/**
* @return Number of tag-name pairs stored
*/
TInt CTagNameSet::Count() const
    {
    return iTags.Count();
    }

/**
* @param aIndex must be >= 0 and < Count()
* @return Voice tag at the given position
* @panic KErrArgument if aIndex is out of bounds
*/    
const MNssTag& CTagNameSet::TagAt( TInt aIndex ) const
    {
    __ASSERT_ALWAYS( aIndex >= 0 && aIndex < iTags.Count(), 
                    User::Panic( KTagNameSetPanic, KErrArgument ));
    return *iTags[aIndex];
    }

/**
* @param aIndex must be >= 0 and < Count()
* @return Recognition text at the given position
* @panic KErrArgument if aIndex is out of bounds
*/        
const TDesC& CTagNameSet::TextAt( TInt aIndex ) const
    {
    __ASSERT_ALWAYS( aIndex >= 0 && aIndex < iTexts.Count(), 
                    User::Panic( KTagNameSetPanic, KErrArgument ));
    return *iTexts[aIndex];
    }

/**
* Train all the stored tag-name pairs. Synchronous
*/
void CTagNameSet::TrainTagsL( const CNssTrainingParameters& aParams )
    {
    __ASSERT_ALWAYS( iCallbacksExpected == 0, User::Leave( KErrInUse) );
    SetCallbacksExpected( Count() );
    if( iCallbacksExpected > 0 )
        {
        for( TInt i = 0; i < Count(); i++ )
            {
            TrainTagL( TagAt( i ), aParams, TextAt( i ) );
            }  // for
        WaitUntilOperationsAreCompletedL();
        }  // if
    }


/**
* Trains the voice tag. Asynchronous
* @leave VAS error code
* @todo Is it ok to mix system-wide codes with the TNssSpeechItemResult codes
*/
void CTagNameSet::TrainTagL( const MNssTag& aTag, 
		const CNssTrainingParameters& aParams, const TDesC& aSpokenText )
	{
	RUBY_DEBUG_BLOCKL( "CTagNameSet::TrainTagL" );
    RUBY_DEBUG1( "Training for spoken text [%S]", &aSpokenText )

    MNssSpeechItem* speechItem = const_cast<MNssTag&>(aTag).SpeechItem();
    speechItem->SetTextL( aSpokenText );
    MNssSpeechItem::TNssSpeechItemResult nssErr = 
		speechItem->TrainTextL( this, const_cast<CNssTrainingParameters*>( &aParams ) );
    
    if ( nssErr != MNssSpeechItem::EVasErrorNone )
        {
        RUBY_ERROR1( "CTagNameSet::TrainTagL training start failed with the nss code [%d]", 
                    nssErr );
        if( iIgnoreErrors )
            {
            RUBY_DEBUG0( "CTagNameSet::TrainTagL ignoring error" );
            DecreaseCallbacksExpected();
            }
        else 
            {
            // Wait for started operations before leaving
            DecreaseCallbacksExpected();
            WaitUntilOperationsAreCompletedL();
            
            switch( nssErr )
                {
                case MNssSpeechItem::EVasInvalidParameter:
                    User::Leave( KErrArgument );
                case MNssSpeechItem::EVasTrainFailed:
                    User::Leave( KErrGeneral );
                default:
                    User::Leave( nssErr );
                } 
            }        
        }
    RUBY_DEBUG0( "CTagNameSet::TrainTagL Tag training has been initiated" );
	}			
			

/**
* Train Complete Event - Voice tag training completed
* @param aErrorCode KErrNone if training was successfull
*/       
void CTagNameSet::HandleTrainComplete( TInt aErrorCode )
	{
	//RUBY_DEBUG0( "Start" );
	ProcessCallback( aErrorCode );
	//RUBY_DEBUG0( "End" );
	}

/**
* Saves the trained voice tag to VAS. Synchronous
*/
void CTagNameSet::SaveTagsL( MNssTagMgr& aTagManager )
	{
	RUBY_DEBUG_BLOCK( "CTagSaver::SaveTagsL" );
	__ASSERT_ALWAYS( iCallbacksExpected == 0, User::Leave( KErrInUse) );
    SetCallbacksExpected( Count() );
    if( iCallbacksExpected > 0 )
        {
        for( TInt i = 0; i < Count(); i++ )
            {
            SaveTagL( aTagManager, TagAt( i ) );
            }  // for
            
        WaitUntilOperationsAreCompletedL();
        }  // if
	}
	

/**
* Saves the trained voice tag to VAS. 
*/
void CTagNameSet::SaveTagL( MNssTagMgr& aTagManager, const MNssTag& aTag )
	{
	RUBY_DEBUG_BLOCKL( "CTagNameSet::SaveTagL" );
    TInt nssErr = 
            aTagManager.SaveTag( this, const_cast<MNssTag*>( &aTag ) );
    if( nssErr != KErrNone ) 
        {
        RUBY_ERROR1( "CTagNameSet::SaveTagL Savetag start failed with the nss code [%d]", nssErr );
        if( iIgnoreErrors )
            {
            RUBY_DEBUG0( "CTagNameSet::SaveTagL ignoring error" );
            DecreaseCallbacksExpected();
            }
        else 
            {
            // Wait for started operations before leaving
            DecreaseCallbacksExpected();
            WaitUntilOperationsAreCompletedL();
            
            User::Leave( KErrGeneral );
            }        
        }
    RUBY_DEBUG0( "CTagNameSet::SaveTagL Savetag sequence started" );

	}

/**
* Callback to indicate that SaveTag sequence has been completed
* @param aErrorCode KErrNone if saving of tag was successfull
*/
void CTagNameSet::SaveTagCompleted( TInt aErrorCode )
	{
	RUBY_DEBUG0( "Start" );
    ProcessCallback( aErrorCode );
    RUBY_DEBUG0( "End" );
    }

/**
* Deletes the voice tag from VAS. Asynchronous
* @leave VAS error codes
*/
void CTagNameSet::DeleteTagL( MNssTagMgr& aTagManager, MNssTag& aTag )
    {
    User::LeaveIfError( aTagManager.DeleteTag( this, &aTag ) );
    }

/**
* Callback to indicate a tag was deleted successfully.
* @param aErrorCode KErrNone if deletion of tag was successfull
*/
void CTagNameSet::DeleteTagCompleted( TInt aErrorCode )
    {
    RUBY_DEBUG0( "Start" );
    ProcessCallback( aErrorCode );
    RUBY_DEBUG0( "End" );
    }

/**
* Handles the common part of the callback processing
* Decrements the number of still expected callbacks and
* handles the errors according to aIgnoreErrors from the 
* public methods
*/
void CTagNameSet::ProcessCallback( TInt aErrorCode )
    {
    //RUBY_DEBUG0( "Start" );
    if( iIgnoreErrors || aErrorCode == KErrNone )
        {
        if( DecreaseCallbacksExpected() == 0 )
            {
            StopAsyncWaitingOrPanic( KErrNone );
            }  
        }
    else
        {
        RUBY_ERROR1( "Callback reported error [%d] ", aErrorCode );
        if( DecreaseCallbacksExpected() == 0 )
            {
            StopAsyncWaitingOrPanic( aErrorCode );
            }
        }
    //RUBY_DEBUG0( "End" );    
    }

/**
* Sets the number of callbacks to expect
*/
void CTagNameSet::SetCallbacksExpected (TUint aCallbacksExpected )
    {
    RUBY_DEBUG2( "Changing from [%d] to [%d]", iCallbacksExpected, aCallbacksExpected );
    iCallbacksExpected = aCallbacksExpected;
    }

/**
* Decreases the number of callbacks to expect by one
* @return Number of callbacks expected after decreasing        
*/
TUint CTagNameSet::DecreaseCallbacksExpected()
    {
    __ASSERT_ALWAYS( iCallbacksExpected > 0, User::Panic( KTagNameSetPanic, KErrNotReady ) );
    RUBY_DEBUG2( "Changing from [%d] to [%d]", iCallbacksExpected, iCallbacksExpected - 1 );
    return --iCallbacksExpected;
    }

/**
* Waits until all the expected callbacks are received
* If no callbacks are expected returns immediately
* @leave @see CAsyncWorker::WaitForAsyncCallbackL
*/
void CTagNameSet::WaitUntilOperationsAreCompletedL()
    {
    RUBY_DEBUG_BLOCK( "" );
    if( iCallbacksExpected > 0 )
        {
        RUBY_DEBUG1( "[%d] callbacks expected. Waiting for them", iCallbacksExpected );
        WaitForAsyncCallbackL();
        }
    else 
        {
        RUBY_DEBUG0( "no callbacks expected. Returning immediately" );
        }
    }

//End of file