--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/idlefw/plugins/mcsplugin/publisher/src/mcspluginengine.cpp Thu Dec 17 08:54:17 2009 +0200
@@ -0,0 +1,788 @@
+/*
+* Copyright (c) 2009 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: The engine class of MCS plugin.
+*
+*/
+
+
+// INCLUDE FILES
+#include "mcspluginengine.h"
+
+#include <gulicon.h>
+#include <AknsItemID.h>
+#include <gslauncher.h>
+#include <aisystemuids.hrh>
+
+#include <mcsmenuitem.h>
+#include <mcsmenufilter.h>
+#include <mcsmenuoperation.h>
+#include <mcsmenuiconutility.h>
+#include <ActiveFavouritesDbNotifier.h>
+#include <FavouritesItemList.h>
+
+#include <bautils.h>
+#include <StringLoader.h>
+#include <aknnotedialog.h>
+#include <avkon.rsg>
+#include <mcspluginres.rsg>
+#include "mcsplugin.h"
+#include "mcsplugindata.h"
+#include "mcspluginuids.hrh"
+
+#include <apgtask.h>
+#include <apgcli.h>
+#include <apacmdln.h>
+#include <gfxtranseffect/gfxtranseffect.h> // For Transition effect
+#include <akntranseffect.h>
+
+#include <AknsConstants.h>
+_LIT( KMyMenuData, "matrixmenudata" );
+_LIT( KSkin, "skin" );
+_LIT( KMif, "mif" );
+_LIT( KResourceDrive, "Z:" );
+_LIT( KResourceFile, "mcspluginres.rsc" );
+_LIT( KResPath, "\\resource\\" );
+_LIT( KMenuAttrRefcount, "ref_count" );
+_LIT( KMMApplication, "mm://" );
+_LIT( KHideExit, "?exit=hide" );
+_LIT( KHideExit2, "&exit=hide" );
+_LIT( KSetFocusString, "!setfocus?applicationgroup_name=" );
+_LIT( KApplicationGroupName, "applicationgroup_name" );
+_LIT( KSuiteName, "suite_name" );
+_LIT( KIcon, "icon" );
+_LIT( KMenuAttrUndefUid, "0x99999991" );
+
+const TUid KHomescreenUid = { AI_UID3_AIFW_COMMON };
+const TUid KMMUid = { 0x101F4CD2 };
+
+// ======== LOCAL FUNCTIONS ========
+
+static TPtrC NextIdToken( TLex& aLexer )
+ {
+ aLexer.SkipSpace();
+ aLexer.Mark();
+ while( !aLexer.Eos() && !aLexer.Peek().IsSpace() && aLexer.Peek() != ')' )
+ {
+ aLexer.Inc();
+ }
+ return aLexer.MarkedToken();
+ }
+
+// ============================ MEMBER FUNCTIONS ===============================
+// ---------------------------------------------------------
+// Default constructor
+// ---------------------------------------------------------
+//
+CMCSPluginEngine::CMCSPluginEngine( CMCSPlugin& aPlugin, const TDesC8& aInstanceUid )
+ : iPlugin( aPlugin ), iInstanceUid( aInstanceUid ),
+ iSuspend( EFalse )
+ {
+ }
+
+// ---------------------------------------------------------
+// Two-phased constructor.
+// Create instance of concrete ECOM interface implementation
+// ---------------------------------------------------------
+//
+CMCSPluginEngine* CMCSPluginEngine::NewL( CMCSPlugin& aPlugin, const TDesC8& aInstanceUid )
+ {
+ CMCSPluginEngine* self = new( ELeave ) CMCSPluginEngine( aPlugin, aInstanceUid );
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop( self );
+
+ return self;
+ }
+
+// ---------------------------------------------------------
+// Symbian 2nd phase constructor can leave
+// ---------------------------------------------------------
+//
+void CMCSPluginEngine::ConstructL()
+ {
+ TFullName resourceFile( KResourceDrive );
+ resourceFile.Append( KResPath );
+ resourceFile.Append( KResourceFile );
+ BaflUtils::NearestLanguageFile(
+ CCoeEnv::Static()->FsSession(),
+ resourceFile );
+ iResourceOffset =
+ CCoeEnv::Static()->AddResourceFileL( resourceFile );
+ InitL();
+ StartObservingL();
+ }
+
+
+// ---------------------------------------------------------
+// Destructor.
+// ---------------------------------------------------------
+//
+CMCSPluginEngine::~CMCSPluginEngine()
+ {
+ StopObserving();
+
+ delete iPluginData;
+ iNotifier.Close();
+ iMenu.Close();
+ //iWatcher->Cancel();
+ delete iWatcher;
+ delete iNotifyWatcher;
+ CCoeEnv::Static()->DeleteResourceFile( iResourceOffset );
+ }
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void CMCSPluginEngine::InitL()
+ {
+ iMenu.OpenL( KMyMenuData );
+ iPluginData = CMCSPluginData::NewL( *this, iInstanceUid );
+ iWatcher = CMCSPluginWatcher::NewL( CMCSPluginWatcher::EOperation );
+ TInt err = iNotifier.Open( iMenu );
+ if ( err == KErrNone )
+ {
+ iNotifyWatcher = CMCSPluginWatcher::NewL( CMCSPluginWatcher::ENotify );
+ iNotifier.Notify( 0,
+ RMenuNotifier::EItemsAddedRemoved |
+ RMenuNotifier::EItemsReordered |
+ RMenuNotifier::EItemAttributeChanged,
+ iNotifyWatcher->iStatus );
+ iNotifyWatcher->WatchNotify( this );
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// Tells the settings container to start observing for changes
+// ---------------------------------------------------------------------------
+//
+void CMCSPluginEngine::StartObservingL()
+ {
+ // registering to bookmarks db. changes observing
+ User::LeaveIfError( iBookmarkSession.Connect() );
+ User::LeaveIfError( iBookmarkDb.Open( iBookmarkSession, KBrowserBookmarks ) );
+
+ iBookmarkDbObserver = new (ELeave) CActiveFavouritesDbNotifier(
+ iBookmarkDb, *this );
+ iBookmarkDbObserver->Start();
+
+ // registering to mailbox db. changes observing
+ iMsvSession = CMsvSession::OpenAsObserverL( *this) ;
+ }
+
+// ---------------------------------------------------------------------------
+// Tells the settings container to stop observing for changes
+// ---------------------------------------------------------------------------
+//
+void CMCSPluginEngine::StopObserving()
+ {
+ if ( iBookmarkDbObserver )
+ {
+ delete iBookmarkDbObserver;
+ iBookmarkDbObserver = NULL;
+ }
+ iBookmarkDb.Close();
+ iBookmarkSession.Close();
+
+ if ( iMsvSession )
+ {
+ delete iMsvSession;
+ iMsvSession = NULL;
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TMCSData& CMCSPluginEngine::MenuDataL( const TInt& aIndex )
+ {
+ return iPluginData->DataItemL( aIndex );
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+TInt CMCSPluginEngine::MenuItemCount()
+ {
+ return iPluginData->DataCount();
+ }
+
+// ---------------------------------------------------------------------------
+// Returns the menu item header, which matches the given filter.
+// ---------------------------------------------------------------------------
+//
+TMenuItem CMCSPluginEngine::FindMenuItemL( CMenuFilter& aFilter )
+ {
+ TMenuItem item;
+ const TInt root = iMenu.RootFolderL();
+ RArray<TMenuItem> items;
+ CleanupClosePushL( items );
+ iMenu.GetItemsL( items, root, &aFilter, ETrue );
+ if( items.Count() > 0 )
+ {
+
+ item = items[0];
+ }
+
+ CleanupStack::PopAndDestroy( &items );
+ return item;
+ }
+
+// ---------------------------------------------------------------------------
+// Returns the actual menu item for the given header.
+// ---------------------------------------------------------------------------
+//
+CMenuItem* CMCSPluginEngine::FetchMenuItemL( const TMenuItem& aMenuItem )
+ {
+ return CMenuItem::OpenL( iMenu, aMenuItem );
+ }
+
+// ---------------------------------------------------------------------------
+// Returns MCS default icon if attribute is 'icon' else parses the
+// skin definition from attribute and sets attributes to aMenuItem.
+// ---------------------------------------------------------------------------
+//
+CGulIcon* CMCSPluginEngine::ItemIconL( CMenuItem& aMenuItem, const TDesC& aAttr )
+ {
+ CAknIcon* icon( NULL );
+ CGulIcon* gIcon( NULL );
+ TBool exists( ETrue );
+ if( aAttr != KIcon )
+ {
+ // Resolve secondary icon definition from attribute
+ TPtrC iconDef = aMenuItem.GetAttributeL( aAttr, exists );
+ if( exists )
+ {
+ exists = ConstructMenuItemForIconL( iconDef, aMenuItem );
+ }
+ }
+ if( exists )
+ {
+ icon = MenuIconUtility::GetItemIconL( aMenuItem );
+ if( icon )
+ {
+ CleanupStack::PushL( icon );
+ gIcon = CGulIcon::NewL(icon->Bitmap(), icon->Mask());
+ // Detach and delete
+ icon->SetBitmap( NULL );
+ icon->SetMask( NULL );
+ CleanupStack::PopAndDestroy( icon );
+ }
+ }
+ return gIcon;
+ }
+
+// ---------------------------------------------------------------------------
+// Returns text string for the given attribute
+// ---------------------------------------------------------------------------
+//
+TPtrC CMCSPluginEngine::ItemTextL( CMenuItem& aMenuItem, const TDesC& aAttr )
+ {
+ TBool exists( KErrNotFound );
+ TPtrC name = aMenuItem.GetAttributeL( aAttr, exists );
+ if( exists )
+ {
+ return name;
+ }
+ else
+ {
+ return KNullDesC();
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// Calls the open command for the given menu item header
+// ---------------------------------------------------------------------------
+//
+void CMCSPluginEngine::LaunchItemL( const TInt& aIndex )
+ {
+
+ if ( iSuspend )
+ {
+ HBufC* temp = StringLoader::LoadLC( R_MCS_DISABLE_OPEN_ITEM );
+
+ CAknNoteDialog* dialog = new (ELeave) CAknNoteDialog(
+ CAknNoteDialog::EConfirmationTone,
+ CAknNoteDialog::ENoTimeout );
+ dialog->SetTextL( temp->Des() );
+ dialog->ExecuteDlgLD( R_MCS_DISABLE_OPEN_ITEM_DLG );
+ CleanupStack::PopAndDestroy( temp );
+ return;
+ }
+ if( iWatcher->IsActive())
+ {
+ return;
+ }
+
+
+ TMCSData& dataItem = iPluginData->DataItemL( aIndex );
+ CMenuItem* item = CMenuItem::OpenL( iMenu, dataItem.MenuItem());
+ CleanupStack::PushL( item );
+ TPtrC type = item->Type();
+
+ // run suite/folder
+ if ( type == KMenuTypeSuite || type == KMenuTypeFolder )
+ {
+
+ // message for MM application
+ HBufC8* message;
+
+ if ( type == KMenuTypeSuite )
+ {
+ // prepare message for launching suite
+ TBool hasSuiteName = EFalse;
+ TPtrC suiteName = item->GetAttributeL( KSuiteName, hasSuiteName );
+ if ( !hasSuiteName )
+ {
+ CleanupStack::PopAndDestroy( item );
+ return;
+ }
+ message = HBufC8::NewLC( KMMApplication().Length() +
+ suiteName.Length() +
+ KHideExit().Length() );
+
+ message->Des().Copy( KMMApplication );
+ message->Des().Append( suiteName );
+ message->Des().Append( KHideExit );
+ }
+ else
+ {
+ // prepare message for launching folder
+ TBool hasApplicationGroupName = EFalse;
+ TPtrC applicationGroupName = item->GetAttributeL( KApplicationGroupName,
+ hasApplicationGroupName );
+ if ( !hasApplicationGroupName )
+ {
+ CleanupStack::PopAndDestroy( item );
+ return;
+ }
+ message = HBufC8::NewLC( KMMApplication().Length() +
+ KSetFocusString().Length() +
+ applicationGroupName.Length() +
+ KHideExit2().Length() );
+
+ message->Des().Copy( KMMApplication );
+ message->Des().Append( KSetFocusString );
+ message->Des().Append( applicationGroupName );
+ message->Des().Append( KHideExit2 );
+ }
+
+ // find MM application
+ TApaTaskList taskList( CCoeEnv::Static()->WsSession() );
+ TApaTask task = taskList.FindApp( KMMUid );
+
+ if ( task.Exists() )
+ {
+ // MM is already running in background - send APA Message
+ task.SendMessage( TUid::Uid( KUidApaMessageSwitchOpenFileValue ), *message );
+ }
+ else
+ {
+ // MM not running yet - use Command Line Tail
+ RApaLsSession appArcSession;
+ CleanupClosePushL( appArcSession );
+ User::LeaveIfError( appArcSession.Connect() );
+ TApaAppInfo appInfo;
+ TInt err = appArcSession.GetAppInfo( appInfo, KMMUid );
+ if ( err == KErrNone )
+ {
+ CApaCommandLine* cmdLine = CApaCommandLine::NewLC();
+ cmdLine->SetExecutableNameL( appInfo.iFullName );
+ cmdLine->SetCommandL( EApaCommandRun );
+ cmdLine->SetTailEndL( *message );
+ appArcSession.StartApp( *cmdLine );
+ CleanupStack::PopAndDestroy( cmdLine );
+ }
+ CleanupStack::PopAndDestroy( &appArcSession );
+ }
+ CleanupStack::PopAndDestroy( message );
+ }
+ else
+ {
+ TBool exists( EFalse );
+ TPtrC desc( item->GetAttributeL( KMenuAttrUid, exists ) );
+
+ if( exists )
+ {
+ _LIT( KPrefix, "0x" );
+ const TInt pos( desc.FindF( KPrefix ) );
+
+ if( pos != KErrNotFound )
+ {
+ TLex lex( desc.Mid( pos + KPrefix().Length() ) );
+ // Hex parsing needs unsigned int
+ TUint32 value = 0;
+ const TInt parseResult = lex.Val( value, EHex );
+
+ if ( parseResult == KErrNone )
+ {
+ TUid uid( KNullUid );
+ TInt32 value32( value );
+ uid.iUid = value32;
+
+ if( uid != KNullUid )
+ {
+ //start a full screen effect
+ GfxTransEffect::BeginFullScreen(
+ AknTransEffect::EApplicationStart,
+ TRect(0,0,0,0),
+ AknTransEffect::EParameterType,
+ AknTransEffect::GfxTransParam( uid,
+ AknTransEffect::TParameter::EActivateExplicitContinue ));
+ }
+ }
+ }
+ }
+
+ // run application/shortcut/bookmark
+ CMenuOperation* operation = item->HandleCommandL(
+ KMenuCmdOpen, KNullDesC8, iWatcher->iStatus );
+ iWatcher->Watch( operation );
+ }
+ CleanupStack::PopAndDestroy( item );
+ }
+
+// ---------------------------------------------------------------------------
+// Handle the change in Menu Content
+// ---------------------------------------------------------------------------
+//
+void CMCSPluginEngine::HandleNotifyL()
+ {
+ TInt count( iPluginData->DataCount());
+ for( TInt i = 0; i < count; i++ )
+ {
+ TMCSData& data = iPluginData->DataItemL(i);
+ // Check that all the data still exist is MCS, if flag is hidden or
+ // missing, we have to remove data from UI
+ CMenuItem* menuItem = CMenuItem::OpenL( iMenu, data.MenuItem().Id() );
+ CleanupStack::PushL( menuItem );
+ if ( !menuItem ||
+ ( menuItem->Flags() & TMenuItem::EHidden ) ||
+ ( menuItem->Flags() & TMenuItem::EMissing ) )
+ {
+ // Get the replacement for hidden data
+ CMenuFilter* filter = CMenuFilter::NewL();
+ CleanupStack::PushL( filter );
+ // 'Undefined' item
+ filter->HaveAttributeL( KMenuAttrUid, KMenuAttrUndefUid );
+ TMenuItem undefItem = FindMenuItemL( *filter );
+ iPluginData->ReplaceMenuItemL( i, undefItem );
+ iPluginData->SaveSettingsL( i, *FetchMenuItemL(undefItem) );
+ CleanupStack::PopAndDestroy( filter );
+ }
+ CleanupStack::PopAndDestroy( menuItem );
+ menuItem = NULL;
+ }
+ // Notification must be activated again
+ iNotifyWatcher->Cancel();
+ iNotifier.Notify( 0,
+ RMenuNotifier::EItemsAddedRemoved |
+ RMenuNotifier::EItemsReordered |
+ RMenuNotifier::EItemAttributeChanged,
+ iNotifyWatcher->iStatus );
+
+ iNotifyWatcher->WatchNotify( this );
+ // Publish changed data
+ iPlugin.PublishL();
+ }
+
+// ---------------------------------------------------------------------------
+// From class MMsvSessionObserver.
+// Handles an event from the message server.
+// ---------------------------------------------------------------------------
+//
+void CMCSPluginEngine::HandleSessionEventL(
+ TMsvSessionEvent aEvent, TAny* /*aArg1*/, TAny* /*aArg2*/, TAny* /*aArg3*/)
+ {
+ switch ( aEvent )
+ {
+ case EMsvEntriesDeleted:
+ // fall-through intended here
+ case EMsvEntriesChanged:
+ {
+
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// From class MFavouritesDbObserver.
+// Handles database event.
+// -----------------------------------------------------------------------------
+//
+void CMCSPluginEngine::HandleFavouritesDbEventL( RDbNotifier::TEvent aEvent )
+ {
+ switch ( aEvent )
+ {
+ case RDbNotifier::ERollback:
+ // fall-through intended here
+ case RDbNotifier::ERecover:
+ // fall-through intended here
+ case RDbNotifier::ECommit:
+ {
+ // Get list of favourites bookmarks
+ CFavouritesItemList* favItems =
+ new (ELeave) CFavouritesItemList();
+ CleanupStack::PushL( favItems );
+ TInt err = iBookmarkDb.GetAll( *favItems, KFavouritesNullUid,
+ CFavouritesItem::EItem );
+ if ( err != KErrNone )
+ {
+ ASSERT(0);
+ }
+ TInt count_fav = favItems->Count();
+
+ // Do for each plugin data (4x times)
+ TInt count_data( iPluginData->DataCount() );
+ for ( TInt item_index = 0; item_index < count_data; item_index++ )
+ {
+ // Get item ID and open its menu related item
+ TMCSData& data = iPluginData->DataItemL( item_index );
+ TInt itemID( data.MenuItem().Id() );
+ CMenuItem* menuItem = CMenuItem::OpenL( iMenu, itemID );
+ CleanupStack::PushL( menuItem );
+
+ // Get URL aatribute
+ TBool attrExists = EFalse;
+ TPtrC url = menuItem->GetAttributeL( _L("url"), attrExists );
+ // If bookmark...
+ if ( attrExists )
+ {
+ // Get bookmark UID
+ TPtrC uid_item_ptr = menuItem->GetAttributeL(
+ KMenuAttrUid, attrExists );
+
+ // Compare with each item in fav. bookmarks list
+ TBool itemExists = EFalse;
+ for ( TInt fav_index = count_fav - 1; fav_index >= 0; fav_index-- ) // newest on top
+ {
+ // Get list item UID
+ TUid uid_fav = TUid::Uid( favItems->At( fav_index )->Uid() );
+ if ( uid_fav.Name() == uid_item_ptr )
+ {
+ // Bookmark still exist in fav. bookmarks list
+ itemExists = ETrue;
+ break;
+ }
+ }
+
+ if ( !itemExists )
+ {
+ // If item not axist any more, replace it by undefined icon
+ CMenuFilter* filter = CMenuFilter::NewL();
+ CleanupStack::PushL( filter );
+ // 'Undefined' item
+ filter->HaveAttributeL( KMenuAttrUid,
+ KMenuAttrUndefUid );
+ TMenuItem undefItem = FindMenuItemL( *filter );
+ iPluginData->ReplaceMenuItemL( item_index, undefItem );
+ iPluginData->SaveSettingsL( item_index, *FetchMenuItemL(
+ undefItem ) );
+ CleanupStack::PopAndDestroy( filter );
+ }
+ }
+ CleanupStack::PopAndDestroy( menuItem );
+ }
+ CleanupStack::PopAndDestroy( favItems );
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// Resumes the engine
+// ---------------------------------------------------------------------------
+//
+void CMCSPluginEngine::ResumeL()
+ {
+ iSuspend = EFalse;
+ }
+
+// ---------------------------------------------------------------------------
+// Suspends the engine
+// ---------------------------------------------------------------------------
+//
+void CMCSPluginEngine::Suspend()
+ {
+ iSuspend = ETrue;
+ }
+
+// ---------------------------------------------------------------------------
+// Launch General Settings plugin
+// ---------------------------------------------------------------------------
+//
+void CMCSPluginEngine::ShowSettingsL()
+ {
+ TUid uid = {AI_UID_ECOM_IMPLEMENTATION_SETTINGS_MCSPLUGIN};
+ CGSLauncher* l = CGSLauncher::NewLC();
+ l->LaunchGSViewL ( uid,
+ KHomescreenUid,
+ iInstanceUid );
+ CleanupStack::PopAndDestroy( l );
+
+ }
+// ---------------------------------------------------------------------------
+// ResolveSkinItemId
+// Syntax: skin(major minor):mif(filename bimapId maskId)
+// ---------------------------------------------------------------------------
+//
+TBool CMCSPluginEngine::ConstructMenuItemForIconL( const TDesC& aPath, CMenuItem& aMenuItem )
+ {
+ TInt pos = aPath.Locate( ':' );
+ if( pos == KErrNotFound )
+ {
+ pos = aPath.Length();
+ }
+ TPtrC skin = aPath.Left( pos );
+ TInt sf = skin.FindF( KSkin );
+ if( sf == KErrNotFound )
+ {
+ return EFalse;
+ }
+ TPtrC temp = skin.Mid( sf + KSkin().Length());
+ TLex input( temp );
+ input.SkipSpace();
+ if( !input.Eos() && input.Peek() == '(')
+ {
+ input.Inc();
+ }
+ TPtrC majorId = NextIdToken( input );
+ TPtrC minorId = NextIdToken( input );
+ aMenuItem.SetAttributeL( KMenuAttrIconSkinMajorId, majorId );
+ aMenuItem.SetAttributeL( KMenuAttrIconSkinMinorId, minorId );
+
+ //TPtrC mif = aPath.Mid( pos + 1 );
+ //TInt mf = mif.FindF( KMif );
+ if( aPath.Length() > pos && (aPath.Mid( pos + 1 ).FindF( KMif ) != KErrNotFound ))
+ {
+ TPtrC mif = aPath.Mid( pos + 1 );
+ TInt mf = mif.FindF( KMif );
+ //TPtrC temp1 = mif.Mid( mf+ KMif().Length());
+ TLex input1( mif.Mid( mf+ KMif().Length()) );
+ input1.SkipSpace();
+ if( !input1.Eos() && input1.Peek() == '(')
+ {
+ input1.Inc();
+ }
+ TPtrC file = NextIdToken( input1 );
+ TPtrC bitmapId = NextIdToken( input1 );
+ TPtrC maskId = NextIdToken( input1 );
+ aMenuItem.SetAttributeL( KMenuAttrIconFile, file );
+ aMenuItem.SetAttributeL( KMenuAttrIconId, bitmapId );
+ aMenuItem.SetAttributeL( KMenuAttrMaskId, maskId );
+ }
+ return ETrue;
+ }
+
+// ---------------------------------------------------------------------------
+// Called during plugin desctruction
+// Decrements reference counters of all run-time generated items
+// and deletes those which have reference counter == 0
+// ---------------------------------------------------------------------------
+//
+void CMCSPluginEngine::CleanMCSItemsL()
+ {
+ const TInt count( iPluginData->DataCount() );
+ for( TInt i = 0; i < count; i++ )
+ {
+ TMCSData& data = iPluginData->DataItemL(i);
+
+ CMenuItem* menuItem = CMenuItem::OpenL( iMenu, data.MenuItem().Id() );
+ if( !menuItem )
+ {
+ continue;
+ }
+ CleanupStack::PushL( menuItem );
+
+ // check if ref_count attribute exists
+ TBool exists = EFalse;
+ TPtrC param = menuItem->GetAttributeL( KMenuAttrRefcount, exists );
+ if( exists )
+ {
+ const TInt references = UpdateMenuItemsRefCountL( menuItem, -1 );
+
+ // Create a nested loop inside CActiveScheduler.
+ CActiveSchedulerWait* wait = new (ELeave) CActiveSchedulerWait;
+ CleanupStack::PushL( wait );
+
+ if( references > 0 )
+ {
+ // if counter is still > 0, update its value in MCS
+ CMenuOperation* op = menuItem->SaveL( iWatcher->iStatus );
+ iWatcher->StopAndWatch( op, wait );
+
+ // Start the nested scheduler loop.
+ wait->Start();
+ }
+ else
+ {
+ // counter reached 0 -> item is not referenced by any shortcut
+ // so remove it from MCS
+ if( !iWatcher->IsActive() )
+ {
+ CMenuOperation* op = iMenu.RemoveL( menuItem->Id(), iWatcher->iStatus );
+ iWatcher->StopAndWatch( op, wait );
+
+ // Start the nested scheduler loop.
+ wait->Start();
+ }
+ }
+
+ CleanupStack::PopAndDestroy( wait );
+ wait = NULL;
+ }
+
+ CleanupStack::PopAndDestroy( menuItem );
+ menuItem = NULL;
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// Helper method. Adds a given constant to a value of reference counter
+// ---------------------------------------------------------------------------
+//
+TInt CMCSPluginEngine::UpdateMenuItemsRefCountL( CMenuItem* aItem,
+ const TInt aValueToAdd )
+ {
+ TBool exists = EFalse;
+ CleanupStack::PushL( aItem );
+ TPtrC param = aItem->GetAttributeL( KMenuAttrRefcount, exists );
+ CleanupStack::Pop( aItem );
+ if ( exists )
+ {
+ TInt references;
+ TLex16 lextmp( param );
+ lextmp.Val( references );
+ references += aValueToAdd;
+ TBuf<128> buf;
+ buf.NumUC( references );
+
+ // set new ref_count
+ CleanupStack::PushL( aItem );
+ aItem->SetAttributeL( KMenuAttrRefcount, buf);
+ CleanupStack::Pop( aItem );
+ // return new ref_count
+ return references;
+ }
+ return -1;
+ }