sl@0: // Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0: // All rights reserved.
sl@0: // This component and the accompanying materials are made available
sl@0: // under the terms of "Eclipse Public License v1.0"
sl@0: // which accompanies this distribution, and is available
sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0: //
sl@0: // Initial Contributors:
sl@0: // Nokia Corporation - initial contribution.
sl@0: //
sl@0: // Contributors:
sl@0: //
sl@0: // Description:
sl@0: //
sl@0: 
sl@0: #include "WSGRAPHICDRAWERARRAY.H"
sl@0: #include "graphics/WSGRAPHICDRAWER.H"
sl@0: #include <graphics/WSGRAPHICDRAWERINTERFACE.H>
sl@0: #include "panics.h"
sl@0: 
sl@0: // CWsGraphicDrawerArray::XRollBackBase \\\\\\\\\\\\\\\\\\\\\\\\
sl@0: 
sl@0: /** Base class for cleanup operations - used as a handle for the CommitP() method
sl@0: 	This cleanup object is created on the heap with new(ELeave).
sl@0: 	It must be immediately pushed onto the cleanup stack, BEFORE the operation it protects,
sl@0: 	and must be written so that it does nothing until "activated" by the operation completing successfully.
sl@0: 	iArray==NULL indicates this state.
sl@0: 	This is because the client does not know whether the new(ELeave), the PushL, or the operational meat 
sl@0: 	generated the exception, and therefore the operation must be the last exception thrown in the method.
sl@0: 	@internalComponent
sl@0: 	@released
sl@0: */
sl@0: NONSHARABLE_STRUCT(CWsGraphicDrawerArray::XRollBackBase)
sl@0: 	{
sl@0: public:
sl@0: 	XRollBackBase():	iArray(NULL)	{}
sl@0: 	virtual ~XRollBackBase()			{}
sl@0: public:
sl@0: 	CWsGraphicDrawerArray*				iArray;
sl@0: 	};
sl@0: // CWsGraphicDrawerArray::XAddRollBack \\\\\\\\\\\\\\\\\\\\\\\\
sl@0: 
sl@0: /** Cleanup record for Add operation. Removes the array entry at the recorded array index.
sl@0: 	@internalComponent
sl@0: 	@released
sl@0: */
sl@0: NONSHARABLE_STRUCT(CWsGraphicDrawerArray::XAddRollBack) :public  CWsGraphicDrawerArray::XRollBackBase
sl@0: 	{
sl@0: 	TGraphicDrawerId iId;
sl@0: 	static void RollBackD(TAny* aAddRollBack);
sl@0: 	};
sl@0: 
sl@0: /** Rolls back an adding of a drawer to an array, but does not delete the drawer.
sl@0: 	Removes the array entry at the given array index.	
sl@0: */
sl@0: void CWsGraphicDrawerArray::XAddRollBack::RollBackD(TAny* aAddRollBack)
sl@0: 	{
sl@0: 	__ASSERT_DEBUG(aAddRollBack,Panic(EWsGraphicDrawerPanicBadAddLCCleanup));
sl@0: 	if(aAddRollBack)
sl@0: 		{
sl@0: 		XAddRollBack* rollBack = static_cast<XAddRollBack*>(aAddRollBack);
sl@0: 		// iArray would be NULL if you pushed a NULL drawer in release builds
sl@0: 		//It can also be null if the Add operation Leaves
sl@0: 		if(rollBack->iArray) 
sl@0: 			{
sl@0: 			rollBack->iArray->Remove(rollBack->iId);
sl@0: 			}
sl@0: 		delete  rollBack;
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: // CWsGraphicDrawerArray::XRemoveRollBack \\\\\\\\\\\\\\\\\\\\\\\\
sl@0: 
sl@0: /** Cleanup record for Swap operation. Re-inserts the recorded drawer by finding its index.
sl@0: 	@internalComponent
sl@0: 	@released
sl@0: */
sl@0: NONSHARABLE_STRUCT(CWsGraphicDrawerArray::XSwapRollBack) :public  CWsGraphicDrawerArray::XRollBackBase
sl@0: 	{
sl@0: 	CWsGraphicDrawer* iDrawer;
sl@0: 	static void RollBackD(TAny* aSwapRollBack);
sl@0: 	};
sl@0: 
sl@0: /** Rolls back the swapping (replacing) of a drawer to an array, but does not delete the replacing drawer.
sl@0: 	Re-inserts the recorded drawer by finding its index.
sl@0:  */
sl@0: void CWsGraphicDrawerArray::XSwapRollBack::RollBackD(TAny* aSwapRollBack)
sl@0: 	{
sl@0: 	__ASSERT_DEBUG(aSwapRollBack,Panic(EWsGraphicDrawerPanicBadSwapLCCleanup));
sl@0: 	if(aSwapRollBack)
sl@0: 		{
sl@0: 		XSwapRollBack* rollBack = static_cast<XSwapRollBack*>(aSwapRollBack);
sl@0: 		// would be NULL if you removed an id that wasn't in the array in release builds
sl@0: 		// or if the swap itself Leaves
sl@0: 		if(rollBack->iArray) 
sl@0: 			{
sl@0: 			const TInt idx = rollBack->iArray->IndexOf(rollBack->iDrawer->Id());
sl@0: 			__ASSERT_DEBUG(0 <= idx,Panic(EWsGraphicDrawerPanicBadSwapLCCleanup));
sl@0: 			if(0 <= idx) // hmm, don't see how this could ever happen.  If it does, better to leak memory etc 
sl@0: 				{
sl@0: 				rollBack->iArray->iArray[idx].iDrawer = rollBack->iDrawer;
sl@0: 				}
sl@0: 			}
sl@0: 		delete rollBack;
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: // CWsGraphicDrawerArray::XRemoveRollBack \\\\\\\\\\\\\\\\\\\\\\\\
sl@0: 
sl@0: /** Cleanup record for Remove operation. Re-inserts the recorded drawer by finding its index.
sl@0: 	@internalComponent
sl@0: 	@released
sl@0: */
sl@0: NONSHARABLE_STRUCT(CWsGraphicDrawerArray::XRemoveRollBack) :public  CWsGraphicDrawerArray::XRollBackBase
sl@0: 	{
sl@0: 	CWsGraphicDrawer* iDrawer;
sl@0: 	static void RollBackD(TAny* aSwapRollBack);
sl@0: 	};
sl@0: 
sl@0: /** Rolls back the deleting of a drawer from an array, but does not delete the replacing drawer.
sl@0: 	Re-inserts the recorded drawer by finding its index.
sl@0:  */
sl@0: void CWsGraphicDrawerArray::XRemoveRollBack::RollBackD(TAny* aRemoveRollBack)
sl@0: 	{
sl@0: 	__ASSERT_DEBUG(aRemoveRollBack,Panic(EWsGraphicDrawerPanicBadSwapLCCleanup));
sl@0: 	if(aRemoveRollBack)
sl@0: 		{
sl@0: 		XRemoveRollBack* rollBack = static_cast<XRemoveRollBack*>(aRemoveRollBack);
sl@0: 		// would be NULL if you removed an id that wasn't in the array in release builds
sl@0: 		// or if the swap itself Leaves
sl@0: 		if(rollBack->iArray) 
sl@0: 			{
sl@0: 			TGraphic graphic;
sl@0: 			graphic.iId = rollBack->iDrawer->Id();
sl@0: 			graphic.iDrawer = rollBack->iDrawer;
sl@0: 			TInt errCode= rollBack->iArray->iArray.InsertInOrder(graphic,GraphicDrawerCompare); // dups not allowed
sl@0: 			//This should not happen unless some non-transactional method has modified the array
sl@0: 			//between the call and the leave.
sl@0: 			__ASSERT_DEBUG(KErrAlreadyExists != errCode,Panic(EWsGraphicDrawerPanicBadSwapLCCleanup));
sl@0: 			//Other memory failure errors should not occur unless the array has been Compress()ed
sl@0: 			//between the call and the leave, and then memory fails.
sl@0: 			__ASSERT_DEBUG(KErrNone <= errCode,Panic(EWsGraphicDrawerPanicBadSwapLCCleanup));
sl@0: 			}
sl@0: 		delete rollBack;
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: // CWsGraphicDrawerArray \\\\\\\\\\\\\\\\\\\\\\\\
sl@0: 
sl@0: /** Compares two graphic array slots for id equality; the iDrawer pointer is ignored.
sl@0: 	Used to order the array.
sl@0: @internalComponent
sl@0: @released
sl@0: */
sl@0: TInt CWsGraphicDrawerArray::GraphicDrawerCompare(const TGraphic& aFirst,const TGraphic& aSecond)
sl@0: 	{
sl@0: 	return aFirst.iId.Compare(aSecond.iId);
sl@0: 	}
sl@0: 
sl@0: /** Adds a drawer to the array, with a transactional cleanup item that automatically removes
sl@0: 	it until popped (not destroying the drawer, however). This operation leaks memory and should not be used.
sl@0: 	@deprecated	 - Use AddL or AddRLC
sl@0: */
sl@0: EXPORT_C void CWsGraphicDrawerArray::AddLC(CWsGraphicDrawer* aDrawer)
sl@0: 	{
sl@0: 	__ASSERT_DEBUG(aDrawer,Panic(EWsGraphicDrawerPanicBadArgument));
sl@0: 	XAddRollBack* rollBack = new(ELeave) XAddRollBack;
sl@0: 	CleanupStack::PushL(TCleanupItem(XAddRollBack::RollBackD,rollBack));
sl@0: 	if(aDrawer)
sl@0: 		{
sl@0: 		User::LeaveIfError(Add(aDrawer));
sl@0: 		rollBack->iArray = this;
sl@0: 		rollBack->iId = aDrawer->Id();		
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: /** Adds a drawer to the array, with a transactional cleanup item that automatically removes
sl@0: 	it (not destroying the drawer, however).
sl@0: 	CommitP() must be called on the returned pointer to release resources owned by the cleanup item,
sl@0: 	unless a Leave occurs.
sl@0: 	@param 	 aDrawer	the drawer to add
sl@0: 	@return		cleanup record
sl@0: */
sl@0: EXPORT_C CWsGraphicDrawerArray::XRollBackBase* CWsGraphicDrawerArray::AddTLC(CWsGraphicDrawer* aDrawer)
sl@0: 	{
sl@0: 	if(!aDrawer)
sl@0: 		{
sl@0: 		User::Leave(KErrArgument);
sl@0: 		}
sl@0: 	//need to create the rollback before the add because the client can't tell the difference between 
sl@0: 	//the add failing and the new(ELeave) failing!
sl@0: 	XAddRollBack* rollBack = new(ELeave) XAddRollBack;
sl@0: 	CleanupStack::PushL(TCleanupItem(XAddRollBack::RollBackD,rollBack));
sl@0: 	User::LeaveIfError(Add(aDrawer));
sl@0: 	rollBack->iId = aDrawer->Id();		
sl@0: 	rollBack->iArray = this;
sl@0: 	
sl@0: 	return rollBack;
sl@0: 	}
sl@0: 
sl@0: /** Adds a drawer to the array. No cleanup - no leak 
sl@0: 	@param 	 aDrawer	the drawer to add
sl@0: 	@return		error code if the Add did not take place
sl@0: */
sl@0: EXPORT_C TInt CWsGraphicDrawerArray::Add(CWsGraphicDrawer* aDrawer)
sl@0: 	{
sl@0: 	if(aDrawer)
sl@0: 		{
sl@0: 		TGraphic graphic;
sl@0: 		graphic.iId = aDrawer->Id();
sl@0: 		graphic.iDrawer = aDrawer;
sl@0: 		return iArray.InsertInOrder(graphic,GraphicDrawerCompare); // dups not allowed
sl@0: 		}
sl@0: 	else
sl@0: 		return KErrArgument;
sl@0: 	}
sl@0: 
sl@0: /*Internal method to swap the given drawer into the array, removing the existing one and returning a pointer to it.
sl@0: 	Note that in an error just a NULL pointer is returned.
sl@0: 	Internal caller must infer KErrNotFound error code.
sl@0: 	@param 	 aDrawer	the drawer to add
sl@0: 	@return				the drawer displaced, or NULL if the operation did not take place
sl@0: */
sl@0: CWsGraphicDrawer* CWsGraphicDrawerArray::SwapIn(CWsGraphicDrawer* aDrawer)
sl@0: 	{
sl@0: 	if (aDrawer==NULL)
sl@0: 		return NULL;
sl@0: 	const TInt idx = IndexOf(aDrawer->Id());
sl@0: 	if (idx<KErrNone)
sl@0: 		return NULL;
sl@0: 	CWsGraphicDrawer* rv= iArray[idx].iDrawer;
sl@0: 	iArray[idx].iDrawer=aDrawer;
sl@0: 	return rv;
sl@0: 	}
sl@0: 
sl@0: /** Replaces the drawer with the existing Id with this newer one.  
sl@0: 	Pushes a transactional cleanup item to restore the previous drawer. 
sl@0: 	This operation leaks memory when it does not get Leave clean-up and should not be used.
sl@0: 	@deprecated	 - Use SwapL or SwapRLC
sl@0: */
sl@0: EXPORT_C TInt CWsGraphicDrawerArray::SwapLC(CWsGraphicDrawer* aDrawer)
sl@0: 	{
sl@0: 	__ASSERT_DEBUG(aDrawer,Panic(EWsGraphicDrawerPanicBadArgument));
sl@0: 	XSwapRollBack* rollBack = new(ELeave) XSwapRollBack;
sl@0: 	CleanupStack::PushL(TCleanupItem(XSwapRollBack::RollBackD,rollBack));
sl@0: 	CWsGraphicDrawer* rollBackDrawer=SwapIn(aDrawer);
sl@0: 	if (rollBackDrawer)
sl@0: 		{
sl@0: 		rollBack->iArray = this;
sl@0: 		rollBack->iDrawer = rollBackDrawer;
sl@0: 		return KErrNone;
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 		__ASSERT_DEBUG(0,Panic(EWsGraphicDrawerPanicBadArgument));
sl@0: 		return KErrNotFound;
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: /** Replaces the drawer with the existing Id with this newer one.  
sl@0: 	Pushes a transactional cleanup item to restore the previous drawer. 
sl@0: 	CommitP() must be called on the returned pointer to release resources owned by the cleanup item,
sl@0: 	unless a Leave occurs.
sl@0: 	@param 	 aDrawer	the drawer to add
sl@0: 	@return		cleanup record
sl@0: */
sl@0: EXPORT_C CWsGraphicDrawerArray::XRollBackBase* CWsGraphicDrawerArray::SwapTLC(CWsGraphicDrawer* aDrawer)
sl@0: 	{
sl@0: 	if (!aDrawer)
sl@0: 		User::Leave(KErrArgument);
sl@0: 	XSwapRollBack* rollBack = new(ELeave) XSwapRollBack;
sl@0: 	CleanupStack::PushL(TCleanupItem(XSwapRollBack::RollBackD,rollBack));
sl@0: 	CWsGraphicDrawer* rollBackDrawer=SwapIn(aDrawer);
sl@0: 	if (!rollBackDrawer)
sl@0: 		User::Leave(KErrNotFound);
sl@0: 	rollBack->iDrawer = rollBackDrawer;
sl@0: 	rollBack->iArray = this;
sl@0: 	return rollBack;
sl@0: 	}
sl@0: 
sl@0: /** Replaces the drawer with the existing Id with this newer one. No cleanup - no leak 
sl@0: 	@param 	 aDrawer	the drawer to add
sl@0: 	@return		error code if the Swap did not take place
sl@0: */
sl@0: EXPORT_C TInt CWsGraphicDrawerArray::Swap(CWsGraphicDrawer* aDrawer)
sl@0: 	{
sl@0: 	if (!aDrawer)
sl@0: 		return KErrArgument;
sl@0: 	CWsGraphicDrawer* oldDrawer=SwapIn(aDrawer);
sl@0: 	if (!oldDrawer)
sl@0: 		return KErrNotFound;
sl@0: 	else
sl@0: 		return KErrNone;
sl@0: 	}
sl@0: 	
sl@0: /**	Removes the cleanup record after a SwapTLC or AddTLC operation,
sl@0: 	removing the opportunity to back out of the operation.
sl@0: 	Note that SwapTLC, AddTLC, and RemoveTLC cleanup operations can be stacked and should be committed 
sl@0: 	in the opposite order. They cannot be safely intermingled with non-transactional operations.
sl@0: 	This method can be safely called with a NULL parameter indicating a failed operation.
sl@0: 	@param aRollBack	handle to rollback information that will be discarded.
sl@0: **/
sl@0: EXPORT_C void  CWsGraphicDrawerArray::CommitP(CWsGraphicDrawerArray::XRollBackBase* aRollBack)
sl@0: 	{
sl@0: 	if (aRollBack)
sl@0: 		{
sl@0: 		CleanupStack::Pop(aRollBack);
sl@0: 		delete aRollBack;
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: /** Removes the specified drawer from the array.
sl@0: 	Pushes a transactional cleanup item to restore the previous drawer.
sl@0: 	@note 	The array should not be Compressed() during the transaction period 
sl@0: 			to ensure that the RollBack operation will always succeed.
sl@0: 	@param aId the ID of the drawer to remove
sl@0: 	@return	cleanup record
sl@0: */
sl@0: EXPORT_C CWsGraphicDrawerArray::XRollBackBase*  CWsGraphicDrawerArray::RemoveTLC(const TGraphicDrawerId& aId)
sl@0: 	{
sl@0: 	XRemoveRollBack* rollBack = new(ELeave) XRemoveRollBack;
sl@0: 	CleanupStack::PushL(TCleanupItem(XRemoveRollBack::RollBackD,rollBack));
sl@0: 	const TInt idx = IndexOf(aId);
sl@0: 	if(0 > idx)
sl@0: 		{
sl@0: 		User::Leave(idx);
sl@0: 		}
sl@0: 	rollBack->iDrawer=iArray[idx].iDrawer;
sl@0: 	iArray.Remove(idx);
sl@0: 	rollBack->iArray=this;
sl@0: 	return rollBack;
sl@0: 	}
sl@0: 	
sl@0: /** Removes the specified drawer from the array
sl@0: 	@param aId the ID of the drawer to remove
sl@0: 	@return KErrNone if the drawer was removed, KErrNotFound if the drawer was not in the array
sl@0: */
sl@0: EXPORT_C TInt CWsGraphicDrawerArray::Remove(const TGraphicDrawerId& aId)
sl@0: 	{
sl@0: 	const TInt idx = IndexOf(aId);
sl@0: 	if(0 <= idx)
sl@0: 		{
sl@0: 		iArray.Remove(idx);
sl@0: 		return KErrNone;
sl@0: 		}
sl@0: 	return idx;
sl@0: 	}
sl@0: 	
sl@0: EXPORT_C TInt CWsGraphicDrawerArray::RemoveAndDestroy(const TGraphicDrawerId& aId)
sl@0: /** Removes and deletes the specified drawer from the array
sl@0: 	@param aId the ID of the drawer to remove and delete
sl@0: 	@return KErrNone if the drawer was removed and deleted, KErrNotFound if the drawer was not in the array
sl@0: */	{
sl@0: 	const TInt idx = IndexOf(aId);
sl@0: 	if(0 <= idx)
sl@0: 		{
sl@0: 		delete iArray[idx].iDrawer;
sl@0: 		iArray.Remove(idx);
sl@0: 		// coverity[extend_simple_error]
sl@0: 		return KErrNone;
sl@0: 		}
sl@0: 	return idx;
sl@0: 	}
sl@0: 
sl@0: /** Removes all drawers from the array which are owned by the specified client session
sl@0: 	@param aOwner the client session that owns the drawers to be removed
sl@0: 	@return the number of drawers that were removed
sl@0: */
sl@0: EXPORT_C TInt CWsGraphicDrawerArray::RemoveAll(const MWsClient& aOwner)
sl@0: 	{
sl@0: 	TInt removed = 0;
sl@0: 	TInt count = iArray.Count();
sl@0: 	TInt i = 0;
sl@0: 	while(i < count)
sl@0: 		{
sl@0: 		if(iArray[i].iDrawer && (&(iArray[i].iDrawer->Owner()) == &aOwner))
sl@0: 			{
sl@0: 			iArray.Remove(i);
sl@0: 			count--;
sl@0: 			removed++;
sl@0: 			}
sl@0: 		else
sl@0: 			{
sl@0: 			i++;
sl@0: 			}
sl@0: 		}
sl@0: 	return removed;
sl@0: 	}
sl@0: 
sl@0: /** Removes and deletes all drawers from the array which are owned by the specified client session
sl@0: 	@param aOwner the client session that owns the drawers to be removed and deleted
sl@0: 	@return the number of drawers that were removed and deleted
sl@0: */
sl@0: EXPORT_C TInt CWsGraphicDrawerArray::RemoveAndDestroyAll(const MWsClient& aOwner)
sl@0: 	{
sl@0: 	TInt removed = 0;
sl@0: 	TInt count = iArray.Count();
sl@0: 	TInt i = 0;
sl@0: 	while(i < count)
sl@0: 		{
sl@0: 		if(iArray[i].iDrawer && (&(iArray[i].iDrawer->Owner()) == &aOwner))
sl@0: 			{
sl@0: 			delete iArray[i].iDrawer;
sl@0: 			iArray.Remove(i);
sl@0: 			count--;
sl@0: 			removed++;
sl@0: 			}
sl@0: 		else
sl@0: 			{
sl@0: 			i++;
sl@0: 			}
sl@0: 		}
sl@0: 	// coverity[extend_simple_error]
sl@0: 	return removed;
sl@0: 	}
sl@0: 
sl@0: EXPORT_C const CWsGraphicDrawer* CWsGraphicDrawerArray::ResolveGraphic(const TGraphicDrawerId& aId) const
sl@0: /** Find a graphic by it's ID
sl@0: 	@param aId the ID of the graphic to find
sl@0: 	@return the drawer if it is in the array, else NULL
sl@0: */	{
sl@0: 	const TInt idx = IndexOf(aId);
sl@0: 	if(KErrNotFound != idx)
sl@0: 		{
sl@0: 		return iArray[idx].iDrawer;
sl@0: 		}
sl@0: 	return NULL;
sl@0: 	}
sl@0: 
sl@0: EXPORT_C void CWsGraphicDrawerArray::Close()
sl@0: /** Close the array, not destroying the drawers that it indexes
sl@0: */	{
sl@0: 	iArray.Close();
sl@0: 	}
sl@0: 
sl@0: EXPORT_C void CWsGraphicDrawerArray::ResetAndDestroy()
sl@0: /** Reset the array, destroying the drawers that it indexes.
sl@0: Only the 'owner' array should call this
sl@0: */	{
sl@0: 	const TInt count = iArray.Count();
sl@0: 	for(TInt i=0; i<count; i++)
sl@0: 		{
sl@0: 		delete iArray[i].iDrawer;
sl@0: 		}
sl@0: 	iArray.Reset();
sl@0: 	// coverity[extend_simple_error]
sl@0: 	}
sl@0: 	
sl@0: EXPORT_C TBool CWsGraphicDrawerArray::IsEmpty() const
sl@0: /** @return ETrue if the array contains no drawers
sl@0: */	{
sl@0: 	return !iArray.Count();
sl@0: 	}
sl@0: 	
sl@0: TInt CWsGraphicDrawerArray::IndexOf(const TGraphicDrawerId& aId) const
sl@0: /** @internalComponent
sl@0: */	{
sl@0: 	return iArray.FindInOrder(reinterpret_cast<const TGraphic&>(aId),GraphicDrawerCompare);
sl@0: 	}
sl@0: