phonebookui/Phonebook/Engine/src/CPbkEntryCopier.cpp
changeset 0 e686773b3f54
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookui/Phonebook/Engine/src/CPbkEntryCopier.cpp	Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,711 @@
+/*
+* Copyright (c) 2002 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: 
+*		Offers interface for adding entries to Phonebook.
+*
+*/
+
+
+// INCLUDE FILES
+#include    <CPbkEntryCopier.h>
+#include    <cntdb.h>
+
+// Phonebook debug
+#include    <PbkDebug.h>
+
+// Phonebook engine
+#include    "CPbkContactEngine.h"
+#include    "CPbkIdleFinder.h"
+#include    "CPbkContactItem.h"
+
+// Phonebook copy
+#include    "CPbkNameLookup.h"
+#include    "CPbkEntryCopyAddToExisting.h"
+
+/// Unnamed namespace for local definitions
+namespace {
+
+// LOCAL CONSTANTS AND MACROS
+
+#ifdef _DEBUG
+enum TPanicCode
+    {
+    EPanicPreCond_FindExistingNameL = 0,
+    EPanicLogic_ProceedToNextStateL,
+    EPanicPreCond_FindAsyncNameL,
+    EPanicPreCond_IdleFindCallback
+    };
+
+void Panic(TInt aReason)
+    {
+    _LIT(KPanicText, "CPbkEntryCopier");
+    User::Panic(KPanicText, aReason);
+    }
+#endif // _DEBUG
+
+} // namespace
+
+
+// MODULE DATA STRUCTURES
+enum KPbkAddNewDataState
+    {
+    EPbkAsyncFindState = 0,
+    EPbkNameLookupState,
+    EPbkInsertToPbkState,
+    EPbkCompressDbState,
+    EPbkFinishedState
+    };
+
+/**
+ * Interface for states that perform adding new data to Phonebook.
+ */
+class MPbkAddNewDataState
+    {
+    public: // interface
+        /**
+         * Virtual destructor.
+         */
+        virtual ~MPbkAddNewDataState() {};
+        /**
+         * Initializes the state.
+         */
+        virtual void Initialize() {};
+        /**
+         * Searches for the contact item asynchronously.
+         * @param aName The contact item to search for.
+         */
+        virtual void FindAsyncNameL(CPbkContactItem& /*aName*/) {};
+        /**
+         * Returns the contact id array of matched names.
+         * Ownership is transferred to caller.
+         * @return Contact id array of matched names.
+         */
+        virtual CContactIdArray* GetContactIdArray() { return NULL; };
+        /**
+         * Lookup the given name from the array of contact ids.
+         * @param aContactIds array of contact ids to serach for the name.
+         * @param aName The contact to search for.
+         */
+        virtual void NameLookupL
+            (CContactIdArray* /*aContactIds*/, CPbkContactItem& /*aName*/) {};
+        /**
+         * Returns the contact id that matched the search.
+         */
+        virtual TContactItemId GetContactId() const { return KNullContactId; };
+        /**
+         * Inserts the entry to Phonebook.
+         * @param aContactId If a contact id is provided here, an existing
+         *                   entry will be updated.
+         * @param aEntry Entry that will be added to Phonebook.
+         */
+        virtual void InsertToPbkL(TContactItemId /*aContactId*/, 
+                CPbkContactItem& /*aEntry*/) { };
+
+        /**
+         * Performs Phonebook database compression.
+         */
+        virtual void CompressL() {};
+
+    };
+
+/**
+ * Base class for states that add new data to Phonebook.
+ */
+NONSHARABLE_CLASS(CPbkAddNewDataBaseState) :
+        public CBase, 
+        public MPbkAddNewDataState
+    {
+    protected: // Construction / destruction
+        CPbkAddNewDataBaseState(CPbkEntryCopier& aProcess);
+        ~CPbkAddNewDataBaseState();
+
+    protected: // utility function
+        void AdvanceToNextState(TInt aState, TInt aError);
+
+    private: // data members
+        /// Ref: state advancement
+        CPbkEntryCopier& iProcess;
+    };
+
+/**
+ * State for finding data asynchronously from Phonebook.
+ */
+NONSHARABLE_CLASS(CPbkAsyncFindState) : 
+        public CPbkAddNewDataBaseState, 
+        private MIdleFindObserver
+    {
+    public: // construction / destruction
+        static CPbkAsyncFindState* NewL(CPbkContactEngine& aEngine, 
+                CPbkEntryCopier& aProcess);
+        ~CPbkAsyncFindState();
+
+    public: // From CPbkAddNewDataBaseState
+        void FindAsyncNameL(CPbkContactItem& aEntry);
+        CContactIdArray* GetContactIdArray();
+        
+    private:    // from MIdleFindObserver
+        void IdleFindCallback();
+    
+    private: // implementation
+        CPbkAsyncFindState(CPbkContactEngine& aEngine,
+                CPbkEntryCopier& aProcess);
+        void ConstructL();
+
+    private: // data members
+        /// Ref: contact engine
+        CPbkContactEngine& iEngine;
+        /// Own: find id array for finding
+        CPbkFieldIdArray* iFindFrom;
+        /// Own: contact Id array
+        CContactIdArray* iContactIds;
+        /// Own: idle finder active object
+        CPbkIdleFinder* iIdleFinder;
+    };
+
+
+/**
+ * State for finding data asynchronously from Phonebook.
+ */
+NONSHARABLE_CLASS(CPbkNameLookupState) : 
+        public CPbkAddNewDataBaseState, 
+        private MPbkNameLookupObserver
+    {
+    public: // construction / destruction
+        static CPbkNameLookupState* NewL(CPbkContactEngine& aEngine,
+                CPbkEntryCopier& aProcess);
+        ~CPbkNameLookupState();
+
+    public: // From CPbkAddNewDataBaseState
+        void NameLookupL(CContactIdArray* aContactIds, CPbkContactItem& aName);
+        TContactItemId GetContactId() const;
+        void Initialize();
+
+    private:    // from MPbkNameLookupObserver
+        void NameLookupCompleted(TContactItemId aContactId);
+        void NameLookupFailed(TInt aError);
+    
+    private: // implementation
+        CPbkNameLookupState(CPbkContactEngine& aEngine,
+                CPbkEntryCopier& aProcess);
+        void ConstructL();
+
+    private: // data members
+        /// Ref: phonebook engine
+        CPbkContactEngine& iEngine;
+        /// Own: name lookup active object
+        CPbkNameLookup* iNameLookup;
+        /// Own: Contact id of the contact that was found
+        TContactItemId iContactId;
+    };
+
+/**
+ * State for inserting data to Phonebook.
+ */
+NONSHARABLE_CLASS(CPbkInsertToPhonebookState) : 
+        public CActive, 
+        public MPbkAddNewDataState
+    {
+    public: // construction / destruction
+        static CPbkInsertToPhonebookState* NewL(CPbkContactEngine& aEngine,
+                CPbkEntryCopier& aProcess);
+        ~CPbkInsertToPhonebookState();
+
+    public: // From MPbkAddNewDataState
+        void InsertToPbkL(TContactItemId aContactId, CPbkContactItem& aEntry);        
+        TContactItemId GetContactId() const;
+
+    private: // from CActive
+	    void DoCancel();
+	    void RunL();
+	    TInt RunError(TInt aError);
+
+    private: // implementation
+        CPbkInsertToPhonebookState(CPbkContactEngine& aEngine,
+                CPbkEntryCopier& aProcess);        
+        void AdvanceToNextState(TInt aState, TInt aError);
+    
+    private: // data members
+        /// Ref: phonebook engine
+        CPbkContactEngine& iEngine;
+        /// Ref: state advancement
+        CPbkEntryCopier& iProcess;
+        /// Own: contact id of the inserted contact
+        TContactItemId iContactId;
+        /// Ref: entry reference
+        CPbkContactItem* iEntry;
+    };
+
+/**
+ * State for performing the Phonebook DB compression.
+ */
+NONSHARABLE_CLASS(CPbkDbCompressState) : 
+        public CPbkAddNewDataBaseState, 
+        private MContactUiCompactObserver
+    {
+    public: // interface
+        static CPbkDbCompressState* NewL(CPbkContactEngine& aEngine,
+                CPbkEntryCopier& aProcess);        
+        ~CPbkDbCompressState();
+
+    public: // From CPbkAddNewDataBaseState
+        void CompressL();
+
+    private: // from MContactUiCompactObserver
+    	void Step(TInt aStep);
+	    void HandleError(TInt aError);
+
+    private: // implementation
+        CPbkDbCompressState(CPbkContactEngine& aEngine,
+                CPbkEntryCopier& aProcess);
+        void ConstructL();
+
+    private: // data members
+        /// Ref: contact engine
+        CPbkContactEngine& iEngine;
+        /// Own: compressor active object
+        CContactActiveCompress* iCompressor;
+    };
+
+// ================= MEMBER FUNCTIONS =======================
+
+CPbkAddNewDataBaseState::CPbkAddNewDataBaseState
+        (CPbkEntryCopier& aProcess) :
+    iProcess(aProcess)
+    {
+    }
+
+CPbkAddNewDataBaseState::~CPbkAddNewDataBaseState()
+    {
+    }
+
+void CPbkAddNewDataBaseState::AdvanceToNextState
+        (TInt aState, 
+        TInt aError)
+    {
+    iProcess.ProceedToNextState(aState, aError);
+    }
+
+///////////////////////////////////////////////////////////////////////////////
+//// CPbkAsyncFindState
+
+inline CPbkAsyncFindState::CPbkAsyncFindState
+        (CPbkContactEngine& aEngine,
+        CPbkEntryCopier& aProcess) :
+    CPbkAddNewDataBaseState(aProcess),
+    iEngine(aEngine)
+    {
+    }
+
+inline void CPbkAsyncFindState::ConstructL()
+    {
+    // Build a CPbkFieldArray specifying the field types to search
+    iFindFrom = new(ELeave) CPbkFieldIdArray;
+    iFindFrom->AppendL(EPbkFieldIdLastName);
+    }
+
+CPbkAsyncFindState* CPbkAsyncFindState::NewL
+        (CPbkContactEngine& aEngine,
+        CPbkEntryCopier& aProcess)
+    {
+    CPbkAsyncFindState* self = new(ELeave) CPbkAsyncFindState(aEngine, aProcess);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+CPbkAsyncFindState::~CPbkAsyncFindState()
+    {
+    delete iIdleFinder;
+    delete iContactIds;
+    delete iFindFrom;
+    }
+
+void CPbkAsyncFindState::IdleFindCallback()
+    {
+    __ASSERT_DEBUG(iIdleFinder, Panic(EPanicPreCond_IdleFindCallback));
+
+    TInt error = iIdleFinder->Error();
+    if (error)
+        {
+        AdvanceToNextState(EPbkFinishedState, error);
+        }
+    if (iIdleFinder->IsComplete())
+        {
+        if (iContactIds)
+            {
+            delete iContactIds;
+            iContactIds = NULL;
+            }
+        // take ownership of contact id array
+        iContactIds = iIdleFinder->TakeContactIds();
+        AdvanceToNextState(EPbkNameLookupState, error);
+        }
+    }
+
+CContactIdArray* CPbkAsyncFindState::GetContactIdArray()
+    {
+    CContactIdArray* idArray = iContactIds;
+    iContactIds = NULL;
+    return idArray;
+    }
+
+void CPbkAsyncFindState::FindAsyncNameL(CPbkContactItem& aEntry)
+    {
+    if (iIdleFinder)
+        {
+        iIdleFinder->IdleFinder()->Cancel();
+        }
+
+    TPbkContactItemField* lastNameField = aEntry.FindField(EPbkFieldIdLastName);
+    __ASSERT_DEBUG(lastNameField, Panic(EPanicPreCond_FindAsyncNameL));
+    CPbkIdleFinder* idleFinder = 
+        iEngine.FindAsyncL(lastNameField->Text(), iFindFrom, this);
+    if (iIdleFinder)
+        {
+        delete iIdleFinder;
+        iIdleFinder = NULL;
+        }
+    iIdleFinder = idleFinder;
+    }
+
+///////////////////////////////////////////////////////////////////////////////
+//// CPbkNameLookupState
+
+inline CPbkNameLookupState::CPbkNameLookupState
+        (CPbkContactEngine& aEngine,
+        CPbkEntryCopier& aProcess) :
+    CPbkAddNewDataBaseState(aProcess),
+    iEngine(aEngine),
+    iContactId(KNullContactId)
+    {
+    }
+
+inline void CPbkNameLookupState::ConstructL()
+    {
+    iNameLookup = CPbkNameLookup::NewL(iEngine, *this);
+    }
+
+CPbkNameLookupState* CPbkNameLookupState::NewL
+        (CPbkContactEngine& aEngine,
+        CPbkEntryCopier& aProcess)
+    {
+    CPbkNameLookupState* self = new(ELeave) CPbkNameLookupState(aEngine, aProcess);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+CPbkNameLookupState::~CPbkNameLookupState()
+    {
+    delete iNameLookup;
+    }
+
+void CPbkNameLookupState::NameLookupCompleted
+        (TContactItemId aContactId)
+    {
+    // Proceed to next state
+    iContactId = aContactId;
+    AdvanceToNextState(EPbkInsertToPbkState, KErrNone);
+    }
+
+void CPbkNameLookupState::NameLookupFailed
+        (TInt aError)
+    {
+    AdvanceToNextState(EPbkFinishedState, aError);
+    }
+
+TContactItemId CPbkNameLookupState::GetContactId() const
+    {
+    return iContactId;
+    }
+
+void CPbkNameLookupState::NameLookupL(CContactIdArray* aContactIds, 
+                                      CPbkContactItem& aEntry)
+    {
+    iNameLookup->Cancel();
+    iNameLookup->IssueNameLookupL(aContactIds, aEntry);
+    }
+
+void CPbkNameLookupState::Initialize()
+    {
+    iContactId = KNullContactId;
+    };
+
+///////////////////////////////////////////////////////////////////////////////
+//// CPbkInsertToPhonebookState
+
+inline CPbkInsertToPhonebookState::CPbkInsertToPhonebookState
+        (CPbkContactEngine& aEngine,
+        CPbkEntryCopier& aProcess) :
+    CActive(EPriorityIdle),
+    iEngine(aEngine),
+    iProcess(aProcess)
+    {
+    CActiveScheduler::Add(this);
+    }
+
+CPbkInsertToPhonebookState* CPbkInsertToPhonebookState::NewL
+        (CPbkContactEngine& aEngine,
+        CPbkEntryCopier& aProcess)
+    {
+    return new(ELeave) CPbkInsertToPhonebookState(aEngine, aProcess);    
+    }
+
+CPbkInsertToPhonebookState::~CPbkInsertToPhonebookState()
+    {
+    Cancel();
+    }
+
+void CPbkInsertToPhonebookState::InsertToPbkL
+        (TContactItemId aContactId, 
+        CPbkContactItem& aEntry)
+    {
+    Cancel();
+    iContactId = aContactId;
+    iEntry = &aEntry;
+
+    TRequestStatus* rs = &iStatus;
+    User::RequestComplete(rs, KErrNone);
+    SetActive();
+    }
+
+TContactItemId CPbkInsertToPhonebookState::GetContactId() const
+    { 
+    return iContactId; 
+    }
+
+void CPbkInsertToPhonebookState::DoCancel()
+    {
+    }
+
+void CPbkInsertToPhonebookState::RunL()
+    {
+    if (iContactId == KNullContactId)
+        {
+        // add new entry if it is not empty
+        CPbkContactItem* emptyItem = iEngine.CreateEmptyContactL();
+        CleanupStack::PushL(emptyItem);
+        if (*emptyItem != *iEntry)
+            {
+            iContactId = iEngine.AddNewContactL(*iEntry);
+            }
+        CleanupStack::PopAndDestroy(emptyItem);
+        }
+    else
+        {
+        // Add to the existing phonebook entry
+        CPbkEntryCopyAddToExisting* entryHandler = 
+            CPbkEntryCopyAddToExisting::NewLC(*iEntry, iEngine, iContactId);
+        iContactId = entryHandler->CopyL();
+        CleanupStack::PopAndDestroy(entryHandler);
+        }
+    AdvanceToNextState(EPbkFinishedState, KErrNone); // skip the compress here.
+    }
+
+TInt CPbkInsertToPhonebookState::RunError
+        (TInt aError)
+    {
+    if (aError)
+        {
+        AdvanceToNextState(EPbkFinishedState, aError);
+        }
+    return KErrNone;
+    }
+
+void CPbkInsertToPhonebookState::AdvanceToNextState
+        (TInt aState, 
+        TInt aError)
+    {
+    iProcess.ProceedToNextState(aState, aError);
+    }
+
+///////////////////////////////////////////////////////////////////////////////
+//// CPbkDbCompressState
+
+inline CPbkDbCompressState::CPbkDbCompressState
+        (CPbkContactEngine& aEngine,
+        CPbkEntryCopier& aProcess) : 
+    CPbkAddNewDataBaseState(aProcess),
+    iEngine(aEngine)
+    {
+    }
+
+CPbkDbCompressState* CPbkDbCompressState::NewL
+        (CPbkContactEngine& aEngine,
+        CPbkEntryCopier& aProcess)
+    {
+    return new(ELeave) CPbkDbCompressState(aEngine, aProcess);    
+    }
+
+CPbkDbCompressState::~CPbkDbCompressState()
+    {
+    delete iCompressor;
+    }
+
+void CPbkDbCompressState::Step
+        (TInt /*aStep*/)
+    {
+    if (iCompressor->StepsTogo() <= 0)
+        {
+        AdvanceToNextState(EPbkFinishedState, KErrNone);
+        }
+    }
+
+void CPbkDbCompressState::HandleError
+        (TInt aError)
+    {
+    AdvanceToNextState(EPbkFinishedState, aError);
+    }
+
+void CPbkDbCompressState::CompressL()
+    {
+    CContactActiveCompress* compressor = iEngine.Database().CreateCompressorLC();
+    compressor->SetObserver(this);
+    CleanupStack::Pop(compressor);
+    delete iCompressor;
+    iCompressor = compressor;
+    }
+
+///////////////////////////////////////////////////////////////////////////////
+/// CPbkEntryCopier
+
+inline CPbkEntryCopier::CPbkEntryCopier
+        (CPbkContactEngine& aEngine, MPbkEntryCopyObserver& aObserver) : 
+    iEngine(aEngine),
+    iObserver(aObserver),
+    iStateArray(4) // array granularity
+    {
+    }
+
+inline void CPbkEntryCopier::ConstructL()
+    {
+    // create the states
+    CPbkAsyncFindState* findState = CPbkAsyncFindState::NewL(iEngine, *this);
+    CleanupStack::PushL(findState);
+    User::LeaveIfError(iStateArray.Append(findState));
+    CleanupStack::Pop(findState);
+
+    CPbkNameLookupState* lookupState = 
+        CPbkNameLookupState::NewL(iEngine, *this);
+    CleanupStack::PushL(lookupState);
+    User::LeaveIfError(iStateArray.Append(lookupState));
+    CleanupStack::Pop(lookupState);
+
+    CPbkInsertToPhonebookState* insertState = 
+        CPbkInsertToPhonebookState::NewL(iEngine, *this);
+    CleanupStack::PushL(insertState);
+    User::LeaveIfError(iStateArray.Append(insertState));
+    CleanupStack::Pop(insertState);
+
+    CPbkDbCompressState* compressState = 
+        CPbkDbCompressState::NewL(iEngine, *this);
+    CleanupStack::PushL(compressState);
+    User::LeaveIfError(iStateArray.Append(compressState));
+    CleanupStack::Pop(compressState);
+    }
+
+EXPORT_C CPbkEntryCopier* CPbkEntryCopier::NewL
+        (CPbkContactEngine& aEngine, MPbkEntryCopyObserver& aObserver)
+    {
+    CPbkEntryCopier* self = new(ELeave) CPbkEntryCopier(aEngine, aObserver);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+EXPORT_C void CPbkEntryCopier::AddToPhonebookL(CPbkContactItem& aEntry)
+    {
+    iEntry = &aEntry;
+    iNewContactId = KNullContactId;
+
+    TInt state = EPbkAsyncFindState;
+    iStateArray[EPbkNameLookupState]->Initialize();
+    HBufC* title = iEntry->GetContactTitleOrNullL();
+    if (!title)
+        {
+        // if no name insert to phonebook
+        state = EPbkInsertToPbkState;
+        }
+    delete title;
+    ProceedToNextState(state, KErrNone);
+    }
+
+CPbkEntryCopier::~CPbkEntryCopier()
+    {
+    iStateArray.ResetAndDestroy();
+    iStateArray.Close();
+    }
+
+void CPbkEntryCopier::ProceedToNextState(TInt aState, TInt aError)
+    {
+    // check if error
+    if (aError != KErrNone)
+        {
+        iObserver.CopyError(aError);
+        }
+    else
+        {
+        TRAPD(error, DoProceedToNextStateL(aState));
+        if (error)
+            {
+            iObserver.CopyError(error);
+            }
+        }
+    }
+
+void CPbkEntryCopier::DoProceedToNextStateL(TInt aState)
+    {
+    switch (aState)
+        {
+        case EPbkAsyncFindState:
+            {
+            iStateArray[EPbkAsyncFindState]->FindAsyncNameL(*iEntry);
+            break;
+            }
+        case EPbkNameLookupState:
+            {
+            CContactIdArray* idArray = 
+                iStateArray[EPbkAsyncFindState]->GetContactIdArray();
+            iStateArray[EPbkNameLookupState]->NameLookupL(idArray, *iEntry);
+            break;
+            }
+        case EPbkInsertToPbkState:
+            {
+            const TContactItemId id = 
+                iStateArray[EPbkNameLookupState]->GetContactId();
+            iStateArray[EPbkInsertToPbkState]->InsertToPbkL(id, *iEntry);
+            break;
+            }
+        case EPbkCompressDbState:
+            {
+            iStateArray[EPbkCompressDbState]->CompressL();
+            break;
+            }
+        case EPbkFinishedState:
+            {
+            iNewContactId = iStateArray[EPbkInsertToPbkState]->GetContactId();
+            iObserver.CopySuccess(iNewContactId);
+            break;
+            }
+        default:
+            {
+            __ASSERT_DEBUG(EFalse, Panic(EPanicLogic_ProceedToNextStateL));
+            }
+        }
+    }
+
+//  End of File