phonebookui/Phonebook2/UIControls/src/CPbk2NamesListControl.cpp
branchRCL_3
changeset 3 04ab22b956c2
parent 0 e686773b3f54
child 14 81f8547efd4f
--- a/phonebookui/Phonebook2/UIControls/src/CPbk2NamesListControl.cpp	Tue Feb 02 10:12:17 2010 +0200
+++ b/phonebookui/Phonebook2/UIControls/src/CPbk2NamesListControl.cpp	Fri Feb 19 22:40:27 2010 +0200
@@ -41,17 +41,22 @@
 #include <Pbk2InternalUID.h>
 #include "CPbk2PredictiveSearchFilter.h"
 #include "cpbk2contactviewdoublelistbox.h"
+#include <CPbk2ThumbnailManager.h>
+#include <Pbk2CommonUi.rsg>
+#include <Pbk2UIControls.rsg>
 
 // Virtual Phonebook
 #include <MVPbkContactViewBase.h>
 #include <MVPbkViewContact.h>
 #include <MVPbkContactLink.h>
+#include <CVPbkContactLinkArray.h>
 
 // System includes
 #include <barsread.h>
 #include <aknsfld.h>
 #include <AknPriv.hrh>
 #include <featmgr.h>
+#include <AknWaitDialog.h>
 
 // Debugging headers
 #include <Pbk2Debug.h>
@@ -265,6 +270,82 @@
         MPbk2UiControlEventSender& iEventSender;
     };
 
+
+/**
+ * Background Task Handler.
+ */
+NONSHARABLE_CLASS(CPbk2NamesListControlBgTask) : public CActive
+    {    
+    
+    public:
+        CPbk2NamesListControlBgTask( CPbk2NamesListControl& aControl );
+        ~CPbk2NamesListControlBgTask();
+
+        void AddEvent( CPbk2NamesListControl::TPbk2NamesListBgEvents aEvent );
+        void ClearAllEvents();
+        void RemoveEvent( CPbk2NamesListControl::TPbk2NamesListBgEvents aEvent );
+        
+    private: // From CActive
+        void DoCancel();
+        void RunL();
+        TInt RunError(TInt aError);
+
+    private:
+        //Owns
+        RArray <CPbk2NamesListControl::TPbk2NamesListBgEvents> iEventQueue;  
+        
+        //doesnt Own
+        CPbk2NamesListControl& iControl;
+    };
+
+/**
+ * A helper class for mass update cases.
+ */
+NONSHARABLE_CLASS( CPbk2HandleMassUpdate ) : public CBase
+    {
+    public: // Construction and destruction
+        /**
+         * Creates new instance of this class.
+         * @return new instance of this class.
+         */
+        static CPbk2HandleMassUpdate* NewL(CEikListBox& iListBox);
+
+        /**
+         * Destructor.
+         */
+       ~CPbk2HandleMassUpdate();
+
+    public: 
+        /**
+         * Call this function after each update event.
+         * @return  ETrue if this event is part of a mass update.
+         */	
+       TBool MassUpdateCheckThis();
+
+        /**
+         * Call this function to check if mass update process is ongoing.
+         * @return  ETrue if mass update process is ongoing.
+         */	   
+       TBool MassUpdateDetected();
+       
+    private: 
+        CPbk2HandleMassUpdate(CEikListBox& iListBox);
+        void ConstructL();
+        TBool HandleMassUpdateCheckL(); 
+        void HandleMassUpdateCheckReset();
+        void HandleMassUpdateDone();
+        static TInt HandleMassUpdateTimerCallBack(TAny* aAny);        
+
+    private: 
+		CEikListBox& iListBox;
+        TBool iHandleMassUpdate;
+        TTime iHandleMassUpdateFirst;
+        TTime iHandleMassUpdatePrev;        
+        TInt  iHandleMassUpdateCount;
+        CPeriodic* iHandleMassUpdateTimer;      
+		CAknWaitDialog*  iHandleMassUpdateDialog;		
+    };
+
 // --------------------------------------------------------------------------
 // CPbk2UiControlEventSender::CPbk2UiControlEventSender
 // --------------------------------------------------------------------------
@@ -541,6 +622,195 @@
     }
 
 // --------------------------------------------------------------------------
+// CPbk2HandleMassUpdate::NewL
+// --------------------------------------------------------------------------
+//
+CPbk2HandleMassUpdate* CPbk2HandleMassUpdate::NewL(CEikListBox& aListBox)
+    {
+    CPbk2HandleMassUpdate* self =
+        new( ELeave ) CPbk2HandleMassUpdate(aListBox);
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2HandleMassUpdate::~CPbk2HandleMassUpdate
+// --------------------------------------------------------------------------
+//
+CPbk2HandleMassUpdate::~CPbk2HandleMassUpdate()
+    {
+    delete iHandleMassUpdateDialog;
+    delete iHandleMassUpdateTimer;    
+    }
+    
+// --------------------------------------------------------------------------
+// CPbk2HandleMassUpdate::CPbk2HandleMassUpdate
+// --------------------------------------------------------------------------
+//
+CPbk2HandleMassUpdate::CPbk2HandleMassUpdate(CEikListBox& aListBox) :
+    iListBox(aListBox)
+    {
+    }	
+	
+// --------------------------------------------------------------------------
+// CPbk2HandleMassUpdate::ConstructL
+// --------------------------------------------------------------------------
+//
+void CPbk2HandleMassUpdate::ConstructL()
+    {
+    iHandleMassUpdateTimer = CPeriodic::NewL( CActive::EPriorityIdle );
+    }    
+
+// --------------------------------------------------------------------------
+// CPbk2HandleMassUpdate::HandleMassUpdateCheckThis
+//
+// Functionality to detect mass updates done to contact database and to prevent
+// e.g nameslist flickering when constant updates are happening in background
+// when pc sync etc is adding hundreds of contacts in line
+// --------------------------------------------------------------------------
+//
+TBool CPbk2HandleMassUpdate::MassUpdateCheckThis()
+    {
+    TBool ret(EFalse);
+    const TInt KNbrUpdBeforeMassCheck(5); 
+    iHandleMassUpdateTimer->Cancel();
+
+    if( iHandleMassUpdateCount > KNbrUpdBeforeMassCheck ) 
+        {
+        //candidates to be checked are they continual of a mass update
+        TRAP_IGNORE(ret = HandleMassUpdateCheckL());
+        }
+    else if( iHandleMassUpdateCount > 0 ) 
+        {
+        //Subsequent updates that are handled normally even if 
+        // they would be first ones in a mass update burst
+        iHandleMassUpdateCount++;
+        iHandleMassUpdatePrev.UniversalTime();
+        }    
+    else
+        {
+        //very first update, set time & counter
+        HandleMassUpdateCheckReset();       
+        }
+    return ret;
+    }
+	
+// --------------------------------------------------------------------------
+// CPbk2HandleMassUpdate::MassUpdateDetected
+// --------------------------------------------------------------------------
+//
+TBool CPbk2HandleMassUpdate::MassUpdateDetected()
+    {
+	return iHandleMassUpdate;
+	}
+
+// --------------------------------------------------------------------------
+// CPbk2HandleMassUpdate::HandleMassUpdateCheckL
+// --------------------------------------------------------------------------
+//
+TBool CPbk2HandleMassUpdate::HandleMassUpdateCheckL()
+    {
+    //KDeltaAverage time per update to be considered as mass
+    //update. One occasional update can take KDeltaMax time as long as 
+    //average time not exeeded (therefore timeout for the very first updates in 
+    //practice is also KDeltaAverage).  
+    const TInt64 KDeltaAverage(2000000); 
+    const TInt64 KDeltaMax(KDeltaAverage * 2);     
+    const TTimeIntervalMicroSeconds KMaxPrev(KDeltaMax);  
+    TBool ret(EFalse);
+
+    TTime now;
+    now.UniversalTime();    
+    TTimeIntervalMicroSeconds fs = now.MicroSecondsFrom(iHandleMassUpdateFirst);
+    TTimeIntervalMicroSeconds ps = now.MicroSecondsFrom(iHandleMassUpdatePrev);
+    TTimeIntervalMicroSeconds maxCumu(KDeltaAverage * iHandleMassUpdateCount);
+
+    if( fs < maxCumu && ps < KMaxPrev )
+        {
+        //mass update burst ongoing
+        iHandleMassUpdate=ETrue;        
+        iHandleMassUpdateCount++;
+        iHandleMassUpdatePrev.UniversalTime();   
+        iListBox.UpdateScrollBarsL();
+		
+        if( !iHandleMassUpdateDialog )
+            {
+            iHandleMassUpdateDialog = new(ELeave) CAknWaitDialog
+                (reinterpret_cast<CEikDialog**>(&iHandleMassUpdateDialog), EFalse);
+            iHandleMassUpdateDialog->SetTone(CAknNoteDialog::ENoTone);
+            iHandleMassUpdateDialog->ExecuteLD(R_QTN_GEN_NOTE_SYNCHRONIZING_PROGRESS);  
+			//ExecuteLD above handles validity of pointer iHandleMassUpdateDialog plus 
+			//cleanupstack
+            }
+			
+        TCallBack callback(HandleMassUpdateTimerCallBack, this);
+        TTimeIntervalMicroSeconds32 delta32(KDeltaMax);
+        iHandleMassUpdateTimer->Start( delta32, delta32, callback );
+        ret = ETrue;
+        }
+    else if(iHandleMassUpdate)
+        {
+        //mass update burst ended    
+        HandleMassUpdateDone();
+        ret = ETrue;        
+        }
+    else
+        {
+        //just normal update, set time & counter
+        HandleMassUpdateCheckReset();
+        }
+    return ret;
+    }
+
+// ----------------------------------------------------------------------------
+// CPbk2HandleMassUpdate::HandleMassUpdateCheckReset
+// ----------------------------------------------------------------------------
+//
+void CPbk2HandleMassUpdate::HandleMassUpdateCheckReset()
+    {
+    iHandleMassUpdate=EFalse;        
+    iHandleMassUpdateCount = 1;  //set as first candidate for next burst
+    iHandleMassUpdateFirst.UniversalTime();
+    iHandleMassUpdatePrev=iHandleMassUpdateFirst;    
+    }
+
+// ----------------------------------------------------------------------------
+// CPbk2HandleMassUpdate::HandleMassUpdateTimerCallBack
+// ----------------------------------------------------------------------------
+//
+TInt CPbk2HandleMassUpdate::HandleMassUpdateTimerCallBack(TAny* aAny)
+    {
+    CPbk2HandleMassUpdate* self = static_cast<CPbk2HandleMassUpdate*>( aAny );
+    self->iHandleMassUpdateTimer->Cancel();    
+    self->HandleMassUpdateDone();
+    return KErrNone;
+    }
+
+// ----------------------------------------------------------------------------
+// CPbk2HandleMassUpdate::HandleMassUpdateDone
+// ----------------------------------------------------------------------------
+//
+void CPbk2HandleMassUpdate::HandleMassUpdateDone()
+    {
+    if( iHandleMassUpdateDialog ) 
+        {
+        TRAP_IGNORE(iHandleMassUpdateDialog->ProcessFinishedL());
+        //The below 2 lines just in case... ProcessFinishedL already took care of these
+        delete iHandleMassUpdateDialog;     
+        iHandleMassUpdateDialog = NULL;
+        }
+
+    HandleMassUpdateCheckReset();        
+    iListBox.SetCurrentItemIndex(0);
+    iListBox.SetTopItemIndex(0);
+    }
+	
+///////////////////////// End of helper classes /////////////////////////////
+
+
+// --------------------------------------------------------------------------
 // CPbk2NamesListControl::CPbk2NamesListControl
 // --------------------------------------------------------------------------
 //
@@ -586,11 +856,25 @@
 //
 CPbk2NamesListControl::~CPbk2NamesListControl()
     {
+    ClearMarkedContactsInfo();
+    
+    if (iBgTask)
+        {    
+        delete iBgTask;
+        iBgTask = NULL;
+        }
+    
     if ( iViewStack && iStackObserver )
         {
         iViewStack->RemoveStackObserver( *iStackObserver );
         }
 
+    if( iThumbManager )
+        {
+        TRAP_IGNORE( iThumbManager->SetContactViewL( NULL ) );
+        iThumbManager->RemoveObserver();
+        }
+    
     if (iCommand)
         {
         // inform the command that the control is deleted
@@ -598,6 +882,7 @@
         }
     iObservers.Reset();
     iCommandItems.ResetAndDestroy();
+	delete iCheckMassUpdate;
     delete iListBoxSelectionObserver;
     delete iStateFactory;
     delete iListBox;
@@ -608,7 +893,10 @@
     delete iUiExtension;
     delete iViewStack;
     delete iSearchFilter;
-
+    if( iOwnThumbManager )
+        {
+        delete iThumbManager;
+        }
     if (iOwnBaseView)
         {
         delete iBaseView;
@@ -617,13 +905,6 @@
         {
         FeatureManager::UnInitializeLib();
         }
-
-    // if thumbmanager, remove observer
-    if( iThumbManager )
-        {
-        iThumbManager->RemoveObserver();
-        }
-
     }
 
 // --------------------------------------------------------------------------
@@ -689,6 +970,7 @@
     CleanupStack::PopAndDestroy(); // resReader
     FeatureManager::InitializeLibL();
     iFeatureManagerInitilized = ETrue;
+	iCheckMassUpdate = CPbk2HandleMassUpdate::NewL(*iListBox); //iListbox created in ConstructFromResourceL
     }
 
 // --------------------------------------------------------------------------
@@ -740,16 +1022,19 @@
     // Create the listbox and its model
     if( flags & KPbk2ContactViewListControlDoubleRow )
         {
+        if( !iThumbManager )
+            {
+            iThumbManager = CPbk2ThumbnailManager::NewL( iContactManager );
+            iOwnThumbManager = ETrue;
+            }
+    
         iDoubleListBox = CPbk2ContactViewDoubleListBox::NewL
             ( *this, aReader, iContactManager,
             *iViewStack, iNameFormatter, iStoreProperties,
             iUiExtension, *iSearchFilter, *iThumbManager );
 
-        if( iThumbManager )
-            {
-            iThumbManager->SetObserver( *iDoubleListBox );
-            iViewStack->AddObserverL( *iThumbManager );
-            }
+        iThumbManager->SetObserver( *iDoubleListBox );
+        iThumbManager->SetContactViewL( iViewStack );
 
         iListBox = iDoubleListBox;
         }
@@ -821,6 +1106,8 @@
     // Create the initial state
     iCurrentState = &iStateFactory->ActivateStartupStateL( iCurrentState );
 
+    iBgTask = new (ELeave) CPbk2NamesListControlBgTask( *this );
+    
     PBK2_DEBUG_PRINT(PBK2_DEBUG_STRING
         ("CPbk2NamesListControl::ConstructFromResourceL end"));
     }
@@ -1075,7 +1362,7 @@
         {
         HideThumbnail();
         }
-    ReportEventL( MCoeControlObserver::EEventStateChanged );
+    TRAP_IGNORE(ReportEventL( MCoeControlObserver::EEventStateChanged ));
     }
 
 // --------------------------------------------------------------------------
@@ -1331,6 +1618,7 @@
 void CPbk2NamesListControl::ClearMarks()
     {
     iCurrentState->ClearMarks();
+	ClearMarkedContactsInfo();
     }
 
 // --------------------------------------------------------------------------
@@ -1668,8 +1956,11 @@
 
     if (&aView == iViewStack)
         {
-        TRAPD(err, DoHandleContactAdditionL(aIndex));
-        HandleError(err);
+        if( !iCheckMassUpdate->MassUpdateDetected() ) 
+            {
+            TRAPD(err, DoHandleContactAdditionL(aIndex));
+            HandleError(err);
+            }
         }
     }
 
@@ -1874,8 +2165,11 @@
         SelectAndChangeReadyStateL(); 
         }        
 
-    iCurrentState->HandleContactViewEventL
-        ( MPbk2NamesListState::EItemAdded, aIndex );
+    if( !iCheckMassUpdate->MassUpdateDetected() )
+        {
+        iCurrentState->HandleContactViewEventL
+            ( MPbk2NamesListState::EItemAdded, aIndex );
+        }
 
     // At least names list view needs control event about contact addition,
     // so it knows to update CBAs
@@ -2020,7 +2314,11 @@
         iCurrentState->ResetFindL();
         });
     HandleError( res );
-    Reset();
+
+    if( !iCheckMassUpdate->MassUpdateCheckThis() )
+        {
+        Reset();
+        }
 
     // Do not handle contact addition here (DoHandleContactAdditionL),
     // ContactAddedToView to notification is sent separately
@@ -2129,7 +2427,7 @@
     {
     //send event to current state
     //ETrue means that the event came from adaptvie search grid.
-    iCurrentState->HandleControlEventL( aSearchField, MCoeControlObserver::EEventStateChanged, ETrue );
+    TRAP_IGNORE(iCurrentState->HandleControlEventL( aSearchField, MCoeControlObserver::EEventStateChanged, ETrue));
     }
 
 // --------------------------------------------------------------------------
@@ -2144,6 +2442,190 @@
         iSearchFilter->HandleForegroundEventL( aForeground );
         }
     }
+        
+// ---------------------------------------------------------------------------
+// CPbk2NamesListControl::StoreMarkedContactsAndResetViewL
+// ---------------------------------------------------------------------------
+//
+void CPbk2NamesListControl::StoreMarkedContactsAndResetViewL()
+    {  
+    delete iSelectedLinkArray;
+    iSelectedLinkArray = NULL;
+    
+    iSelectedLinkArray = iCurrentState->SelectedContactsL();
+    }
+
+
+// ---------------------------------------------------------------------------
+// CPbk2NamesListControl::RestoreMarkedContactsL
+// ---------------------------------------------------------------------------
+//
+void CPbk2NamesListControl::RestoreMarkedContactsL()
+    {    
+    //Set the Marked Contacts
+    if ( iSelectedLinkArray )
+        {
+        for ( TInt index = 0; index<iSelectedLinkArray->Count(); index++ )
+            {
+            iCurrentState->SetSelectedContactL( iSelectedLinkArray->At(index), ETrue );
+            }        
+        }    
+    
+    delete iSelectedLinkArray;
+    iSelectedLinkArray = NULL;
+    }
+
+// ---------------------------------------------------------------------------
+// CPbk2NamesListControl::ClearMarkedContactsInfo
+// ---------------------------------------------------------------------------
+//
+void CPbk2NamesListControl::ClearMarkedContactsInfo()
+    {   
+    if ( iBgTask )
+        {
+        iBgTask->ClearAllEvents();
+        }
+    delete iSelectedLinkArray;
+    iSelectedLinkArray = NULL;
+    }
+
+// ---------------------------------------------------------------------------
+// CPbk2NamesListControl::HandleViewForegroundEventL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CPbk2NamesListControl::HandleViewForegroundEventL( TBool aForeground )
+    {
+    if ( aForeground )
+        {
+        if ( iBgTask )
+            {
+            iBgTask->AddEvent( CPbk2NamesListControl::EStateRestoreMarkedContacts );
+            }
+        }
+    else
+        {
+        if ( iBgTask )
+            {
+            iBgTask->AddEvent( CPbk2NamesListControl::EStateSaveMarkedContacts );
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CPbk2NamesListControlBgTask::CPbk2NamesListControlBgTask
+// ---------------------------------------------------------------------------
+//
+CPbk2NamesListControlBgTask::CPbk2NamesListControlBgTask( CPbk2NamesListControl& aControl ) :
+    CActive(CActive::EPriorityStandard),
+    iControl( aControl )
+    {
+    CActiveScheduler::Add(this);
+    iEventQueue.Append(CPbk2NamesListControl::EStateBgTaskEmpty);
+    }
+
+// ---------------------------------------------------------------------------
+// CPbk2NamesListControlBgTask::~CPbk2NamesListControlBgTask
+// ---------------------------------------------------------------------------
+//
+CPbk2NamesListControlBgTask::~CPbk2NamesListControlBgTask()
+    {
+    Cancel();
+    iEventQueue.Reset();
+    }
 
 
+// ---------------------------------------------------------------------------
+// CPbk2NamesListControlBgTask::DoCancel
+// ---------------------------------------------------------------------------
+//
+void CPbk2NamesListControlBgTask::DoCancel()
+    {    
+    }
+
+// ---------------------------------------------------------------------------
+// CPbk2NamesListControlBgTask::RunL
+// ---------------------------------------------------------------------------
+//
+void CPbk2NamesListControlBgTask::RunL()
+    {
+    
+    if ( iEventQueue.Count() )
+        {
+        switch ( iEventQueue[0] )
+            {
+            case CPbk2NamesListControl::EStateSaveMarkedContacts:
+                iControl.StoreMarkedContactsAndResetViewL();
+                iEventQueue.Remove( 0 );
+                break;
+                
+            case CPbk2NamesListControl::EStateRestoreMarkedContacts:
+                iControl.RestoreMarkedContactsL();
+                iEventQueue.Remove( 0 );
+                break;
+            
+            case CPbk2NamesListControl::EStateBgTaskEmpty :    
+            default:            
+                iControl.ClearMarkedContactsInfo();
+                break;
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CPbk2NamesListControlBgTask::RunError
+// ---------------------------------------------------------------------------
+//
+TInt CPbk2NamesListControlBgTask::RunError(TInt /*aError*/)
+    {    
+    return KErrNone;
+    }
+
+// ---------------------------------------------------------------------------
+// CPbk2NamesListControlBgTask::AddEvent
+// ---------------------------------------------------------------------------
+//
+void CPbk2NamesListControlBgTask::AddEvent( CPbk2NamesListControl::TPbk2NamesListBgEvents aEvent )
+    {
+    iEventQueue.Insert( aEvent, iEventQueue.Count() - 1 );
+    if ( !IsActive() )
+        {
+        TRequestStatus* status = &iStatus;
+        User::RequestComplete(status, KErrNone);
+        SetActive();
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CPbk2NamesListControlBgTask::RemoveEvent
+// ---------------------------------------------------------------------------
+//
+void CPbk2NamesListControlBgTask::RemoveEvent( CPbk2NamesListControl::TPbk2NamesListBgEvents aEvent )
+    {
+    for ( TInt index = 0; index < iEventQueue.Count(); index++ )
+        {
+        if ( aEvent == iEventQueue[index] )
+            {
+            iEventQueue.Remove( index );      
+            if ( 0 == index )
+                {
+                Cancel(); 
+                }
+            break;
+            }
+        }    
+    }
+
+
+// ---------------------------------------------------------------------------
+// CPbk2NamesListControlBgTask::ClearAllEvents
+// ---------------------------------------------------------------------------
+//
+void CPbk2NamesListControlBgTask::ClearAllEvents()
+    {
+    iEventQueue.Reset();
+    iEventQueue.Append( CPbk2NamesListControl::EStateBgTaskEmpty );
+    Cancel();
+    }
+
 //  End of File