// 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);
}
}