diff -r 000000000000 -r 2f259fa3e83a lafagnosticuifoundation/cone/src/coecontrolarray.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lafagnosticuifoundation/cone/src/coecontrolarray.cpp Tue Feb 02 01:00:49 2010 +0200 @@ -0,0 +1,672 @@ +// Copyright (c) 2004-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 // class CCoeControlArray +#include // class CCoeControl +#include "coepanic.h" // Cone panic codes +#include // class EUser + +/** +Flags used internally. +*/ +enum TFlags + { + /** Controls are owned externally. This means that the destructor + shouldn't delete the individual controls. + */ + EControlsOwnedExternally = 0x01, + /** When the array is locked any attempt to add or remove elements will result in KErrLocked. + */ + EArrayLocked = 0x02 + }; + +LOCAL_C void CleanupComponentControl(TAny* aCleanupItem) + { + CCoeControl* control = reinterpret_cast(aCleanupItem); + if (control) + { + control->RemoveFromParent(); + delete control; + } + } + +LOCAL_C void CleanupExternallyOwnedComponentControl(TAny* aCleanupItem) + { + CCoeControl* control = reinterpret_cast(aCleanupItem); + if (control) + { + control->RemoveFromParent(); + } + } + +// +// class CCoeControlArray::TCursor +// + +/** Updates the cursor so that it points to the previous element in the array. +If the current element is the first one then this function does nothing and returns EFalse. + +@return EFalse if the current element was the first one in the array, ETrue if it wasn't and the function +actually did something. +*/ +EXPORT_C TBool CCoeControlArray::TCursor::Prev() + { + if(iIndex <= 0) + return EFalse; + + iIndex--; + UpdateMemento(); + return ETrue; + } + +/** Updates the cursor so that it points to the next element in the array. +If the current element is the last one then this function returns EFalse. + +@return EFalse if the current element was the last one in the array, ETrue otherwise +*/ +EXPORT_C TBool CCoeControlArray::TCursor::Next() + { + const TInt count = iArray->Count(); + if(iIndex >= count-1) //If last element or beyond move to just off the end of the array + { + iIndex = count; + iMemento = TCoeControlWithId(KCoeNoControlId); + return EFalse; + } + iIndex++; + UpdateMemento(); + return ETrue; + } + +/** Checks if the cursor is valid. Use this to replace the comparison with NULL that you would +do with pointers. This function is typically used on the cursors returned by the find operations. +@return ETrue if the cursor points to a control, EFalse otherwise +*/ +EXPORT_C TBool CCoeControlArray::TCursor::IsValid() const + { + UpdateIndex(); + return (iIndex != KErrNotFound); + } + +/** Checks if the cursors are equal. Cursors are equal if they point to the same control in the +same array else they are different. +@param aCursor The other cursor. +@return ETrue if the cursors point to the same position in the same array, EFalse +otherwise. +*/ +EXPORT_C TBool CCoeControlArray::TCursor::operator ==(const TCursor& aCursor) const + { + UpdateIndex(); + aCursor.UpdateIndex(); + + ASSERT(IsValid()); + ASSERT(aCursor.IsValid()); + + return (iIndex == aCursor.iIndex && iArray == aCursor.iArray); + } + +/** Checks if the cursors are different. Cursors are equal if they point to the same control in the +same array else they are different. +@param aCursor The other cursor. +@return EFalse if the cursors point to the same position in the same array, EFalse +otherwise. +*/ +EXPORT_C TBool CCoeControlArray::TCursor::operator !=(const TCursor& aCursor) const + { + UpdateIndex(); + aCursor.UpdateIndex(); + + ASSERT(IsValid()); + ASSERT(aCursor.IsValid()); + + return !(iIndex == aCursor.iIndex && iArray == aCursor.iArray); + } + +/** Constructor. +@param aArray The array +@param aIndex The index into the array +*/ +CCoeControlArray::TCursor::TCursor(const CCoeControlArray& aArray, TInt aIndex) : + iArray(&aArray), iIndex(aIndex), iMemento(KCoeNoControlId) + { + if(aIndex >= 0 && aIndex < aArray.Count()) + iMemento = TCoeControlWithId(aArray.At(aIndex)); + } + +/** Gets the index of the cursor. +@return The index i.e. the position in the array +*/ +TInt CCoeControlArray::TCursor::Index() const + { + UpdateIndex(); + return iIndex; + } + +/** Gets the control of the cursor. +@return The control. +*/ +EXPORT_C CCoeControl* CCoeControlArray::TCursor::Ctrl() const + { + UpdateIndex(); + if(iIndex == KErrNotFound || iIndex >= iArray->Count()) + return NULL; + else + return iArray->At(iIndex).iControl; + } + +/** This function is used by any operation that requires an update of the memento. +*/ +void CCoeControlArray::TCursor::UpdateMemento() const + { + if(iIndex >= 0 && iIndex < iArray->Count()) + iMemento = iArray->At(iIndex); + else + { + iIndex = KErrNotFound; + iMemento = TCoeControlWithId(KErrNotFound); + } + } + +/** This function is used by any operation that requires an update of the index. +*/ +void CCoeControlArray::TCursor::UpdateIndex() const + { + if(!iMemento.iControl) // If we don't know what control this cursor should point to + { + // This is either an invalid cursor (if iIndex == -1) + // or one that points to the element just beyond the end of the array (iIndex == iArray->Count()) + + // If the iIndex is pointing anywhere but at CCoeControlArray::End() it has gone bad + if(iIndex != KErrNotFound && iIndex != iArray->Count()) + { + iIndex = KErrNotFound; + iMemento = TCoeControlWithId(KErrNotFound); + } + + return; + } + + if(iIndex >= 0 && iIndex < iArray->Count()) // If the index is within the valid range + { + // Check that the control at iIndex is the same as the memento + + const TCoeControlWithId controlWithId = iArray->At(iIndex); + if(iMemento.iControl != controlWithId.iControl) // If not, update the index to match the memento + { + const TInt newIndex = iArray->Find(iMemento.iControl).iIndex; + if(newIndex != KErrNotFound) + iIndex = newIndex; + else + { + // If the memento control is no longer in the array, try update the memento instead + UpdateMemento(); + } + } + } + else + { + const TInt newIndex = iArray->Find(iMemento.iControl).iIndex; + if(newIndex != KErrNotFound) + iIndex = newIndex; + else + iMemento = TCoeControlWithId(KErrNotFound); + } + } + + +// +// class CCoeControlArray +// + +/** Creates a new CCoeControlArray. +@param aOwner The control that owns the new array +@return A new CCoeControlArray instance +*/ +EXPORT_C CCoeControlArray* CCoeControlArray::NewL(CCoeControl& aOwner) + { + CCoeControlArray* self = new (ELeave) CCoeControlArray(aOwner); + return self; + } + +/** Constructor. +*/ +TCoeControlWithId::TCoeControlWithId(TInt aControlId, CCoeControl* aControl) : iControl(aControl), iId(aControlId) + { + } + +/** The destructor will delete the controls in the array only if the EControlsOwnedExternally flag is not set. +*/ +EXPORT_C CCoeControlArray::~CCoeControlArray() + { + if(!ControlsOwnedExternally()) + ResetAndDestroy(); + + iControls.Close(); + } + +const TInt KControlArrayGranularity = 1; + +/** Constructor +@param aOwner The control that owns the new array +*/ +EXPORT_C CCoeControlArray::CCoeControlArray(CCoeControl& aOwner) + : iOwner(aOwner), iControls(KControlArrayGranularity, _FOFF(TCoeControlWithId, iId)) + { + } + +/** Gets the number of elements in the array. +@return The number of elements in the array +*/ +EXPORT_C TInt CCoeControlArray::Count() const + { + return iControls.Count(); + } + +/** Removes all the controls from the array but doesn't delete them. +*/ +EXPORT_C void CCoeControlArray::Reset() + { + iControls.Reset(); + } + +/** Removes all the controls from the array and deletes them. +*/ +EXPORT_C void CCoeControlArray::ResetAndDestroy() + { + for(TInt i = iControls.Count()-1; i >= 0; i--) // remove from the end, so we don't need to move any items + { + delete iControls[i].iControl; + // The array must be shrunk immediately to avoid Kern-Exec 3 when calling CCoeControl::Components() + // or CCoeControl::ComponentControl(TInt aIndex) inside MCoeFocusObserver::HandleDestructionOfFocusedItem + iControls.Remove(i); + } + + iControls.Reset(); + } + +/** Sorts the controls using their index as the key. +*/ +EXPORT_C void CCoeControlArray::SortById() + { + iControls.SortSigned(); + } + +/**This function provides a pluggable implementation to sort the array of controls. +@param aOrder The user defined static method which implements the algorithm for sorting. +*/ +EXPORT_C void CCoeControlArray::Sort(TLinearOrder< TCoeControlWithId > aOrder) + { + iControls.Sort(aOrder); + } +/** This function checks if the controls are owned by the array or not. If the controls are owned by the array they +will be deleted when the array is destroyed else they will not. + +@return ETrue if the array does NOT own the controls, EFalse if the array owns the controls. +*/ +EXPORT_C TBool CCoeControlArray::ControlsOwnedExternally() const + { + return (iFlags&EControlsOwnedExternally); + } + +/** Is used to set whether the array owns the controls or not. If the controls are owned by the array they +will be deleted when the array is destroyed else they will not. + +@param aOwnedExternally ETrue if the controls are owned externally, EFalse if +they are owned by the array. +*/ +EXPORT_C void CCoeControlArray::SetControlsOwnedExternally(TBool aOwnedExternally) + { + if(aOwnedExternally) + { + iFlags |= EControlsOwnedExternally; + } + else + { + iFlags &= ~EControlsOwnedExternally; + } + } + +/** Checks whether the array is locked or not. If an array is locked any attempt to add or remove controls +will fail with KErrLocked. + +@return ETrue if the array is locked, EFalse otherwise +*/ +EXPORT_C TBool CCoeControlArray::IsArrayLocked() const + { + return (iFlags&EArrayLocked); + } + +/** Locks the array. If an array is locked any attempt to add or remove controls +will fail with KErrLocked. +*/ +EXPORT_C void CCoeControlArray::SetArrayLocked() + { + iFlags |= EArrayLocked; + } + +/** Gets a cursor that points to the first element of the array. Note that if the array is empty +this is actually equivalent to a call to End(). + +@return A cursor that points to the first control in the array. +*/ +EXPORT_C CCoeControlArray::TCursor CCoeControlArray::Begin() const + { + return TCursor(*this, 0); + } + +/** Gets a cursor to the position right after the last element in the array. To get the last element +use Prev(). This cursor is useful as argument to the insertion function to add the new control at the end of the array. + +@return A cursor that points right after the last element +*/ +EXPORT_C CCoeControlArray::TCursor CCoeControlArray::End() const + { + return TCursor(*this, Count()); + } + +/** Gets a cursor to the control, if the control is found in the array. Use +the TCursor::IsValid function to check that the search found something or not. + +@param aControl The control to find. +@return A cursor to the control. This may be an invalid cursor if we didn't +find the requested control. Use TCursor::IsValid() to check if the cursor is valid. +*/ +EXPORT_C CCoeControlArray::TCursor CCoeControlArray::Find(const CCoeControl* aControl) const + { + const TInt numControls = iControls.Count(); + for(TInt index = 0; index < numControls; index++) + { + if(iControls[index].iControl == aControl) + return TCursor(*this, index); + } + + return TCursor(*this, KCoeNoControlId); + } + +/** Gets a cursor to the control, if the control with the given id is found in the array. +Use the TCusror::IsValid function to check that the search found something or not. + +@param aControlId The id of the control to find. +@return A cursor to the control. This may be an invalid cursor if we didn't +find the requested control. Use TCursor::IsValid() to check if the cursor is valid. +*/ +EXPORT_C CCoeControlArray::TCursor CCoeControlArray::Find(TInt aControlId) const + { + const TInt index = iControls.Find(TCoeControlWithId(aControlId)); + return TCursor(*this, index); + } + +/** Appends a control at the end of the array. + +@param aControl The control to add +@param aControlId The id for the new control +@return A cursor to the added control +*/ +EXPORT_C CCoeControlArray::TCursor CCoeControlArray::AppendLC(CCoeControl* aControl, TInt aControlId) + { + TCursor cursor = End(); + InsertLC(cursor, aControl, aControlId); + return cursor; + } + +/** Inserts a control after the control with the given id. + +Each array has an owner (an instance of the CCoeControl class) which is the container of all the child controls. +Each control has a parent and for the child controls this parent must be the container. This function will automatically +update the parent of aControl. + +The function will also result in the CCoeControl::HandleControlArrayEventL method being called +on the owner of the array. The event being generated is EControlAdded. + +@param aInsertAfterId The id of the control after which we want to insert the new control. If a control with this +id can't be found in the array the function will leave with KErrNotFound. +@param aControl The new control we want to add. +@param aControlId The id of the new control. +@return A cursor to the added control +@leave KErrLocked if the array has been locked using the CCoeControlArray::SetArrayLocked() function. +@leave KErrNotFound if the array doesn't contain a control identified by aInsertAfterId. +*/ +EXPORT_C CCoeControlArray::TCursor CCoeControlArray::InsertAfterLC(TInt aInsertAfterId, CCoeControl* aControl, TInt aControlId) + { + const TInt index = IndexById(aInsertAfterId); + if(index == KErrNotFound) + { + if(!(iFlags & EControlsOwnedExternally)) + delete aControl; + User::Leave(KErrNotFound); + } + TCursor cursor(*this, index); + cursor.Next(); // insert before the next item + return(InsertLC(cursor, aControl, aControlId)); + } + +/** Inserts a control at the given position. + +Each array has an owner (an instance of the CCoeControl class) which is the container of all the child controls. +Each control has a parent and for the child controls this parent must be the container. This function will automatically +update the parent of aControl. + +The function will also result in the CCoeControl::HandleControlArrayEventL method being called +on the owner of the array. The event being generated is EControlAdded. + +@param aInsertAt The position at which we want to insert the new control. +@param aControl The new control we want to add. +@param aControlId The id of the new control. +@return A cursor to the added control +@leave KErrLocked if the array has been locked using the CCoeControlArray::SetArrayLocked() function. +*/ +EXPORT_C CCoeControlArray::TCursor CCoeControlArray::InsertLC(TCursor& aInsertAt, CCoeControl* aControl, TInt aControlId) + { + __ASSERT_DEBUG(this, Panic(ECoePanicNonExistentArray)); + + const TBool externallyOwned = iFlags & EControlsOwnedExternally; + + // Set parent before pushing the CleanupComponenetControl, so that we can + // look for external ownership on parent if something leaves + const TInt err = aControl->SetParent(&iOwner); + if(err != KErrNone) + { + if(!externallyOwned) + delete aControl; + User::Leave(err); + } + + CleanupStack::PushL(TCleanupItem((externallyOwned ? + CleanupExternallyOwnedComponentControl : + CleanupComponentControl), + aControl)); + + if(IsArrayLocked()) + User::Leave(KErrLocked); + +#ifdef _DEBUG + __ASSERT_DEBUG(aControlId == KCoeNoControlId || + iControls.Find(TCoeControlWithId(aControlId)) == KErrNotFound, Panic(ECoePanicDuplicateControlId)); +#endif + + // To preserve the insertion order of controls without assigned ID + if(aControlId == KCoeNoControlId) // If the control has not been given an ID... + { + // ...loop through all controls and find the largest negative ID (i.e. the one closest to zero) + TInt autoId = KMinTInt32; + const TInt count = iControls.Count(); + for(TInt i = 0; i < count; i++) + { + const TInt controlId = iControls[i].iId; + if(controlId < 0 && autoId <= controlId) + { + autoId = controlId+1; + } + } + + aControlId = autoId; // Give the new control the next larger negative ID + } + + iControls.InsertL(TCoeControlWithId(aControlId, aControl), aInsertAt.Index()); + iOwner.HandleControlArrayEventL(EControlAdded, this, aControl, aControlId); + + const TCursor newItemCursor = aInsertAt; + aInsertAt.Next(); // Move the cursor forward to presserve its position in the array + + return newItemCursor; + } + +/** Removes a control but does NOT delete the control itself. The ownership of the control is +transferred to the caller. + +The function will also result in the CCoeControl::HandleControlArrayEventL method being called +on the owner of the array. The event being generated is EControlRemoved. + +@param aControl The control to remove +@return KErrNone if the control was removed successfully, KErrNotFound if the control could not be found. +*/ +EXPORT_C TInt CCoeControlArray::Remove(const CCoeControl* aControl) + { + for(TInt i = 0; i < iControls.Count(); i++) + { + const TCoeControlWithId controlWithId = iControls[i]; + if(controlWithId.iControl == aControl) + { + iControls.Remove(i); + // EControlRemoved event must never cause leave + TRAP_IGNORE(iOwner.HandleControlArrayEventL(EControlRemoved, this, controlWithId.iControl, controlWithId.iId)); + return KErrNone; + } + } + + return KErrNotFound; + } + +/** Removes a control but does NOT delete the control itself. The ownership of the control is +transferred to the caller. + +The function will also result in the CCoeControl::HandleControlArrayEventL method being called +on the owner of the array. The event being generated is EControlRemoved. + +@param aRemoveAt The position of the control to remove +@return A pointer to the control that has been removed. This can be used by the caller to delete the control. +*/ +EXPORT_C CCoeControl* CCoeControlArray::Remove(TCursor aRemoveAt) + { + const TCoeControlWithId controlWithId = iControls[aRemoveAt.Index()]; + iControls.Remove(aRemoveAt.Index()); + // EControlRemoved event must never cause leave + TRAP_IGNORE(iOwner.HandleControlArrayEventL(EControlRemoved, this, controlWithId.iControl, controlWithId.iId)); + + return controlWithId.iControl; + } + +/** Removes a control but does NOT delete the control itself. The ownership of the control is +transferred to the caller. + +The function will also result in the CCoeControl::HandleControlArrayEventL method being called +on the owner of the array. The event being generated is EControlRemoved. + +@param aControlId The id of the control to remove +@return A pointer to the control that has been removed. This can be used by the caller to delete the control. The function +returns NULL if no control with the given aControlId has been found. +*/ +EXPORT_C CCoeControl* CCoeControlArray::RemoveById(TInt aControlId) + { + const TInt index = IndexById(aControlId); + if(index != KErrNotFound) + { + const TCoeControlWithId controlWithId = iControls[index]; + iControls.Remove(index); + // EControlRemoved event must never cause leave + TRAP_IGNORE(iOwner.HandleControlArrayEventL(EControlRemoved, this, controlWithId.iControl, controlWithId.iId)); + return controlWithId.iControl; + } + + return NULL; + } + +/** Gets the element at the given index. +@param aIndex The index of the control +@return The control and its id +*/ +EXPORT_C TCoeControlWithId CCoeControlArray::At(TInt aIndex) + { + return iControls[aIndex]; + } + +/** Gets the element at the given index. +@param aIndex The index of the control +@return The control and its id +*/ +EXPORT_C const TCoeControlWithId CCoeControlArray::At(TInt aIndex) const + { + return iControls[aIndex]; + } + +/** Gets the id of the control. +@param aControl The control +@return The id of the control or KErrNotFound if the control can't be found. +*/ +EXPORT_C TInt CCoeControlArray::Id(const CCoeControl& aControl) const + { + for(TInt i = 0; i < iControls.Count(); i++) + { + if(iControls[i].iControl == &aControl) + return iControls[i].iId; + } + + return KErrNotFound; + } + +/** Replaces a control in the array with another control. + +@param aOriginalControl The control that must be replaced +@param aNewControl The new control +@return A standard error code +*/ +EXPORT_C TInt CCoeControlArray::Replace(CCoeControl* aOriginalControl, CCoeControl* aNewControl) + { + __ASSERT_DEBUG(this, Panic(ECoePanicNonExistentArray)); + for(TInt i = 0; i < iControls.Count(); i++) + { + if(iControls[i].iControl == aOriginalControl) + { + iControls[i].iControl = aNewControl; + return KErrNone; + } + } + + return KErrNotFound; + } + +/** Gets the control with the given id or NULL if there is no control with the given id. +@param aControlId The id of the control +@return The control with the given id or null. +*/ +EXPORT_C CCoeControl* CCoeControlArray::CtrlById(TInt aControlId) const + { + const TInt index = IndexById(aControlId); + return (index != KErrNotFound ? iControls[index].iControl : NULL); + } + +/** Gets the index of the control with the given id or KErrNotFound if there is no control that has +that id. +@param aControlId The id of the control +@return The index of the control with the given id or KErrNotFound. +*/ +TInt CCoeControlArray::IndexById(TInt aControlId) const + { + if(aControlId == KErrNotFound) + return KErrNotFound; + + const TInt index = iControls.Find(TCoeControlWithId(aControlId)); + return index; + }