ganeswidgets/src/HgScrollBufferManager.cpp
changeset 1 e48454f237ca
parent 0 89c329efa980
child 2 49c70dcc3f17
equal deleted inserted replaced
0:89c329efa980 1:e48454f237ca
   214     bufferStart = mBufferPosition;
   214     bufferStart = mBufferPosition;
   215     bufferEnd = mBufferPosition+mBufferSize > mTotalCount-1 ?
   215     bufferEnd = mBufferPosition+mBufferSize > mTotalCount-1 ?
   216         mTotalCount-1 : mBufferPosition+mBufferSize;
   216         mTotalCount-1 : mBufferPosition+mBufferSize;
   217 }
   217 }
   218 
   218 
   219 void HgScrollBufferManager::removeItems(int start, int end, int totalCount)
   219 void HgScrollBufferManager::addItems(int start, int end)
   220 {
   220 {
   221     int oldTotalCount = mTotalCount;
   221     FUNC_LOG;
   222     mTotalCount = totalCount;
   222 
   223 
   223     mTotalCount += (end-start+1);
   224     if (isInsideBuffer(start, end)) {
   224     int lastBufferItem = mBufferPosition+mBufferSize-1;
   225         if (mTotalCount > mBufferSize && mBufferPosition+mBufferSize == oldTotalCount) {
   225 
   226             // We are at the end of items, move buffer
   226     if (start < mBufferPosition) {
   227             int oldBufferPos = mBufferPosition;
   227         simpleAddItems(start, end);
   228             mBufferPosition = qMax(0, totalCount-mBufferSize);
   228         // New items push the buffer forward, items inside the buffer do not change
   229 
   229     }
   230             if (start < oldBufferPos) { // Removed items are partially inside buffer
   230     // Check buffer higher limit
   231                 emit requestItems(mBufferPosition, start-1);
   231     else if (start <= lastBufferItem && end > lastBufferItem) {
   232             }
   232         simpleAddItems(start, lastBufferItem);
   233             else {
   233         // Items added after the buffer are ignored
   234                 emit requestItems(mBufferPosition, oldBufferPos-1);
   234     }
   235             }
   235     else {
       
   236         simpleAddItems(start, end);
       
   237     }
       
   238 }
       
   239 
       
   240 void HgScrollBufferManager::removeItems(int start, int end)
       
   241 {
       
   242     FUNC_LOG;
       
   243 
       
   244     int lastBufferItem = mBufferPosition+mBufferSize-1;
       
   245     int removedItemCount = end-start+1;
       
   246 
       
   247     if (mTotalCount < mBufferSize) {
       
   248         // Do nothing
       
   249     }
       
   250     else if (start > lastBufferItem) {
       
   251         // Do nothing
       
   252     }
       
   253     else if (end < mBufferPosition) {
       
   254         mTotalCount = mTotalCount-removedItemCount;
       
   255         simpleRemoveItems(start, end);
       
   256     }
       
   257     else if (start < mBufferPosition && end > lastBufferItem) {
       
   258         mTotalCount = mTotalCount-removedItemCount;
       
   259         mBufferPosition = qBound(0, mBufferPosition, mTotalCount-mBufferSize);
       
   260         resetBuffer(mBufferPosition, mTotalCount);
       
   261     }
       
   262     // Check buffer higher limit
       
   263     else if (start <= lastBufferItem && end > lastBufferItem) {
       
   264         mTotalCount = mTotalCount-(end-lastBufferItem);
       
   265         simpleRemoveItems(lastBufferItem+1, end);
       
   266         mTotalCount = mTotalCount-(lastBufferItem-start+1);
       
   267         simpleRemoveItems(start, lastBufferItem);
       
   268         // Order does matter
       
   269         mTotalCount = mTotalCount-(end-lastBufferItem);
       
   270         simpleRemoveItems(lastBufferItem+1, end);
       
   271         mTotalCount = mTotalCount-(lastBufferItem-start+1);
       
   272         simpleRemoveItems(start, lastBufferItem);
       
   273     }
       
   274     // Check buffer lower limit
       
   275     else if (start < mBufferPosition && end >= mBufferPosition) {
       
   276         // Order does matter
       
   277         mTotalCount = mTotalCount-(end-mBufferPosition+1);
       
   278         simpleRemoveItems(mBufferPosition, end);
       
   279         mTotalCount = mTotalCount-(mBufferPosition-start);
       
   280         simpleRemoveItems(start, mBufferPosition-1);
       
   281     }
       
   282     else {
       
   283         mTotalCount = mTotalCount-removedItemCount;
       
   284         simpleRemoveItems(start, end);
       
   285     }
       
   286 }
       
   287 
       
   288 void HgScrollBufferManager::moveItems(int start, int end, int target)
       
   289 {
       
   290     int lastBufferItem = mBufferPosition+mBufferSize-1;
       
   291 
       
   292     INFO("Move" << start << "-" << end << "to" << target << ",buffer:" << mBufferPosition << "-" << lastBufferItem << "total count:" << mTotalCount);
       
   293 
       
   294     if (mTotalCount < mBufferSize) {
       
   295         // Do nothing
       
   296     }
       
   297     else if (start < mBufferPosition && end > lastBufferItem) {
       
   298         resetBuffer(mBufferPosition, mTotalCount);
       
   299     }
       
   300     else if (start > lastBufferItem && target > lastBufferItem) {
       
   301         // Do nothing
       
   302     }
       
   303     else if (start > lastBufferItem && target < mBufferPosition) {
       
   304         simpleAddItems(start, end);
       
   305     }
       
   306     else if (end < mBufferPosition && target < mBufferPosition) {
       
   307         // Do nothing
       
   308     }
       
   309     else if (end < mBufferPosition && target > lastBufferItem) {
       
   310         simpleRemoveItems(start, end);
       
   311     }
       
   312     else if (start >= mBufferPosition && end <= lastBufferItem &&
       
   313              target >= mBufferPosition && target <= lastBufferItem) {
       
   314         // Do nothing
       
   315     }
       
   316     else {
       
   317         // Rare and complicated use cases: reset the whole buffer
       
   318         resetBuffer(mBufferPosition, mTotalCount);
       
   319     }
       
   320 }
       
   321 
       
   322 void HgScrollBufferManager::flushRequestBuffers()
       
   323 {
       
   324     FUNC_LOG;
       
   325 
       
   326     qSort(mReleaseBuffer);
       
   327     int releaseCount = mReleaseBuffer.count();
       
   328     int lastReleased = -1;
       
   329     for (int i = 0; i < releaseCount; i++) {
       
   330         UpdatePair update = mReleaseBuffer.at(i);
       
   331         emit releaseItems(qMax(lastReleased+1, update.start()), update.end());
       
   332         lastReleased = update.end();
       
   333     }
       
   334     mReleaseBuffer.clear();
       
   335 
       
   336     qSort(mRequestBuffer);
       
   337     int requestCount = mRequestBuffer.count();
       
   338     int lastRequested = -1;
       
   339     for (int i = 0; i < requestCount; i++) {
       
   340         UpdatePair update = mRequestBuffer.at(i);
       
   341         emit requestItems(qMax(lastRequested+1, update.start()), update.end());
       
   342         lastRequested = update.end();
       
   343     }
       
   344     mRequestBuffer.clear();
       
   345 }
       
   346 
       
   347 int HgScrollBufferManager::changeBufferPosition(int newPos)
       
   348 {
       
   349     FUNC_LOG;
       
   350     INFO("Change buffer position to" << newPos << "total count:" << mTotalCount);
       
   351     HANDLE_ERROR_BOOL((newPos >= 0));
       
   352     HANDLE_ERROR_BOOL((newPos+mBufferSize <= mTotalCount));
       
   353 
       
   354     int bufferShift = newPos-mBufferPosition;
       
   355     if (bufferShift > 0) {
       
   356         mRequestBuffer.shiftRight(mBufferPosition, bufferShift);
       
   357         mReleaseBuffer.shiftRight(mBufferPosition, bufferShift);
       
   358     }
       
   359     else if (bufferShift < 0) {
       
   360         mRequestBuffer.shiftLeft(mBufferPosition, -bufferShift);
       
   361         mReleaseBuffer.shiftLeft(mBufferPosition, -bufferShift);
       
   362     }
       
   363     mBufferPosition = newPos;
       
   364     return bufferShift;
       
   365 }
       
   366 
       
   367 /**
       
   368     This function manages only simple item additions: all items are either
       
   369     outside the buffer or inside it.
       
   370     Firs call prepare, then update model, then call fecth.
       
   371 */
       
   372 void HgScrollBufferManager::simpleAddItems(int start, int end)
       
   373 {
       
   374     FUNC_LOG;
       
   375 
       
   376     int lastBufferItem = mBufferPosition+mBufferSize-1;
       
   377     int numAddedItems = end-start+1; // [start, end] inclusive
       
   378 
       
   379     if (mTotalCount < mBufferSize) {
       
   380         appendRequestBuffer(start, numAddedItems);
       
   381     }
       
   382     else if (start > lastBufferItem) {
       
   383         // Do nothing
       
   384     }
       
   385     else if (start <= mBufferPosition) {
       
   386         changeBufferPosition(mBufferPosition+numAddedItems);
       
   387         // No need to fetch items, the indexes just change
       
   388     }
       
   389     else {
       
   390         // free from end
       
   391         appendReleaseBuffer(lastBufferItem+1-numAddedItems, numAddedItems);
       
   392         mReleaseBuffer.shiftRight(start, numAddedItems);
       
   393         mRequestBuffer.shiftRight(start, numAddedItems);
       
   394         appendRequestBuffer(start, numAddedItems);
       
   395     }
       
   396 }
       
   397 
       
   398 /**
       
   399     This function manages only simple item removals: all items are either
       
   400     outside the buffer or inside it.
       
   401     Firs call prepare, then update model, then call fecth.
       
   402 */
       
   403 void HgScrollBufferManager::simpleRemoveItems(int start, int end)
       
   404 {
       
   405     FUNC_LOG;
       
   406 
       
   407     int lastBufferItem = mBufferPosition+mBufferSize-1;
       
   408     int numRemovedItems = end-start+1; // [start, end] inclusive
       
   409 
       
   410     if (start > lastBufferItem) {
       
   411         // Do nothing
       
   412     }
       
   413     else if (end < mBufferPosition) {
       
   414         changeBufferPosition(qMax(0, mBufferPosition-numRemovedItems));
       
   415         // No need to fetch items, the indexes just change
       
   416     }
       
   417     else {
       
   418         if (mTotalCount < mBufferPosition+mBufferSize) {
       
   419             // Buffer is at the end of items
       
   420             int bufferShift = changeBufferPosition(qMax(0, mTotalCount-mBufferSize));
       
   421             // Fetch from beginning
       
   422             // Releasing removed items has been done outside this class
       
   423             appendRequestBuffer(mBufferPosition, qAbs(bufferShift));
   236         }
   424         }
   237         else {
   425         else {
   238             int first = qBound(mBufferPosition, start, mBufferPosition+mBufferSize-1);
   426             // Fetch from end
   239             int last = qBound(mBufferPosition, end, mBufferPosition+mBufferSize-1);
   427             appendRequestBuffer(lastBufferItem+1-numRemovedItems, numRemovedItems);
   240 
   428         }
   241             // Requested from the end
   429     }
   242             emit requestItems(mBufferPosition+mBufferSize-(last-first+1),
   430 }
   243                               qMin(mBufferPosition+mBufferSize-1, mTotalCount));
   431 
   244         }
   432 void HgScrollBufferManager::appendRequestBuffer(int start, int count)
   245     }
   433 {
   246 }
   434     FUNC_LOG;
   247 
   435     INFO("Request items" << start << ":" << count)
   248 void HgScrollBufferManager::addItems(int start, int end, int totalCount)
   436 
   249 {
   437     mRequestBuffer.add(start, count);
   250     int oldTotalCount = mTotalCount;
   438     mReleaseBuffer.remove(start, count);
   251     mTotalCount = totalCount;
   439 }
   252 
   440 
   253     if (isInsideBuffer(start, end)) {
   441 void HgScrollBufferManager::appendReleaseBuffer(int start, int count)
   254         int first = start;
   442 {
   255         int last = end;
   443     FUNC_LOG;
   256 
   444     INFO("Release items" << start << ":" << count)
   257         if (mTotalCount > mBufferSize && mBufferPosition+mBufferSize == oldTotalCount) {
   445 
   258             // We are at the end of items, keep it that way
   446     mReleaseBuffer.add(start, count);
   259             int oldBufferPos = mBufferPosition;
   447     mRequestBuffer.remove(start, count);
   260             mBufferPosition = qMin(mBufferPosition+(end-start+1), totalCount-mBufferSize);
   448 }
   261 
   449 
   262             if (oldBufferPos < mBufferPosition) {
   450 UpdatePair::UpdatePair(int start, int count) : mStart(start), mCount(count)
   263                 // Release from the beginning
   451 {
   264                 emit releaseItems(oldBufferPos, mBufferPosition-1);
   452     HANDLE_ERROR_BOOL(mCount > 0);
   265             }
   453 }
   266 
   454 
   267             // Added items may fall outside the buffer as the buffer is moved
   455 int UpdatePair::start() const
   268             if (isInsideBuffer(start, end)) {
   456 {
   269                 first = qBound(mBufferPosition, start, mBufferPosition+mBufferSize-1);
   457     return mStart;
   270                 last = qBound(mBufferPosition, end, mBufferPosition+mBufferSize-1);
   458 }
   271                 emit requestItems(first, last);
   459 
   272             }
   460 int UpdatePair::end() const
   273         }
   461 {
   274         else {
   462     return mStart+mCount-1;
   275             first = qBound(mBufferPosition, start, mBufferPosition+mBufferSize-1);
   463 }
   276             last = qBound(mBufferPosition, end, mBufferPosition+mBufferSize-1);
   464 
   277 
   465 bool UpdatePair::adjacent(int start, int count) const
   278             if (mTotalCount > mBufferSize) {
   466 {
   279                 // Release from the end
   467     if (start+count < mStart) return false;
   280                 emit releaseItems(mBufferPosition+mBufferSize,
   468     if (start > mStart+mCount) return false;
   281                                   mBufferPosition+mBufferSize+(last-first+1)-1);
   469     return true;
   282             }
   470 }
   283             // If all the items fit in the buffer no need to release items
   471 
   284 
   472 bool UpdatePair::contains(const UpdatePair &other) const
   285             emit requestItems(first, last);
   473 {
   286         }
   474     if (other.mStart+other.mCount-1 < mStart) return false;
   287     }
   475     if (other.mStart > mStart+mCount-1) return false;
   288 }
   476     return true;
   289 
   477 }
   290 void HgScrollBufferManager::moveItems(int start, int end, int target, int totalCount)
   478 
   291 {
   479 void UpdatePair::extend(int start, int count)
   292     if (isInsideBuffer(start) && isInsideBuffer(end) && isInsideBuffer(target)) {
   480 {
   293         return;
   481     int end = qMax(mStart+mCount, start+count);
   294     }
   482     mStart = qMin(mStart, start);
   295 
   483     mCount = end-mStart;
   296     if (!isInsideBuffer(start, end) && !isInsideBuffer(target)) {
   484     INFO("Pair extended to:" << mStart << ":" << mCount);
   297         return;
   485 }
   298     }
   486 
   299 
   487 void UpdatePair::subtract(int start, int count)
   300     if (!isInsideBuffer(target)) {
   488 {
   301         if (isInsideBuffer(start) && isInsideBuffer(end)) {
   489     int end = qMin(mStart+mCount, start+count);
   302             if (mBufferPosition+mBufferSize == mTotalCount) {
   490     mStart = qMax(mStart, start);
   303                 // Fetch from beginning
   491     mCount = end-mStart;
   304                 emit requestItems(mBufferPosition, mBufferPosition+end-start);
   492     INFO("Pair reduced to:" << mStart << ":" << mCount);
   305             }
   493 }
   306             else {
   494 
   307                 // Fetch from end
   495 void UpdatePair::shiftRight(int count)
   308                 emit requestItems(mBufferPosition+mBufferSize-(end-start+1),
   496 {
   309                                   qMin(mBufferPosition+mBufferSize-1, mTotalCount));
   497     mStart += count;
   310             }
   498     INFO("Pair shifted to:" << mStart << ":" << mCount);
   311         }
   499 }
   312         else if (isInsideBuffer(start) && end >= mBufferPosition+mBufferSize-1) {
   500 
   313             emit requestItems(start, mBufferPosition+mBufferSize-1);
   501 void UpdatePair::shiftLeft(int count)
   314         }
   502 {
   315         else if (start <= mBufferPosition && isInsideBuffer(end)) {
   503     mStart -= count;
   316             emit requestItems(mBufferPosition, end);
   504     HANDLE_ERROR_BOOL((mStart >= 0));
   317         }
   505     INFO("Pair shifted to:" << mStart << ":" << mCount);
   318         else {
   506 }
   319             emit requestItems(mBufferPosition, mBufferPosition+mBufferSize-1);
   507 
   320         }
   508 bool UpdatePair::operator== (const UpdatePair &other) const
   321     }
   509 {
   322 
   510     return mStart == other.mStart && mCount == other.mCount;
   323     if (isInsideBuffer(target)) {
   511 }
   324         // start-end may be partially inside buffer
   512 
   325         if (!isInsideBuffer(start, end)) {
   513 bool UpdatePair::operator< (const UpdatePair &other) const
   326             addItems(target, target+end-start, totalCount);
   514 {
   327         }
   515     return (mStart < other.mStart || mStart == other.mStart && mCount < other.mCount);
   328         else if (isInsideBuffer(start)) {
   516 }
   329             addItems(target+(mBufferPosition+mBufferSize-start), target+end-start, totalCount);
   517 
   330         }
   518 UpdateBuffer::UpdateBuffer()
   331         else { // end is inside buffer
   519 {
   332             addItems(target, target+mBufferPosition-start-1, totalCount);
   520     FUNC_LOG;
   333         }
   521 }
   334     }
   522 
   335 }
   523 void UpdateBuffer::add(int start, int count)
   336 
   524 {
   337 bool HgScrollBufferManager::isInsideBuffer(int pos)
   525     FUNC_LOG;
   338 {
   526 
   339     return (pos >= mBufferPosition && pos < mBufferPosition+mBufferSize);
   527     int itemCount = this->count();
   340 }
   528     for (int i = 0; i < itemCount; i++) {
   341 
   529         if (at(i).contains(UpdatePair(start, count))) {
   342 bool HgScrollBufferManager::isInsideBuffer(int start, int end)
   530             // It is already there
   343 {
   531             return;
   344     INFO("Buffer:" << mBufferPosition << "-" << mBufferPosition+mBufferSize-1);
   532         }
   345     INFO("Change:" << start << "-" << end);
   533         if (at(i).adjacent(start, count)) {
   346 
   534             (*this)[i].extend(start, count);
   347     if (isInsideBuffer(start)) {
   535             return;
   348         return true;
   536         }
   349     }
   537     }
   350     if (isInsideBuffer(end)) {
   538     append(UpdatePair(start, count));
   351         return true;
   539 }
   352     }
   540 
   353     if (start < mBufferPosition && end >= mBufferPosition+mBufferSize) {
   541 void UpdateBuffer::remove(int start, int count)
   354         return true;
   542 {
   355     }
   543     FUNC_LOG;
   356 
   544 
   357     INFO("Buffer not affected");
   545     int itemCount = this->count();
   358     return false;
   546     for (int i = itemCount-1; i >= 0; i--) {
   359 }
   547         UpdatePair pair = at(i);
   360 
   548         UpdatePair comp = UpdatePair(start, count);
       
   549         if (comp.contains(pair)) {
       
   550             INFO("Removing pair" << pair.start() << "-" << pair.end());
       
   551             removeAt(i);
       
   552         }
       
   553         else if (pair.contains(comp)) {
       
   554             // Subtraction from middle is not applicable in mediawall use cases
       
   555             (*this)[i].subtract(start, count);
       
   556         }
       
   557         // Item may be present in multiple pairs.
       
   558     }
       
   559 }
       
   560 
       
   561 void UpdateBuffer::shiftRight(int startingFrom, int amount)
       
   562 {
       
   563     FUNC_LOG;
       
   564 
       
   565     int itemCount = this->count();
       
   566     for (int i = 0; i < itemCount; i++) {
       
   567         if (at(i).start() >= startingFrom) {
       
   568             (*this)[i].shiftRight(amount);
       
   569         }
       
   570     }
       
   571 }
       
   572 
       
   573 void UpdateBuffer::shiftLeft(int startingFrom, int amount)
       
   574 {
       
   575     FUNC_LOG;
       
   576 
       
   577     int itemCount = this->count();
       
   578     for (int i = 0; i < itemCount; i++) {
       
   579         if (at(i).start() >= startingFrom) {
       
   580             (*this)[i].shiftLeft(amount);
       
   581         }
       
   582     }
       
   583 }