/*
* Copyright (c) 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:
*
*/
#include "cxestatemachinebase.h"
#include "cxutils.h"
#include "cxeerrormappingsymbian.h"
#include "cxestate.h"
CxeStateMachineBase::CxeStateMachineBase( const char* stateMachineName ) :
mStateId(0), mName(stateMachineName)
{
}
CxeStateMachineBase::~CxeStateMachineBase()
{
qDeleteAll(mStates);
mStates.clear();
}
bool CxeStateMachineBase::addState( CxeState* state )
{
bool success = true;
if (!state) {
// given parameter is null pointer
success = false;
} else {
// Make sure any of the existing stateId don't have overlapping bits.
// We need to be able to use bitwise AND operator for stateIds.
QList<int> stateIds = mStates.keys();
foreach(int i, stateIds) {
if ((i & state->stateId()) != 0) {
success = false;
break;
}
}
}
// if no errors
if (success) {
mStates[state->stateId()] = state; // state is now owned by the state machine
}
return success;
}
bool CxeStateMachineBase::setState( int stateId, int error )
{
bool success = true;
if (stateId == mStateId) {
// No transition, nothing needs to be done
return success;
}
if (mStates.contains(stateId)) {
// New state name known, print it
CX_DEBUG(("%s::setState(%s, %d)", mName.toAscii().constData(),
mStates[stateId]->name().toAscii().constData(), error));
} else {
// Unknown state...
CX_DEBUG(("%s::setState(UNKNOWN[%d], %d)", mName.toAscii().constData(),
stateId, error));
}
// State state machine does not use the error parameter itself.
// It is only forwarded to handleStateChanged to be passed
// on as a parameter in the stateChanged() signal.
// setStateId itself will never return an error.
// If an illegal state or state change is detected, it will panic the application (because it is a design error).
success = verifyStateChange(stateId);
if (success) {
mStateId = stateId;
handleStateChanged(mStateId, CxeErrorHandlingSymbian::map(error));
}
return success;
}
bool CxeStateMachineBase::setInitialState( int stateId )
{
bool success = mStates.contains(stateId);
if (success) {
// New state name known, print it
CX_DEBUG(("%s::setInitialState(%s)", mName.toAscii().constData(),
mStates[stateId]->name().toAscii().constData()));
} else {
// Unknown state...
CX_DEBUG(("%s::setInitialState(UNKNOWN[%d])", mName.toAscii().constData(),
stateId));
}
// check that state changes have not been made
// and this is the one and only setInitialState call
success = (success && mStateId == 0);
if (success) {
mStateId = stateId;
} else {
CX_DEBUG(("%s state has already been set", mName.toAscii().constData()));
}
return success;
}
int CxeStateMachineBase::stateId() const
{
return mStateId;
}
bool CxeStateMachineBase::verifyStateChange( int newStateId )
{
bool allowStateChange = false;
// Check that current state can be found in the state chart
if ( mStates.contains(stateId()) ) {
// Check that current state allows change to the new state
CxeState *currentState = mStates[stateId()];
allowStateChange = (currentState->allowedNextStates() & newStateId);
}
return allowStateChange;
}