idlefw/plugins/mcsplugin/publisher/src/mcsplugindata.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 15 Mar 2010 12:41:53 +0200
branchRCL_3
changeset 19 502e5d91ad42
parent 18 bd874ee5e5e2
child 51 15e4dd19031c
permissions -rw-r--r--
Revision: 201009 Kit: 201010

/*
* 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:  
*
*/
#include <mcsmenuitem.h>
#include <mcsmenufilter.h>
#include <itemmap.h>
#include <aistrcnv.h>
#include <favouritesdbobserver.h>
#include <favouritesdb.h>        
#include <msvuids.h>        // For KMsvRootIndexEntryIdValue

#include <mcsmenuitem.h>
#include <mcsmenufilter.h>

#include "mcsplugindata.h"
#include "mcspluginengine.h"

using namespace HSPluginSettingsIf;

_LIT( KMenuAttrParam, "param" );
_LIT( KMenuAttrLocked, "locked" );
_LIT8( KProperNameType, "type" );
_LIT8( KProperNameParam, "param" );
_LIT8( KProperNameUid, "uid" );
_LIT8( KProperNameView, "view" );
_LIT8( KProperValueFolder, "folder" );
_LIT8( KProperValueBookmark, "bookmark" );
_LIT8( KProperValueAppl, "application" );

_LIT( KMailboxUid, "0x100058c5" );
_LIT8( KMailboxUid8, "0x100058c5" );
_LIT( KMenuMailboxIconId, "16388" );
_LIT( KMenuMailboxMaskId, "16389" );

_LIT( KUrl, "url" );
_LIT( KMenuIconFile, "aimcsplugin.mif" );
_LIT( KMenuBookmarkIconId, "16386" );
_LIT( KMenuBookmarkMaskId, "16387" );
_LIT( KInitialRefCount, "1" );
_LIT( KMenuAttrRefcount, "ref_count" );
_LIT( KMyMenuData, "matrixmenudata" );
_LIT( KMenuTypeShortcut, "menu:shortcut" );
_LIT( KMenuAttrParameter, "param" );

#define KMCSCmailMtmUidValue 0x2001F406

// ======== LOCAL FUNCTIONS ========

static void ItemMapArrayCleanupFunc( TAny* aPointerArray )
    {
    RPointerArray<CItemMap>* p = static_cast<RPointerArray<CItemMap>*>( aPointerArray ); 
    p->ResetAndDestroy();
    p->Close();
    }

// ======== MEMBER FUNCTIONS ========

void TMCSData::SetMenuItem( TMenuItem& aMenuItem )
    {
    iMenuItem = aMenuItem;
    }

TMenuItem& TMCSData::MenuItem()
    {
    return iMenuItem;
    }

void TMCSData::SetDirty( TBool aDirty )
    {
    iDirty = aDirty;
    }

TBool TMCSData::IsDirty() const
    {
    return iDirty;
    }
    
// ---------------------------------------------------------------------------
// Symbian 2nd phase constructor can leave
// ---------------------------------------------------------------------------
//
CMCSPluginData* CMCSPluginData::NewL( CMCSPluginEngine& aEngine, const TDesC8& aInstanceUid )
    {
    CMCSPluginData* self = new (ELeave) CMCSPluginData( aEngine, aInstanceUid );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
 
    return self;
    }
    
// ---------------------------------------------------------------------------
// Default constructor
// ---------------------------------------------------------------------------
//
CMCSPluginData::CMCSPluginData( CMCSPluginEngine& aEngine, const TDesC8& aInstanceUid )
    : iEngine( aEngine ), iInstanceUid( aInstanceUid )
    {
    }
    
// ---------------------------------------------------------------------------
// Symbian 2nd phase constructor can leave
// ---------------------------------------------------------------------------
//
void CMCSPluginData::ConstructL()
    {
    iMsvSession = CMsvSession::OpenAsObserverL( *this );
    iPluginSettings = CHomescreenSettings::Instance();
    if( iPluginSettings == NULL )
        {
        User::Leave( KErrUnknown );
        }
    iPluginSettings->AddObserverL( this );

    iSaveWatcher = CMCSPluginWatcher::NewL( CMCSPluginWatcher::EOperation );

    iMenu.OpenL( KMyMenuData );

    UpdateDataL();
    }

// ---------------------------------------------------------------------------
// Destructor
// ---------------------------------------------------------------------------
//
CMCSPluginData::~CMCSPluginData()
    {
    if( iPluginSettings )
        {
        iPluginSettings->RemoveObserver( this );
        }

    iData.Close();
    iMenu.Close();

    delete iSaveWatcher;
    delete iMsvSession;
    }

// ---------------------------------------------------------------------------
// Gets the instance specific settings from HSPS and creates data items
// ---------------------------------------------------------------------------
//
void CMCSPluginData::UpdateDataL()
    {
    RPointerArray<CItemMap> settings;
    TCleanupItem settingsCleanupItem( ItemMapArrayCleanupFunc, &settings );
    CleanupStack::PushL( settingsCleanupItem );
    iPluginSettings->GetSettingsL( iInstanceUid, settings );
    TInt count = settings.Count();
    TBool wasEmpty = !iData.Count();
    
    for ( TInt i = 0; i < count; i++ )
       {
        CItemMap* itemMap = settings[ i ];
        RPointerArray<HSPluginSettingsIf::CPropertyMap>& properties
            = itemMap->Properties();
        TMenuItem item = CreateMenuItemL( properties );
        TMCSData data;

        if ( wasEmpty )
            {
            // list of shortcut slot was empty
            // we append the shortcut data slots one-by-one to the list
            data.SetMenuItem( item );
            data.SetDirty( ETrue );
            iData.AppendL( data );
            }
        else 
            {
            // check for updates in existing shortcut data slot
            // if menuitem id has changed, replace the item and 
            // set as dirty
            TInt id = -1;
            id = iData[ i ].MenuItem().Id();
            
            if ( item.Id() != id )
                {
                data.SetMenuItem( item );
                data.SetDirty( ETrue );
                iData.Remove( i );
                iData.InsertL( data, i );
                }
            }
        }
    
        CleanupStack::PopAndDestroy(); // settingsCleanupItem 
    }


// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
void CMCSPluginData::SettingsChangedL( const TDesC8& /*aEvent*/,  const TDesC8& /*aPluginName*/,
                           const TDesC8& /*aPluginUid*/, const TDesC8& aPluginId )
    {
    if( aPluginId.CompareF( iInstanceUid ) == 0 )
        {
        UpdateDataL();
        }   
    }

// ---------------------------------------------------------------------------
// Gets the menu item from engine using the setting properties as filter
// ---------------------------------------------------------------------------
//
TMenuItem CMCSPluginData::CreateMenuItemL( RPointerArray<HSPluginSettingsIf::CPropertyMap>& aProperties )
    {
    CMenuFilter* filter = CMenuFilter::NewLC();

    // Exclude 'view' and 'param' attributes from search criteria by default
    // Criterias will be added to filter if setting defines them
    filter->DoNotHaveAttributeL( KMenuAttrView );
    filter->DoNotHaveAttributeL( KMenuAttrParam );
    TBool isFolder = EFalse;
    
    // first, we need to check if the item is folder
    for ( TInt i = 0; i < aProperties.Count(); i++ )
        {
        if ( aProperties[i]->Name() == KProperNameType )
            {
            if ( aProperties[i]->Value() == KProperValueFolder )
                {
                isFolder = ETrue;
                }
            break;
            }
        }

    // then add all property/value pairs to the filter
    for ( TInt i = 0; i < aProperties.Count(); i++ )
        {

        // skip the type property
        if( aProperties[i]->Name() == KProperNameType )
            {
            continue;
            }

        HBufC* name( NULL );
        HBufC* value( NULL );
        name = AiUtility::CopyToBufferL( name, aProperties[i]->Name() );
        CleanupStack::PushL( name );
        value = AiUtility::CopyToBufferL( value, aProperties[i]->Value() );
        CleanupStack::PushL( value );

        if ( value->Length() != 0 )
            {
            // in case of folder, we just have to extract 
            // id from param attribute and return item with this id
            if ( aProperties[i]->Name() ==  KProperNameParam && isFolder )
                {
                TMenuItem item;
                // convert id to integer
                TInt id;
                TLex16 lextmp( value->Ptr() );
                lextmp.Val( id );
                item.SetType( KMenuTypeFolder );
                item.SetId( id );

                CleanupStack::PopAndDestroy( value );
                CleanupStack::PopAndDestroy( name );
                CleanupStack::PopAndDestroy( filter );

                return item;
                }
            else
                {
                // otherwise, we just add name/value into filter
                filter->HaveAttributeL( *name, *value );
                }
            }
        CleanupStack::PopAndDestroy( value );
        CleanupStack::PopAndDestroy( name );
        }
    
    // locked property excluded from search pattern 
    filter->DoNotHaveAttributeL( KMenuAttrLocked );
    
    TMenuItem item = iEngine.FindMenuItemL( *filter );
    CleanupStack::PopAndDestroy( filter );
    return item;
    }

// ---------------------------------------------------------------------------
// Returns menu item for given index
// ---------------------------------------------------------------------------
//
TMCSData& CMCSPluginData::DataItemL( TInt aIndex )
    {
    if( aIndex < 0 || aIndex >= iData.Count())
        {
        User::Leave( KErrArgument ); 
        }
    return iData[aIndex];
    }

// ---------------------------------------------------------------------------
// Replaces menuitem in data instance
// ---------------------------------------------------------------------------
//
void CMCSPluginData::ReplaceMenuItemL( const TInt& aIndex, TMenuItem& aMenuItem )
    {
    TMCSData& data = iData[aIndex];
    data.SetMenuItem( aMenuItem );
    data.SetDirty( ETrue );
    }

// ---------------------------------------------------------------------------
// Save the setting persistently to HSPS
// TODO HSPS setting api should be changed so that items and properties can 
// be added/removed dynamically. Now widgetconfiguration.xml must have all the
// properties for every item even though property is not used.
// It makes this function more compolicated.
// ---------------------------------------------------------------------------
//
void CMCSPluginData::SaveSettingsL( const TInt& aIndex, CMenuItem& aMenuItem )
    {
    RPointerArray<CItemMap> settingItems;
    CleanupClosePushL( settingItems );
    iPluginSettings->GetSettingsL( iInstanceUid, settingItems );
    if ( aIndex >= 0 && aIndex < settingItems.Count() )
        {
        TBool exists( EFalse );
        CItemMap* itemMap = settingItems[aIndex];
        RPointerArray<HSPluginSettingsIf::CPropertyMap> properties;
        properties = itemMap->Properties();
        for ( TInt i= 0; i < properties.Count(); i++ )
            {
            if ( properties[i]->Name() == KProperNameType )
                {
                TPtrC type = aMenuItem.Type();
                if ( type == KMenuTypeUrl )
                    {
                    properties[i]->SetValueL( KProperValueBookmark );
                    }
                else
                    {
                    properties[i]->SetValueL( KProperValueAppl );
                    }
                }
            else if ( properties[i]->Name() == KProperNameUid )
                {
                TPtrC uid = aMenuItem.GetAttributeL( KMenuAttrUid, exists );
                if ( exists )
                    {
                    HBufC8* uid8( NULL );
                    uid8 = AiUtility::CopyToBufferL( uid8, uid );
                    CleanupStack::PushL( uid8 );
                    properties[i]->SetValueL( *uid8 );
                    CleanupStack::PopAndDestroy( uid8 );
                    }
                else
                    {
                    properties[i]->SetValueL( KNullDesC8 );
                    }
                }
            else if ( properties[i]->Name() == KProperNameView )
                {
                TPtrC view = aMenuItem.GetAttributeL( KMenuAttrView, exists );
                if ( exists )
                    {
                    HBufC8* view8( NULL );
                    view8 = AiUtility::CopyToBufferL( view8, view );
                    CleanupStack::PushL( view8 );
                    properties[i]->SetValueL( *view8 );
                    CleanupStack::PopAndDestroy( view8 );
                    }
                else
                    {
                    properties[i]->SetValueL( KNullDesC8 );
                    }
                }
            else if ( properties[i]->Name() == KProperNameParam )
                {
                TPtrC param = aMenuItem.GetAttributeL( KMenuAttrParam, exists );
                if ( exists )
                    {
                    HBufC8* param8( NULL );
                    param8 = AiUtility::CopyToBufferL( param8, param );
                    CleanupStack::PushL( param8 );
                    properties[i]->SetValueL( *param8 );
                    CleanupStack::PopAndDestroy( param8 );
                    }
                else
                    {
                    properties[i]->SetValueL( KNullDesC8 );
                    }
                }
            }
        }
    // ETrue tells that changes are stored also to plugin reference 
    iPluginSettings->SetSettingsL( iInstanceUid, settingItems, ETrue );
    CleanupStack::PopAndDestroy( &settingItems );
    }

// ---------------------------------------------------------------------------
// Gets MCS Plugin folder ID. This hidden folder in matrixmenudata.xml is used 
// for storing run-time generated menuitems
// ---------------------------------------------------------------------------
//
TInt CMCSPluginData::GetMCSPluginFolderIdL()
    {
    TInt folderId;
    
    _LIT( KMCSFolder, "mcsplugin_folder" );

    CMenuItem* item( NULL );
    CMenuFilter* filter = CMenuFilter::NewL();
    CleanupStack::PushL( filter );
    filter->SetType( KMenuTypeFolder );
    filter->HaveAttributeL( KMenuAttrLongName, KMCSFolder );

    const TInt rootId = iMenu.RootFolderL();
    RArray<TMenuItem> itemArray;
    CleanupClosePushL( itemArray );
    iMenu.GetItemsL( itemArray, rootId, filter, ETrue );
    if ( itemArray.Count() > 0 )
        {
        item = CMenuItem::OpenL( iMenu, itemArray[0] );
        folderId = item->Id();
        }
    else 
        {
        folderId = iMenu.RootFolderL();
        }
    CleanupStack::PopAndDestroy( &itemArray );
    CleanupStack::PopAndDestroy( filter ); 

    delete item; 

    return folderId;
    }

// ---------------------------------------------------------------------------
// Creates runtime generated menuitems (bookmarks/mailboxes if they 
// it does not exist yet in MCS. If they do, their ref_count is incremented.
// Called during Plugin startup.
// ---------------------------------------------------------------------------
//
void CMCSPluginData::CreateRuntimeMenuItemsL()
    {
    
    // start mailboxes observing and get the number of
    // mailboxes defined in the device

    TMsvId entryID = KMsvRootIndexEntryIdValue;
    CMsvEntry* rootEntry = iMsvSession->GetEntryL( entryID );
    TInt mailboxCount = rootEntry->Count();
    CleanupStack::PushL( rootEntry );
    
    RPointerArray<CItemMap> settings;
    TCleanupItem settingsCleanupItem( ItemMapArrayCleanupFunc, &settings );
    CleanupStack::PushL( settingsCleanupItem );
    iPluginSettings->GetSettingsL( iInstanceUid, settings );

    RFavouritesSession bookmarkSess;
    RFavouritesDb bookmarkDb;

    User::LeaveIfError( bookmarkSess.Connect() );
    User::LeaveIfError( bookmarkDb.Open( bookmarkSess, KBrowserBookmarks ));

    TInt count = settings.Count();
    for( TInt i = 0; i < count; i++ )
       {
        CItemMap* itemMap = settings[i];
        RPointerArray<HSPluginSettingsIf::CPropertyMap>& properties
            = itemMap->Properties();

        TPtrC8 uid8, type, param8;

        for( TInt j = 0; j < properties.Count(); j++ )
            {

            if( properties[j]->Name() == KProperNameType )
                {
                type.Set( properties[j]->Value() );
                }
            else if ( properties[j]->Name() == KProperNameUid )
                {
                uid8.Set( properties[j]->Value() );
                }
            else if ( properties[j]->Name() ==  KProperNameParam )
                {
                param8.Set( properties[j]->Value() );
                }
            }

        if( type == KProperValueBookmark )
            {
            
            // The shortcut is a bookmark
            TMenuItem menuItem = CreateMenuItemL( properties );

            CActiveSchedulerWait* wait = 
                            new ( ELeave ) CActiveSchedulerWait;
            CleanupStack::PushL( wait );
            
            if( menuItem.Id() == 0 )
                {
                TLex8 uidLex( uid8.Mid( 1, uid8.Length() - 2 ) );
                TUint32 id;
                uidLex.Val(id, EHex);

                CFavouritesItem* bkmItem = CFavouritesItem::NewLC();
                TInt bcount = bookmarkDb.Get( TInt32( id ), *bkmItem );

                HBufC *uid( NULL );
                uid = AiUtility::CopyToBufferL( uid, uid8 );
                CleanupStack::PushL( uid );

                CMenuItem* newItem = CMenuItem::CreateL( iMenu, 
                                                         KMenuTypeUrl, 
                                                         GetMCSPluginFolderIdL(),
                                                         0 );
                CleanupStack::PushL( newItem );

                newItem->SetAttributeL( KMenuAttrUid, *uid );
                newItem->SetAttributeL( KMenuAttrLongName, bkmItem->Name() );
                newItem->SetAttributeL( KMenuAttrIconFile, KMenuIconFile );
                newItem->SetAttributeL( KMenuAttrIconId, KMenuBookmarkIconId );
                newItem->SetAttributeL( KMenuAttrMaskId, KMenuBookmarkMaskId );
                newItem->SetAttributeL( KMenuAttrRefcount, KInitialRefCount );
                newItem->SetAttributeL( KUrl , bkmItem->Url() );

                CMenuOperation* op = newItem->SaveL( iSaveWatcher->iStatus );

                iSaveWatcher->StopAndWatch( op, wait );

                // Start the nested scheduler loop.
                wait->Start();

                SaveSettingsL( i, *newItem );

                CleanupStack::PopAndDestroy( newItem );
                CleanupStack::PopAndDestroy( uid );
                CleanupStack::PopAndDestroy( bkmItem );
                }
            else
                {
                CMenuItem* item = CMenuItem::OpenL( iMenu, menuItem );
                CleanupStack::PushL( item );
                if ( iEngine.UpdateMenuItemsRefCountL( item, 1 ) > 0 )
                    {
                    CMenuOperation* op = item->SaveL( iSaveWatcher->iStatus );
                    iSaveWatcher->StopAndWatch( op, wait );
                    // Start the nested scheduler loop.
                    wait->Start();
                    SaveSettingsL( i, *item );
                    }
                CleanupStack::PopAndDestroy( item );
                }

            CleanupStack::PopAndDestroy( wait );
            wait = NULL;
            }

        else if ( uid8 == KMailboxUid8 && mailboxCount > 0 )
             {
             // The shortcut is a Mailbox
             
             TMenuItem menuItem = CreateMenuItemL( properties );

             CActiveSchedulerWait* wait = 
                             new ( ELeave ) CActiveSchedulerWait;
             CleanupStack::PushL( wait );

             if ( menuItem.Id() == 0 )
                {
                // mailbox menuitem does not exist yet. We have to create it
                // first, we try to find its ID among existing mailboxes:bì 

                // extract Mailbox ID from HSPS
                TInt pos = param8.Locate( TChar( ':' ) ) + 1;
                TPtrC8 mailboxId8 = param8.Mid( pos );
                
                HBufC *mailboxId( NULL );
                mailboxId = AiUtility::CopyToBufferL( mailboxId, mailboxId8 );
                CleanupStack::PushL( mailboxId );
                
                // compare ID with existing mailboxes
                rootEntry->SetSortTypeL( TMsvSelectionOrdering( 
                            KMsvGroupByType | KMsvGroupByStandardFolders, 
                            EMsvSortByDetailsReverse, ETrue ) );
                
                TBuf<255> boxId;
                TBool found = EFalse;
                TInt index = rootEntry->Count();

                while ( !found && --index >= 0 )
                    {
                    const TMsvEntry& tentry = ( *rootEntry )[ index ];
                    if ( tentry.iMtm.iUid == KMCSCmailMtmUidValue )
                        {
                        boxId.Num( tentry.Id() );
                        if ( boxId == *mailboxId )
                            {
                            found = ETrue;
                            }
                        }
                    }

                CleanupStack::PopAndDestroy( mailboxId );
                
                // mailbox still exists in Mail application
                // we have to create a new menuitem
                if ( found )
                    {

                    // get the mailbox name
                    const TMsvEntry& tentry = ( *rootEntry )[ index ];
                    TPtrC name = tentry.iDetails;

                    HBufC *param( NULL );
                    param = AiUtility::CopyToBufferL( param, param8 );
                    CleanupStack::PushL( param );

                    // create a new menuitem with ref_count 1
                    CMenuItem* newItem = CMenuItem::CreateL( iMenu, 
                                                         KMenuTypeShortcut, 
                                                         GetMCSPluginFolderIdL(), 
                                                         0 );
                    CleanupStack::PushL( newItem );

                    // mailbox is a shortcut item with "mailbox:mailboxID" parameter
                    newItem->SetAttributeL( KMenuAttrUid, KMailboxUid );
                    newItem->SetAttributeL( KMenuAttrLongName, name );
                    newItem->SetAttributeL( KMenuAttrParameter, *param );
                    newItem->SetAttributeL( KMenuAttrRefcount, KInitialRefCount );

                    // setting icon for the shortcut
                    newItem->SetAttributeL( KMenuAttrIconFile, KMenuIconFile );
                    newItem->SetAttributeL( KMenuAttrIconId, KMenuMailboxIconId );
                    newItem->SetAttributeL( KMenuAttrMaskId, KMenuMailboxMaskId );

                    CMenuOperation* op = newItem->SaveL( iSaveWatcher->iStatus );
                    iSaveWatcher->StopAndWatch( op, wait );

                    // Start the nested scheduler loop.
                    wait->Start();

                    SaveSettingsL( i, *newItem );

                    CleanupStack::PopAndDestroy( newItem );
                    CleanupStack::PopAndDestroy( param );
                    }
                }
             else 
                {
                // mailbox menu item already exists -> increment ref_count by 1
                CMenuItem* item = CMenuItem::OpenL( iMenu, menuItem );
                CleanupStack::PushL( item );
                if ( iEngine.UpdateMenuItemsRefCountL( item, 1 ) > 0 )
                    {
                    CMenuOperation* op = item->SaveL( iSaveWatcher->iStatus );
                    iSaveWatcher->StopAndWatch( op, wait );

                    // Start the nested scheduler loop.
                    wait->Start();
                    SaveSettingsL( i, *item );
                    }
                 CleanupStack::PopAndDestroy( item );
                }
             CleanupStack::PopAndDestroy( wait );
             wait = NULL;
             
             }
        }
    CleanupStack::PopAndDestroy(); // settingsCleanupItem
    CleanupStack::PopAndDestroy( rootEntry );
    }

// ---------------------------------------------------------------------------
// From class MMsvSessionObserver.
// Handles an event from the message server.
// ---------------------------------------------------------------------------
//
void CMCSPluginData::HandleSessionEventL(
                                     TMsvSessionEvent /*aEvent*/, 
                                     TAny* /*aArg1*/, 
                                     TAny* /*aArg2*/,
                                     TAny* /*aArg3*/ )
    {

    }