diff -r 000000000000 -r 2f259fa3e83a uifw/AvKon/aknhlist/src/akntree.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uifw/AvKon/aknhlist/src/akntree.cpp Tue Feb 02 01:00:49 2010 +0200 @@ -0,0 +1,1463 @@ +/* +* Copyright (c) 2006, 2007 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: Implementation for CAknTree class. +* +*/ + + + +#include +#include +#include +#include +#include + +#include "akntree.h" +#include "akntreelist.h" +#include "akntreeordering.h" +#include "aknhlistlib.h" +#include "akntreeiterator.h" +#include "akntreelisticon.h" +#include "akncustomtreeordering.h" +#include "akntreelistinternalconstants.h" + +const TInt KObserverArrayGranularity = 1; + +// Tree flag definitions +enum TAknTreeFlags + { + ETabModeFunctionIndicators + }; + + +// ======== MEMBER FUNCTIONS ======== + +// --------------------------------------------------------------------------- +// Two-phased constructor. +// --------------------------------------------------------------------------- +// +CAknTree* CAknTree::NewL( CAknTreeList& aList, CAknTreeOrdering* aOrdering ) + { + CAknTree* self = new( ELeave ) CAknTree( aList, aOrdering ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + + +// --------------------------------------------------------------------------- +// Destructor. +// --------------------------------------------------------------------------- +// +CAknTree::~CAknTree() + { + delete iOrdering; iOrdering = NULL; + iCustomOrdering = NULL; + iObservers.Close(); + iItems.Close(); + iIcons.ResetAndDestroy(); + delete iMarquee; iMarquee = NULL; + iMarqueeItem = NULL; + } + + +// --------------------------------------------------------------------------- +// Id for the given item. +// --------------------------------------------------------------------------- +// +TAknTreeItemID CAknTree::Id( const CAknTreeItem* aItem ) const + { + if ( aItem == this ) + { + return KAknTreeIIDRoot; + } + else + { + return reinterpret_cast( aItem ); + } + } + + +// --------------------------------------------------------------------------- +// Sets ordering for tree items. Previously set ordering is deleted and +// customized ordering interface discarded. +// --------------------------------------------------------------------------- +// +void CAknTree::SetOrdering( CAknTreeOrdering* aOrdering, TBool aDrawNow ) + { + delete iOrdering; + iOrdering = aOrdering; + + iCustomOrdering = NULL; + + Sort( aDrawNow ); + } + + +// --------------------------------------------------------------------------- +// Sets custom ordering for tree items. +// --------------------------------------------------------------------------- +// +void CAknTree::SetCustomOrdering( MAknCustomTreeOrdering* aOrdering, + TBool aDrawNow ) + { + iCustomOrdering = aOrdering; + + delete iOrdering; + iOrdering = NULL; + + Sort( aDrawNow ); + } + + +// --------------------------------------------------------------------------- +// Sorts the specified tree node. +// --------------------------------------------------------------------------- +// +void CAknTree::Sort( TAknTreeItemID aNode, TBool aSortDescendants, + TBool aDrawNow ) + { + // The sorting can be done only when ordering is set for the tree. + if ( iCustomOrdering || iOrdering ) + { + CAknTreeNode* node = Node( aNode ); + node->Sort(); + if ( aSortDescendants ) + { + // Iterate through the descendants of the node and sort + // each descendant node separately. + TAknTreeIterator iterator( node, NULL ); + while ( iterator.HasNext() ) + { + node = iterator.Next()->Node(); + if ( node ) + { + node->Sort(); + } + } + } + } + + NotifyObservers( MAknTreeObserver::ETreeSorted, this, aDrawNow ); + } + + +// --------------------------------------------------------------------------- +// Compares two tree list items. +// --------------------------------------------------------------------------- +// +TInt CAknTree::Compare( const CAknTreeItem& aFirst, + const CAknTreeItem& aSecond ) const + { + TInt value = NULL; + if ( iCustomOrdering ) + { + value = iCustomOrdering->Compare( Id( &aFirst ), Id( &aSecond ) ); + } + else if ( iOrdering ) + { + value = iOrdering->Compare( aFirst, aSecond ); + } + else + { + TInt first = KMaxTInt; + TInt second = KMaxTInt; + if ( aFirst.Parent() ) + { + first = aFirst.Parent()->Index( &aFirst ); + } + if ( aSecond.Parent() ) + { + second = aSecond.Parent()->Index( &aSecond ); + } + value = first - second; + } + return value; + } + + +// --------------------------------------------------------------------------- +// Returns the number of items in the tree. +// --------------------------------------------------------------------------- +// +TInt CAknTree::ItemCount() const + { + return iItems.Count(); + } + + +// --------------------------------------------------------------------------- +// Returns the number of visible items in the tree. +// --------------------------------------------------------------------------- +// +TInt CAknTree::VisibleItemCount() const + { + return VisibleDescendantCount(); + } + + +// --------------------------------------------------------------------------- +// Returns the index of specified item. The index equals to the number of +// tree items in the tree structure before the specified item. +// The value KErrNotFound is returned, if the specified item is not found, +// and this applies also to the root node. +// --------------------------------------------------------------------------- +// +TInt CAknTree::ItemIndex( const CAknTreeItem* aItem ) const + { + TInt count = KErrNotFound; // ( -1 ) + if ( iItems.FindInAddressOrder( aItem ) >= 0 ) + { + const CAknTreeItem* item = aItem; + const CAknTreeNode* parent = item->Parent(); + while ( parent ) + { + // Add the number of descendants of each sibling preceeding the + // item to the count. + const TInt index = parent->Index( item ); + __ASSERT_DEBUG( index >= 0, User::Invariant() ); + for ( TInt ii = 0; ii < index; ++ii ) + { + const CAknTreeNode* node = parent->Child( ii )->Node(); + if ( node ) + { + count += node->DescendantCount(); + } + } + + // Add the item and its preceeding siblings to the count. + count += index + 1; + + item = parent; + parent = item->Parent(); + } + } + return count; + } + + +// --------------------------------------------------------------------------- +// Similar to ItemIndex, but returns the index from subset of items that +// belong to expanded part of the tree. +// --------------------------------------------------------------------------- +// +TInt CAknTree::VisibleItemIndex( const CAknTreeItem* aItem ) const + { + TInt count = KErrNotFound; // ( -1 ) + if ( iItems.FindInAddressOrder( aItem ) >= 0 ) + { + const CAknTreeItem* item = aItem; + const CAknTreeNode* parent = item->Parent(); + while ( parent ) + { + if ( !parent->IsExpanded() ) + { + return KErrNotFound; + } + + // Add the number of visible descentants of each sibling preceeding + // the item to the count. + const TInt index = parent->Index( item ); + __ASSERT_DEBUG( index >= 0, User::Invariant() ); + for ( TInt ii = 0; ii < index; ++ii ) + { + const CAknTreeNode* node = parent->Child( ii )->Node(); + if ( node ) + { + count += node->VisibleDescendantCount(); + } + } + + // Add the item and its preceeding siblings to the count. + count += index + 1; + + // All ancestors of specified item has to be expanded in order to + // the item to be in expanded tree structure. + if ( parent->IsExpanded() ) + { + item = parent; + parent = item->Parent(); + } + else + { + // Specified item is not visible, KErrNotFound returned. + parent = NULL; + count = KErrNotFound; + } + } + } + return count; + } + + +// --------------------------------------------------------------------------- +// Returns the tree item at the specified index of the expanded tree. +// --------------------------------------------------------------------------- +// +CAknTreeItem* CAknTree::VisibleItem( TInt aIndex ) const + { + if ( aIndex < 0 || aIndex >= iItems.Count() ) + { + return NULL; + } + + TAknTreeIterator iterator = Iterator(); + while( aIndex && iterator.HasNext() ) + { + iterator.Next(); + --aIndex; + } + + return iterator.Next(); + } + + +// --------------------------------------------------------------------------- +// Returns the depth of the tree. Iterates through the whole tree structure. +// --------------------------------------------------------------------------- +// +TInt CAknTree::Depth() const + { + TAknTreeIterator iterator = Iterator(); + TInt depth = 0; + while ( iterator.HasNext() ) + { + CAknTreeItem* item = iterator.Next(); + depth = Max( depth, item->Level() ); + } + return depth; + } + + +// --------------------------------------------------------------------------- +// Finds the specified item from the sorted array of tree items. The constants +// KAknTreeIIDRoot and KAknTreeIIDNone are handled as special cases. +// +// Note: Recently used items could be cached somehow to eliminate the need to +// lookup them from the table when consecutive calls refer to the same items, +// for example, when adding several items to the same node. +// --------------------------------------------------------------------------- +// +TInt CAknTree::GetItem( TAknTreeItemID aItemId, CAknTreeItem*& aItem ) const + { + TInt error = KErrNone; + if ( aItemId == KAknTreeIIDRoot ) + { + aItem = const_cast( this ); + } + else if ( aItemId == KAknTreeIIDNone ) + { + error = KErrNotFound; + } + else + { + TInt index = iItems.FindInAddressOrder( + reinterpret_cast( aItemId ) ); + if ( index == KErrNotFound ) + { + error = KErrNotFound; + } + else + { + aItem = iItems[index]; + } + } + return error; + } + + +// --------------------------------------------------------------------------- +// Retrieves an item from the tree structure. Panics if the item is not found. +// --------------------------------------------------------------------------- +// +CAknTreeItem* CAknTree::Item( TAknTreeItemID aItemId ) const + { + CAknTreeItem* item = NULL; + TInt error = GetItem( aItemId, item ); + __ASSERT_ALWAYS( item && !error, Panic( EAknHListPanicInvalidItemID ) ); + return item; + } + + +// --------------------------------------------------------------------------- +// Retrieves a node from the tree structure. Panics if the node is not found, +// or if the specified item is not a node. +// --------------------------------------------------------------------------- +// +CAknTreeNode* CAknTree::Node( TAknTreeItemID aNodeId ) const + { + CAknTreeNode* node = Item( aNodeId )->Node(); + __ASSERT_ALWAYS( node, Panic( EAknHListPanicInvalidItemType ) ); + return node; + } + + +// --------------------------------------------------------------------------- +// Adds an item to the tree structure. +// --------------------------------------------------------------------------- +// +TAknTreeItemID CAknTree::AddItemL( CAknTreeItem* aItem, + TAknTreeItemID aParent, TBool aDrawNow ) + { + __ASSERT_DEBUG( aItem, User::Invariant() ); + + // Add item to the specified parent node. + CAknTreeNode* parent = Node( aParent ); + + if ( iOrdering ) + { + // Let ordering determine the position of the new child. + parent->AddChildL( aItem ); + } + else + { + // Append to the end, as custom ordering cannot be used to determine + // the correct position when inserting new items to the tree. + parent->AddChildL( aItem, parent->ChildCount() ); + } + + // Store pointer also in lookup table. + TInt error = iItems.InsertInAddressOrder( aItem ); + if ( error ) + { + parent->RemoveChild( aItem ); + User::Leave( error ); + } + + aItem->SetParent( parent ); + + NotifyObservers( MAknTreeObserver::EItemAdded, aItem, aDrawNow ); + + return Id( aItem ); + } + + +// --------------------------------------------------------------------------- +// Moves the specified item to specified target node. The method has to make +// sure that the target node is not a descendant of the moved item in order +// to keep the tree structure intact. +// --------------------------------------------------------------------------- +// +void CAknTree::MoveItemL( TAknTreeItemID aItem, TAknTreeItemID aTargetNode, + TBool aDrawNow ) + { + CAknTreeItem* item = Item( aItem ); + CAknTreeNode* targetNode = Node( aTargetNode ); + + // The current parent of the moved item. + CAknTreeNode* parent = item->Parent(); + + // Move is necessary only when target node differs from current node. + if ( targetNode != parent ) + { + // Check that the moved item is neither the target node nor an ancestor + // of target node. This should also ensure that the root is not moved. + CAknTreeNode* ancestor = targetNode; + while ( ancestor ) + { + if ( ancestor == item ) + { + User::Leave( KErrArgument ); + } + ancestor = ancestor->Parent(); + } + + // Move the item to the target node. + targetNode->AddChildL( item ); + item->SetParent( targetNode ); + if ( parent ) + { + parent->RemoveChild( item ); + } + + NotifyObservers( MAknTreeObserver::EItemMoved, item, aDrawNow ); + } + } + + +// --------------------------------------------------------------------------- +// Removes an item from the tree structure. If the specified item is not +// found, method is paniced with panic code EAknHListPanicInvalidItemID. +// +// When removed item is a node with descendants, the node and its descendants +// are removed from the list separately and each removal is also reported +// separately to the observers. +// +// Note: Observers are notified of the removal before the item is actually +// removed from the tree and deleted, so that the observers can still query +// the item's position in the tree. +// --------------------------------------------------------------------------- +// +void CAknTree::RemoveItem( TAknTreeItemID aItem, TBool aDrawNow ) + { + // Get the item from the array. + CAknTreeItem* item = Item( aItem ); + + TBool drawNow( EFalse ); + + // Remove from array and delete the descendants of node non-recursively. + if ( item->IsNode() ) + { + TAknTreeIterator iterator = Iterator( item->Node(), NULL ); + CAknTreeItem* current = iterator.Last(); + iterator.SetCurrent( current ); + while ( current ) + { + CAknTreeItem* previous = iterator.Previous(); + if ( previous == NULL) + { + drawNow = aDrawNow; + } + + // Notify tree observers of removal before the item is removed. + NotifyObservers( MAknTreeObserver::EItemRemoveBegin, current, EFalse ); + + // Remove item from the table. + TInt index = iItems.FindInAddressOrder( current ); + __ASSERT_DEBUG( index >= 0, User::Invariant() ); + iItems.Remove( index ); + + // Remove item from its parent node. + CAknTreeNode* parent = current->Parent(); + __ASSERT_DEBUG( parent, User::Invariant() ); + parent->RemoveChild( current ); + current->SetParent( NULL ); + + __ASSERT_DEBUG( current->IsLeaf() || + current->Node()->ChildCount() == 0, User::Invariant() ); + + // Notify tree observers when the item has been removed. + NotifyObservers( MAknTreeObserver::EItemRemoveEnd, current, drawNow ); + + // Notify also tree list observers of removal. + iList.NotifyObservers( MAknTreeListObserver::EItemRemoved, + Id( current ) ); + + delete current; + current = previous; + } + } + + // Remove the specified item, unless it is the root node. + if ( item != this ) + { + // Notify tree observers before removing the item. + NotifyObservers( MAknTreeObserver::EItemRemoveBegin, item, EFalse ); + + // Remove the item from array and from the tree and delete it. + TInt index = iItems.FindInAddressOrder( item ); + __ASSERT_DEBUG( index >= 0, User::Invariant() ); + iItems.Remove( index ); + + CAknTreeNode* parent = item->Parent(); + __ASSERT_DEBUG( parent, User::Invariant() ); + parent->RemoveChild( item ); + item->SetParent( NULL ); + + __ASSERT_DEBUG( item->IsLeaf() || item->Node()->ChildCount() == 0, + User::Invariant() ); + + // Notify tree observers after the item has been removed. + NotifyObservers( MAknTreeObserver::EItemRemoveEnd, item, aDrawNow ); + + // Notify also tree list observers of removal. + iList.NotifyObservers( MAknTreeListObserver::EItemRemoved, + Id( item ) ); + + delete item; + } + } + + +// --------------------------------------------------------------------------- +// Expands the specified node. +// --------------------------------------------------------------------------- +// +void CAknTree::ExpandNode( TAknTreeItemID aNode, TBool aDrawNow ) + { + CAknTreeNode* node = Node( aNode ); + DoExpandNode( node, aDrawNow ); + } + + +// --------------------------------------------------------------------------- +// Collapses the specified node and removes the children from collapsed node +// that are not set perisitent or do not contain any persistent descendants. +// --------------------------------------------------------------------------- +// +void CAknTree::CollapseNode( TAknTreeItemID aNode, TBool aDrawNow ) + { + CAknTreeNode* node = Node( aNode ); + + node->Collapse(); + iList.NotifyObservers( MAknTreeListObserver::ENodeCollapsed, aNode ); + NotifyObservers( MAknTreeObserver::ENodeCollapsed, node, aDrawNow ); + + if ( aNode != KAknTreeIIDRoot ) + { + // Remove all the children from the node that are not persistent or + // marked and do not contain any persistent or marked descendants. + for ( TInt ii = node->ChildCount() - 1; ii >= 0; --ii ) + { + CAknTreeItem* item = node->Child( ii ); + __ASSERT_DEBUG( item, User::Invariant() ); + if ( item->IsRemovableFromCollapsedNode() ) + { + RemoveItem( Id( item ), EFalse ); + } + } + } + } + + +// --------------------------------------------------------------------------- +// Checks whether the specified node is expanded. +// --------------------------------------------------------------------------- +// +TBool CAknTree::IsExpanded( TAknTreeItemID aNode ) const + { + return Node( aNode )->IsExpanded(); + } + + +// --------------------------------------------------------------------------- +// Returns the child count for the specified node. +// --------------------------------------------------------------------------- +// +TInt CAknTree::ChildCount( TAknTreeItemID aNode ) const + { + return Node( aNode )->ChildCount(); + } + + +// --------------------------------------------------------------------------- +// Returns the item ID of specified child for a tree node. +// --------------------------------------------------------------------------- +// +TAknTreeItemID CAknTree::Child( TAknTreeItemID aNode, TInt aIndex ) const + { + return Id( Node( aNode )->Child( aIndex ) ); + } + + +// --------------------------------------------------------------------------- +// Returns the item ID of a parent of specified item. +// --------------------------------------------------------------------------- +// +TAknTreeItemID CAknTree::Parent( TAknTreeItemID aItem ) const + { + return Id( Item( aItem )->Parent() ); + } + + +// --------------------------------------------------------------------------- +// Adds a tree observer. +// --------------------------------------------------------------------------- +// +void CAknTree::AddObserverL( MAknTreeObserver* aObserver ) + { + iObservers.InsertInAddressOrderL( aObserver ); + } + + +// --------------------------------------------------------------------------- +// Removes a tree observer. +// --------------------------------------------------------------------------- +// +TInt CAknTree::RemoveObserver( MAknTreeObserver* aObserver ) + { + TInt index = iObservers.FindInAddressOrder( aObserver ); + if ( index != KErrNotFound ) + { + iObservers.Remove( index ); + return KErrNone; + } + else + { + return KErrNotFound; + } + } + + +// --------------------------------------------------------------------------- +// Checks whether the specified item is marked. +// --------------------------------------------------------------------------- +// +TBool CAknTree::IsMarked( TAknTreeItemID aItem ) const + { + return Item( aItem )->IsMarked(); + } + + +// --------------------------------------------------------------------------- +// Sets the specified item marked or unmarked. +// --------------------------------------------------------------------------- +// +void CAknTree::SetMarked( TAknTreeItemID aItem, TBool aMarked, TBool aDrawNow ) + { + CAknTreeItem* item = Item( aItem ); + if ( item->IsMarkable() ) + { + if ( item->IsNode() ) + { + // When specified item is a node, the same marking is set to + // every descendant as well. + TAknTreeIterator iterator = Iterator( item->Node(), NULL ); + while ( iterator.HasNext() ) + { + iterator.Next()->SetMarked( aMarked ); + } + } + + item->SetMarked( aMarked ); + + if ( aMarked == EFalse) + { + CAknTreeNode* parent = item->Parent(); + if ( parent && parent->IsNode() && parent->IsMarkable() && parent->IsMarked() ) + { + TAknTreeIterator iterator = Iterator( parent->Node(), NULL ); + TBool marked = EFalse; + + while ( iterator.HasNext() ) + { + CAknTreeItem* item = iterator.Next(); + if ( item->IsMarkable() && item->IsMarked() ) + { + marked = ETrue; + break; + } + } + // all items under the parent are unmarked, unmark parent + if ( !marked ) + { + parent->SetMarked( EFalse ); + } + + } + + } + + iList.NotifyObservers( aMarked ? MAknTreeListObserver::EItemMarked : + MAknTreeListObserver::EItemUnmarked, Id( item ) ); + NotifyObservers( MAknTreeObserver::EItemModified, item, aDrawNow ); + } + } + + +// --------------------------------------------------------------------------- +// Enables/disables marking for specified list item. +// --------------------------------------------------------------------------- +// +void CAknTree::EnableMarking( TAknTreeItemID aItem, TBool aEnable ) + { + CAknTreeItem* item = Item( aItem ); + item->SetMarkable( aEnable ); + } + + +// --------------------------------------------------------------------------- +// Gets all the marked items from the specified node to the given array. +// --------------------------------------------------------------------------- +// +void CAknTree::GetMarkedItemsL( TAknTreeItemID aNode, + RArray& aMarkedItems ) const + { + aMarkedItems.Reset(); + if ( aNode == KAknTreeIIDRoot ) + { + // Get marked items from the tree by iterating through array. + CAknTreeItem* item = NULL; + const TInt count = iItems.Count(); + for ( TInt ii = 0; ii < count; ++ii ) + { + item = iItems[ii]; + __ASSERT_DEBUG( item, User::Invariant() ); + if ( item->IsMarked() ) + { + aMarkedItems.AppendL( Id( item ) ); + } + } + } + else + { + // Get marked items only from the specified node with iterator. + TAknTreeIterator iterator( Node( aNode ), NULL ); + CAknTreeItem* item = NULL; + while ( iterator.HasNext() ) + { + item = iterator.Next(); + __ASSERT_DEBUG( item, User::Invariant() ); + if ( item->IsMarked() ) + { + aMarkedItems.AppendL( Id( item ) ); + } + } + } + } + + +// --------------------------------------------------------------------------- +// Checks whether the specified node is empty. +// --------------------------------------------------------------------------- +// +TBool CAknTree::IsEmpty( TAknTreeItemID aNode ) const + { + return Node( aNode )->IsEmpty(); + } + + +// --------------------------------------------------------------------------- +// Sets whether the node appears as non-empty when it is empty. +// --------------------------------------------------------------------------- +// +void CAknTree::SetNonEmpty( TAknTreeItemID aNode, TBool aNonEmpty, + TBool aDrawNow ) + { + CAknTreeNode* node = Node( aNode ); + node->SetNonEmpty( aNonEmpty ); + NotifyObservers( MAknTreeObserver::EItemModified, node, aDrawNow ); + } + + +// --------------------------------------------------------------------------- +// Checks whether the specified item is persistent. +// --------------------------------------------------------------------------- +// +TBool CAknTree::IsPersistent( TAknTreeItemID aItem ) const + { + return Item( aItem )->IsPersistent(); + } + + +// --------------------------------------------------------------------------- +// Sets the specified item persistent or non-persistent. +// --------------------------------------------------------------------------- +// +void CAknTree::SetPersistent( TAknTreeItemID aItem, TBool aPersistent ) + { + Item( aItem )->SetPersistent( aPersistent ); + } + + +// --------------------------------------------------------------------------- +// Returns iterator for the expanded tree structure. +// --------------------------------------------------------------------------- +// +TAknTreeIterator CAknTree::Iterator() const + { + return TAknTreeIterator( const_cast( this ), + KAknSkipCollapsedNodeContents ); + } + + +// --------------------------------------------------------------------------- +// Returns iterator for the specified node. +// --------------------------------------------------------------------------- +// +TAknTreeIterator CAknTree::Iterator( CAknTreeNode* aNode, TUint aFlags ) const + { + return TAknTreeIterator( aNode, aFlags ); + } + + +// --------------------------------------------------------------------------- +// Notifies the observers that an item in the tree has been modified. +// --------------------------------------------------------------------------- +// +void CAknTree::ItemModified( CAknTreeItem* aItem ) + { + NotifyObservers( MAknTreeObserver::EItemModified, aItem, ETrue ); + } + + +// --------------------------------------------------------------------------- +// Adds an icon to the tree and returns the index of created icon. +// --------------------------------------------------------------------------- +// +TInt CAknTree::AddIconL( const TAknsItemID& aId, const TDesC& aFilename, + TInt aBitmapId, TInt aMaskId, TScaleMode aScaleMode ) + { + TInt newIconId = AvailableIconId(); + CAknTreeListIcon* icon = CAknTreeListIcon::NewLC( newIconId, aId, + aFilename, aBitmapId, aMaskId, aScaleMode ); + AddIconL( icon ); + CleanupStack::Pop( icon ); + return newIconId; + } + + +// --------------------------------------------------------------------------- +// Adds an icon to the tree and returns the index of created icon. +// --------------------------------------------------------------------------- +// +TInt CAknTree::AddIconL( CFbsBitmap* aIcon, CFbsBitmap* aMask, + TBool aTransferOwnership, TScaleMode aScaleMode ) + { + TInt newIconId = AvailableIconId(); + CAknTreeListIcon* icon = CAknTreeListIcon::NewLC( newIconId, aIcon, aMask, + aTransferOwnership, aScaleMode ); + AddIconL( icon ); + CleanupStack::Pop( icon ); + return newIconId; + } + + +// --------------------------------------------------------------------------- +// Adds colored icon to the tree. +// --------------------------------------------------------------------------- +// +TInt CAknTree::AddColorIconL( const TAknsItemID& aId, + const TAknsItemID& aColorId, TInt aColorIndex, const TDesC& aFilename, + TInt aBitmapId, TInt aMaskId, TRgb aDefaultColor, TScaleMode aScaleMode ) + { + TInt newIconId = AvailableIconId(); + CAknTreeListIcon* icon = CAknTreeListIcon::NewLC( newIconId, aId, + aColorId, aColorIndex, aFilename, aBitmapId, aMaskId, aDefaultColor, + aScaleMode ); + AddIconL( icon ); + CleanupStack::Pop( icon ); + return newIconId; + } + + +// --------------------------------------------------------------------------- +// Sets icon for specified ID. +// --------------------------------------------------------------------------- +// +void CAknTree::SetIconL( TInt aIconId, const TAknsItemID& aId, + const TDesC& aFilename, TInt aBitmapId, TInt aMaskId, + TScaleMode aScaleMode ) + { + CAknTreeListIcon* icon = CAknTreeListIcon::NewLC( aIconId, aId, aFilename, + aBitmapId, aMaskId, aScaleMode ); + AddIconL( icon ); + CleanupStack::Pop( icon ); + } + + +void CAknTree::SetIconL( TInt aIconId, CFbsBitmap* aIcon, CFbsBitmap* aMask, + TBool aTransferOwnership, TScaleMode aScaleMode ) + { + CAknTreeListIcon* icon = CAknTreeListIcon::NewLC( aIconId, aIcon, aMask, + aTransferOwnership, aScaleMode ); + AddIconL( icon ); + CleanupStack::Pop( icon ); + } + + +// --------------------------------------------------------------------------- +// Sets color icon for specified ID. +// --------------------------------------------------------------------------- +// +void CAknTree::SetColorIconL( TInt aIconId, const TAknsItemID& aId, + const TAknsItemID& aColorId, TInt aColorIndex, const TDesC& aFilename, + TInt aBitmapId, TInt aMaskId, TRgb aDefaultColor, TScaleMode aScaleMode ) + { + CAknTreeListIcon* icon = CAknTreeListIcon::NewLC( aIconId, aId, aColorId, + aColorIndex, aFilename, aBitmapId, aMaskId, aDefaultColor, + aScaleMode ); + AddIconL( icon ); + CleanupStack::Pop( icon ); + } + + +// --------------------------------------------------------------------------- +// Removes previously added icon from the tree. +// --------------------------------------------------------------------------- +// +void CAknTree::RemoveIconL( TInt aIconId ) + { + // Pre-defined icons constructed by the tree cannot be removed. + if ( aIconId <= EPreDefinedIconIdRange ) + { + User::Leave( KErrArgument ); + } + + TInt index = iIcons.FindInOrder( aIconId, CAknTreeListIcon::CompareId ); + if ( index != KErrNotFound ) + { + delete iIcons[index]; + iIcons.Remove( index ); + } + } + + +// --------------------------------------------------------------------------- +// Returns pointer to the requested icon. +// --------------------------------------------------------------------------- +// +CAknTreeListIcon* CAknTree::Icon( TInt aIconId ) const + { + CAknTreeListIcon* icon = NULL; + TInt index = iIcons.FindInOrder( aIconId, CAknTreeListIcon::CompareId ); + if ( index >= NULL ) + { + icon = iIcons[index]; + } + return icon; + } + + +// --------------------------------------------------------------------------- +// Draws the specified icon. +// --------------------------------------------------------------------------- +// +TInt CAknTree::DrawIcon( TInt aIconId, const TSize& aSize, CWindowGc& aGc, + const TPoint& aPoint, const TRect& aSourceRect ) + { + TInt value = KErrNotFound; + CAknTreeListIcon* icon = Icon( aIconId ); + if ( icon && icon->Bitmap() ) + { + icon->SetSize( aSize ); + aGc.BitBltMasked( aPoint, icon->Bitmap(), aSourceRect, + icon->Mask(), ETrue ); + value = KErrNone; + } + return value; + } + + +// --------------------------------------------------------------------------- +// Draws the given text string. +// --------------------------------------------------------------------------- +// +void CAknTree::DrawText( CWindowGc& aGc, const TRect& aRect, + const TAknTextComponentLayout& aTextLayout, const TDesC& aText, + const CFont* aFont, const CAknTreeItem* aItem, TBool aFocused, + TBool aMarquee ) + { + TRgb textColor; + TAknsQsnTextColorsIndex index = + aFocused ? EAknsCIQsnTextColorsCG10 : EAknsCIQsnTextColorsCG6; + AknsUtils::GetCachedColor( AknsUtils::SkinInstance(), textColor, + KAknsIIDQsnTextColors, index ); + + TAknLayoutText layoutText; + layoutText.LayoutText( aRect, aTextLayout.LayoutLine(), aFont ); + + if ( iMarquee ) + { + if ( aFocused && aItem != iMarqueeItem ) + { + iMarqueeItem = aItem; + iMarquee->Reset(); + } + else if ( !aFocused && aItem == iMarqueeItem ) + { + iMarqueeItem = NULL; + iMarquee->Stop(); + } + } + + // Marquee scrolling is used when the given text does not fit in the given + // layout rectangle, but only if text is focused, marquee is allowed to be + // used with the given text, and marquee is enabled for the list. + TBool useMarquee = aFocused && aMarquee && iMarquee && + iMarquee->IsMarqueeOn() && layoutText.TextRect().Width() < + layoutText.Font()->TextWidthInPixels( aText ); + + if ( !useMarquee || iMarquee->DrawText( aGc, aRect, aTextLayout, aText, + aFont, textColor ) ) + { + layoutText.DrawText( aGc, aText, ETrue, textColor ); + } + } + + +// --------------------------------------------------------------------------- +// Handles skin change by reconstruction all the used icons. +// --------------------------------------------------------------------------- +// +void CAknTree::HandleSkinChangeL() + { + for ( TInt ii = 0; ii < iIcons.Count(); ++ii ) + { + iIcons[ii]->ReconstructL(); + } + } + + +// --------------------------------------------------------------------------- +// Enables or disables marquee scrolling. +// --------------------------------------------------------------------------- +// +void CAknTree::EnableMarquee( TBool aEnable ) + { + if ( iMarquee ) + { + iMarquee->EnableMarquee( aEnable ); + } + } + + +// --------------------------------------------------------------------------- +// Returns whether marquee scrolling is enabled. +// --------------------------------------------------------------------------- +// +TBool CAknTree::IsMarqueeOn() const + { + return iMarquee ? iMarquee->IsMarqueeOn() : EFalse; + } + + +// --------------------------------------------------------------------------- +// Redraw request from marquee control. +// --------------------------------------------------------------------------- +// +TInt CAknTree::MarqueeRedrawRequest( TAny* aThis ) + { + CAknTree* tree = static_cast( aThis ); + return tree ? tree->DoMarqueeRedrawRequest() : NULL; + } + + +// --------------------------------------------------------------------------- +// Enables tabulator mode expand/collapse function indicators. +// --------------------------------------------------------------------------- +// +void CAknTree::EnableTabModeFunctionIndicatorsL( TBool aEnable ) + { + if ( iFlags.IsSet( ETabModeFunctionIndicators ) && !aEnable ) + { + // Change to normal expand/collapse function indicators. + SetIconL( ECollapseFunctionIndication, KAknsIIDQgnIndiHlColSuper, + AknIconUtils::AvkonIconFileName(), + EMbmAvkonQgn_indi_hl_col_super, + EMbmAvkonQgn_indi_hl_col_super_mask, + EAspectRatioPreserved ); + + SetIconL( EExpandFunctionIndication, KAknsIIDQgnIndiHlExpSuper, + AknIconUtils::AvkonIconFileName(), + EMbmAvkonQgn_indi_hl_exp_super, + EMbmAvkonQgn_indi_hl_exp_super_mask, + EAspectRatioPreserved ); + + iFlags.Clear( ETabModeFunctionIndicators ); + } + else if ( !iFlags.IsSet( ETabModeFunctionIndicators ) && aEnable ) + { + // Change to tab mode expand/collapse function indicators. + SetIconL( ECollapseFunctionIndication, KAknsIIDQgnIndiHlTabColSuper, + AknIconUtils::AvkonIconFileName(), + EMbmAvkonQgn_indi_col_super, + EMbmAvkonQgn_indi_col_super_mask, + EAspectRatioPreserved ); + + SetIconL( EExpandFunctionIndication, KAknsIIDQgnIndiHlTabExpSuper, + AknIconUtils::AvkonIconFileName(), + EMbmAvkonQgn_indi_exp_super, + EMbmAvkonQgn_indi_exp_super_mask, + EAspectRatioPreserved ); + + iFlags.Set( ETabModeFunctionIndicators ); + } + } + + +// --------------------------------------------------------------------------- +// Checks whether tabulator mode expand/collapse function indicators are +// enabled. +// --------------------------------------------------------------------------- +// +TBool CAknTree::TabModeFunctionIndicators() const + { + return iFlags.IsSet( ETabModeFunctionIndicators ); + } + + +// --------------------------------------------------------------------------- +// From class CAknTreeItem. +// Returns the type of concrete item class. +// --------------------------------------------------------------------------- +// +TInt CAknTree::Type() const + { + return AknTreeList::KTree; + } + + +// --------------------------------------------------------------------------- +// From class CAknTreeItem. +// Instance of CAknTree is always set as tree root, so it can just return +// pointer to itself. +// --------------------------------------------------------------------------- +// +CAknTree* CAknTree::Root() const + { + return const_cast( this ); + } + + +// --------------------------------------------------------------------------- +// From class CAknTreeNode. +// Changes the state of every node in the tree to expanded. +// --------------------------------------------------------------------------- +// +void CAknTree::Expand() + { + TAknTreeIterator iterator( this, NULL ); + while ( iterator.HasNext() ) + { + CAknTreeItem* item = iterator.Next(); + if ( item->IsNode() ) + { + DoExpandNode( item->Node(), EFalse ); + } + } + } + + +// --------------------------------------------------------------------------- +// From class CAknTreeNode. +// Changes the state of every node in the tree to collapsed. +// --------------------------------------------------------------------------- +// +void CAknTree::Collapse() + { + TAknTreeIterator iterator( this, NULL ); + iterator.SetCurrent( iterator.Last() ); + iterator.Next(); + while( iterator.HasPrevious() ) + { + CAknTreeItem* item = iterator.Previous(); + if ( item->IsNode() ) + { + // Note: Might be a good idea to add for internal use an overload + // accepting the pointer to the collapsed node as parameter. + CollapseNode( Id( item->Node() ), EFalse ); + } + } + } + + +// --------------------------------------------------------------------------- +// C++ constructor. +// --------------------------------------------------------------------------- +// +CAknTree::CAknTree( CAknTreeList& aList, CAknTreeOrdering* aOrdering ) + : CAknTreeNode( EExpanded ), + iList( aList ), + iOrdering( aOrdering ), + iObservers( KObserverArrayGranularity ) + { + } + + +// --------------------------------------------------------------------------- +// Second phase constructor. +// --------------------------------------------------------------------------- +// +void CAknTree::ConstructL() + { + TCallBack callBack( CAknTree::MarqueeRedrawRequest, this ); + iMarquee = CAknMarqueeControl::NewL(); + iMarquee->SetRedrawCallBack( callBack ); + + SetIconL( ECollapseFunctionIndication, KAknsIIDQgnIndiHlColSuper, + AknIconUtils::AvkonIconFileName(), + EMbmAvkonQgn_indi_hl_col_super, + EMbmAvkonQgn_indi_hl_col_super_mask, + EAspectRatioPreserved ); + + SetIconL( EExpandFunctionIndication, KAknsIIDQgnIndiHlExpSuper, + AknIconUtils::AvkonIconFileName(), + EMbmAvkonQgn_indi_hl_exp_super, + EMbmAvkonQgn_indi_hl_exp_super_mask, + EAspectRatioPreserved ); + + SetIconL( ELineBranchIndication, KAknsIIDQgnIndiHlLineBranch, + AknIconUtils::AvkonIconFileName(), + EMbmAvkonQgn_indi_hl_line_branch, + EMbmAvkonQgn_indi_hl_line_branch, + EAspectRatioNotPreserved ); + + SetIconL( ELineEndIndication, KAknsIIDQgnIndiHlLineEnd, + AknIconUtils::AvkonIconFileName(), + EMbmAvkonQgn_indi_hl_line_end, + EMbmAvkonQgn_indi_hl_line_end_mask, + EAspectRatioNotPreserved ); + + SetIconL( ELineStraightIndication, KAknsIIDQgnIndiHlLineStraight, + AknIconUtils::AvkonIconFileName(), + EMbmAvkonQgn_indi_hl_line_straight, + EMbmAvkonQgn_indi_hl_line_straight_mask, + EAspectRatioNotPreserved ); + + SetIconL( EDefaultFileIndication, KAknsIIDQgnPropHlFile, + AknIconUtils::AvkonIconFileName(), + EMbmAvkonQgn_prop_hl_file, + EMbmAvkonQgn_prop_hl_file_mask, + EAspectRatioPreserved ); + + SetIconL( EClosedFolderIndication, KAknsIIDQgnPropHlFolder, + AknIconUtils::AvkonIconFileName(), + EMbmAvkonQgn_prop_hl_folder, + EMbmAvkonQgn_prop_hl_folder_mask, + EAspectRatioPreserved ); + + SetIconL( EOpenFolderIndication, KAknsIIDQgnPropHlFolderOpen, + AknIconUtils::AvkonIconFileName(), + EMbmAvkonQgn_prop_hl_folder_open, + EMbmAvkonQgn_prop_hl_folder_open_mask, + EAspectRatioPreserved ); + + SetColorIconL( EMarkedIndication, KAknsIIDQgnIndiMarkedAdd, + KAknsIIDQsnIconColors, EAknsCIQsnIconColorsCG13, + AknIconUtils::AvkonIconFileName(), + EMbmAvkonQgn_indi_marked_add, + EMbmAvkonQgn_indi_marked_add_mask, + KRgbBlack, EAspectRatioPreserved ); + + SetColorIconL( EHighlightedMarkedIndication, KAknsIIDQgnIndiMarkedAdd, + KAknsIIDQsnIconColors, EAknsCIQsnIconColorsCG16, + AknIconUtils::AvkonIconFileName(), + EMbmAvkonQgn_indi_marked_add, + EMbmAvkonQgn_indi_marked_add_mask, + KRgbBlack, EAspectRatioPreserved ); + + } + + +// --------------------------------------------------------------------------- +// Sends the specified event to every registered observer. +// --------------------------------------------------------------------------- +// +void CAknTree::NotifyObservers( MAknTreeObserver::TEvent aEvent, + CAknTreeItem* aItem, TBool aDrawNow ) + { + const TInt count = iObservers.Count(); + for ( TInt ii = 0; ii < count; ++ii ) + { + iObservers[ii]->HandleTreeEvent( aEvent, aItem, aDrawNow ); + } + } + + +// --------------------------------------------------------------------------- +// Sends notification to tree observers when requested by the marquee control. +// --------------------------------------------------------------------------- +// +TInt CAknTree::DoMarqueeRedrawRequest() + { + // Makes sure the tree still contains the scrolled item before sending + // the notification to the observers. + CAknTreeItem* item; + if ( !GetItem( Id( iMarqueeItem ), item ) ) + { + ItemModified( item ); + return 1; + } + return NULL; + } + + +// --------------------------------------------------------------------------- +// Searches for available icon ID. +// --------------------------------------------------------------------------- +// +TInt CAknTree::AvailableIconId() const + { + const TInt count = iIcons.Count(); + TInt last = count ? iIcons[count - 1]->Id() : NULL; + TInt next = Max( last, EPreDefinedIconIdRange ) + 1; + + if ( next <= EPreDefinedIconIdRange ) + { + next = KMaxTInt; + TBool found = EFalse; + for ( TInt ii = 0; ii < count - 1 && !found; ++ii ) + { + if ( iIcons[ii]->Id() < iIcons[ii + 1]->Id() - 1 ) + { + next = iIcons[ii]->Id() + 1; + found = ETrue; + } + } + } + + return next; + } + + +// --------------------------------------------------------------------------- +// Adds icon to the icon array. +// --------------------------------------------------------------------------- +// +void CAknTree::AddIconL( CAknTreeListIcon* aIcon ) + { + __ASSERT_DEBUG( aIcon, User::Invariant() ); + TLinearOrder order( CAknTreeListIcon::Compare ); + TInt index = iIcons.FindInOrder( aIcon, order ); + if ( index == KErrNotFound ) + { + // Add icon to the array. + iIcons.InsertInOrderL( aIcon, order ); + } + else + { + // Replace existing icon in the array. + delete iIcons[index]; + iIcons[index] = aIcon; + } + } + + +// --------------------------------------------------------------------------- +// Sorts the list by sorting every node in the tree separately. +// --------------------------------------------------------------------------- +// +void CAknTree::Sort( TBool aDrawNow ) + { + CAknTreeNode::Sort(); + for ( TInt ii = 0; ii < iItems.Count(); ++ii ) + { + CAknTreeNode* node = iItems[ii]->Node(); + if ( node ) + { + node->Sort(); + } + } + + NotifyObservers( MAknTreeObserver::ETreeSorted, NULL, aDrawNow ); + } + + +// --------------------------------------------------------------------------- +// Expands the specified node. +// --------------------------------------------------------------------------- +// +void CAknTree::DoExpandNode( CAknTreeNode* aNode, TBool aDrawNow ) + { + __ASSERT_DEBUG( aNode, User::Invariant() ); + iList.NotifyObservers( MAknTreeListObserver::ENodeExpanded, Id( aNode ) ); + aNode->Expand(); + NotifyObservers( MAknTreeObserver::ENodeExpanded, aNode, aDrawNow ); + } + + +// --------------------------------------------------------------------------- +// From class CAknTreeItem. +// Empty implementation for the pure virtal function declared in CAknTreeItem. +// --------------------------------------------------------------------------- +// +void CAknTree::Draw( CWindowGc& /*aGc*/, const TRect& /*aItemRect*/, + const TRect& /*aRect*/, TBool /*aFocused*/ ) const + { + // The root node should never be drawn! + __ASSERT_DEBUG( EFalse, User::Invariant() ); + } +