menucontentsrv/src/menuitem.cpp
changeset 0 79c6a41cd166
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menucontentsrv/src/menuitem.cpp	Thu Dec 17 08:54:17 2009 +0200
@@ -0,0 +1,475 @@
+/*
+* 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;
+    }
+
+