ganeswidgets/src/HgScrollBufferManager.cpp
changeset 0 89c329efa980
child 1 e48454f237ca
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ganeswidgets/src/HgScrollBufferManager.cpp	Mon Apr 19 14:40:06 2010 +0300
@@ -0,0 +1,360 @@
+/*
+* 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 <QTimer>
+
+#include "HgScrollBufferManager.h"
+#include "trace.h"
+
+// -----------------------------------------------------------------------------
+// HgScrollBufferManager::HgScrollBufferManager()
+// -----------------------------------------------------------------------------
+//
+HgScrollBufferManager::HgScrollBufferManager(
+        int bufferSize,
+        int bufferTreshold,
+        int initialPosition,
+        int totalCount )
+:   mBufferSize( bufferSize ),
+    mBufferTreshold( bufferTreshold ),
+    mBufferPosition( initialPosition ),
+    mDiff(0),
+    mTotalCount( totalCount ),
+    mResetOrdered(false),
+    mRequestStart(0),
+    mRequestCount(0),
+    mReleaseStart(0),
+    mReleaseCount(0)
+    {
+    init();
+    }
+
+// -----------------------------------------------------------------------------
+// HgScrollBufferManager::init()
+// -----------------------------------------------------------------------------
+//
+void HgScrollBufferManager::init()
+    {
+    mResetOrdered = ETrue;
+    mTimer.setSingleShot(true);
+    connect(&mTimer, SIGNAL(timeout()), this, SLOT(timeout()));
+    }
+
+// -----------------------------------------------------------------------------
+// HgScrollBufferManager::~HgScrollBufferManager()
+// -----------------------------------------------------------------------------
+//
+HgScrollBufferManager::~HgScrollBufferManager()
+    {
+    mTimer.stop();
+    }
+
+// -----------------------------------------------------------------------------
+// HgScrollBufferManager::resetBuffer()
+// -----------------------------------------------------------------------------
+//
+void HgScrollBufferManager::resetBuffer( int aPosition, int totalCount )
+    {
+    if( !mResetOrdered )
+        {
+        // release Old buffer
+        mReleaseStart = mBufferPosition;
+        mReleaseCount = mBufferSize;
+        }
+
+    // set position and count
+    mBufferPosition = aPosition - (mBufferSize / 2);
+    mTotalCount = totalCount;
+    mDiff = 0;
+
+    if( mBufferPosition + mBufferSize > mTotalCount - 1 )
+        {
+        mBufferPosition = mTotalCount - mBufferSize;
+        }
+
+    if(mBufferPosition < 0 )
+        {
+        mBufferPosition = 0;
+        }
+
+    //request new Buffer
+    mRequestStart = mBufferPosition;
+    mRequestCount = mBufferSize;
+    mResetOrdered = ETrue;
+    asyncUpdate();
+    }
+
+void HgScrollBufferManager::scrollPositionChanged( int newPosition )
+    {
+    // If all the items fit in the buffer no need to move the buffer.
+    if( mTotalCount <= mBufferSize ) return;
+
+    bool forceUpdate = EFalse;
+    newPosition -= mBufferSize / 2; // normalize index to Buffer start
+
+    if(newPosition < 0)
+        {
+        newPosition = 0;
+        forceUpdate = ETrue;
+        }
+    else if( newPosition > mTotalCount - mBufferSize )
+        {
+        newPosition = mTotalCount - mBufferSize;
+        forceUpdate = ETrue;
+        }
+
+    mDiff = mBufferPosition - newPosition;
+
+    // Too large change reset whole buffer
+    if( mDiff >= mBufferSize || -mDiff >= mBufferSize || mResetOrdered )
+        {
+        resetBuffer(newPosition + (mBufferSize/2), mTotalCount );
+        }
+    // Move Up
+    else if( mDiff >= mBufferTreshold )
+        {
+        mRequestCount = mDiff;
+        mReleaseCount = mDiff;
+        asyncUpdate();
+        }
+    // Move Down
+    else if( -mDiff >= mBufferTreshold )
+        {
+        mRequestCount = -mDiff;
+        mReleaseCount = -mDiff;
+        asyncUpdate();
+        }
+    // Top or bottom has been reached
+    else if( forceUpdate && mDiff )
+        {
+        int diff = mDiff < 0 ? -mDiff : mDiff;
+        mRequestCount = diff;
+        mReleaseCount = diff;
+        asyncUpdate();
+        }
+    }
+
+void HgScrollBufferManager::timeout()
+{
+    if(mResetOrdered)
+        {
+        mResetOrdered = EFalse;
+        }
+    else
+        {
+        if(mDiff < 0)
+            {
+            mReleaseStart = mBufferPosition;
+            mRequestStart = mBufferPosition + mBufferSize;
+            }
+        else if( mDiff > 0)
+            {
+            mReleaseStart = mBufferPosition + mBufferSize - mDiff;
+            mRequestStart = mBufferPosition - mDiff;
+            }
+        }
+
+    // Release
+    int end = mReleaseStart + mReleaseCount < mTotalCount ?
+        mReleaseStart + mReleaseCount: mTotalCount;
+    end--;
+    if(end >= mReleaseStart )
+        {
+        emit releaseItems( mReleaseStart, end );
+        }
+
+    mReleaseCount = 0;
+
+    // Request
+    end = mRequestStart + mRequestCount < mTotalCount ?
+        mRequestStart + mRequestCount : mTotalCount;
+
+    end--;
+    if(end >= mRequestStart )
+        {
+        emit requestItems( mRequestStart, end );
+        }
+
+    mRequestCount = 0;
+
+    // Move Buffer
+    mBufferPosition -= mDiff;
+    // Reset Diff
+    mDiff = 0;
+}
+
+bool HgScrollBufferManager::positionInsideBuffer( int position )
+{
+    return position >= mBufferPosition && position <= (mBufferPosition+mBufferSize);
+}
+
+void HgScrollBufferManager::asyncUpdate()
+{
+    if( !mTimer.isActive())
+        mTimer.start(0);
+}
+
+void HgScrollBufferManager::currentBuffer(int& bufferStart, int& bufferEnd)
+{
+    bufferStart = mBufferPosition;
+    bufferEnd = mBufferPosition+mBufferSize > mTotalCount-1 ?
+        mTotalCount-1 : mBufferPosition+mBufferSize;
+}
+
+void HgScrollBufferManager::removeItems(int start, int end, int totalCount)
+{
+    int oldTotalCount = mTotalCount;
+    mTotalCount = totalCount;
+
+    if (isInsideBuffer(start, end)) {
+        if (mTotalCount > mBufferSize && mBufferPosition+mBufferSize == oldTotalCount) {
+            // We are at the end of items, move buffer
+            int oldBufferPos = mBufferPosition;
+            mBufferPosition = qMax(0, totalCount-mBufferSize);
+
+            if (start < oldBufferPos) { // Removed items are partially inside buffer
+                emit requestItems(mBufferPosition, start-1);
+            }
+            else {
+                emit requestItems(mBufferPosition, oldBufferPos-1);
+            }
+        }
+        else {
+            int first = qBound(mBufferPosition, start, mBufferPosition+mBufferSize-1);
+            int last = qBound(mBufferPosition, end, mBufferPosition+mBufferSize-1);
+
+            // Requested from the end
+            emit requestItems(mBufferPosition+mBufferSize-(last-first+1),
+                              qMin(mBufferPosition+mBufferSize-1, mTotalCount));
+        }
+    }
+}
+
+void HgScrollBufferManager::addItems(int start, int end, int totalCount)
+{
+    int oldTotalCount = mTotalCount;
+    mTotalCount = totalCount;
+
+    if (isInsideBuffer(start, end)) {
+        int first = start;
+        int last = end;
+
+        if (mTotalCount > mBufferSize && mBufferPosition+mBufferSize == oldTotalCount) {
+            // We are at the end of items, keep it that way
+            int oldBufferPos = mBufferPosition;
+            mBufferPosition = qMin(mBufferPosition+(end-start+1), totalCount-mBufferSize);
+
+            if (oldBufferPos < mBufferPosition) {
+                // Release from the beginning
+                emit releaseItems(oldBufferPos, mBufferPosition-1);
+            }
+
+            // Added items may fall outside the buffer as the buffer is moved
+            if (isInsideBuffer(start, end)) {
+                first = qBound(mBufferPosition, start, mBufferPosition+mBufferSize-1);
+                last = qBound(mBufferPosition, end, mBufferPosition+mBufferSize-1);
+                emit requestItems(first, last);
+            }
+        }
+        else {
+            first = qBound(mBufferPosition, start, mBufferPosition+mBufferSize-1);
+            last = qBound(mBufferPosition, end, mBufferPosition+mBufferSize-1);
+
+            if (mTotalCount > mBufferSize) {
+                // Release from the end
+                emit releaseItems(mBufferPosition+mBufferSize,
+                                  mBufferPosition+mBufferSize+(last-first+1)-1);
+            }
+            // If all the items fit in the buffer no need to release items
+
+            emit requestItems(first, last);
+        }
+    }
+}
+
+void HgScrollBufferManager::moveItems(int start, int end, int target, int totalCount)
+{
+    if (isInsideBuffer(start) && isInsideBuffer(end) && isInsideBuffer(target)) {
+        return;
+    }
+
+    if (!isInsideBuffer(start, end) && !isInsideBuffer(target)) {
+        return;
+    }
+
+    if (!isInsideBuffer(target)) {
+        if (isInsideBuffer(start) && isInsideBuffer(end)) {
+            if (mBufferPosition+mBufferSize == mTotalCount) {
+                // Fetch from beginning
+                emit requestItems(mBufferPosition, mBufferPosition+end-start);
+            }
+            else {
+                // Fetch from end
+                emit requestItems(mBufferPosition+mBufferSize-(end-start+1),
+                                  qMin(mBufferPosition+mBufferSize-1, mTotalCount));
+            }
+        }
+        else if (isInsideBuffer(start) && end >= mBufferPosition+mBufferSize-1) {
+            emit requestItems(start, mBufferPosition+mBufferSize-1);
+        }
+        else if (start <= mBufferPosition && isInsideBuffer(end)) {
+            emit requestItems(mBufferPosition, end);
+        }
+        else {
+            emit requestItems(mBufferPosition, mBufferPosition+mBufferSize-1);
+        }
+    }
+
+    if (isInsideBuffer(target)) {
+        // start-end may be partially inside buffer
+        if (!isInsideBuffer(start, end)) {
+            addItems(target, target+end-start, totalCount);
+        }
+        else if (isInsideBuffer(start)) {
+            addItems(target+(mBufferPosition+mBufferSize-start), target+end-start, totalCount);
+        }
+        else { // end is inside buffer
+            addItems(target, target+mBufferPosition-start-1, totalCount);
+        }
+    }
+}
+
+bool HgScrollBufferManager::isInsideBuffer(int pos)
+{
+    return (pos >= mBufferPosition && pos < mBufferPosition+mBufferSize);
+}
+
+bool HgScrollBufferManager::isInsideBuffer(int start, int end)
+{
+    INFO("Buffer:" << mBufferPosition << "-" << mBufferPosition+mBufferSize-1);
+    INFO("Change:" << start << "-" << end);
+
+    if (isInsideBuffer(start)) {
+        return true;
+    }
+    if (isInsideBuffer(end)) {
+        return true;
+    }
+    if (start < mBufferPosition && end >= mBufferPosition+mBufferSize) {
+        return true;
+    }
+
+    INFO("Buffer not affected");
+    return false;
+}
+