phonebookengines/contactsmodel/cntsrv/src/CCntPermanentData.cpp
changeset 0 e686773b3f54
child 24 0ba2181d7c28
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookengines/contactsmodel/cntsrv/src/CCntPermanentData.cpp	Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,401 @@
+// Copyright (c) 2005-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:
+//
+
+/**
+ @file
+ @internalComponent
+ @released
+*/
+
+
+#include <e32base.h>
+
+#include "CCntRequest.h"
+#include "CCntDbManager.h"
+#include "CCntDbManagerController.h"
+#include "CCntStateMachine.h"
+#include "cntviewprivate.h"
+#include "CViewSubSessions.h"
+#include <cntviewstore.h>
+#include "CCntPermanentData.h"
+#include "CCntLogger.h"
+
+/**
+Object factory method.
+*/
+CCntPermanentData* CCntPermanentData::NewL(CCntDbManagerController& aController)
+	{
+	CCntPermanentData* self = new (ELeave) CCntPermanentData(aController);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+
+/**
+First phase constructor.
+*/
+CCntPermanentData::CCntPermanentData(CCntDbManagerController& aController) 
+: CActive(CActive::EPriorityLow), iState(EStateInitial), iController(aController)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+
+/**
+Second phase constructor.
+*/
+void CCntPermanentData::ConstructL()
+	{
+	}
+
+	
+/**
+Object destructor.
+*/	
+CCntPermanentData::~CCntPermanentData()
+	{
+	Cancel();
+	Close();
+	}
+
+	
+/*
+*/
+void CCntPermanentData::Close()
+	{
+	iViewDefs.ResetAndDestroy();
+	for (TInt i = 0; i < iViews.Count(); i++)
+		{
+		iViews[i]->Close(*this);
+		}
+	iViews.Close();
+	if (iManager)
+		{
+		iController.CloseDatabase(*iManager);
+		iManager = NULL;
+		}	
+	}
+
+
+/**
+The permanent data is created in a number of asynchronous steps. The AO uses
+a simple state machine to control the steps:
+
+1. Open the default database - EStateOpeningDb.
+2. Open each default view one at a time - EStateOpeningView.
+   (Views are created one at a time to avoid thrashing the dbms/file server
+   with multiple requests for data that is not contiguous.)
+3. Once all views are opened, or if there is an error, or the AO is cancelled -
+   EStateFinished.
+*/	
+void CCntPermanentData::RunL()
+	{
+	if (iStatus.Int() == KErrNone)
+		{
+		switch (iState)
+			{
+			case EStateOpeningDb:
+				{
+				if (OpenNextViewL())
+					{
+					iState = EStateOpeningView;
+					iStatus = KRequestPending;
+					SetActive();
+					}
+				else
+					{
+					iState = EStateFinished;
+					}
+				break;
+				}
+			case EStateOpeningView:
+				{
+				if (OpenNextViewL())
+					{
+					iState = EStateOpeningView;
+					iStatus = KRequestPending;
+					SetActive();
+					}
+				else
+					{
+					iState = EStateFinished;
+					}		
+				break;
+				}
+			case EStateFinished:
+				{
+				// Nothing left to do
+				break;
+				}
+			default:
+				{
+				__ASSERT_DEBUG(0, User::Invariant());
+				break;
+				}
+			}
+		}
+	else if (iStatus.Int() == KErrNotFound)
+		{
+		// File could not be found to open.
+		iState = EStateFinished;
+		}		
+	}
+
+
+/**
+Only need to cancel requests in certain states, otherwise there is nothing to
+do.
+*/	
+void CCntPermanentData::DoCancel()
+	{
+	if (IsActive())
+		{
+		switch (iState)
+			{
+			case EStateOpeningDb:
+				{
+				// Cancel the asynchronous open to stop this from recieving any notifications.
+				CReqCancelInternalAsyncOpen* req = NULL;
+
+				TRAP_IGNORE(
+				    {
+    				// req is Pop'd from the cleanup stack to keep cleanup stack balanced
+    				// before and after the TRAP.
+				    req = CReqCancelInternalAsyncOpen::NewLC(0);
+				    CleanupStack::Pop(req);
+                    iManager->StateMachineL().ProcessRequestL(req);  // ownership transferred
+
+	                // ProcessRequestL received ownership of the request, req can be set to 
+	                // NULL
+                    req = NULL;
+					});
+
+                // if request is not being cleaned up within TRAP, clean it up now!
+                if (req)
+                    {
+                    req->Complete();
+                    delete req;
+                    }
+
+				break;
+				}
+			case EStateOpeningView: // intentional fall-through.
+			default:
+				{
+				// Self-complete the currently active request.
+				CompleteSelf(KErrCancel);
+				break;
+				}
+			}
+		iState = EStateFinished;
+		}
+	}
+
+
+/**
+Any errors will have come from OpenNextViewL() leaving.  This is not a fatal
+error for this class so do not pass it on to the scheduler.
+*/
+TInt CCntPermanentData::RunError(TInt /*aError*/)
+	{
+	iState = EStateFinished;
+	return KErrNone;
+	}
+
+	
+void CCntPermanentData::CompleteSelf(TInt aReason)
+	{
+	TRequestStatus* pStat = &iStatus;
+  	User::RequestComplete(pStat, aReason);
+	}
+
+
+/**
+Kicks off the creation of the default data. This means:
+
+1. Opening the default database.
+2. Opening any views that are specified in the default view 'store' (a CenRep
+   repository).
+*/	
+void CCntPermanentData::StartDataCreationL()
+	{
+	__ASSERT_ALWAYS(!IsActive(), User::Leave(KErrInUse));
+	
+	TContactViewStore::GetDefaultViewsL(iViewDefs);
+	
+	if (iViewDefs.Count() == 0)
+		{
+		// No views; no need to open the default database.
+		iState = EStateFinished;
+		}
+	else
+		{
+		// Only attempt to open the default file if it exists.
+		if (iController.DatabaseExistsL(KNullDesC))
+			{
+			// Open the default database (this is asynchronous).
+			CReqInternalAsyncOpen* openReq = CReqInternalAsyncOpen::NewLC(0, KNullDesC, iStatus);
+			// Get an instance of the database manager for this file. One db manager is 
+			// created per file and shared amoung sessions working on that file.
+			iManager = iController.GetDbManagerL(openReq->FileName(), ECntFileOpen);
+			// Process the open request via the state machine
+			// The state machine ensures the file - owned by the manager - is in a valid
+			// state to process the request.
+			iManager->StateMachineL().ProcessRequestL(openReq);  // ownership transferred
+
+	        // ProcessRequestL received ownership of the request, the request only need
+	        // to be popped from CleanupStack.
+			CleanupStack::Pop(openReq);
+
+			iState = EStateOpeningDb;
+			SetActive();
+			}
+		else
+			{
+			iState = EStateFinished;
+			}
+		}
+	}
+
+
+/**
+Checks to see if the given CCntDbManager is being held open by this object AND
+that it has a reference count of 1, i.e. this is the only object holding a
+reference to it.
+  
+@return ETrue if this is the only object with a reference to the CCntDbManager,
+EFalse otherwise.
+*/
+TBool CCntPermanentData::IsOnlyClientOfDbManager(CCntDbManager* manager) const
+	{
+	if (iManager == manager && manager->SessionCount() == 1)
+		{
+		return ETrue;
+		}
+	return EFalse;
+	}
+
+
+/**
+Destroy any views and the manager being held by this object
+*/	
+void CCntPermanentData::ReleaseDbManagerL(CCntDbManager* manager)
+	{
+	__ASSERT_ALWAYS(manager == iManager, User::Leave(KErrArgument));
+	Close();
+	}
+
+
+/**
+Creates the next view from the list of view definitions.  The actual
+construction of the view is done asynchronously.  When it has finished this
+object is notified by a call to HandleContactViewEvent().
+  
+@return EFalse if no view was created, ETrue otherwise.
+*/
+TBool CCntPermanentData::OpenNextViewL()
+	{
+	if (iViewDefs.Count() == 0)
+		{
+		return EFalse;
+		}
+
+	TBool viewCreated(EFalse);
+	do 
+		{		
+		CContactDefaultViewDefinition* viewDef = iViewDefs[0];
+		CleanupStack::PushL(viewDef);
+		iViewDefs.Remove(0);
+		
+		// Attempt to create a view from the definition.
+		// If this leaves, the do..while ensures that
+		// an attempt to create the next view will happen.
+		CContactViewBase* view = NULL;
+		TRAPD(err, view = OpenViewFromDefinitionL(*viewDef));
+		if (err == KErrNone)
+			{
+			iViews.AppendL(view);
+			viewCreated = ETrue;
+			}
+		else
+			{
+  
+
+//		 Log the details of the view that failed to be created.
+            DEBUG_PRINTF1(__VERBOSE_DEBUG__,"[CNTMODEL] CCntPermanentData::OpenNextViewL(): Failed to create a view:\n");
+            DEBUG_PRINTF2(__VERBOSE_DEBUG__,"[CNTMODEL] View type: %d\n", viewDef->ViewType());
+            DEBUG_PRINTF2(__VERBOSE_DEBUG__,"[CNTMODEL] View preferences: %d\n", viewDef->ViewPreferences());
+			DEBUG_PRINT2(__VERBOSE_DEBUG__,_L("[CNTMODEL] View name: %S\n"), &viewDef->ViewNameL());
+			DEBUG_PRINT2(__VERBOSE_DEBUG__,_L("[CNTMODEL] Sort plugin name: %S\n"), &viewDef->SortPluginNameL());
+			DEBUG_PRINTF1(__VERBOSE_DEBUG__,"[CNTMODEL] View field sort order: ");
+			RContactViewSortOrder sortOrder = viewDef->SortOrder();
+			for (TInt i = 0; i < sortOrder.Count(); i++)
+				{
+				DEBUG_PRINTF2(__VERBOSE_DEBUG__,"[CNTMODEL] 0x%x, ", sortOrder[i].iUid);
+				}
+			RDebug::Printf("\n");
+
+			}
+		
+		CleanupStack::PopAndDestroy(viewDef);
+		}
+	while (!viewCreated && (iViewDefs.Count() > 0));
+	return viewCreated;
+	}
+
+	
+CContactViewBase* CCntPermanentData::OpenViewFromDefinitionL(const CContactDefaultViewDefinition& aViewDef)
+	{
+	CContactViewBase* view = NULL;
+	switch (aViewDef.ViewType())
+		{
+		case CContactDefaultViewDefinition::ERemoteView:
+			{
+			view = &iManager->ViewManagerL().OpenViewL(aViewDef.SortOrder(), *this, 
+														aViewDef.ViewPreferences(), 
+														KNullUid, aViewDef.SortPluginNameL());
+			break;
+			}
+		case CContactDefaultViewDefinition::ENamedRemoteView:
+			{
+			view = &iManager->ViewManagerL().OpenNamedViewL(aViewDef.ViewNameL(), 
+															aViewDef.SortOrder(), *this, 
+															aViewDef.ViewPreferences(), 
+															KNullUid, aViewDef.SortPluginNameL());
+			break;
+			}
+		default:
+			{
+			User::Leave(KErrArgument);
+			}
+		}
+	return view;	
+	}
+
+
+void CCntPermanentData::HandleContactViewEvent(const CContactViewBase& /*aView*/, const TContactViewEvent& /*aEvent*/)
+	{
+	// Complete the active object regardless of whether the view was 
+	// created successfully or not. This class is only trying to pre-create 
+	// the view(s) for the main Contacts application. If there are errors 
+	// creating the view then the application should deal with them 
+	// (as it would if this class didn't exist).
+	if (iState == EStateOpeningView)
+		{
+		CompleteSelf(KErrNone);
+		}
+	}