iaupdate/IAD/engine/controller/src/iaupdatenodeimpl.cpp
changeset 0 ba25891c3a9e
child 11 3ba40be8e484
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/iaupdate/IAD/engine/controller/src/iaupdatenodeimpl.cpp	Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,974 @@
+/*
+* Copyright (c) 2007-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:   This module contains the implementation of CIAUpdateNode class 
+*                member functions.
+*
+*/
+
+#include <ncdnode.h>
+#include <ncdnodepurchase.h>
+#include <ncdnodedownload.h>
+#include <ncdnodeinstall.h>
+
+#include "iaupdatenodeimpl.h"
+#include "iaupdatenodeobserver.h"
+#include "iaupdatenodedependencyimpl.h"
+#include "iaupdatenodedetails.h"
+#include "iaupdatecontrollerimpl.h"
+#include "iaupdateutils.h"
+#include "iaupdatecontentoperationmanager.h"
+#include "iaupdatedebug.h"
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateNode::NewLC
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+// 
+CIAUpdateNode* CIAUpdateNode::NewLC( MNcdNode* aNode,
+                                     CIAUpdateController& aController )
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::NewLC() begin");
+
+    CIAUpdateNode* self = 
+        new( ELeave ) CIAUpdateNode( aController );
+    CleanupStack::PushL( self );    
+    self->ConstructL( aNode );
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::NewLC() end");
+
+    return self;
+    }
+
+    
+// -----------------------------------------------------------------------------
+// CIAUpdateNode::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//     
+CIAUpdateNode* CIAUpdateNode::NewL( MNcdNode* aNode,
+                                    CIAUpdateController& aController )
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::NewL() begin");
+    CIAUpdateNode* self = 
+        CIAUpdateNode::NewLC( aNode, aController );
+    CleanupStack::Pop( self );
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::NewL() end");
+    return self;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateNode::CIAUpdateNode
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CIAUpdateNode::CIAUpdateNode( CIAUpdateController& aController ) 
+: CIAUpdateBaseNode( aController )
+    {
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateNode::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CIAUpdateNode::ConstructL( MNcdNode* aNode )
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::ConstructL() begin");
+
+    // Let the parent handle it all.
+    CIAUpdateBaseNode::ConstructL( aNode );
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::ConstructL() end");
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateNode::~CIAUpdateNode
+// Destructor
+// -----------------------------------------------------------------------------
+//    
+CIAUpdateNode::~CIAUpdateNode()
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::~CIAUpdateNode() begin");
+
+    iDependants.Reset();
+    iExcessDependencyNodes.Reset();
+    
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::~CIAUpdateNode() end");
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateBaseNode overloaded functions
+// 
+// ---------------------------------------------------------------------------
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::ContentSizeL
+// 
+// ---------------------------------------------------------------------------
+//
+TInt CIAUpdateNode::ContentSizeL() const
+    {
+    // Notice, here we give the total content size through the interface.
+    // Here we want only the dependency nodes that are hidden.
+    // Skip visible dependencies because those nodes are visible in UI
+    // and their content size is separately shown and calculated in UI.
+    return 
+        Controller().
+            ContentOperationManager().
+                TotalContentSizeL( *this, ETrue, EFalse, ETrue, EFalse );        
+    }
+
+
+// ---------------------------------------------------------------------------
+// MIAUpdateNode functions
+// 
+// ---------------------------------------------------------------------------
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::Type
+// 
+// ---------------------------------------------------------------------------
+//    
+MIAUpdateNode::TPackageType CIAUpdateNode::Type() const
+    {
+    IAUPDATE_TRACE_1("[IAUPDATE] CIAUpdateNode::Type() = %d", 
+                     Details().ContentType());
+    return Details().ContentType();
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::IsSelfUpdate
+// 
+// ---------------------------------------------------------------------------
+//
+TBool CIAUpdateNode::IsSelfUpdate() const    
+    {
+    return EFalse;
+    }        
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::GetDependenciesL
+// 
+// ---------------------------------------------------------------------------
+//       
+void CIAUpdateNode::GetDependenciesL( 
+    RPointerArray< MIAUpdateNode >& aDependencies,
+    TBool aIncludeHidden ) const
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::GetDependenciesL() begin");
+
+    RPointerArray< CIAUpdateNode > dependencies;
+    CleanupClosePushL( dependencies );
+
+    GetDependencyNodesL( dependencies, aIncludeHidden );
+
+    aDependencies.ReserveL( dependencies.Count() );    
+    for ( TInt i = 0; i < dependencies.Count(); ++i )
+        {
+        aDependencies.AppendL( dependencies[ i ] );
+        }
+
+    CleanupStack::PopAndDestroy( &dependencies );
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::GetDependenciesL() end");
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::GetDependantsL
+// 
+// ---------------------------------------------------------------------------
+//    
+void CIAUpdateNode::GetDependantsL( 
+    RPointerArray< MIAUpdateNode >& aDependants,
+    TBool aIncludeHidden ) const
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::GetDependantsL() begin");
+
+    aDependants.Reserve( iDependants.Count() );
+    for( TInt i = 0; i < iDependants.Count(); ++i )
+        {
+        CIAUpdateNode* dependant( iDependants[ i ] );
+        if ( aIncludeHidden 
+             || !dependant->Hidden() )
+            {
+            aDependants.AppendL( iDependants[ i ] );
+            }
+        } 
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::GetDependantsL() end"); 	
+    }
+    
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::IsDownloaded
+// 
+// ---------------------------------------------------------------------------
+//
+TBool CIAUpdateNode::IsDownloaded() const
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::IsDownloaded() begin");
+
+    TBool downloaded( EFalse );
+    TRAP_IGNORE ( downloaded = IsDownloadedL() );
+
+    IAUPDATE_TRACE_1("[IAUPDATE] CIAUpdateNode::IsDownloaded() end: %d",
+                     downloaded);
+
+    return downloaded;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::IsInstalled
+// 
+// ---------------------------------------------------------------------------
+//
+TBool CIAUpdateNode::IsInstalled() const
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::IsInstalled() begin");
+
+    TBool installed( EFalse );
+    TRAP_IGNORE ( installed = IsInstalledL() );
+
+    IAUPDATE_TRACE_1("[IAUPDATE] CIAUpdateNode::IsInstalled() end: %d",
+                     installed);
+
+    return installed;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::DownloadL
+// 
+// ---------------------------------------------------------------------------
+//
+void CIAUpdateNode::DownloadL( MIAUpdateNodeObserver& aObserver )
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::DownloadL() begin");
+
+    if( iOperationObserver )
+        {
+        User::Leave( KErrInUse );
+        }
+
+    // Instead of starting download operation here, we start purchase operation.
+    // Purchase needs to be done before download. When purchase compeletes,
+    // the call back function is called and that will start download operation.
+    // Notice, that we can try to create the purchase even if it has already been
+    // done. Then, the operation just finishes without repurchasing.
+
+    // Use content operation manager.
+    // It can handle the possible hidden node chain that requires operations 
+    // for multiple nodes.
+    Controller().
+        ContentOperationManager().
+            StartL( *this, 
+                    CIAUpdateContentOperationManager::EPurchaseOperation, 
+                    *this );
+
+    iOperationObserver = &aObserver;
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::DownloadL() end");
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::InstallL
+// 
+// ---------------------------------------------------------------------------
+//
+void CIAUpdateNode::InstallL( MIAUpdateNodeObserver& aObserver )
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::InstallL() begin");
+    
+    if( iOperationObserver )
+        {
+        User::Leave( KErrInUse );
+        }
+
+    // Use content operation manager.
+    // It can handle the possible hidden node chain that requires operations 
+    // for multiple nodes.
+    Controller().
+        ContentOperationManager().
+            StartL( *this, 
+                    CIAUpdateContentOperationManager::EInstallOperation, 
+                    *this );
+
+    iOperationObserver = &aObserver;
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::InstallL() end");
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::CancelOperation()
+// 
+// ---------------------------------------------------------------------------
+//
+void CIAUpdateNode::CancelOperation()
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::CancelOperation() begin");
+
+    // This will cancel the possible ongoing operation
+    Controller().ContentOperationManager().Cancel();
+    
+    // Also, set the observer to NULL.
+    // Because this value is used to check if operations are going on.
+    iOperationObserver = NULL;
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::CancelOperation() end");
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::Depth()
+// 
+// ---------------------------------------------------------------------------
+//
+TInt CIAUpdateNode::Depth() const
+    {
+    return iDepth;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::NodeType
+// 
+// ---------------------------------------------------------------------------
+//
+MIAUpdateAnyNode::TNodeType CIAUpdateNode::NodeType() const
+    {
+    return MIAUpdateAnyNode::ENodeTypeNormal;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::Base
+// 
+// ---------------------------------------------------------------------------
+//
+MIAUpdateBaseNode& CIAUpdateNode::Base()
+    {
+    return *this;   
+    }
+
+
+// ---------------------------------------------------------------------------
+// MIAUpdateContentOperationObserver functions
+// 
+// ---------------------------------------------------------------------------
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::ContentOperationCompleteL
+// 
+// ---------------------------------------------------------------------------
+//
+void CIAUpdateNode::ContentOperationComplete( CIAUpdateBaseNode& /*aNode*/, 
+                                              TInt aError )
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::ContentOperationComplete() begin");
+
+    // Get the observer to a temporary pointer. So, we can use it 
+    // when informing observers. The member variable needs to be set to NULL
+    // before callbacks are called.
+    MIAUpdateNodeObserver* tmpObserver( iOperationObserver );
+    
+    const CIAUpdateContentOperationManager::TContentOperationType& operationType(
+        Controller().ContentOperationManager().OperationType() );
+
+    if ( operationType == CIAUpdateContentOperationManager::EPurchaseOperation )
+        {
+        IAUPDATE_TRACE_1("[IAUPDATE] Purchase operation complete: %d", aError);
+        if ( aError == KErrNone )
+            {
+            // Purchase operation was successfull.
+            // So, now try to download the actual content.
+            TRAPD ( trapError, 
+                    Controller().
+                        ContentOperationManager().
+                            StartL( *this, 
+                                    CIAUpdateContentOperationManager::EDownloadOperation, 
+                                    *this ); );
+            IAUPDATE_TRACE_1("[IAUPDATE] download trap error code: %d", trapError );
+            if ( trapError != KErrNone )
+                {
+                IAUPDATE_TRACE("[IAUPDATE] Could not create download operation.");
+                // Something went wrong when initializing download operation.
+                iOperationObserver = NULL;
+                // Inform observer about the completion of operation.
+                tmpObserver->DownloadComplete( *this, trapError );
+                }            
+            }
+        else
+            {
+            IAUPDATE_TRACE("[IAUPDATE] Purchase was not success. Complete download.");
+            // Operation was not successfull.
+            // There is no reason to continue.
+            // Inform observer about the completion of operation.
+            iOperationObserver = NULL;
+            tmpObserver->DownloadComplete( *this, aError );
+            }
+        }
+    else if ( operationType == CIAUpdateContentOperationManager::EDownloadOperation )
+        {
+        IAUPDATE_TRACE("[IAUPDATE] Download operation complete");
+        iOperationObserver = NULL;
+        // Inform observer about the completion of operation.
+        tmpObserver->DownloadComplete( *this, aError );
+        }
+    else if ( operationType == CIAUpdateContentOperationManager::EInstallOperation )
+        {
+        IAUPDATE_TRACE("[IAUPDATE] Install operation complete");
+        iOperationObserver = NULL;
+        // Inform observers about the completion of operation.
+        tmpObserver->InstallComplete( *this, aError );        
+        }
+    else
+        {
+        // We should never come here.
+        IAUPDATE_TRACE("[IAUPDATE] ERROR No operation was going on even if callback called");        
+        iOperationObserver = NULL;
+        }
+        
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::ContentOperationComplete() end");
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::ContentOperationProgress
+// 
+// ---------------------------------------------------------------------------
+// 
+void CIAUpdateNode::ContentOperationProgress( CIAUpdateBaseNode& /*aNode*/, 
+                                              TInt aProgress, 
+                                              TInt aMaxProgress )
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::ContentOperationProgress() begin");
+
+    // Inform the observer about the progress of download and install.
+    // There is no need to inform about the purchase progress.
+    switch( Controller().ContentOperationManager().OperationType() )
+        {
+        case CIAUpdateContentOperationManager::EDownloadOperation:
+            IAUPDATE_TRACE("[IAUPDATE] Download operation progress");
+            iOperationObserver->
+                DownloadProgress( *this, aProgress, aMaxProgress );
+            break;
+
+        case CIAUpdateContentOperationManager::EInstallOperation:
+            IAUPDATE_TRACE("[IAUPDATE] Install operation progress");
+            iOperationObserver->
+                InstallProgress( *this, aProgress, aMaxProgress );
+            break;
+
+        default:
+            IAUPDATE_TRACE_1("[IAUPDATE] Do not inform observer: %d",
+                             Controller().
+                                ContentOperationManager().
+                                    OperationType());
+            break;
+        }
+        
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::ContentOperationProgress() end");
+    }
+
+
+// ---------------------------------------------------------------------------
+// Public functions
+// 
+// ---------------------------------------------------------------------------
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::Reset
+// 
+// ---------------------------------------------------------------------------
+//
+void CIAUpdateNode::Reset()
+    {
+    SetDependencyCheckStatus( 
+        CIAUpdateNode::EDependencyCheckNotSet );
+    SetDepth( 0 );
+    SetLeafDistance( 0 );
+    iDependants.Reset();
+    iExcessDependencyNodes.Reset();
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::IsPurchased
+// 
+// ---------------------------------------------------------------------------
+//
+TBool CIAUpdateNode::IsPurchased() const
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::IsPurchased() begin");
+
+    TBool purchased( EFalse );
+    TRAP_IGNORE( purchased = IsPurchasedL() );
+
+    IAUPDATE_TRACE_1("[IAUPDATE] CIAUpdateNode::IsPurchased() end: %d", purchased);
+
+    return purchased;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::SetExcessDependencyL
+// 
+// ---------------------------------------------------------------------------
+//
+void CIAUpdateNode::SetExcessDependencyL( 
+    CIAUpdateNode& aDependencyNode,
+    TBool aAddDependency )
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::SetExcessDependencyL() begin");
+    
+    // First check if the dependency has already been set in details.
+    RPointerArray< CIAUpdateNodeDependency > dependencies;
+    CleanupClosePushL( dependencies );
+    Details().GetDependenciesL( dependencies );
+    for ( TInt i = 0; i < dependencies.Count(); ++i )
+        {
+        CIAUpdateNodeDependency* dependency( dependencies[ i ] );
+        if ( dependency->Uid() == aDependencyNode.Uid() )
+            {
+            // Dependency has already been set.
+            CleanupStack::PopAndDestroy( &dependencies );
+            return;
+            }
+        }
+    CleanupStack::PopAndDestroy( &dependencies );
+
+    // Check if the node already exists in excess array.
+    for ( TInt i = 0; i < iExcessDependencyNodes.Count(); ++i )
+        {
+        CIAUpdateNode* node( iExcessDependencyNodes[ i ] );
+        if ( node->Uid() == aDependencyNode.Uid() )
+            {
+            // Dependency has already been set.            
+            return;
+            }
+        }
+
+    // Depth update and loop check.
+    RPointerArray< CIAUpdateNode > dependencyNodes;
+    CleanupClosePushL( dependencyNodes );
+    // Get dependency hierarchy.
+    // Accept all kind of nodes.
+    Controller().
+        ContentOperationManager().
+            GetOperationNodesL( aDependencyNode, 
+                                dependencyNodes,
+                                ETrue, ETrue );
+    TInt findError( 
+        dependencyNodes.Find( this ) );
+    CleanupStack::PopAndDestroy( &dependencyNodes );
+
+    // If the given dependency node depends on this node,
+    // then new dependency would create a loop. So, only
+    // accept node if loop will not occur.
+    if ( findError == KErrNotFound )
+        {
+        IAUPDATE_TRACE("[IAUPDATE] Check passed");
+
+        // Update the leaf distances of the this dependant node
+        // and its dependant hierarchy if necessary. Dependant leaf
+        // distance is always at least one greater than its dependency
+        // leaf distance.
+        UpdateDependantLeafDistancesL(
+            aDependencyNode.LeafDistance() + 1 );
+
+        // Update the depth of the dependency hierarchy
+        // if necessary. Dependency depth is always at least one
+        // greater than depth of its dependant.
+        aDependencyNode.
+            UpdateDependencyDepthsL( Depth() + 1 );
+
+        if ( aAddDependency )
+            {
+            IAUPDATE_TRACE("[IAUPDATE] Add dependency"); 
+            // Insert the given dependant node into the array.
+            // The given node is thought as the best match for the dependency.
+            // Also, this function supposes that the dependency chain below the dependency
+            // node is intact.
+            iExcessDependencyNodes.AppendL( &aDependencyNode );
+            // Also, because new dependency is inserted, make sure that
+            // the dependency node dependant info is set correctly.
+            aDependencyNode.AddDependantL( *this );            
+            }
+        }
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::SetExcessDependencyL() end");
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::GetDependencyNodesL
+// 
+// ---------------------------------------------------------------------------
+//
+void CIAUpdateNode::GetDependencyNodesL( 
+    RPointerArray< CIAUpdateNode >& aDependencies,
+    TBool aIncludeHidden ) const
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::GetDependencyNodesL() begin");
+    
+    RPointerArray< CIAUpdateNodeDependency > dependencies;
+    CleanupClosePushL( dependencies );
+
+    // First get the dependencies from the details object.
+    // These are dependencies given by the server itself.
+    Details().GetDependenciesL( dependencies );
+    
+    aDependencies.ReserveL( 
+        dependencies.Count() + iExcessDependencyNodes.Count() );
+    
+    // Insert node that corresponds the details to the array.
+    for ( TInt i = 0; i < dependencies.Count(); ++i )
+        {
+        CIAUpdateNodeDependency* dependency( dependencies[ i ] );
+        CIAUpdateNode* node( dependency->BestMatch() );
+        if ( node && ( aIncludeHidden || !node->Hidden() ) )
+            {
+            aDependencies.AppendL( node );        
+            }
+        }
+    
+    CleanupStack::PopAndDestroy( &dependencies );
+
+    // Insert excess dependencies to the array.
+    for ( TInt i = 0; i < iExcessDependencyNodes.Count(); ++i )
+        {
+        CIAUpdateNode* node( iExcessDependencyNodes[ i ] );
+        if ( aIncludeHidden || !node->Hidden() )
+            {
+            aDependencies.AppendL( node );
+            }
+        }
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::GetDependencyNodesL() end");
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::SetDependencyCheckStatus
+// 
+// ---------------------------------------------------------------------------
+//
+void CIAUpdateNode::SetDependencyCheckStatus( 
+    CIAUpdateNode::TDependencyCheckStatus aStatus )
+    {
+    IAUPDATE_TRACE_1("[IAUPDATE] CIAUpdateNode::SetDependencyCheckStatus() = %d", 
+                     aStatus );
+    iDependencyCheckStatus = aStatus;
+    }
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::DependencyCheckStatus()
+// 
+// ---------------------------------------------------------------------------
+//    
+CIAUpdateNode::TDependencyCheckStatus CIAUpdateNode::DependencyCheckStatus() const
+    {
+    IAUPDATE_TRACE_1("[IAUPDATE] CIAUpdateNode::DependencyCheckStatus() = %d", 
+                     iDependencyCheckStatus );
+    return iDependencyCheckStatus;
+    }   
+    
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::LeafDistance
+// 
+// ---------------------------------------------------------------------------
+//
+TInt CIAUpdateNode::LeafDistance() const
+    {
+    IAUPDATE_TRACE_1("[IAUPDATE] CIAUpdateNode::LeafDistance() = %d", 
+                     iLeafDistance );
+    return iLeafDistance;
+    }
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::SetLeafDistance
+// 
+// ---------------------------------------------------------------------------
+//
+void CIAUpdateNode::SetLeafDistance( TInt aDistance )
+    {
+    IAUPDATE_TRACE_1("[IAUPDATE] CIAUpdateNode::SetLeafDistance() = %d", 
+                     aDistance );
+    iLeafDistance = aDistance;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::SetDepth
+// 
+// ---------------------------------------------------------------------------
+//
+void CIAUpdateNode::SetDepth( TInt aDepth )
+    {
+    IAUPDATE_TRACE_1("[IAUPDATE] CIAUpdateNode::SetDepth() = %d", 
+                     aDepth );
+    iDepth = aDepth;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::DependantNodes
+// 
+// ---------------------------------------------------------------------------
+//
+const RPointerArray< CIAUpdateNode >& CIAUpdateNode::DependantNodes() const
+    {
+    return iDependants;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::AddDependantL
+// 
+// ---------------------------------------------------------------------------
+//
+void CIAUpdateNode::AddDependantL( CIAUpdateNode& aDependantNode ) 
+    {
+	IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::AddDependantL() begin");
+
+	for ( TInt i = 0; i < iDependants.Count(); ++i )
+	    {
+	    CIAUpdateNode* node( iDependants[ i ] );
+	    if ( node->Uid() == aDependantNode.Uid() )
+	        {
+	        // Corresponding node is already in the array.
+	        return;
+	        }
+	    }
+
+	iDependants.AppendL( &aDependantNode );
+
+	IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::AddDependantL() end");
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::UpdateDependencyDepthsL
+// 
+// ---------------------------------------------------------------------------
+//
+void CIAUpdateNode::UpdateDependencyDepthsL( TInt aDepth )
+    {
+    IAUPDATE_TRACE_1("[IAUPDATE] CIAUpdateNode::UpdateDependencyDepthsL() begin: %d",
+                     aDepth);
+    
+    // Notice, that by comparing depths here, we also make sure
+    // that the depth is increased correctly if we come to same
+    // dependency node via multiple branches. Multiple dependants 
+    // can depend on the same node.
+
+    // If dependant depth had increased, then depenencies should
+    // also increase their depth. Also, update if negative value is given.
+    // Then, think this node as root.
+    if ( aDepth > Depth() )
+        {
+        IAUPDATE_TRACE("[IAUPDATE] Update dependency depth");
+
+        SetDepth( aDepth );
+
+        RPointerArray< CIAUpdateNode > dependencies;
+        CleanupClosePushL( dependencies );
+        
+        // Also, accept hidden nodes here.
+        GetDependencyNodesL( dependencies, ETrue );
+        
+        // Recursively loop all the dependencies of the node
+        for ( TInt i = 0; i < dependencies.Count(); ++i )
+            {
+            dependencies[ i ]
+                ->UpdateDependencyDepthsL( 
+                    Depth() + 1 );
+            }
+
+        CleanupStack::PopAndDestroy( &dependencies );
+        }
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::UpdateDependencyDepthsL() end");
+    }
+
+
+// ---------------------------------------------------------------------------
+// Protected functions
+// 
+// ---------------------------------------------------------------------------
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::IsPurchasedL
+// 
+// ---------------------------------------------------------------------------
+//
+TBool CIAUpdateNode::IsPurchasedL() const
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::IsPurchasedL() begin");
+    
+    TBool purchased( EFalse );
+    
+    MNcdNodePurchase* purchase( 
+        Node().QueryInterfaceLC< MNcdNodePurchase >() );
+    
+    if ( purchase )
+        {
+        if( purchase->IsPurchased() )
+            {
+            purchased = ETrue;
+            }
+
+        CleanupStack::PopAndDestroy( purchase );
+        }
+
+    IAUPDATE_TRACE_1("[IAUPDATE] CIAUpdateNode::IsPurchasedL() end: %d", 
+                     purchased);
+
+    return purchased;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::IsDownloadedL
+// 
+// ---------------------------------------------------------------------------
+//
+TBool CIAUpdateNode::IsDownloadedL() const
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::IsDownloadedL() begin");
+    
+    TBool downloaded( EFalse );
+    
+    MNcdNodeDownload* download( 
+        Node().QueryInterfaceLC< MNcdNodeDownload >() );
+    
+    if ( download )
+        {
+        if( download->IsDownloadedL() )
+            {
+            downloaded = ETrue;            
+            }
+
+        CleanupStack::PopAndDestroy( download );
+        }
+
+    IAUPDATE_TRACE_1("[IAUPDATE] CIAUpdateNode::IsDownloadedL() end: %d", 
+                     downloaded);
+
+    return downloaded;
+    }    
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::IsInstalledL
+// 
+// ---------------------------------------------------------------------------
+//
+TBool CIAUpdateNode::IsInstalledL() const
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::IsInstalledL() begin");
+
+    TIAUpdateVersion installedVersion;
+    TBool installed( IAUpdateUtils::IsAppInstalledL( Uid(), installedVersion ) );
+    IAUPDATE_TRACE_3("CIAUpdateNode::IsInstalledL() Installed version  %d.%d.%d", 
+            installedVersion.iMajor, 
+            installedVersion.iMinor, 
+            installedVersion.iBuild );
+    IAUPDATE_TRACE_3("CIAUpdateNode::IsInstalledL() Metadata version  %d.%d.%d", 
+            Version().iMajor, 
+            Version().iMinor, 
+            Version().iBuild );
+    if ( installed && installedVersion >= Version() )
+        {
+        // If the installed version is same or newer, then think the node as
+        // installed.
+        IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::IsInstalledL() end ETrue");
+        return ETrue;
+        }
+    else
+        {
+        IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::IsInstalledL() end EFalse");
+        return EFalse;
+        }
+    }    
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::OperationObserverL
+// 
+// ---------------------------------------------------------------------------
+//
+MIAUpdateNodeObserver* CIAUpdateNode::OperationObserver() const
+    {
+    return iOperationObserver;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Private functions
+// 
+// ---------------------------------------------------------------------------
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateNode::UpdateDependantLeafDistancesL
+// 
+// ---------------------------------------------------------------------------
+//
+void CIAUpdateNode::UpdateDependantLeafDistancesL( TInt aLeafDistance )
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::UpdateDependantLeafDistancesL() begin");
+    
+    // Notice, that by comparing depths here, we also make sure
+    // that the leaf distance is increased correctly if we come to same
+    // dependant node via multiple branches. Multiple dependants 
+    // can depend on the same node.
+
+    // Dependant leaf distance should be at least one greater than
+    // dependency depth. 
+    if ( aLeafDistance > LeafDistance() )
+        {
+        IAUPDATE_TRACE("[IAUPDATE] Update dependant distance");
+
+        SetLeafDistance( aLeafDistance );
+
+        // Recursively loop all the dependants of the node
+        for ( TInt i = 0; i < DependantNodes().Count(); ++i )
+            {
+            DependantNodes()[ i ]
+                ->UpdateDependantLeafDistancesL( 
+                    LeafDistance() + 1 );
+            }
+        }
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateNode::UpdateDependantLeafDistancesL() end");
+    }