--- /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;
+ }
+
+