diff -r 000000000000 -r ba25891c3a9e ncdengine/provider/server/src/ncdnodeseeninfo.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ncdengine/provider/server/src/ncdnodeseeninfo.cpp Thu Dec 17 08:51:10 2009 +0200 @@ -0,0 +1,1073 @@ +/* +* Copyright (c) 2007-2008 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 "ncdnodeseeninfo.h" + +#include "ncdnodeidentifierutils.h" +#include "ncdnodeidentifier.h" +#include "ncdstorage.h" +#include "ncdstoragemanager.h" +#include "ncdproviderdefines.h" +#include "ncddatabasestorage.h" +#include "ncdstorageitem.h" +#include "ncdrootnode.h" +#include "ncdnodeidentifiereditor.h" +#include "catalogsutils.h" +#include "ncdchildentity.h" +#include "ncdchildentitymap.h" +#include "ncdnodefolderlink.h" +#include "ncdgeneralmanager.h" + +#include "catalogsdebug.h" + +CNcdNodeSeenInfo* CNcdNodeSeenInfo::NewL( CNcdGeneralManager& aGeneralManager ) + { + CNcdNodeSeenInfo* self = NewLC( aGeneralManager ); + CleanupStack::Pop( self ); + return self; + } + + +CNcdNodeSeenInfo* CNcdNodeSeenInfo::NewLC( CNcdGeneralManager& aGeneralManager ) + { + CNcdNodeSeenInfo* self = new( ELeave ) CNcdNodeSeenInfo( aGeneralManager ); + CleanupStack::PushL( self ); + self->ConstructL(); + return self; + } + + +CNcdNodeSeenInfo::CNcdNodeSeenInfo( CNcdGeneralManager& aGeneralManager ) : + iGeneralManager( aGeneralManager ), + iStorageManager( aGeneralManager.StorageManager() ), + iNodeManager( aGeneralManager.NodeManager() ) + { + } + + +void CNcdNodeSeenInfo::ConstructL() + { + } + + +CNcdNodeSeenInfo::~CNcdNodeSeenInfo() + { + DLTRACEIN(("")); + iClientSeenInfos.ResetAndDestroy(); + } + +void CNcdNodeSeenInfo::AddNewIdL( const CNcdChildEntity& aChildEntity ) + { + DLTRACEIN(("")); + AddNewIdL( aChildEntity.Identifier(), ENcdStatusNew, aChildEntity.NodeType() ); + } + +void CNcdNodeSeenInfo::AddNewIdL( const CNcdNodeIdentifier& aNodeIdentifier, + TNcdNewStatus aNewStatus, CNcdNodeFactory::TNcdNodeType aNodeType ) + { + DLTRACEIN(("")); + + const TUid& clientUid = aNodeIdentifier.ClientUid(); + + if ( !IsClientInfoLoaded( clientUid ) ) + { + DbLoadClientInfoL( clientUid ); + } + + CClientSeenInfo* info = ClientInfo( clientUid ); + DASSERT( info ); + +#ifdef CATALOGS_BUILD_CONFIG_DEBUG + DLINFO(("New status array:")); + for( TInt i = 0 ; i < info->iNodeNewStatusArray.Count() ; i++ ) + { + DLINFO((_L("index: %d, id: %S"),i, &info->iNodeNewStatusArray[i]->Identifier().NodeId() )); + } +#endif + + // Latest "new" nodes will be added to the top of the list and older "new" nodes will + // drop out when max size is exceeded. + TInt index = IndexInNewStatusArray( aNodeIdentifier ); + if( index == KErrNotFound ) + { + DLTRACE(("Not found, create new.")); + // Create new status. + CNcdNodeNewStatus* nodeNewStatus = CNcdNodeNewStatus::NewLC( + aNodeIdentifier, + aNewStatus, + aNodeType ); + // Insert to the top of the list. + info->iNodeNewStatusArray.InsertL( nodeNewStatus, 0 ); + CleanupStack::Pop( nodeNewStatus ); + + } + else + { + DLTRACE(("Found, update.")); + // Node is already in the new list -> move it to the top of the list. + CNcdNodeNewStatus* nodeNewStatus = info->iNodeNewStatusArray[index]; + info->iNodeNewStatusArray.InsertL( nodeNewStatus, 0 ); + info->iNodeNewStatusArray.Remove( index + 1 ); + // Remove seen status if any + RemoveFromSeenListL( aNodeIdentifier ); + // Update new status. + nodeNewStatus->SetNewStatus( TNcdNewStatus(nodeNewStatus->NewStatus() | aNewStatus) ); + } + + // Set parent new as well. + if( !NcdNodeIdentifierEditor::IdentifiesSomeRoot( aNodeIdentifier ) ) + { + CNcdNodeIdentifier* parent = NcdNodeIdentifierEditor::ParentOfLC( aNodeIdentifier ); + AddNewIdL( *parent, ENcdStatusNewNodesInside, CNcdNodeFactory::ENcdNodeFolder ); + CleanupStack::PopAndDestroy( parent ); + } + + // Remove identifiers from the bottom if max size is exceeded. + while( info->iNodeNewStatusArray.Count() > KNewListMaxSize ) + { + delete info->iNodeNewStatusArray[info->iNodeNewStatusArray.Count() - 1]; + info->iNodeNewStatusArray.Remove( + info->iNodeNewStatusArray.Count() - 1 ); + } + +#ifdef CATALOGS_BUILD_CONFIG_DEBUG + DLINFO(("New status array:")); + for( TInt i = 0 ; i < info->iNodeNewStatusArray.Count() ; i++ ) + { + DLINFO((_L("index: %d, id: %S"),i, &info->iNodeNewStatusArray[i]->Identifier().NodeId() )); + } +#endif + } + + +TBool CNcdNodeSeenInfo::IsSeenL( const CNcdNodeIdentifier& aNodeIdentifier ) + { + DLTRACEIN((_L("ns: %S, id: %S"), &aNodeIdentifier.NodeNameSpace(), &aNodeIdentifier.NodeId())); + + const TUid& clientUid = aNodeIdentifier.ClientUid(); + + if ( !IsClientInfoLoaded( clientUid ) ) + { + DbLoadClientInfoL( clientUid ); + } + + CClientSeenInfo* clientInfo = ClientInfo( aNodeIdentifier.ClientUid() ); + DASSERT( clientInfo ); + DLINFO((("clientInfo-ptr: %x"), clientInfo )); + + DLINFO(("new count: %d", clientInfo->iNodeNewStatusArray.Count() )); + TInt index = IndexInNewStatusArray( aNodeIdentifier ); + DLINFO(("index in new status array: %d", index )); + return index == KErrNotFound; + } + + +TBool CNcdNodeSeenInfo::ChildExistsInArrayL( const CNcdChildEntity& aChildEntity, + const RPointerArray& aChildArray, + TBool& aNodeWithSameIndexFound ) + { + DLTRACEIN(("")); + TBool childFound = EFalse; + aNodeWithSameIndexFound = EFalse; + for( TInt i = 0 ; i < aChildArray.Count() ; i++ ) + { + if( aChildArray[i]->Identifier().Equals( aChildEntity.Identifier() ) ) + { + childFound = ETrue; + } + if( aChildArray[i]->Index() == aChildEntity.Index() ) + { + aNodeWithSameIndexFound = ETrue; + } + } + DLINFO(("childFound %d, aNodeWithSameIndexFound: %d", childFound, + aNodeWithSameIndexFound)); + return childFound; + } + +void CNcdNodeSeenInfo::RefreshFolderSeenStatusL( + const CNcdNodeIdentifier& aNodeIdentifier ) + { + DLTRACEIN((_L("aNodeIdentifier: %S"), &aNodeIdentifier.NodeId() )); + const TUid& clientUid = aNodeIdentifier.ClientUid(); + + if ( !IsClientInfoLoaded( clientUid ) ) + { + DbLoadClientInfoL( clientUid ); + } + + CClientSeenInfo* info = ClientInfo( clientUid ); + DASSERT( info ); + + TInt index = IndexInNewStatusArray( aNodeIdentifier ); + if( index == KErrNotFound ) + { + DLTRACE(("Not in new status array")); + return; + } + + if( !FolderHasNewChildrenL( aNodeIdentifier ) ) + { + CNcdNodeNewStatus* newStatus = info->iNodeNewStatusArray[index]; + // Don't touch folders that are really new, only folders that have just + // new items inside. + if( !( newStatus->NewStatus() & ENcdStatusNew || + newStatus->NewStatus() & ENcdStatusNewButSeen ) ) + { + // Special case: all new children have been removed, immediately remove folder's new status + // (better user experience when compared to just setting it seen) + RemoveFromNewListL( aNodeIdentifier ); + RemoveFromSeenListL( aNodeIdentifier ); + // Check parent as well. + if( !NcdNodeIdentifierEditor::IdentifiesSomeRoot( aNodeIdentifier ) ) + { + CNcdNodeIdentifier* parent = NcdNodeIdentifierEditor::ParentOfLC( aNodeIdentifier ); + RefreshFolderSeenStatusL( *parent ); + CleanupStack::PopAndDestroy( parent ); + } + } + } + } + +void CNcdNodeSeenInfo::SetFolderSeenIfNeededL( + const CNcdNodeIdentifier& aNodeIdentifier ) + { + DLTRACEIN(("")); + + TInt index = IndexInNewStatusArray( aNodeIdentifier ); + if( index == KErrNotFound || IsAddedAsSeen( aNodeIdentifier ) ) + { + DLTRACE(("Not in new status array, or already set seen")); + return; + } + + if( !FolderHasNewUnseenChildrenL( aNodeIdentifier ) ) + { + // Add to seen list. + AddSeenIdL( aNodeIdentifier ); + // Check parent as well. + if( !NcdNodeIdentifierEditor::IdentifiesSomeRoot( aNodeIdentifier ) ) + { + CNcdNodeIdentifier* parent = NcdNodeIdentifierEditor::ParentOfLC( aNodeIdentifier ); + SetFolderSeenIfNeededL( *parent ); + CleanupStack::PopAndDestroy( parent ); + } + } + } + +TBool CNcdNodeSeenInfo::FolderHasNewUnseenChildrenL( + const CNcdNodeIdentifier& aNodeIdentifier ) + { + DLTRACEIN(("")); + CNcdNodeFolder& folder = iNodeManager.FolderL( aNodeIdentifier ); + const RPointerArray& childArray = folder.ChildArray(); + for( TInt i = 0 ; i < childArray.Count() ; i++ ) + { + // NOTE: Children that are set seen are not considered new here. + CNcdNodeNewStatus* nodeNewStatus = NodeNewStatus( childArray[i]->Identifier() ); + if( nodeNewStatus && !IsAddedAsSeen( childArray[i]->Identifier() ) ) + { + DLTRACE(("New child found")); + return ETrue; + } + } + return EFalse; + } + + TBool CNcdNodeSeenInfo::FolderHasNewChildrenL( + const CNcdNodeIdentifier& aNodeIdentifier ) + { + DLTRACEIN(("")); + CNcdNodeFolder& folder = iNodeManager.FolderL( aNodeIdentifier ); + const RPointerArray& childArray = folder.ChildArray(); + for( TInt i = 0 ; i < childArray.Count() ; i++ ) + { + // NOTE: Children that are set seen are considered new here. + CNcdNodeNewStatus* nodeNewStatus = NodeNewStatus( childArray[i]->Identifier() ); + if( nodeNewStatus ) + { + DLTRACE(("New child found")); + return ETrue; + } + } + return EFalse; + } + +void CNcdNodeSeenInfo::AddSeenIdL( const CNcdNodeIdentifier& aNodeIdentifier ) + { + DLTRACEIN(("")); + CClientSeenInfo* info = ClientInfo( aNodeIdentifier.ClientUid() ); + DASSERT( info ); + // Add to seen list. + CNcdNodeIdentifier* copy = CNcdNodeIdentifier::NewLC( aNodeIdentifier ); + info->iSeenStructureIds.AppendL( copy ); + CleanupStack::Pop( copy ); + } + +void CNcdNodeSeenInfo::SetSeenL( const CNcdNodeIdentifier& aNodeIdentifier ) + { + DLTRACEIN(("")); + + const TUid& clientUid = aNodeIdentifier.ClientUid(); + + if ( !IsClientInfoLoaded( clientUid ) ) + { + DbLoadClientInfoL( clientUid ); + } + TInt index = IndexInNewStatusArray( aNodeIdentifier ); + + if( index == KErrNotFound || IsAddedAsSeen( aNodeIdentifier ) ) + { + DLTRACE(("Not in new status array, or already set seen")); + return; + } + + CClientSeenInfo* info = ClientInfo( clientUid ); + DASSERT( info ); + + CNcdNodeNewStatus* nodeNewStatus = info->iNodeNewStatusArray[index]; + if( nodeNewStatus->NodeType() == CNcdNodeFactory::ENcdNodeItem ) + { + AddSeenIdL( aNodeIdentifier ); + } + else if ( nodeNewStatus->NewStatus() & ENcdStatusNew && + nodeNewStatus->NewStatus() & ENcdStatusNewNodesInside ) + { + nodeNewStatus->SetNewStatus( + TNcdNewStatus( ENcdStatusNewButSeen | ENcdStatusNewNodesInside ) ); + } + else if ( nodeNewStatus->NewStatus() & ENcdStatusNew ) + { + AddSeenIdL( aNodeIdentifier ); + } + + if( !NcdNodeIdentifierEditor::IdentifiesSomeRoot( aNodeIdentifier ) ) + { + CNcdNodeIdentifier* parent = NcdNodeIdentifierEditor::ParentOfLC( aNodeIdentifier ); + SetFolderSeenIfNeededL( *parent ); + CleanupStack::PopAndDestroy( parent ); + } + } + +void CNcdNodeSeenInfo::CheckFolderNewStatusL( CNcdNodeFolder& aParentFolder ) + { + DLTRACEIN(("")); + // New checking for children can only be done if the previous + // child array has been stored. (Not stored e.g. on first time browse and + // after restart) + if( aParentFolder.PreviousChildCount() != KErrNotFound ) + { + DLTRACE(("Previous children set -> do new comparison")); + const RPointerArray& previousChildArray = + aParentFolder.PreviousChildArray(); + CheckFolderNewStatusL( aParentFolder, previousChildArray ); + } + } + +void CNcdNodeSeenInfo::CheckFolderNewStatusL( CNcdNodeFolder& aParentFolder, + const RPointerArray& aPreviousChildArray ) + { + const TUid& clientUid = aParentFolder.Identifier().ClientUid(); + + if ( !IsClientInfoLoaded( clientUid ) ) + { + DbLoadClientInfoL( clientUid ); + } + + CClientSeenInfo* info = ClientInfo( clientUid ); + DASSERT( info ); + + // This flag is used to determine whether this folder contains any new items. + TBool newChildrenFound = EFalse; + // Check new array against the previous array + const RPointerArray& childArray = + aParentFolder.ChildArray(); + CNcdNodeNewStatus* parentNewStatus = NodeNewStatus( aParentFolder.Identifier() ); + TBool parentIsNew = parentNewStatus && + ( parentNewStatus->NewStatus() & ENcdStatusNew || + parentNewStatus->NewStatus() & ENcdStatusNewButSeen ); + for( TInt i = 0 ; i < childArray.Count() ; i++ ) + { + // compare with previous list + TBool nodeWithSameIndexFound = EFalse; + TBool childFound = ChildExistsInArrayL( *childArray[i], + aPreviousChildArray, + nodeWithSameIndexFound ); + + if( parentIsNew ) + { + DLTRACE(("Parent folder is new -> all children are new ")); + AddNewIdL( *childArray[i] ); + newChildrenFound = ETrue; + } + // if found -> old + else if( childFound ) + { + DLTRACE(("Child found -> old")); + } + // if not found && index < old child count && no node with this index in previous list + // -> old ( cannot know whether this is new or old so default to old, special case! ) + else if( !childFound + && childArray[i]->Index() < aParentFolder.PreviousChildCount() + && !nodeWithSameIndexFound ) + { + DLTRACE(("Child not found and index < previous child count && node with same index not found -> default to old")); + } + // if not found && index < old child count && node exists with this index in previous list + // -> new ( the "usual" new case ) + else if( !childFound + && childArray[i]->Index() < aParentFolder.PreviousChildCount() + && nodeWithSameIndexFound ) + { + DLTRACE(("New")); + AddNewIdL( *childArray[i] ); + newChildrenFound = ETrue; + } + // if not found && index > old child count -> new + else if( !childFound + && childArray[i]->Index() >= aParentFolder.PreviousChildCount() ) + { + DLTRACE(("New")); + AddNewIdL( *childArray[i] ); + newChildrenFound = ETrue; + } + + // If no new children are found before, check that is this node previously new + if( !newChildrenFound ) + { + DLTRACE(("Check if already set new")); + // Must be in new array and not in seen array to be new + // (internally new, i.e. new even after commit). + CNcdNodeNewStatus* nodeNewStatus = NodeNewStatus( + childArray[i]->Identifier() ); + if( nodeNewStatus ) + { + newChildrenFound = ETrue; + } + } + } + + if( !newChildrenFound && parentIsNew ) + { + // Special case: all new items have been removed, immediately remove parent's new status + // (better user experience when compared to just setting it seen) + RemoveFromNewListL( aParentFolder.Identifier() ); + } + } + +void CNcdNodeSeenInfo::CheckChildNewStatusL( CNcdNodeFolder& aParentFolder, + TInt aChildIndex ) + { + DLTRACEIN(("")); + const TUid& clientUid = aParentFolder.Identifier().ClientUid(); + + if ( !IsClientInfoLoaded( clientUid ) ) + { + DbLoadClientInfoL( clientUid ); + } + + CNcdNodeNewStatus* parentNewStatus = NodeNewStatus( aParentFolder.Identifier() ); + TBool parentIsNew = parentNewStatus && + ( parentNewStatus->NewStatus() & ENcdStatusNew || + parentNewStatus->NewStatus() & ENcdStatusNewButSeen ); + if( parentIsNew ) + { + DLTRACE(("Parent is new, set child new as well")); + AddNewIdL( aParentFolder.ChildEntityByServerIndexL( aChildIndex ) ); + } + else if( aParentFolder.PreviousChildCount() != KErrNotFound ) + { + DLTRACE(("Previous child list set, do comparison.")); + const CNcdChildEntity& child = aParentFolder.ChildEntityByServerIndexL( aChildIndex ); + // compare with previous list + TBool nodeWithSameIndexFound = EFalse; + TBool childFound = ChildExistsInArrayL( child, + aParentFolder.PreviousChildArray(), + nodeWithSameIndexFound ); + + // if found -> old + if( childFound ) + { + DLTRACE(("Child found -> old")); + } + // if not found && index < old child count && no node with this index in previous list + // -> old ( cannot know whether this is new or old so default to old, special case! ) + else if( !childFound + && child.Index() < aParentFolder.PreviousChildCount() + && !nodeWithSameIndexFound ) + { + DLTRACE(("Child not found and index < previous child count && node with same index not found -> default to old")); + } + // if not found && index < old child count && node exists with this index in previous list + // -> new ( the "usual" new case ) + else if( !childFound + && child.Index() < aParentFolder.PreviousChildCount() + && nodeWithSameIndexFound ) + { + DLTRACE(("New")); + AddNewIdL( child ); + } + // if not found && index > old child count -> new + else if( !childFound + && child.Index() >= aParentFolder.PreviousChildCount() ) + { + DLTRACE(("New")); + AddNewIdL( child ); + } + } + } + +void CNcdNodeSeenInfo::ClearInfoL( const TUid& aClientUid ) + { + DLTRACEIN(("")); + if ( !IsClientInfoLoaded( aClientUid ) ) + { + DbLoadClientInfoL( aClientUid ); + } + CClientSeenInfo* info = ClientInfo( aClientUid ); + DASSERT( info ); + info->iNodeNewStatusArray.ResetAndDestroy(); + info->iSeenStructureIds.ResetAndDestroy(); + } + +void CNcdNodeSeenInfo::CommitChangesL( const TUid& aClientUid ) + { + DLTRACEIN(("")); + + CClientSeenInfo* info = ClientInfo( aClientUid ); + if ( !info ) + { + // No changes made, return; + return; + } + + for( TInt i = info->iNodeNewStatusArray.Count() - 1 ; i >= 0 ; i-- ) + { + CNcdNodeNewStatus* nodeNewStatus = info->iNodeNewStatusArray[i]; + if( nodeNewStatus->NewStatus() & ENcdStatusNewButSeen ) + { + nodeNewStatus->SetNewStatus( + TNcdNewStatus(nodeNewStatus->NewStatus() ^ ENcdStatusNewButSeen ) ); + } + } + + TInt count = info->iSeenStructureIds.Count(); + // Remove the seen identifiers from the new list. + while ( count-- ) + { + RemoveFromNewListL( *info->iSeenStructureIds[ count ] ); + delete info->iSeenStructureIds[ count]; + // Removing here in case RemoveFromNewListL leaves + info->iSeenStructureIds.Remove( count ); + } + + DASSERT( info->iSeenStructureIds.Count() == 0 ); + // Save the changes to db. + DbSaveClientInfoL( aClientUid ); + } + + void CNcdNodeSeenInfo::CreatePreviousListsForChildrenL( + CNcdNodeFolder& aParentFolder, + RPointerArray& aChildEntityMaps ) + { + DLTRACEIN(("")); + for( TInt i = 0 ; i < aParentFolder.ChildArray().Count() ; i++ ) + { + if( aParentFolder.ChildArray()[i]->NodeType() == + CNcdNodeFactory::ENcdNodeFolder ) + { + CNcdNodeFolder* child = NULL; + TRAPD(err, child = &iNodeManager.FolderL( + aParentFolder.ChildArray()[i]->Identifier() ) ); //TRAPD + // Special handling for bundles + if( err != KErrNone ) + { + DLTRACE(("Child not found from cache or db.")); + continue; + } + TInt childCount = 0; + if( CNcdNodeFactory::NodePurposeL( *child ) == + CNcdNodeFactory::ENcdBundleNode && + child->ChildrenPreviouslyLoaded() ) + { + DLTRACE(("")) + CreatePreviousListsForChildrenL( *child, aChildEntityMaps ); + childCount = child->ChildCount(); + } + else + { + childCount = child->FolderLinkL().ExpectedChildrenCount(); + } + // Store only if previously loaded. + if( child->ChildrenPreviouslyLoaded() ) + { + DLTRACEIN((_L("Creating previous list for: %S"), + &child->Identifier().NodeId() )); + CNcdChildEntityMap* childEntityMap = + CNcdChildEntityMap::NewLC( + child->Identifier(), + child->ChildArray(), + childCount ); + aChildEntityMaps.AppendL( childEntityMap ); + CleanupStack::Pop( childEntityMap ); + } + } + } + } + +void CNcdNodeSeenInfo::StorePreviousListsToExistingChildrenL( + CNcdNodeFolder& aParentFolder, + const RPointerArray& aChildEntityMaps ) + { + DLTRACEIN(("")); + const RPointerArray& children = aParentFolder.ChildArray(); + for( TInt i = 0 ; i < children.Count() ; i++ ) + { + CNcdNodeFolder* folder = NULL; + TRAPD(err, folder = + &iNodeManager.FolderL( children[i]->Identifier() ) ); //TRAPD + if( err != KErrNone ) + { + DLTRACE(("Child not found from cache or db.")); + continue; + } + if( CNcdNodeFactory::NodePurposeL( + *folder ) == CNcdNodeFactory::ENcdBundleNode ) + { + DLTRACE(("Child is bundle -> store it's children's previous lists.")); + StorePreviousListsToExistingChildrenL( *folder, aChildEntityMaps ); + } + + for( TInt j = 0 ; j < aChildEntityMaps.Count() ; j++ ) + { + // Should remove child entity map when matching child is found. + const CNcdChildEntityMap* previousChildEntityMap = aChildEntityMaps[j]; + if( previousChildEntityMap->ParentIdentifier().Equals( + folder->Identifier() ) ) + { + DLTRACE(("Matching child found, store it's previous list.")); + folder->StoreChildrenToPreviousListL( + previousChildEntityMap->ChildArray(), + previousChildEntityMap->ChildCount() ); + break; + } + } + } + } + +void CNcdNodeSeenInfo::DoNewCheckForTransparentChildrenL( + CNcdNodeFolder& aParentFolder ) + { + DLTRACEIN(("")); + const RPointerArray& children = aParentFolder.ChildArray(); + for( TInt i = 0 ; i < children.Count() ; i++ ) + { + if( children[i]->NodeType() == CNcdNodeFactory::ENcdNodeFolder + && children[i]->IsTransparent() ) + { + CNcdNodeFolder* folder = NULL; + TRAPD(err, folder = + &iNodeManager.FolderL( children[i]->Identifier() ) ); //TRAPD + if( err == KErrNone ) + { + CNcdNodeNewStatus* parentNewStatus = NodeNewStatus( children[i]->Identifier() ); + TBool parentIsNew = parentNewStatus && + ( parentNewStatus->NewStatus() & ENcdStatusNew || + parentNewStatus->NewStatus() & ENcdStatusNewButSeen ); + if( parentIsNew ) + { + SetChildrenNewL( *folder ); + } + else + { + CheckFolderNewStatusL( *folder ); + } + } + } + } + } + +CNcdNodeSeenInfo::CClientSeenInfo* CNcdNodeSeenInfo::ClientInfo( + const TUid& aClientUid ) const + { + for ( TInt i = 0; i < iClientSeenInfos.Count(); i++ ) + { + if ( iClientSeenInfos[ i ]->iClientUid == aClientUid ) + { + return iClientSeenInfos[ i ]; + } + } + return NULL; + } + + +TInt CNcdNodeSeenInfo::IndexInSeenArray( const CNcdNodeIdentifier& aNodeIdentifier ) const + { + DLTRACEIN(("")); + CClientSeenInfo* info = ClientInfo( aNodeIdentifier.ClientUid() ); + DASSERT( info ); + return NcdNodeIdentifierUtils::IdentifierIndex( + aNodeIdentifier, info->iSeenStructureIds ); + } + +TBool CNcdNodeSeenInfo::IsAddedAsSeen( const CNcdNodeIdentifier& aNodeIdentifier ) const + { + DLTRACEIN(("")); + return IndexInSeenArray( aNodeIdentifier ) != KErrNotFound; + } + +TInt CNcdNodeSeenInfo::IndexInNewStatusArray( const CNcdNodeIdentifier& aNodeIdentifier ) const + { + DLTRACEIN(("")); + CClientSeenInfo* info = ClientInfo( aNodeIdentifier.ClientUid() ); + DASSERT( info ); + TInt index = KErrNotFound; + for( TInt i = 0 ; i < info->iNodeNewStatusArray.Count() ; i++ ) + { + if( info->iNodeNewStatusArray[i]->Identifier().Equals( aNodeIdentifier ) ) + { + index = i; + break; + } + } + return index; + } + +CNcdNodeSeenInfo::CNcdNodeNewStatus* CNcdNodeSeenInfo::NodeNewStatus( const CNcdNodeIdentifier& aNodeIdentifier ) + { + DLTRACEIN(("")); + CNcdNodeNewStatus* nodeNewStatus = NULL; + TInt index = IndexInNewStatusArray( aNodeIdentifier ); + if( index != KErrNotFound ) + { + CClientSeenInfo* info = ClientInfo( aNodeIdentifier.ClientUid() ); + DASSERT( info ); + nodeNewStatus = info->iNodeNewStatusArray[index]; + } + return nodeNewStatus; + } + +void CNcdNodeSeenInfo::RemoveFromSeenListL( const CNcdNodeIdentifier& aNodeIdentifier ) + { + DLTRACEIN(("")); + const TUid& clientUid = aNodeIdentifier.ClientUid(); + + if ( !IsClientInfoLoaded( clientUid ) ) + { + DbLoadClientInfoL( clientUid ); + } + + CClientSeenInfo* info = ClientInfo( clientUid ); + DASSERT( info ); + + TInt index = NcdNodeIdentifierUtils::IdentifierIndex( + aNodeIdentifier, info->iSeenStructureIds ); + if( index != KErrNotFound ) + { + delete info->iSeenStructureIds[index]; + info->iSeenStructureIds.Remove( index ); + } + } + +void CNcdNodeSeenInfo::RemoveFromNewListL( const CNcdNodeIdentifier& aNodeIdentifier ) + { + DLTRACEIN(("")); + const TUid& clientUid = aNodeIdentifier.ClientUid(); + + if ( !IsClientInfoLoaded( clientUid ) ) + { + DbLoadClientInfoL( clientUid ); + } + + CClientSeenInfo* info = ClientInfo( clientUid ); + DASSERT( info ); + + TInt index = IndexInNewStatusArray( aNodeIdentifier ); + if( index != KErrNotFound ) + { + DLTRACE((_L("Removing from new status array, id: %S"), &aNodeIdentifier.NodeId() )); + delete info->iNodeNewStatusArray[index]; + info->iNodeNewStatusArray.Remove( index ); + } + } + +TBool CNcdNodeSeenInfo::IsClientInfoLoaded( const TUid& aClientUid ) const + { + DLTRACEIN(("")); + return ClientInfo( aClientUid ) != NULL; + } + + +void CNcdNodeSeenInfo::RemoveClientInfo( const TUid& aClientUid ) + { + DLTRACEIN(("")); + for ( TInt i = 0; i < iClientSeenInfos.Count(); i++ ) + { + if ( iClientSeenInfos[ i ]->iClientUid == aClientUid ) + { + delete iClientSeenInfos[ i ]; + iClientSeenInfos.Remove( i ); + break; + } + } + } + + +void CNcdNodeSeenInfo::DbLoadClientInfoL( const TUid& aClientUid ) + { + DLTRACEIN(("")); + + RemoveClientInfo( aClientUid ); + + MNcdStorage& providerStorage = iStorageManager.ProviderStorageL( + iGeneralManager.FamilyName() ); + MNcdDatabaseStorage& database = + providerStorage.DatabaseStorageL( NcdProviderDefines::KDefaultDatabaseUid ); + + if( !database.ItemExistsInStorageL( aClientUid.Name(), + NcdProviderDefines::ENcdNodeSeenInfo ) ) + { + // Create empty client info object. + CClientSeenInfo* empty = new( ELeave ) CClientSeenInfo( aClientUid ); + CleanupStack::PushL( empty ); + iClientSeenInfos.AppendL( empty ); + CleanupStack::Pop( empty ); + } + else + { + // Database contains the data, load it. + // Get the storage item from which the data is loaded + // Note: database has the ownership of the item + MNcdStorageItem* item = database.StorageItemL( + aClientUid.Name(), NcdProviderDefines::ENcdNodeSeenInfo ); + + // Get data from database by using CClientSeenInfo as the target so that + // internalize will be called for it + CClientSeenInfo* data = new( ELeave ) CClientSeenInfo( aClientUid ); + CleanupStack::PushL( data ); + item->SetDataItem( data ); + + // Read data -> calls CClientSeenInfo::InternalizeL + item->ReadDataL(); + + iClientSeenInfos.AppendL( data ); + CleanupStack::Pop( data ); + } + } + + +void CNcdNodeSeenInfo::DbSaveClientInfoL( const TUid& aClientUid ) + { + DLTRACEIN(("")); + + CClientSeenInfo* info = ClientInfo( aClientUid ); + if ( !info ) + { + return; + } + + MNcdStorage& providerStorage = iStorageManager.ProviderStorageL( + iGeneralManager.FamilyName() ); + MNcdDatabaseStorage& database = + providerStorage.DatabaseStorageL( NcdProviderDefines::KDefaultDatabaseUid ); + + // Get the storage item to which the client seen info is stored + // Note: database has the ownership of the item + MNcdStorageItem* item = database.StorageItemL( + aClientUid.Name(), NcdProviderDefines::ENcdNodeSeenInfo ); + item->SetDataItem( info ); + item->OpenL(); + + // Calls ExternalizeL for this + item->WriteDataL(); + item->SaveL(); + } + +void CNcdNodeSeenInfo::SetChildrenNewL( CNcdNodeFolder& aParentFolder ) + { + DLTRACEIN(("")); + const RPointerArray& children = aParentFolder.ChildArray(); + for( TInt i = 0 ; i < children.Count() ; i++ ) + { + AddNewIdL( *children[i] ); + RemoveFromSeenListL( children[i]->Identifier() ); + } + } + + +// ---------------------------------------------------------------------------------------------- +// CNcdNodeSeenInfo::CClientInfo +// ---------------------------------------------------------------------------------------------- +// + +CNcdNodeSeenInfo::CClientSeenInfo::CClientSeenInfo( const TUid& aClientUid ) : + iClientUid( aClientUid ) + { + } + +CNcdNodeSeenInfo::CClientSeenInfo::~CClientSeenInfo() + { + iNodeNewStatusArray.ResetAndDestroy(); + iSeenStructureIds.ResetAndDestroy(); + } + + +// From MNcdStorageDataItem + +void CNcdNodeSeenInfo::CClientSeenInfo::ExternalizeL( RWriteStream& aStream ) + { + DLTRACEIN(("")); + + // Write uid. + aStream.WriteInt32L( iClientUid.iUid ); + + // Write new structure ids. + TInt count = iNodeNewStatusArray.Count(); + aStream.WriteInt32L( count ); + for ( TInt i = 0; i < count; i++ ) + { + iNodeNewStatusArray[ i ]->ExternalizeL( aStream ); + } + } + + +void CNcdNodeSeenInfo::CClientSeenInfo::InternalizeL( RReadStream& aStream ) + { + DLTRACEIN(("")); + iNodeNewStatusArray.ResetAndDestroy(); + + // Read uid. + iClientUid = TUid::Uid( aStream.ReadInt32L() ); + + // Read new structure ids. + TInt count = aStream.ReadInt32L(); + for ( TInt i = 0; i < count; i++ ) + { + CNcdNodeNewStatus* identifier = CNcdNodeNewStatus::NewLC( aStream ); + iNodeNewStatusArray.AppendL( identifier ); + CleanupStack::Pop( identifier ); + } + } + +CNcdNodeSeenInfo::CNcdNodeNewStatus* CNcdNodeSeenInfo::CNcdNodeNewStatus::NewL( + const CNcdNodeIdentifier& aNodeIdentifier, + TNcdNewStatus aNewStatus, + CNcdNodeFactory::TNcdNodeType aNodeType ) + { + DLTRACEIN(("")); + CNcdNodeNewStatus* self = CNcdNodeNewStatus::NewLC( aNodeIdentifier, + aNewStatus, + aNodeType ); + CleanupStack::Pop( self ); + return self; + } + +CNcdNodeSeenInfo::CNcdNodeNewStatus* CNcdNodeSeenInfo::CNcdNodeNewStatus::NewLC( + const CNcdNodeIdentifier& aNodeIdentifier, + TNcdNewStatus aNewStatus, + CNcdNodeFactory::TNcdNodeType aNodeType ) + { + DLTRACEIN(("")); + CNcdNodeNewStatus* self = new ( ELeave ) CNcdNodeNewStatus( aNewStatus, + aNodeType ); + CleanupStack::PushL( self ); + self->ConstructL( aNodeIdentifier ); + return self; + } + +CNcdNodeSeenInfo::CNcdNodeNewStatus* CNcdNodeSeenInfo::CNcdNodeNewStatus::NewL( + RReadStream& aReadStream ) + { + DLTRACEIN(("")); + CNcdNodeNewStatus* self = CNcdNodeNewStatus::NewLC( aReadStream ); + CleanupStack::Pop( self ); + return self; + } + +CNcdNodeSeenInfo::CNcdNodeNewStatus* CNcdNodeSeenInfo::CNcdNodeNewStatus::NewLC( + RReadStream& aReadStream ) + { + DLTRACEIN(("")); + CNcdNodeNewStatus* self = new ( ELeave ) CNcdNodeNewStatus(); + CleanupStack::PushL( self ); + self->InternalizeL( aReadStream ); + return self; + } + +CNcdNodeSeenInfo::CNcdNodeNewStatus::~CNcdNodeNewStatus() + { + DLTRACEIN(("")); + delete iNodeIdentifier; + } + +const CNcdNodeIdentifier& CNcdNodeSeenInfo::CNcdNodeNewStatus::Identifier() const + { + return *iNodeIdentifier; + } + +TNcdNewStatus CNcdNodeSeenInfo::CNcdNodeNewStatus::NewStatus() const + { + return iNewStatus; + } + +void CNcdNodeSeenInfo::CNcdNodeNewStatus::SetNewStatus( TNcdNewStatus aNewStatus ) + { + DLTRACEIN(("")); + iNewStatus = aNewStatus; + } + +CNcdNodeFactory::TNcdNodeType CNcdNodeSeenInfo::CNcdNodeNewStatus::NodeType() const + { + return iNodeType; + } + +void CNcdNodeSeenInfo::CNcdNodeNewStatus::ExternalizeL( RWriteStream& aStream ) + { + DLTRACEIN(("")); + iNodeIdentifier->ExternalizeL( aStream ); + aStream.WriteInt32L( iNewStatus ); + aStream.WriteInt32L( iNodeType ); + } + + +void CNcdNodeSeenInfo::CNcdNodeNewStatus::InternalizeL( RReadStream& aStream ) + { + DLTRACEIN(("")); + CNcdNodeIdentifier* identifier = CNcdNodeIdentifier::NewL( aStream ); + delete iNodeIdentifier; + iNodeIdentifier = identifier; + iNewStatus = static_cast( aStream.ReadInt32L() ); + iNodeType = static_cast( aStream.ReadInt32L() ); + } + +CNcdNodeSeenInfo::CNcdNodeNewStatus::CNcdNodeNewStatus( TNcdNewStatus aNewStatus, + CNcdNodeFactory::TNcdNodeType aNodeType ) + : iNewStatus( aNewStatus ), iNodeType( aNodeType ) + { + } + +CNcdNodeSeenInfo::CNcdNodeNewStatus::CNcdNodeNewStatus() + { + } + +void CNcdNodeSeenInfo::CNcdNodeNewStatus::ConstructL( + const CNcdNodeIdentifier& aNodeIdentifier ) + { + DLTRACEIN(("")); + iNodeIdentifier = CNcdNodeIdentifier::NewL( aNodeIdentifier ); + }