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 } |