appinstaller/AppMngr2/src/appmngr2infoarray.cpp
changeset 0 ba25891c3a9e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/appinstaller/AppMngr2/src/appmngr2infoarray.cpp	Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,392 @@
+/*
+* Copyright (c) 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:   Base class for AppInfo and PackageInfo arrays
+*
+*/
+
+
+#include "appmngr2infoarray.h"          // CAppMngr2InfoArray
+#include <appmngr2debugutils.h>         // FLOG macros
+
+const TInt KGranularity = 32;
+
+
+// ======== LOCAL FUNCTIONS =========
+
+// ---------------------------------------------------------------------------
+// CompareInfoNamesC
+// ---------------------------------------------------------------------------
+// Compares two InfoBase objects and defines the order how they are displayed
+// in the UI (in installed applications list or in installation files list).
+// Returns positive integer if aInfo1 > aInfo2 (in defined/alphabetical order),
+// zero if aInfo == aInfo2, and negative integer if aInfo1 < aInfo2.
+TInt CompareInfoNamesC( const CAppMngr2InfoBase& aInfo1, const CAppMngr2InfoBase& aInfo2 )
+    {
+    // IsShowOnTop() must denote "less than" to get the item be displayed before others.
+    // If IsShowOnTop()==ETrue then item is less than item having IsShowOnTop()==EFalse.
+    TInt result = ( aInfo2.IsShowOnTop() - aInfo1.IsShowOnTop() ); 
+    if( !result )
+        {
+        result = aInfo1.Name().CompareC( aInfo2.Name() );
+        if( !result )
+            {
+            // Compare also locations if the names are the same, as otherwise the order of
+            // two items having the same name changes in MoveCachedItemsToArrayInOrderL().
+            // Memory card location is "greater than" location in phone internal memory.
+            result = ( aInfo1.Location() - aInfo2.Location() );
+            }
+        }
+    return result;
+    }
+
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// CAppMngr2InfoArray::CAppMngr2InfoArray()
+// ---------------------------------------------------------------------------
+//
+CAppMngr2InfoArray::CAppMngr2InfoArray( MAppMngr2InfoArrayObserver& aObserver ) :
+        iObserver( aObserver), iArray( KGranularity ), iCache( KGranularity ),
+        iAlphabeticalOrder( CompareInfoNamesC ), iQuickRefreshes( ETrue )
+    {
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2InfoArray::~CAppMngr2InfoArray()
+// ---------------------------------------------------------------------------
+//
+CAppMngr2InfoArray::~CAppMngr2InfoArray()
+    {
+    iArray.ResetAndDestroy();
+    iCache.ResetAndDestroy();
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2InfoArray::At()
+// ---------------------------------------------------------------------------
+//
+CAppMngr2InfoBase* CAppMngr2InfoArray::At( TInt aIndex ) const
+    {
+    if( IsCacheUsed() )
+        {
+        return iCache[ aIndex ];
+        }
+    return iArray[ aIndex ];
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2InfoArray::Count()
+// ---------------------------------------------------------------------------
+//
+TInt CAppMngr2InfoArray::Count() const
+    {
+    if( IsCacheUsed() )
+        {
+        return iCache.Count();
+        }
+    return iArray.Count();
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2InfoArray::IncrementCacheUseL()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2InfoArray::IncrementCacheUseL()
+    {
+    if( !iUseCache )
+        {
+        // First time - take the cache in use. This starts adding new
+        // items to the CAppMngr2InfoArray. New items are always added
+        // to iArray, and iCache is displayed during adding.
+        if( iForceCacheUse )
+            {
+            // Cache already used - initialize iArray for new items.
+            iArray.ResetAndDestroy();
+            
+            // Make sure that observer is notified even if no items
+            // are added to iArray (e.g. "last item deleted" -case).
+            iArrayChangedObserverNeedsNotification = ETrue;
+            }
+        else
+            {
+            // Cache not used - move items to cache and start using it.
+            MoveItemsToCacheMaintainingOrderL();
+            
+            // Reset flag - need to know if cache is forced in use
+            // while it is still in use because of this increment.
+            iForceCacheUseWhenAddingComplete = EFalse;
+            }
+        }
+    iUseCache++;
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2InfoArray::IncrementCacheUseStartingNewRoundL()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2InfoArray::IncrementCacheUseStartingNewRoundL()
+    {
+    if( iUseCache || iForceCacheUse )
+        {
+        // Cache already used - initialize iArray for new items.
+        iArray.ResetAndDestroy();
+        iArrayChangedObserverNeedsNotification = ETrue;
+
+        if( iQuickRefreshes )
+            {
+            // Touch luck - cache is not really used (in order to
+            // show the first items quickly on startup) and hence
+            // it is now necessary to show empty list to the user.
+            // If iObserver would not be notified, there would be
+            // USER 130 panics when UI would try to access iArray
+            // items that are deleted.
+            iObserver.ArrayContentChanged( this, iUseCache + 1 );
+            iArrayChangedObserverNeedsNotification = EFalse;
+            }
+        }
+    IncrementCacheUseL();
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2InfoArray::DecrementCacheUse()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2InfoArray::DecrementCacheUse()
+    {
+    if( iUseCache > 0 )
+        {
+        iUseCache--;
+    
+        if( !iUseCache )
+            {
+            // Quick refreshes are enabled on startup, but they need to be
+            // turned off when the first item adding round is complete.
+            // After the first round the cache is used to handle array
+            // content changes.
+            if( iQuickRefreshes )
+                {
+                iQuickRefreshes = EFalse;
+                }
+        
+            // If adding is now complete, check if there is a request to
+            // force cache on. Note that iForceInUse cannot be set when
+            // cache is already in use (because items are added to iArray),
+            // otherwise partial list would be in iCache and the rest in
+            // iArray. This is why force cache in use is enabled only after
+            // the addition is complete.
+            if( iForceCacheUseWhenAddingComplete )
+                {
+                iForceCacheUse = ETrue;
+                iForceCacheUseWhenAddingComplete = EFalse;
+                }
+            }
+        
+        // Notify UI if cache is not used any more (or quickrefreshing is on)
+        if( !IsCacheUsed() )
+            {
+            NotifyObserver();
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2InfoArray::DisableRefreshNotificationsL()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2InfoArray::DisableRefreshNotificationsL()
+    {
+    // Refresh notifications are disabled by forcing cache on. All changes go
+    // to the iArray and current iCache content is displayed unitl notifications
+    // are enabled again. Observer is not called while refreshes are disabled.
+    if( !iForceCacheUse )
+        {
+        if( iUseCache )
+            {
+            // Cannot force cache in use now because items are still being added
+            // to iArray. This would result partial list to be in iCache and the
+            // rest of items in iArray. Later when deletions are enabled, only the
+            // items in iArray would be displayed. So, set a flag that forces cache
+            // on when item additions are complete, so that observer is notified
+            // only after deletions are enabled again.
+            iForceCacheUseWhenAddingComplete = ETrue;
+            }
+        else
+            {
+            // Set cache in use
+            MoveItemsToCacheMaintainingOrderL();
+            iForceCacheUse = ETrue;
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2InfoArray::EnableRefreshNotificationsL()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2InfoArray::EnableRefreshNotificationsL()
+    {
+    // It is safe to call EnableRefreshNotificationsL() many times, even if
+    // notifications have not been disabled first.
+    iForceCacheUseWhenAddingComplete = EFalse;
+    if( iForceCacheUse )
+        {
+        iForceCacheUse = EFalse;
+        if( !iUseCache )
+            {
+            // Refresh notifications were disabled by moving items to iCache. If no
+            // new items were added to iArray while notifications were disabled,
+            // then those moved items must be moved back to iArray again. Otherwise
+            // disabling cache would show just an empty list. If new items were added
+            // while refresh notifications were disabled, then observer needs
+            // notification and cache content can be ignored, as new content is
+            // already available in iArray.
+            if( iArrayChangedObserverNeedsNotification )
+                {
+                NotifyObserver();
+                }
+            else
+                {
+                MoveCachedItemsToArrayInOrderL();
+                }
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2InfoArray::AddItemInOrderL()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2InfoArray::AddItemInOrderL( CAppMngr2InfoBase* aInfo )
+    {
+    if( aInfo )
+        {
+        FLOG( "CAppMngr2InfoArray::AddItemInOrderL( %S )", &( aInfo->Name() ) );
+        
+        // All items are added to iArray and iCache is used while the changes
+        // are not wanted to be seen via Count() and At() functions. Observer
+        // is notified when the iArray is taken in use. 
+        iArray.InsertInOrderAllowRepeatsL( aInfo, iAlphabeticalOrder );
+        if( iForceCacheUse || iForceCacheUseWhenAddingComplete )
+            {
+            iArrayChangedObserverNeedsNotification = ETrue;
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2InfoArray::ImmediateDelete()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2InfoArray::ImmediateDelete( CAppMngr2InfoBase* aInfo )
+    {
+    FLOG( "CAppMngr2InfoArray::ImmediateDelete( 0x%08x )", aInfo );
+    
+    RPointerArray<CAppMngr2InfoBase>* array;
+    if( IsCacheUsed() )
+        {
+        array = &iCache;
+        }
+    else
+        {
+        array = &iArray;
+        }
+    
+    TBool found = EFalse;
+    TInt count = array->Count();
+    for( TInt index = 0; index < count && !found; index++ )
+        {
+        if( ( *array )[ index ] == aInfo )
+            {
+            array->Remove( index );
+            delete aInfo;
+            found = ETrue;
+            }
+        }
+
+    if( found )
+        {
+        iObserver.ArrayContentChanged( this, iUseCache );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2InfoArray::MoveItemsToCacheMaintainingOrderL()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2InfoArray::MoveItemsToCacheMaintainingOrderL()
+    {
+    // Move items from iArray to iCache maintaining order.
+    iCache.ResetAndDestroy();
+    TInt count = iArray.Count();
+    for( TInt index = count - 1; index >= 0; index-- )
+        {
+        iCache.InsertL( iArray[ index ], 0 );
+        iArray.Remove( index );
+        }
+    iArray.ResetAndDestroy();
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2InfoArray::MoveCachedItemsToArrayInOrderL()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2InfoArray::MoveCachedItemsToArrayInOrderL()
+    {
+    // Move items from iCache to iArray using proper order. There may be
+    // new items in iArray hence it is not possible to simply move items
+    // as in MoveItemsToCacheMaintainingOrderL().
+    TInt count = iCache.Count();
+    for( TInt index = count - 1; index >= 0; index-- )
+        {
+        iArray.InsertInOrderAllowRepeatsL( iCache[ index ], iAlphabeticalOrder );
+        iCache.Remove( index );
+        }
+    iCache.ResetAndDestroy();
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2InfoArray::NotifyObserver()
+// ---------------------------------------------------------------------------
+//
+void CAppMngr2InfoArray::NotifyObserver()
+    {
+    iObserver.ArrayContentChanged( this, iUseCache );
+    iArrayChangedObserverNeedsNotification = EFalse;
+    iCache.ResetAndDestroy();
+    }
+
+// ---------------------------------------------------------------------------
+// CAppMngr2InfoArray::IsCacheUsed()
+// ---------------------------------------------------------------------------
+//
+TBool CAppMngr2InfoArray::IsCacheUsed() const
+    {
+    // New items are added to iArray and static old content may be displayed
+    // from iCache while iArray is being updated. Priorities: 1) cache forced
+    // in use, 2) quick refreshes, and 3) normal inc/dec cache usage. If cache
+    // is forced in use, it prevents also changes that quick refreshes might
+    // otherwise display. If quick refreshing is enabled, then item additions
+    // to iArray are visible to observer, although normally iCache would be used.
+    if( iForceCacheUse )
+        {
+        return ETrue;
+        }
+    if( iQuickRefreshes )
+        {
+        return EFalse;
+        }
+    return ( iUseCache > 0 );
+    }
+