/*
* 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 "HgScrollBufferManager.h"
#include <ganes/HgScrollBufferObserverIface.h>
#include <e32debug.h>
// -----------------------------------------------------------------------------
// CHgScrollBufferManager::NewL()
// -----------------------------------------------------------------------------
//
CHgScrollBufferManager* CHgScrollBufferManager::NewL(
MHgScrollBufferObserver& aObserver,
TInt aBufferSize,
TInt aBufferTreshold,
TInt aInitialPosition,
TInt aTotalCount )
{
CHgScrollBufferManager* self = new (ELeave) CHgScrollBufferManager(
aObserver,
aBufferSize,
aBufferTreshold,
aInitialPosition,
aTotalCount );
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
// -----------------------------------------------------------------------------
// CHgScrollBufferManager::CHgScrollBufferManager()
// -----------------------------------------------------------------------------
//
CHgScrollBufferManager::CHgScrollBufferManager(
MHgScrollBufferObserver& aObserver,
TInt aBufferSize,
TInt aBufferTreshold,
TInt aInitialPosition,
TInt aTotalCount )
: CActive( CActive::EPriorityHigh ),
iObserver( aObserver ),
iBufferSize( aBufferSize ),
iBufferTreshold( aBufferTreshold ),
iBufferPosition( aInitialPosition ),
iTotalCount( aTotalCount )
{
}
// -----------------------------------------------------------------------------
// CHgScrollBufferManager::ConstructL()
// -----------------------------------------------------------------------------
//
void CHgScrollBufferManager::ConstructL()
{
CActiveScheduler::Add(this);
iResetOrdered = ETrue;
ResetBuffer(iBufferPosition, iTotalCount);
}
// -----------------------------------------------------------------------------
// CHgScrollBufferManager::~CHgScrollBufferManager()
// -----------------------------------------------------------------------------
//
CHgScrollBufferManager::~CHgScrollBufferManager()
{
Cancel();
}
// -----------------------------------------------------------------------------
// CHgScrollBufferManager::RunL()
// -----------------------------------------------------------------------------
//
void CHgScrollBufferManager::RunL()
{
MHgScrollBufferObserver::THgScrollDirection direction = MHgScrollBufferObserver::EHgBufferNoMove;
if(iResetOrdered)
{
iResetOrdered = EFalse;
direction = MHgScrollBufferObserver::EHgBufferReset;
}
else
{
if(iDiff < 0)
{
iReleaseStart = iBufferPosition;
iRequestStart = iBufferPosition + iBufferSize;
direction = MHgScrollBufferObserver::EHgBufferScrollDown;
}
else if( iDiff > 0)
{
iReleaseStart = iBufferPosition + iBufferSize - iDiff;
iRequestStart = iBufferPosition - iDiff;
direction = MHgScrollBufferObserver::EHgBufferScrollUp;
}
}
// Release
TInt end = iReleaseStart + iReleaseCount < iTotalCount ?
iReleaseStart + iReleaseCount: iTotalCount;
end--;
if(end >= iReleaseStart )
{
iObserver.Release(iReleaseStart, end);
if(iOwner) iOwner->Release( iReleaseStart, end );
}
iReleaseCount = 0;
// Request
end = iRequestStart + iRequestCount < iTotalCount ?
iRequestStart + iRequestCount : iTotalCount;
end--;
if(end >= iRequestStart )
iObserver.Request(iRequestStart, end, direction);
iRequestCount = 0;
// Move Buffer
iBufferPosition -= iDiff;
// Reset Diff
iDiff = 0;
}
// -----------------------------------------------------------------------------
// CHgScrollBufferManager::DoCancel()
// -----------------------------------------------------------------------------
//
void CHgScrollBufferManager::DoCancel()
{
// Nothing to do here
}
// -----------------------------------------------------------------------------
// CHgScrollBufferManager::RunError()
// -----------------------------------------------------------------------------
//
TInt CHgScrollBufferManager::RunError( TInt /*aError*/ )
{
return KErrNone;
}
// -----------------------------------------------------------------------------
// CHgScrollBufferManager::SetPosition()
// -----------------------------------------------------------------------------
//
void CHgScrollBufferManager::SetPosition( TInt aIndex )
{
// If all the items fit in the buffer no need to move the buffer
if(iTotalCount <= iBufferSize) return;
TBool forceUpdate = EFalse;
aIndex -= iBufferSize / 2; // normalize index to Buffer start
if(aIndex < 0)
{
aIndex = 0;
forceUpdate = ETrue;
}
else if( aIndex > iTotalCount - iBufferSize )
{
aIndex = iTotalCount - iBufferSize;
forceUpdate = ETrue;
}
iDiff = iBufferPosition - aIndex;
// Too large change reset whole buffer
if( iDiff >= iBufferSize || -iDiff >= iBufferSize || iResetOrdered )
{
ResetBuffer(aIndex + (iBufferSize/2), iTotalCount);
}
// Move Up
else if( iDiff >= iBufferTreshold )
{
iRequestCount = iDiff;
iReleaseCount = iDiff;
NotifyObserver();
}
// Move Down
else if( -iDiff >= iBufferTreshold )
{
iRequestCount = -iDiff;
iReleaseCount = -iDiff;
NotifyObserver();
}
// Top or bottom has been reached
else if( forceUpdate && iDiff )
{
TInt diff = iDiff < 0 ? -iDiff : iDiff;
iRequestCount = diff;
iReleaseCount = diff;
NotifyObserver();
}
}
// -----------------------------------------------------------------------------
// CHgScrollBufferManager::SetTotalCount()
// -----------------------------------------------------------------------------
//
void CHgScrollBufferManager::SetTotalCount( TInt aTotalCount )
{
iTotalCount = aTotalCount;
}
// -----------------------------------------------------------------------------
// CHgScrollBufferManager::SetBufferOwner()
// -----------------------------------------------------------------------------
//
void CHgScrollBufferManager::SetBufferOwner( MHgBufferOwner& aOwner )
{
iOwner = &aOwner;
}
// -----------------------------------------------------------------------------
// CHgScrollBufferManager::ResetBuffer()
// -----------------------------------------------------------------------------
//
void CHgScrollBufferManager::ResetBuffer( TInt aPosition, TInt aTotalCount)
{
if( !iResetOrdered )
{
// release Old buffer
iReleaseStart = iBufferPosition;
iReleaseCount = iBufferSize;
}
// set position and count
iBufferPosition = aPosition - (iBufferSize / 2);
iTotalCount = aTotalCount;
iDiff = 0;
if( iBufferPosition + iBufferSize > iTotalCount - 1 )
{
iBufferPosition = iTotalCount - iBufferSize;
}
if(iBufferPosition < 0 )
{
iBufferPosition = 0;
}
//request new Buffer
iRequestStart = iBufferPosition;
iRequestCount = iBufferSize;
iResetOrdered = ETrue;
NotifyObserver();
}
// -----------------------------------------------------------------------------
// CHgScrollBufferManager::NotifyObserver()
// -----------------------------------------------------------------------------
//
void CHgScrollBufferManager::NotifyObserver()
{
if( !IsActive() )
{
SetActive();
TRequestStatus* status = &iStatus;
User::RequestComplete(status, KErrNone);
}
}
// -----------------------------------------------------------------------------
// CHgScrollBufferManager::ItemChanged()
// -----------------------------------------------------------------------------
//
void CHgScrollBufferManager::ItemCountChanged(
TInt aIndex,
TBool aRemoved,
TInt aNewTotalCount )
{
iTotalCount = aNewTotalCount;
if ( aIndex >= iBufferPosition && aIndex < iBufferPosition + iBufferSize )
{
// Change inside the buffer
MHgScrollBufferObserver::THgScrollDirection direction = MHgScrollBufferObserver::EHgBufferNoMove;
if( aRemoved )
{
// Release removed item ( Item deleted already from the owner )
iObserver.Release( aIndex, aIndex );
if( iTotalCount >= iBufferSize )
{
// There are more items to keep the buffer filled
if( iBufferPosition + iBufferSize <= iTotalCount )
{
// Requested from the end
iObserver.Request( iBufferPosition + iBufferSize - 1,
iBufferPosition + iBufferSize - 1, direction );
}
else if( iBufferPosition > 0 )
{
// Move buffer and request from the beginning
iBufferPosition--;
iObserver.Request( iBufferPosition, iBufferPosition, direction );
}
}
}
else
{
if( iTotalCount > iBufferSize )
{
// One item needs to be released
if( iBufferPosition + iBufferSize < iTotalCount )
{
// Release from the end of the buffer
iObserver.Release(iBufferPosition + iBufferSize, iBufferPosition + iBufferSize);
if(iOwner)
iOwner->Release(iBufferPosition + iBufferSize, iBufferPosition + iBufferSize);
}
}
// Request added item
iObserver.Request(aIndex, aIndex, direction);
}
}
}