srsf/profileobserverplugin/src/vcommandprofileobserver.cpp
branchRCL_3
changeset 19 e36f3802f733
parent 0 bf1d17376201
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/srsf/profileobserverplugin/src/vcommandprofileobserver.cpp	Wed Sep 01 12:29:17 2010 +0100
@@ -0,0 +1,663 @@
+/*
+* Copyright (c) 2006-2007 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:  implements profile changes handling
+*
+*/
+
+
+#include <aknlists.h>
+#include <bautils.h> 
+
+#include <ProEngFactory.h>
+#include <MProEngProfileNameArray.h>
+
+#include <vcprofileobserver.rsg>
+#include <mmfcontrollerpluginresolver.h> // For CleanupResetAndDestroyPushL
+
+#include "vcommandprofileobserver.h"
+#include "rubydebug.h"
+
+
+// ============================ CONSTANTS ===============================
+
+_LIT( KResourceFile, "z:\\resource\\vcprofileobserver.rsc" );
+
+// UID of the profiles application
+const TUid KUidAppProfiles = { 0x100058F8 };
+
+// Executable for changing profiles.
+const TUid KProfileChangerUid = { 0x10281D15 };
+
+// Starting id for profile command arguments
+const TInt KProfileCommandArgumentBase = 200;
+
+// File name to read the icon from
+_LIT( KIconFile, "Z:\\resource\\apps\\vcommand.mif" );
+
+// Index of the profile folder icon in the default folder icon file
+// @see CVCFolderIcon::NewL
+const TInt KProfileFolderIconIndex = 5;
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CVCommandProfileObserver::CVCommandProfileObserver
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CVCommandProfileObserver::CVCommandProfileObserver()
+ : iProfileUpdateError( EFalse )
+    {
+    }
+ 
+
+// -----------------------------------------------------------------------------
+// CVCommandProfileObserver::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CVCommandProfileObserver::ConstructL()
+    {  
+    RUBY_DEBUG_BLOCK( "CVCommandProfileObserver::ConstructL()" );
+    
+    iService = CVCommandHandler::NewL();  
+
+    iProfileEngine = ProEngFactory::NewEngineL();
+    iNameArray = iProfileEngine->ProfileNameArrayLC();     
+    CleanupStack::Pop(); // we can't popup C-class with M-class argument
+     
+    LoadProfileDataL();
+    SyncVCommandProfilesL();
+    
+    // Create the profile engine notify handler only after construction of
+    // other parts have been completed successfully. This way, should
+    // construction fail, we avoid the situation where a callback is executed
+    // on a partially contructed object
+    iNotifyHandler = ProEngFactory::NewNotifyHandlerL();
+    iNotifyHandler->RequestProfileNameArrayNotificationsL( *this );
+    }
+ 
+   
+// -----------------------------------------------------------------------------
+// CVCommandProfileObserver::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CVCommandProfileObserver* CVCommandProfileObserver::NewL() 
+    {
+    RUBY_DEBUG_BLOCK( "CVCommandProfileObserver::NewL()" );
+    
+    CVCommandProfileObserver* self = new( ELeave ) CVCommandProfileObserver();
+    
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    
+    return self;
+    }
+ 
+
+// -----------------------------------------------------------------------------
+// CVCommandProfileObserver::~CVCommandProfileObserver
+// Destructor.
+// -----------------------------------------------------------------------------
+//
+CVCommandProfileObserver::~CVCommandProfileObserver()
+    {
+    RUBY_DEBUG0( "CVCommandProfileObserver::~CVCommandProfileObserver()" );
+    
+    if( iProfileEngine ) 
+        {
+        iProfileEngine->Release();    
+        }
+    iProfileEngine = NULL;
+     
+    if( iNameArray ) 
+        {
+        delete iNameArray;
+        iNameArray = NULL;
+        }
+       
+    DeleteCache();
+        
+    delete iService;
+    
+    if ( iNotifyHandler )
+        {
+        iNotifyHandler->CancelProfileNameArrayNotifications();
+        }
+    delete iNotifyHandler;
+    delete iProfileFolder;
+    delete iFolderTitle;
+    delete iProfileTooltip;
+    
+    iAddedCommands.ResetAndDestroy();
+    iAddedCommands.Close();    
+    } 
+  
+ 
+// -----------------------------------------------------------------------------
+// CVCommandProfileObserver::SyncVCommandProfilesL
+// -----------------------------------------------------------------------------
+//
+void CVCommandProfileObserver::SyncVCommandProfilesL()
+    {
+    RUBY_DEBUG_BLOCK( "CVCommandProfileObserver::SyncVCommandProfilesL()" );
+    
+    if( !iNameArray || iNameArray->MdcaCount() <= 0 ) 
+        {
+        return;
+        }
+    
+    // Form the set of commands that should be in
+    RVCommandArray profileEngineCommands;
+    CleanupResetAndDestroyPushL( profileEngineCommands );
+    for( TInt i = 0; i < iNameArray->MdcaCount(); i++ )
+        {
+        TInt index = iNameArray->FindByName( iNameArray->MdcaPoint( i ) );
+        TInt profileId = iNameArray->ProfileId( index );
+        CVCommand* command = CreateProfileCommandL( iNameArray->MdcaPoint( i ), profileId );
+        profileEngineCommands.AppendL( command );
+        }
+    
+    // delete cache and force iCommands to be reloaded
+    //
+    DeleteCache();
+
+    const CVCommandArray& storedCommands = ListVCommandsL();
+    CVCommandArray* deduction = storedCommands.ProduceUntrainSetByRunnablesLC( profileEngineCommands );
+    CVCommandArray* addition = storedCommands.ProduceTrainSetByRunnablesLC( profileEngineCommands );
+    
+    iService->RemoveCommandsL( deduction->PointerArray(), ETrue );
+    iService->AddCommandsL( addition->PointerArray(), ETrue );
+    CleanupStack::PopAndDestroy( addition );
+    CleanupStack::PopAndDestroy( deduction );
+    
+    CleanupStack::PopAndDestroy( &profileEngineCommands );
+    
+    }
+
+
+// -----------------------------------------------------------------------------
+// CVCommandProfileObserver::HandleProfileNameArrayModificationL
+// -----------------------------------------------------------------------------
+//
+// Assume that there will be only one change each time this function is called.
+//
+void CVCommandProfileObserver::HandleProfileNameArrayModificationL()
+    {
+    RUBY_DEBUG_BLOCK( "CVCommandProfileObserver::HandleProfileNameArrayModificationL()" );
+    
+    // delete cache and force iCommands to be reloaded
+    //
+    DeleteCache();
+    
+    // new array of profile names
+    MProEngProfileNameArray* nameArray = iProfileEngine->ProfileNameArrayLC();
+          
+    // copy profile names to two descriptor arrays
+    //
+    CDesC16ArrayFlat* oldNames = new ( ELeave ) CDesCArrayFlat( iNameArray->MdcaCount() );   
+    CleanupStack::PushL( oldNames );
+    
+    CDesC16ArrayFlat* newNames = new ( ELeave ) CDesCArrayFlat( nameArray->MdcaCount() );
+    CleanupStack::PushL( newNames );
+        
+    for( TInt i = 0; i < iNameArray->MdcaCount(); i++ )
+        {
+        oldNames->AppendL( iNameArray->MdcaPoint( i ) );
+        }
+    for( TInt j = 0; j < nameArray->MdcaCount(); j++ )
+        {
+        newNames->AppendL( nameArray->MdcaPoint( j ) );
+        }
+ 
+         
+    // Find changes by deleting equivalent commands from both descriptor arrays.
+    //
+    for( TInt i = 0; i < newNames->MdcaCount(); i++ ) // go through the new names
+        {
+        TName searchStr = newNames->MdcaPoint( i );
+        TInt index;
+        
+        oldNames->Find( searchStr, index, ECmpNormal );
+        
+        if( index != oldNames->MdcaCount() ) // String was found
+            {
+            oldNames->Delete( index );
+            newNames->Delete( i );
+            i--;
+            }
+        }
+      
+      
+    // profile name has been edited
+    //
+    if( newNames->MdcaCount() == oldNames->MdcaCount() ) 
+        {
+    
+        // now we should have a pair of original and changed name
+        //
+        if( newNames->MdcaCount() == 1 ) // let's edit the profile name (old name, new name)
+            {
+            TRAPD( error, EditProfileNameL( oldNames->MdcaPoint( 0 ), newNames->MdcaPoint( 0 ) ) );
+            if ( error == KErrGeneral )
+                {
+                CleanupStack::PopAndDestroy( newNames );    
+                CleanupStack::PopAndDestroy( oldNames );
+                CleanupStack::Pop(); // nameArray ( M-class pointer )
+        
+                delete iNameArray;        
+                iNameArray = nameArray;
+        
+                User::Leave( error );
+                }
+            }
+        }
+    // new profile(s) has been added
+    //
+    else if( newNames->MdcaCount() > oldNames->MdcaCount() ) 
+        {
+        AddNewProfilesL( *newNames, *nameArray );
+        }
+    // profile(s) has been deleted
+    //
+    else 
+        {
+        RemoveProfilesL( *oldNames );
+        }
+    
+    // update old profile names
+    //
+    CleanupStack::PopAndDestroy( newNames );    
+    CleanupStack::PopAndDestroy( oldNames );    
+    CleanupStack::Pop(); // nameArray ( M-class pointer )
+    
+    delete iNameArray;
+    iNameArray = nameArray;
+    
+    if ( iProfileUpdateError )
+        {
+        iProfileUpdateError = EFalse;
+        
+        HandleProfileNameArrayModificationL();
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CVCommandProfileObserver::HandleProfileNameArrayNotificationError
+// -----------------------------------------------------------------------------
+//
+void CVCommandProfileObserver::HandleProfileNameArrayNotificationError( TInt aError ) 
+    {
+    RUBY_ERROR1( "HandleProfileNameArrayNotificationError: %d", aError );
+    
+    if ( aError == KErrLocked )
+        {
+        iProfileUpdateError = ETrue;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CVCommandProfileObserver::LoadProfileDataL
+// -----------------------------------------------------------------------------
+//
+void CVCommandProfileObserver::LoadProfileDataL()
+    {
+    RUBY_DEBUG_BLOCK( "CVCommandProfileObserver::LoadProfileDataL()" );
+    
+    RFs fs;
+    CleanupClosePushL( fs );
+    User::LeaveIfError( fs.Connect() );
+    
+    RResourceFile resourceFile;
+    TResourceReader theReader;
+    
+    TFileName name;
+    name.Append( KResourceFile );
+
+    BaflUtils::NearestLanguageFile( fs, name );
+
+    if ( !BaflUtils::FileExists( fs, name ) )
+        {
+        User::Leave( KErrNotFound );
+        }
+    
+    resourceFile.OpenL( fs, name );
+    CleanupClosePushL( resourceFile );
+
+    // Leaves 'res' to cleanupstack
+    HBufC8* res = resourceFile.AllocReadLC( VCPROFILEOBSERVERINFO );
+    theReader.SetBuffer( res );
+
+    iProfileFolder = theReader.ReadHBufCL();
+    iFolderTitle = theReader.ReadHBufCL();
+    iProfileTooltip = theReader.ReadHBufCL();
+    
+    // Cleanup res 
+    CleanupStack::PopAndDestroy( res );
+    CleanupStack::PopAndDestroy( &resourceFile );
+    CleanupStack::PopAndDestroy( &fs );
+    }
+    
+    
+// -----------------------------------------------------------------------------
+// CVCommandProfileObserver::ListVCommandsL
+// -----------------------------------------------------------------------------
+//
+const CVCommandArray& CVCommandProfileObserver::ListVCommandsL()
+    {
+    RUBY_DEBUG_BLOCK( "CVCommandProfileObserver::ListVCommandsL()" );
+    
+    if( !iCommands )
+        {
+        iCommands = iService->ListCommandsL();
+        }
+        
+    return *iCommands;
+    }
+ 
+
+// -----------------------------------------------------------------------------
+// CVCommandProfileObserver::DeleteCache
+// -----------------------------------------------------------------------------
+//
+void CVCommandProfileObserver::DeleteCache()
+    {
+    RUBY_DEBUG0( "CVCommandProfileObserver::DeleteCache()" );
+    
+    // delete cache and force iCommands to be reloaded
+    //
+    delete iCommands;
+    iCommands = NULL;
+    }
+ 
+ 
+// -----------------------------------------------------------------------------
+// CVCommandProfileObserver::AddNewProfileL
+// Adds new profile to VCommandhandler.
+// -----------------------------------------------------------------------------
+//
+void CVCommandProfileObserver::AddNewProfileL( const TDesC& aNewName,
+                                               TInt aProfileId,
+                                               TBool aCommit )
+    {
+    RUBY_DEBUG_BLOCK( "CVCommandProfileObserver::AddNewProfileL()" );
+    
+    // if profile name doesn't exists
+    //
+    if( FindProfileIndexL( aNewName ) == KErrNotFound )
+        {
+        CVCommand* initialCommand = CreateProfileCommandL( aNewName, aProfileId );
+        CleanupStack::PushL( initialCommand );
+
+        if ( aCommit )
+            {
+            iService->AddCommandL( *initialCommand );
+            CleanupStack::PopAndDestroy( initialCommand );
+
+            // delete cache and force iCommands to be reloaded
+            //
+            DeleteCache();
+            }
+        else
+            {
+            iAddedCommands.AppendL( initialCommand );
+        
+            CleanupStack::Pop( initialCommand );            
+            }
+        }
+    }
+    
+// -----------------------------------------------------------------------------
+// CVCommandProfileObserver::AddNewProfilesL
+// Adds new profiles to VCommandhandler.
+// -----------------------------------------------------------------------------
+//
+void CVCommandProfileObserver::AddNewProfilesL( const CDesC16ArrayFlat& aNames,
+                                                const MProEngProfileNameArray& aProfileNames,
+                                                TBool aCommit )
+    {
+    RUBY_DEBUG_BLOCK( "CVCommandProfileObserver::AddNewProfilesL()" );
+    
+    RVCommandArray commands;
+    CleanupClosePushL( commands );
+    CleanupResetAndDestroyPushL( commands );
+    
+    for( TInt i = 0; i < aNames.MdcaCount(); i++ )
+        {
+        TInt index = aProfileNames.FindByName( aNames.MdcaPoint(i) );
+        TInt profileId = aProfileNames.ProfileId( index );
+        
+        // if profile name doesn't exists
+        //
+        if( FindProfileIndexL( aNames.MdcaPoint(i) ) == KErrNotFound )
+            {
+            CVCommand* initialCommand = CreateProfileCommandL( aNames.MdcaPoint(i), profileId );
+            CleanupStack::PushL( initialCommand );
+
+            if ( aCommit )
+                {
+                commands.Append( initialCommand );
+                }
+            else
+                {
+                iAddedCommands.AppendL( initialCommand );
+                }
+                
+            CleanupStack::Pop( initialCommand );  
+            }
+        }
+    
+    if ( aCommit )
+        {
+        iService->AddCommandsL( commands );
+                
+        // delete cache and force iCommands to be reloaded
+        //
+        DeleteCache();
+        }
+
+    CleanupStack::PopAndDestroy( &commands );
+    CleanupStack::PopAndDestroy( &commands );
+    }
+    
+// -----------------------------------------------------------------------------
+// CVCommandProfileObserver::CreateProfileCommandL
+// Creates a VCommand for the given profile attributes
+// -----------------------------------------------------------------------------
+CVCommand* CVCommandProfileObserver::CreateProfileCommandL( const TDesC& profileName, TInt aProfileId ) const
+        {
+        CVCFolderInfo* folderInfo = CVCFolderInfo::NewL( iFolderTitle->Des(), 
+                                                         iProfileFolder->Des(), 0, 
+                                                         KProfileFolderIconIndex,
+                                                         KIconFile );
+        CleanupStack::PushL( folderInfo );
+        CVCCommandUi* commandUi = CVCCommandUi::NewL( profileName,
+                                                      *folderInfo, ETrue,
+                                                      iProfileTooltip->Des(),
+                                                      KUidAppProfiles );
+        CleanupStack::PopAndDestroy( folderInfo );
+        CleanupStack::PushL( commandUi );
+
+        TBuf8<10>  idDescriptor;
+        idDescriptor.Num( KProfileCommandArgumentBase + aProfileId );
+        CVCRunnable* runnable = CVCRunnable::NewL( KProfileChangerUid, idDescriptor.Left( idDescriptor.Length() ) );
+        CleanupStack::PushL( runnable );
+    
+        CVCommand* command = CVCommand::NewL( profileName,
+                                              *runnable,
+                                              *commandUi );
+        CleanupStack::PopAndDestroy( runnable );
+        CleanupStack::PopAndDestroy( commandUi );
+        return command;
+        }
+
+// -----------------------------------------------------------------------------
+// CVCommandProfileObserver::RemoveProfileL
+// Removes profile from VCommandhandler.
+// -----------------------------------------------------------------------------
+//
+void CVCommandProfileObserver::RemoveProfileL( const TDesC& aName )
+    {
+    RUBY_DEBUG_BLOCK( "CVCommandProfileObserver::RemoveProfileL()" );
+    
+    TInt idx = 0;
+    while( ( idx = FindProfileIndexL( aName ) ) != KErrNotFound )  
+        {
+        iService->RemoveCommandL( ListVCommandsL()[ idx ] );
+        
+        // delete cache and force iCommands to be reloaded
+        //
+        DeleteCache(); 
+        }
+    }
+    
+// -----------------------------------------------------------------------------
+// CVCommandProfileObserver::RemoveProfilesL
+// Removes profiles from VCommandhandler.
+// -----------------------------------------------------------------------------
+//
+void CVCommandProfileObserver::RemoveProfilesL( const CDesC16ArrayFlat& aNames )
+    {
+    RUBY_DEBUG_BLOCK( "CVCommandProfileObserver::RemoveProfilesL()" );
+
+    RVCommandArray commands;
+    CleanupClosePushL( commands );
+    
+    for( TInt i = 0; i < aNames.MdcaCount(); i++ )
+        {
+        TInt idx = 0;
+        while( ( idx = FindProfileIndexL( aNames.MdcaPoint(i) ) ) != KErrNotFound )  
+            {
+            commands.Append( &ListVCommandsL()[ idx ] );
+            break;
+            }
+        }
+
+    iService->RemoveCommandsL( commands );
+
+    // delete cache and force iCommands to be reloaded
+    //
+    DeleteCache();
+    
+    CleanupStack::PopAndDestroy( &commands );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CVCommandProfileObserver::EditProfileNameL
+// Edits the profile name.
+// -----------------------------------------------------------------------------
+//
+void CVCommandProfileObserver::EditProfileNameL( const TDesC& aOldName, const TDesC& aNewName )
+    {
+    RUBY_DEBUG_BLOCK( "CVCommandProfileObserver::EditProfileNameL()" );
+    
+    // Get profile id
+    TInt idx = iNameArray->FindByName( aOldName );
+    TInt profileId = iNameArray->ProfileId( idx );
+    
+    idx = FindProfileIndexL( aOldName );
+    
+    // this finds always user edited one, if one exists
+    //
+    if( idx == KErrNotFound )
+        {
+        // for some reason profile doesn't exist in voice command list
+        // so let's add it
+        //
+        return AddNewProfileL( aNewName, profileId ); 
+        }
+    
+    const CVCommand& oldCmd = ListVCommandsL()[ idx ];
+        
+    CVCCommandUi* commandUi = CVCCommandUi::NewL( aNewName, 
+                                                         oldCmd.CommandUi().FolderInfo(), ETrue, 
+                                                         oldCmd.CommandUi().Tooltip(), 
+                                                         oldCmd.CommandUi().IconUid() );
+    CleanupStack::PushL( commandUi );
+                                                      
+    TBuf8<10>  idDescriptor;
+    idDescriptor.Num( profileId );
+    CVCRunnable* runnable = CVCRunnable::NewL( oldCmd.Runnable() );
+    CleanupStack::PushL( runnable );
+    
+    CVCommand* command = CVCommand::NewL( aNewName, *runnable, *commandUi );
+    CleanupStack::PopAndDestroy( runnable );
+    CleanupStack::PopAndDestroy( commandUi );
+    CleanupStack::PushL( command );
+        
+    // Delete old command
+    iService->RemoveCommandL( oldCmd );
+      
+    // delete cache and force iCommands to be reloaded
+    //
+    DeleteCache(); 
+      
+    while( ( idx = FindProfileIndexL( aOldName ) ) != KErrNotFound ) 
+        {
+        iService->RemoveCommandL( ListVCommandsL()[ idx ] );
+        DeleteCache(); 
+        }
+        
+    // Add new command
+    //    
+    iService->AddCommandL( *command );
+    CleanupStack::PopAndDestroy( command ); 
+    
+    // delete cache and force iCommands to be reloaded
+    //
+    DeleteCache(); 
+    }
+
+
+// ---------------------------------------------------------
+// CVCommandProfileObserver::FindProfileIndexL
+// ---------------------------------------------------------
+//
+// Assumes that profiles are in a folder called GetProfileFolderName().
+//
+// Finds always the user edited command if it exists.
+//
+TInt CVCommandProfileObserver::FindProfileIndexL( const TDesC& aName )
+    {
+    RUBY_DEBUG_BLOCK( "CVCommandProfileObserver::FindProfileIndexL()" );
+    
+    TInt retval = KErrNotFound;
+    
+    for( TInt i = 0; i < ListVCommandsL().Count(); i++ ) 
+        {
+        if( ListVCommandsL()[ i ].CommandUi().FolderInfo().Title() == iFolderTitle->Des() && 
+            aName == ListVCommandsL()[ i ].CommandUi().WrittenText() ) 
+            {
+            retval = i;
+            
+            // user edited command
+            //
+            if( ListVCommandsL()[ i ].SpokenText() != 
+                ListVCommandsL()[ i ].CommandUi().WrittenText() ) 
+                {
+                break;
+                }
+            }
+        }
+    return retval;    
+    }
+
+
+// End of File
+