--- a/ganeswidgets/src/HgScrollBufferManager.cpp Mon Apr 19 14:40:06 2010 +0300
+++ b/ganeswidgets/src/HgScrollBufferManager.cpp Mon May 03 13:32:54 2010 +0300
@@ -216,145 +216,368 @@
mTotalCount-1 : mBufferPosition+mBufferSize;
}
-void HgScrollBufferManager::removeItems(int start, int end, int totalCount)
+void HgScrollBufferManager::addItems(int start, int end)
{
- int oldTotalCount = mTotalCount;
- mTotalCount = totalCount;
+ FUNC_LOG;
+
+ mTotalCount += (end-start+1);
+ int lastBufferItem = mBufferPosition+mBufferSize-1;
- 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 < mBufferPosition) {
+ simpleAddItems(start, end);
+ // New items push the buffer forward, items inside the buffer do not change
+ }
+ // Check buffer higher limit
+ else if (start <= lastBufferItem && end > lastBufferItem) {
+ simpleAddItems(start, lastBufferItem);
+ // Items added after the buffer are ignored
+ }
+ else {
+ simpleAddItems(start, end);
+ }
+}
+
+void HgScrollBufferManager::removeItems(int start, int end)
+{
+ FUNC_LOG;
+
+ int lastBufferItem = mBufferPosition+mBufferSize-1;
+ int removedItemCount = end-start+1;
- 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);
+ if (mTotalCount < mBufferSize) {
+ // Do nothing
+ }
+ else if (start > lastBufferItem) {
+ // Do nothing
+ }
+ else if (end < mBufferPosition) {
+ mTotalCount = mTotalCount-removedItemCount;
+ simpleRemoveItems(start, end);
+ }
+ else if (start < mBufferPosition && end > lastBufferItem) {
+ mTotalCount = mTotalCount-removedItemCount;
+ mBufferPosition = qBound(0, mBufferPosition, mTotalCount-mBufferSize);
+ resetBuffer(mBufferPosition, mTotalCount);
+ }
+ // Check buffer higher limit
+ else if (start <= lastBufferItem && end > lastBufferItem) {
+ mTotalCount = mTotalCount-(end-lastBufferItem);
+ simpleRemoveItems(lastBufferItem+1, end);
+ mTotalCount = mTotalCount-(lastBufferItem-start+1);
+ simpleRemoveItems(start, lastBufferItem);
+ // Order does matter
+ mTotalCount = mTotalCount-(end-lastBufferItem);
+ simpleRemoveItems(lastBufferItem+1, end);
+ mTotalCount = mTotalCount-(lastBufferItem-start+1);
+ simpleRemoveItems(start, lastBufferItem);
+ }
+ // Check buffer lower limit
+ else if (start < mBufferPosition && end >= mBufferPosition) {
+ // Order does matter
+ mTotalCount = mTotalCount-(end-mBufferPosition+1);
+ simpleRemoveItems(mBufferPosition, end);
+ mTotalCount = mTotalCount-(mBufferPosition-start);
+ simpleRemoveItems(start, mBufferPosition-1);
+ }
+ else {
+ mTotalCount = mTotalCount-removedItemCount;
+ simpleRemoveItems(start, end);
+ }
+}
- // Requested from the end
- emit requestItems(mBufferPosition+mBufferSize-(last-first+1),
- qMin(mBufferPosition+mBufferSize-1, mTotalCount));
- }
+void HgScrollBufferManager::moveItems(int start, int end, int target)
+{
+ int lastBufferItem = mBufferPosition+mBufferSize-1;
+
+ INFO("Move" << start << "-" << end << "to" << target << ",buffer:" << mBufferPosition << "-" << lastBufferItem << "total count:" << mTotalCount);
+
+ if (mTotalCount < mBufferSize) {
+ // Do nothing
+ }
+ else if (start < mBufferPosition && end > lastBufferItem) {
+ resetBuffer(mBufferPosition, mTotalCount);
+ }
+ else if (start > lastBufferItem && target > lastBufferItem) {
+ // Do nothing
+ }
+ else if (start > lastBufferItem && target < mBufferPosition) {
+ simpleAddItems(start, end);
+ }
+ else if (end < mBufferPosition && target < mBufferPosition) {
+ // Do nothing
+ }
+ else if (end < mBufferPosition && target > lastBufferItem) {
+ simpleRemoveItems(start, end);
+ }
+ else if (start >= mBufferPosition && end <= lastBufferItem &&
+ target >= mBufferPosition && target <= lastBufferItem) {
+ // Do nothing
+ }
+ else {
+ // Rare and complicated use cases: reset the whole buffer
+ resetBuffer(mBufferPosition, mTotalCount);
}
}
-void HgScrollBufferManager::addItems(int start, int end, int totalCount)
+void HgScrollBufferManager::flushRequestBuffers()
{
- int oldTotalCount = mTotalCount;
- mTotalCount = totalCount;
+ FUNC_LOG;
+
+ qSort(mReleaseBuffer);
+ int releaseCount = mReleaseBuffer.count();
+ int lastReleased = -1;
+ for (int i = 0; i < releaseCount; i++) {
+ UpdatePair update = mReleaseBuffer.at(i);
+ emit releaseItems(qMax(lastReleased+1, update.start()), update.end());
+ lastReleased = update.end();
+ }
+ mReleaseBuffer.clear();
- if (isInsideBuffer(start, end)) {
- int first = start;
- int last = end;
+ qSort(mRequestBuffer);
+ int requestCount = mRequestBuffer.count();
+ int lastRequested = -1;
+ for (int i = 0; i < requestCount; i++) {
+ UpdatePair update = mRequestBuffer.at(i);
+ emit requestItems(qMax(lastRequested+1, update.start()), update.end());
+ lastRequested = update.end();
+ }
+ mRequestBuffer.clear();
+}
+
+int HgScrollBufferManager::changeBufferPosition(int newPos)
+{
+ FUNC_LOG;
+ INFO("Change buffer position to" << newPos << "total count:" << mTotalCount);
+ HANDLE_ERROR_BOOL((newPos >= 0));
+ HANDLE_ERROR_BOOL((newPos+mBufferSize <= mTotalCount));
+
+ int bufferShift = newPos-mBufferPosition;
+ if (bufferShift > 0) {
+ mRequestBuffer.shiftRight(mBufferPosition, bufferShift);
+ mReleaseBuffer.shiftRight(mBufferPosition, bufferShift);
+ }
+ else if (bufferShift < 0) {
+ mRequestBuffer.shiftLeft(mBufferPosition, -bufferShift);
+ mReleaseBuffer.shiftLeft(mBufferPosition, -bufferShift);
+ }
+ mBufferPosition = newPos;
+ return bufferShift;
+}
- 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);
+/**
+ This function manages only simple item additions: all items are either
+ outside the buffer or inside it.
+ Firs call prepare, then update model, then call fecth.
+*/
+void HgScrollBufferManager::simpleAddItems(int start, int end)
+{
+ FUNC_LOG;
+
+ int lastBufferItem = mBufferPosition+mBufferSize-1;
+ int numAddedItems = end-start+1; // [start, end] inclusive
- if (oldBufferPos < mBufferPosition) {
- // Release from the beginning
- emit releaseItems(oldBufferPos, mBufferPosition-1);
- }
+ if (mTotalCount < mBufferSize) {
+ appendRequestBuffer(start, numAddedItems);
+ }
+ else if (start > lastBufferItem) {
+ // Do nothing
+ }
+ else if (start <= mBufferPosition) {
+ changeBufferPosition(mBufferPosition+numAddedItems);
+ // No need to fetch items, the indexes just change
+ }
+ else {
+ // free from end
+ appendReleaseBuffer(lastBufferItem+1-numAddedItems, numAddedItems);
+ mReleaseBuffer.shiftRight(start, numAddedItems);
+ mRequestBuffer.shiftRight(start, numAddedItems);
+ appendRequestBuffer(start, numAddedItems);
+ }
+}
- // 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);
- }
+/**
+ This function manages only simple item removals: all items are either
+ outside the buffer or inside it.
+ Firs call prepare, then update model, then call fecth.
+*/
+void HgScrollBufferManager::simpleRemoveItems(int start, int end)
+{
+ FUNC_LOG;
+
+ int lastBufferItem = mBufferPosition+mBufferSize-1;
+ int numRemovedItems = end-start+1; // [start, end] inclusive
+
+ if (start > lastBufferItem) {
+ // Do nothing
+ }
+ else if (end < mBufferPosition) {
+ changeBufferPosition(qMax(0, mBufferPosition-numRemovedItems));
+ // No need to fetch items, the indexes just change
+ }
+ else {
+ if (mTotalCount < mBufferPosition+mBufferSize) {
+ // Buffer is at the end of items
+ int bufferShift = changeBufferPosition(qMax(0, mTotalCount-mBufferSize));
+ // Fetch from beginning
+ // Releasing removed items has been done outside this class
+ appendRequestBuffer(mBufferPosition, qAbs(bufferShift));
}
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);
+ // Fetch from end
+ appendRequestBuffer(lastBufferItem+1-numRemovedItems, numRemovedItems);
}
}
}
-void HgScrollBufferManager::moveItems(int start, int end, int target, int totalCount)
+void HgScrollBufferManager::appendRequestBuffer(int start, int count)
+{
+ FUNC_LOG;
+ INFO("Request items" << start << ":" << count)
+
+ mRequestBuffer.add(start, count);
+ mReleaseBuffer.remove(start, count);
+}
+
+void HgScrollBufferManager::appendReleaseBuffer(int start, int count)
+{
+ FUNC_LOG;
+ INFO("Release items" << start << ":" << count)
+
+ mReleaseBuffer.add(start, count);
+ mRequestBuffer.remove(start, count);
+}
+
+UpdatePair::UpdatePair(int start, int count) : mStart(start), mCount(count)
{
- if (isInsideBuffer(start) && isInsideBuffer(end) && isInsideBuffer(target)) {
- return;
- }
+ HANDLE_ERROR_BOOL(mCount > 0);
+}
+
+int UpdatePair::start() const
+{
+ return mStart;
+}
+
+int UpdatePair::end() const
+{
+ return mStart+mCount-1;
+}
- if (!isInsideBuffer(start, end) && !isInsideBuffer(target)) {
- return;
- }
+bool UpdatePair::adjacent(int start, int count) const
+{
+ if (start+count < mStart) return false;
+ if (start > mStart+mCount) return false;
+ return true;
+}
+
+bool UpdatePair::contains(const UpdatePair &other) const
+{
+ if (other.mStart+other.mCount-1 < mStart) return false;
+ if (other.mStart > mStart+mCount-1) return false;
+ return true;
+}
- 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));
- }
+void UpdatePair::extend(int start, int count)
+{
+ int end = qMax(mStart+mCount, start+count);
+ mStart = qMin(mStart, start);
+ mCount = end-mStart;
+ INFO("Pair extended to:" << mStart << ":" << mCount);
+}
+
+void UpdatePair::subtract(int start, int count)
+{
+ int end = qMin(mStart+mCount, start+count);
+ mStart = qMax(mStart, start);
+ mCount = end-mStart;
+ INFO("Pair reduced to:" << mStart << ":" << mCount);
+}
+
+void UpdatePair::shiftRight(int count)
+{
+ mStart += count;
+ INFO("Pair shifted to:" << mStart << ":" << mCount);
+}
+
+void UpdatePair::shiftLeft(int count)
+{
+ mStart -= count;
+ HANDLE_ERROR_BOOL((mStart >= 0));
+ INFO("Pair shifted to:" << mStart << ":" << mCount);
+}
+
+bool UpdatePair::operator== (const UpdatePair &other) const
+{
+ return mStart == other.mStart && mCount == other.mCount;
+}
+
+bool UpdatePair::operator< (const UpdatePair &other) const
+{
+ return (mStart < other.mStart || mStart == other.mStart && mCount < other.mCount);
+}
+
+UpdateBuffer::UpdateBuffer()
+{
+ FUNC_LOG;
+}
+
+void UpdateBuffer::add(int start, int count)
+{
+ FUNC_LOG;
+
+ int itemCount = this->count();
+ for (int i = 0; i < itemCount; i++) {
+ if (at(i).contains(UpdatePair(start, count))) {
+ // It is already there
+ return;
}
- 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 (at(i).adjacent(start, count)) {
+ (*this)[i].extend(start, count);
+ return;
}
}
+ append(UpdatePair(start, count));
+}
- if (isInsideBuffer(target)) {
- // start-end may be partially inside buffer
- if (!isInsideBuffer(start, end)) {
- addItems(target, target+end-start, totalCount);
+void UpdateBuffer::remove(int start, int count)
+{
+ FUNC_LOG;
+
+ int itemCount = this->count();
+ for (int i = itemCount-1; i >= 0; i--) {
+ UpdatePair pair = at(i);
+ UpdatePair comp = UpdatePair(start, count);
+ if (comp.contains(pair)) {
+ INFO("Removing pair" << pair.start() << "-" << pair.end());
+ removeAt(i);
}
- else if (isInsideBuffer(start)) {
- addItems(target+(mBufferPosition+mBufferSize-start), target+end-start, totalCount);
+ else if (pair.contains(comp)) {
+ // Subtraction from middle is not applicable in mediawall use cases
+ (*this)[i].subtract(start, count);
}
- else { // end is inside buffer
- addItems(target, target+mBufferPosition-start-1, totalCount);
+ // Item may be present in multiple pairs.
+ }
+}
+
+void UpdateBuffer::shiftRight(int startingFrom, int amount)
+{
+ FUNC_LOG;
+
+ int itemCount = this->count();
+ for (int i = 0; i < itemCount; i++) {
+ if (at(i).start() >= startingFrom) {
+ (*this)[i].shiftRight(amount);
}
}
}
-bool HgScrollBufferManager::isInsideBuffer(int pos)
+void UpdateBuffer::shiftLeft(int startingFrom, int amount)
{
- return (pos >= mBufferPosition && pos < mBufferPosition+mBufferSize);
-}
-
-bool HgScrollBufferManager::isInsideBuffer(int start, int end)
-{
- INFO("Buffer:" << mBufferPosition << "-" << mBufferPosition+mBufferSize-1);
- INFO("Change:" << start << "-" << end);
+ FUNC_LOG;
- if (isInsideBuffer(start)) {
- return true;
- }
- if (isInsideBuffer(end)) {
- return true;
+ int itemCount = this->count();
+ for (int i = 0; i < itemCount; i++) {
+ if (at(i).start() >= startingFrom) {
+ (*this)[i].shiftLeft(amount);
+ }
}
- if (start < mBufferPosition && end >= mBufferPosition+mBufferSize) {
- return true;
- }
-
- INFO("Buffer not affected");
- return false;
}
-