menucontentsrv/src/menuitem.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 08:54:17 +0200
changeset 0 79c6a41cd166
permissions -rw-r--r--
Revision: 200949 Kit: 200951

/*
* 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 FILES

#include <s32strm.h>

#include "mcsmenuitem.h"
#include "menuitemattr.h"
#include "menubuf.h"
#include "mcsmenu.h"
#include "menuclientoperation.h"
#include "menucompletedoperation.h"


NONSHARABLE_CLASS( CMenuItem::TData )
    {

public:     // construction

    TData( RMenu& aMenu ): iMenu( aMenu ) {}

public:     // data

    RMenu& iMenu;
    TMenuItem iHdr;
    TUint32 iOrigFlags;
    RMenuItemAttrArray iAttrCache;
    TInt iInsertBefore;

    };

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

/**
* Check if this is a valid attribute name. Leave with KErrArgument if not.
* We don't accept whitespace or exotic characters anywhere, and also
* forbid setting reserved attribute "flags".
* The Engine also checks this, but it's more friendly to leave on client
* side too - no point in attempting something that we know will fail.
*/
LOCAL_C void CheckAttrNameL( const TDesC& aAttrName )
    {
    if ( !aAttrName.Length() )
        {
        User::Leave( KErrArgument );
        }
    if ( KMenuAttrFlags() == aAttrName || KMenuAttrId() == aAttrName )
        {
        // Internal attributes, disallow.
        User::Leave( KErrArgument );
        }
    for ( TInt i = 0; i < aAttrName.Length(); i++ )
        {
        const TChar c = aAttrName[i];
        // Allowed set of characters
        if ( !c.IsAlphaDigit() &&
             '_' != c &&
             '-' != c &&
             ':' != c )
            {
            User::Leave( KErrArgument );
            }
        }
    }


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

// ---------------------------------------------------------
// TMenuItem::ExternalizeL
// ---------------------------------------------------------
//
void TMenuItem::ExternalizeL( RWriteStream& aStream ) const
    {
    aStream.WriteInt32L( iId );
    aStream.WriteInt32L( iParent );
    aStream.WriteUint32L( iFlags );
    aStream.WriteInt32L( iType.Length() );
    aStream.WriteL( iType );
    }

// ---------------------------------------------------------
// TMenuItem::InternalizeL
// ---------------------------------------------------------
//
void TMenuItem::InternalizeL( RReadStream& aStream )
    {
    iId = aStream.ReadInt32L();
    iParent = aStream.ReadInt32L();
    iFlags = aStream.ReadUint32L();
    TInt len = aStream.ReadInt32L();
    aStream.ReadL( iType, len );
    }

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

// ---------------------------------------------------------
// CMenuItem::~CMenuItem
// ---------------------------------------------------------
//
EXPORT_C CMenuItem::~CMenuItem()
    {
    if ( iData )
        {
        iData->iAttrCache.ResetAndDestroy();
        delete iData;
        }
    }

// ---------------------------------------------------------
// CMenuItem::CreateL
// ---------------------------------------------------------
//
EXPORT_C CMenuItem* CMenuItem::CreateL
( RMenu& aMenu, const TDesC& aType, TInt aFolder, TInt aInsertBefore )
    {
    if ( KMenuTypeData() == aType )
        {
        // Internal type, disallow.
        User::Leave( KErrArgument );
        }
    // Item created locally, no IPC.
    CMenuItem* item = NewLC( aMenu );
    item->iData->iHdr.SetType( aType );
    item->iData->iHdr.SetParent( aFolder );
    item->iData->iOrigFlags = item->iData->iHdr.Flags();
    item->iData->iInsertBefore = aInsertBefore;
    CleanupStack::Pop( item );
    return item;
    }

// ---------------------------------------------------------
// CMenuItem::OpenL
// ---------------------------------------------------------
//
EXPORT_C CMenuItem* CMenuItem::OpenL( RMenu& aMenu, TInt aId )
    {
    // Get header from server, IPC needed.
    return OpenL( aMenu, aMenu.GetHdrL( aId ) );
    }

// ---------------------------------------------------------
// CMenuItem::OpenL
// ---------------------------------------------------------
//
EXPORT_C CMenuItem* CMenuItem::OpenL( RMenu& aMenu, const TMenuItem& aHdr )
    {
    // We accept the existing header, no IPC needed.
    CMenuItem* item = NewLC( aMenu );
    item->iData->iHdr = aHdr;
    item->iData->iOrigFlags = item->iData->iHdr.Flags();
    CleanupStack::Pop( item );
    return item;
    }

// ---------------------------------------------------------
// CMenuItem::CMenuItem
// ---------------------------------------------------------
//
CMenuItem::CMenuItem()
    {
    }

// ---------------------------------------------------------
// CMenuItem::NewLC
// ---------------------------------------------------------
//
CMenuItem* CMenuItem::NewLC( RMenu& aMenu )
    {
    CMenuItem* item = new (ELeave) CMenuItem();
    CleanupStack::PushL( item );
    item->iData = new (ELeave) CMenuItem::TData( aMenu );
    return item;
    }

// ---------------------------------------------------------
// CMenuItem::Id
// ---------------------------------------------------------
//
EXPORT_C TInt CMenuItem::Id() const
    {
    return iData->iHdr.Id();
    }

// ---------------------------------------------------------
// CMenuItem::Parent
// ---------------------------------------------------------
//
EXPORT_C TInt CMenuItem::Parent() const
    {
    return iData->iHdr.Parent();
    }

// ---------------------------------------------------------
// CMenuItem::Flags
// ---------------------------------------------------------
//
EXPORT_C TUint32 CMenuItem::Flags() const
    {
    return iData->iHdr.Flags();
    }

// ---------------------------------------------------------
// CMenuItem::SetFlags
// ---------------------------------------------------------
//
EXPORT_C void CMenuItem::SetFlags( TUint32 aMask, TBool aOn )
    {
    if ( aOn )
        {
        iData->iHdr.SetFlags( iData->iHdr.Flags() | aMask );
        }
    else
        {
        iData->iHdr.SetFlags( iData->iHdr.Flags() & ~aMask );
        }
    }

// ---------------------------------------------------------
// CMenuItem::Type
// ---------------------------------------------------------
//
EXPORT_C TPtrC CMenuItem::Type() const
    {
    return iData->iHdr.Type();
    }

// ---------------------------------------------------------
// CMenuItem::GetAttributeL
// ---------------------------------------------------------
//
EXPORT_C TPtrC CMenuItem::GetAttributeL
( const TDesC& aAttrName, TBool& aAttrExists )
    {
    CheckAttrNameL( aAttrName );
    CMenuItemAttr* attr = NULL;
    TInt i = iData->iAttrCache.Find( aAttrName );
    if ( KErrNotFound == i )
        {
        attr = CMenuItemAttr::NewLC( aAttrName );
        HBufC* value;
        if( iData->iHdr.Id() )
            {
            value = iData->iMenu.GetAttributeL( Id(), aAttrName );
            }
           else
            {
            value = NULL;
            }

        attr->SetValue( value ); // Takes ownership.
        attr->SetChanged( EFalse ); // New in cache -> not changed.
        iData->iAttrCache.AppendL( attr );
        CleanupStack::Pop( attr ); // Now owned by the cache.
        }
    else
        {
        attr = iData->iAttrCache[i];
        }
    __ASSERT_DEBUG( attr, User::Invariant() ); // Should be cached by now.
    if ( attr->Value() )
        {
        aAttrExists = ETrue;
        return *attr->Value();
        }
    aAttrExists = EFalse;
    return KNullDesC();
    }

// ---------------------------------------------------------
// CMenuItem::GetAttributeL
// ---------------------------------------------------------
//
EXPORT_C void CMenuItem::GetAttributeListL( RArray<TAttributeName>& aList )
    {
    iData->iMenu.GetAttributeListL( Id(), aList );
    }

// ---------------------------------------------------------
// CMenuItem::SetAttributeL
// ---------------------------------------------------------
//
EXPORT_C void CMenuItem::SetAttributeL
( const TDesC& aAttrName, const TDesC& aAttrValue )
    {
    CheckAttrNameL( aAttrName );
    CMenuItemAttr* attr = NULL;
    TInt i = iData->iAttrCache.Find( aAttrName );
    if ( KErrNotFound == i )
        {
        attr = CMenuItemAttr::NewLC( aAttrName );
        attr->SetChanged( ETrue ); // Changed.
        iData->iAttrCache.AppendL( attr );
        CleanupStack::Pop( attr ); // Now owned by the cache.
        }
    else
        {
        attr = iData->iAttrCache[i];
        }
    __ASSERT_DEBUG( attr, User::Invariant() ); // Should be cached by now.
    attr->SetValue( aAttrValue.AllocL() ); // Sets changed bit as needed.
    }

// ---------------------------------------------------------
// CMenuItem::RemoveAttributeL
// ---------------------------------------------------------
//
EXPORT_C void CMenuItem::RemoveAttributeL( const TDesC& aAttrName )
    {
    CheckAttrNameL( aAttrName );
    CMenuItemAttr* attr = NULL;
    TInt i = iData->iAttrCache.Find( aAttrName );
    if ( KErrNotFound == i )
        {
        attr = CMenuItemAttr::NewLC( aAttrName );
        attr->SetChanged( ETrue ); // Changed.
        iData->iAttrCache.AppendL( attr );
        CleanupStack::Pop( attr ); // Now owned by the cache.
        }
    else
        {
        attr = iData->iAttrCache[i];
        }
    __ASSERT_DEBUG( attr, User::Invariant() ); // Should be cached by now.
    attr->SetValue( NULL ); // Sets changed bit as needed.
    }

// ---------------------------------------------------------
// CMenuItem::SaveL
// ---------------------------------------------------------
//
EXPORT_C CMenuOperation* CMenuItem::SaveL( TRequestStatus& aStatus )
    {
    if ( !Changed() )
        {
        return CMenuCompletedOperation::NewL
            ( iData->iMenu, CActive::EPriorityStandard, aStatus, KErrNone );
        }
    if ( Id() )
        {
        return UpdateL( aStatus );
        }
    return AddL( aStatus );
    }

// ---------------------------------------------------------
// CMenuItem::HandleCommandL
// ---------------------------------------------------------
//
EXPORT_C CMenuOperation* CMenuItem::HandleCommandL(
        const TDesC8& aCommand,
        const TDesC8& aParams,
        TRequestStatus& aStatus )
    {
    return iData->iMenu.HandleCommandL( *this, aCommand, aParams, aStatus );
    }

// ---------------------------------------------------------
// CMenuItem::AddL
// ---------------------------------------------------------
//
CMenuOperation* CMenuItem::AddL( TRequestStatus& aStatus )
    {
    __ASSERT_DEBUG( Changed(), User::Invariant() );
    __ASSERT_DEBUG( !Id(), User::Invariant() );
    RMenuBuf buf;
    User::LeaveIfError( buf.Open( iData->iMenu ) );
    CleanupClosePushL( buf );
    RWriteStream stream( &buf );
    // Flags.
    stream.WriteUint32L( iData->iHdr.Flags() );
    __ASSERT_DEBUG( 0 == iData->iOrigFlags, User::Invariant() ); // New item!
    // Attributes.
    __ASSERT_DEBUG( iData->iAttrCache.Count() == \
        iData->iAttrCache.CountChanged(), User::Invariant() ); // New item!
    iData->iAttrCache.ExternalizeL( stream );
    // Parent folder and insertion point.
    stream.WriteInt32L( Parent() );
    stream.WriteInt32L( iData->iInsertBefore );
    stream.CommitL();
    CMenuClientOperation* op = new (ELeave) CMenuClientOperation
        ( iData->iMenu, CActive::EPriorityStandard, aStatus );
    CleanupStack::PushL( op );
    TInt id = op->AddL( Type(), buf );
    __ASSERT_DEBUG( id, User::Invariant() );
    iData->iHdr.SetId( id ); // Write ID back.
    CleanupStack::Pop( op );
    CleanupStack::PopAndDestroy( &buf );
    ClearChanged();
    return op;
    }

// ---------------------------------------------------------
// CMenuItem::UpdateL
// ---------------------------------------------------------
//
CMenuOperation* CMenuItem::UpdateL( TRequestStatus& aStatus )
    {
    __ASSERT_DEBUG( Changed(), User::Invariant() );
    __ASSERT_DEBUG( Id(), User::Invariant() );
    RMenuBuf buf;
    User::LeaveIfError( buf.Open( iData->iMenu ) );
    CleanupClosePushL( buf );
    RWriteStream stream( &buf );
    // Flags and flag changes (small -> always sent).
    stream.WriteUint32L( iData->iHdr.Flags() );
    stream.WriteUint32L( iData->iOrigFlags ^ iData->iHdr.Flags() );
    // Changed attributes.
    iData->iAttrCache.ExternalizeChangesL( stream );
    stream.CommitL();
    CMenuClientOperation* op = new (ELeave) CMenuClientOperation
        ( iData->iMenu, CActive::EPriorityStandard, aStatus );
    CleanupStack::PushL( op );
    op->UpdateL( Id(), buf );
    CleanupStack::Pop( op );
    CleanupStack::PopAndDestroy( &buf );
    ClearChanged();
    return op;
    }

// ---------------------------------------------------------
// CMenuItem::Changed
// ---------------------------------------------------------
//
TBool CMenuItem::Changed() const
    {
    return !iData->iHdr.Id() || // New item
           iData->iHdr.Flags() != iData->iOrigFlags || // Changed flags
           iData->iAttrCache.CountChanged(); // Changed attributes
    }

// ---------------------------------------------------------
// CMenuItem::ClearChanged
// ---------------------------------------------------------
//
void CMenuItem::ClearChanged()
    {
    iData->iAttrCache.ClearChanged();
    iData->iOrigFlags = iData->iHdr.Flags();
    }


// ---------------------------------------------------------
// CMenuItem::RunningStatus
// ---------------------------------------------------------
//
EXPORT_C TBool CMenuItem::RunningStatusL()
    {
    TBool ret(EFalse);
    HBufC* value;
    value = iData->iMenu.GetAttributeL( Id(), KRunningStatus );
    if( value )
    	{
    	ret = ETrue;
    	}
    delete value;
    return ret;
    }