9#include "core/modelinvariantrowmapper.h"
10#include "core/modelinvariantindex_p.h"
11#include "core/modelinvariantrowmapper_p.h"
16#include "messagelist_debug.h"
31 : mMinimumRowIndex(minRowIndex)
33 , mInvariantHash(invariantHash)
39 for (
const auto idx : std::as_const(*mInvariantHash)) {
40 idx->d->setRowMapper(
nullptr);
42 delete mInvariantHash;
50ModelInvariantRowMapper::ModelInvariantRowMapper()
51 : d(new ModelInvariantRowMapperPrivate(this))
54 d->mCurrentShiftSerial = 0;
56 d->mUpdateTimer =
new QTimer(
this);
57 d->mUpdateTimer->setSingleShot(
true);
58 d->mLazyUpdateChunkInterval = 50;
59 d->mLazyUpdateIdleInterval = 50;
62 d->slotPerformLazyUpdate();
66ModelInvariantRowMapper::~ModelInvariantRowMapper()
68 if (d->mUpdateTimer->isActive()) {
69 d->mUpdateTimer->stop();
73 for (
const auto idx : std::as_const(*d->mCurrentInvariantHash)) {
74 idx->d->setRowMapper(
nullptr);
76 delete d->mCurrentInvariantHash;
78 if (d->mRowShiftList) {
79 while (!d->mRowShiftList->isEmpty()) {
80 delete d->mRowShiftList->takeFirst();
83 delete d->mRowShiftList;
87void ModelInvariantRowMapperPrivate::killFirstRowShift()
89 RowShift *shift = mRowShiftList->at(0);
91 Q_ASSERT(shift->mInvariantHash->isEmpty());
94 mRowShiftList->removeAt(0);
96 if (mRowShiftList->isEmpty()) {
98 mRowShiftList =
nullptr;
104 Q_ASSERT(invariant->d->rowMapper() == q);
106 if (invariant->d->rowMapperSerial() == mCurrentShiftSerial) {
107 mCurrentInvariantHash->remove(invariant->d->modelIndexRow());
111 Q_ASSERT(invariant->d->rowMapperSerial() < mCurrentShiftSerial);
113 if (!mRowShiftList) {
117 uint invariantShiftIndex = invariant->d->rowMapperSerial() - mRemovedShiftCount;
119 Q_ASSERT(invariantShiftIndex <
static_cast<uint
>(mRowShiftList->count()));
121 RowShift *shift = mRowShiftList->at(invariantShiftIndex);
125 shift->mInvariantHash->remove(invariant->d->modelIndexRow());
127 if ((shift->mInvariantHash->isEmpty()) && (invariantShiftIndex == 0)) {
133void ModelInvariantRowMapperPrivate::updateModelInvariantIndex(
int modelIndexRow,
ModelInvariantIndex *invariantToFill)
138 Q_ASSERT(invariantToFill->d->rowMapper() == q);
140 uint invariantShiftIndex = invariantToFill->d->rowMapperSerial() - mRemovedShiftCount;
142 Q_ASSERT(invariantShiftIndex <
static_cast<uint
>(mRowShiftList->count()));
144 RowShift *shift = mRowShiftList->at(invariantShiftIndex);
146 int count = shift->mInvariantHash->remove(invariantToFill->d->modelIndexRow());
152 invariantToFill->d->setModelIndexRowAndRowMapperSerial(modelIndexRow, mCurrentShiftSerial);
154 Q_ASSERT(!mCurrentInvariantHash->contains(invariantToFill->d->modelIndexRow()));
156 mCurrentInvariantHash->insert(invariantToFill->d->modelIndexRow(), invariantToFill);
158 if ((shift->mInvariantHash->isEmpty()) && (invariantShiftIndex == 0)) {
164ModelInvariantIndex *ModelInvariantRowMapperPrivate::modelIndexRowToModelInvariantIndexInternal(
int modelIndexRow,
bool updateIfNeeded)
173 if (!mRowShiftList) {
177 int idx = mRowShiftList->count();
184 int previousIndexRow = modelIndexRow;
187 RowShift *shift = mRowShiftList->at(idx);
203 int potentialPreviousModelIndexRow = previousIndexRow - shift->mShift;
204 if (potentialPreviousModelIndexRow >= shift->mMinimumRowIndex) {
205 previousIndexRow = potentialPreviousModelIndexRow;
208 invariant = shift->mInvariantHash->value(previousIndexRow,
nullptr);
211 if (updateIfNeeded) {
212 updateModelInvariantIndex(modelIndexRow, invariant);
220 qCWarning(MESSAGELIST_LOG) <<
"Requested invariant for storage row index " << modelIndexRow <<
" not found in history";
226 d->mLazyUpdateChunkInterval = chunkInterval;
231 d->mLazyUpdateIdleInterval = idleInterval;
241 if (invariant->d->rowMapper() !=
this) {
245 if (invariant->d->rowMapperSerial() == d->mCurrentShiftSerial) {
246 Q_ASSERT(d->mCurrentInvariantHash->value(invariant->d->modelIndexRow()) == invariant);
247 return invariant->d->modelIndexRow();
300 uint invariantShiftIndex = invariant->d->rowMapperSerial() - d->mRemovedShiftCount;
302 Q_ASSERT(d->mRowShiftList);
306 const uint count =
static_cast<uint
>(d->mRowShiftList->count());
308 Q_ASSERT(invariantShiftIndex < count);
310 int modelIndexRow = invariant->d->modelIndexRow();
313 for (uint idx = invariantShiftIndex; idx < count; idx++) {
314 RowShift *shift = d->mRowShiftList->at(idx);
315 if (modelIndexRow >= shift->mMinimumRowIndex) {
316 modelIndexRow += shift->mShift;
321 d->updateModelInvariantIndex(modelIndexRow, invariant);
323 return modelIndexRow;
329 Q_ASSERT(invariantToFill->d->rowMapper() ==
nullptr);
332 invariantToFill->d->setModelIndexRowAndRowMapperSerial(modelIndexRow, d->mCurrentShiftSerial);
333 invariantToFill->d->setRowMapper(
this);
335 Q_ASSERT(!d->mCurrentInvariantHash->contains(modelIndexRow));
337 d->mCurrentInvariantHash->insert(modelIndexRow, invariantToFill);
342 return d->modelIndexRowToModelInvariantIndexInternal(modelIndexRow,
false);
347 if (!d->mRowShiftList) {
348 if (d->mCurrentInvariantHash->isEmpty()) {
358 const int end = startIndexRow + count;
359 for (
int idx = startIndexRow; idx < end; idx++) {
362 invariantList->append(invariant);
366 if (invariantList->isEmpty()) {
367 delete invariantList;
371 return invariantList;
383 if (!d->mRowShiftList) {
384 if (d->mCurrentInvariantHash->isEmpty()) {
393 if (d->mCurrentInvariantHash->isEmpty()) {
396 Q_ASSERT(d->mRowShiftList->count() > 0);
399 shift = d->mRowShiftList->at(d->mRowShiftList->count() - 1);
402 if (shift->mShift > 0) {
403 if ((shift->mMinimumRowIndex + shift->mShift) == modelIndexRowPosition) {
405 shift->mShift += count;
406 Q_ASSERT(d->mUpdateTimer->isActive());
414 shift =
new RowShift(modelIndexRowPosition, count, d->mCurrentInvariantHash);
415 d->mRowShiftList->append(shift);
417 d->mCurrentShiftSerial++;
420 if (d->mRowShiftList->count() > 7) {
424 if (d->mUpdateTimer->isActive()) {
425 d->mUpdateTimer->stop();
428 d->slotPerformLazyUpdate();
431 if (!d->mUpdateTimer->isActive()) {
432 d->mUpdateTimer->start(d->mLazyUpdateIdleInterval);
446 if (!d->mRowShiftList) {
447 if (d->mCurrentInvariantHash->isEmpty()) {
484 const int end = modelIndexRowPosition + count;
485 for (
int idx = modelIndexRowPosition; idx < end; idx++) {
488 ModelInvariantIndex *dyingInvariant = d->modelIndexRowToModelInvariantIndexInternal(idx,
false);
489 if (dyingInvariant) {
490 d->indexDead(dyingInvariant);
491 dyingInvariant->d->setRowMapper(
nullptr);
492 deadInvariants->append(dyingInvariant);
495 qCWarning(MESSAGELIST_LOG) <<
"Could not find invariant to invalidate at current row " << idx;
499 if (!d->mRowShiftList) {
501 if (d->mCurrentInvariantHash->isEmpty()) {
503 if (deadInvariants->isEmpty()) {
505 delete deadInvariants;
508 return deadInvariants;
515 auto shift =
new RowShift(modelIndexRowPosition + count, -count, d->mCurrentInvariantHash);
516 d->mRowShiftList->append(shift);
518 d->mCurrentShiftSerial++;
522 if (d->mRowShiftList->count() > 7) {
526 if (d->mUpdateTimer->isActive()) {
527 d->mUpdateTimer->stop();
530 d->slotPerformLazyUpdate();
533 if (!d->mUpdateTimer->isActive()) {
534 d->mUpdateTimer->start(d->mLazyUpdateIdleInterval);
538 if (deadInvariants->isEmpty()) {
540 delete deadInvariants;
544 return deadInvariants;
551 for (
const auto idx : std::as_const(*d->mCurrentInvariantHash)) {
552 idx->d->setRowMapper(
nullptr);
554 d->mCurrentInvariantHash->clear();
556 if (d->mRowShiftList) {
557 while (!d->mRowShiftList->isEmpty()) {
558 delete d->mRowShiftList->takeFirst();
561 delete d->mRowShiftList;
562 d->mRowShiftList =
nullptr;
565 d->mCurrentShiftSerial = 0;
566 d->mRemovedShiftCount = 0;
569void ModelInvariantRowMapperPrivate::slotPerformLazyUpdate()
588 while (mRowShiftList) {
590 uint count =
static_cast<uint
>(mRowShiftList->count());
593 RowShift *shift = mRowShiftList->at(0);
596 auto it = shift->mInvariantHash->begin();
597 auto end = shift->mInvariantHash->end();
602 it = shift->mInvariantHash->erase(it);
605 int modelIndexRow = invariant->d->modelIndexRow();
607 for (uint idx = 0; idx < count; ++idx) {
608 RowShift *thatShift = mRowShiftList->at(idx);
609 if (modelIndexRow >= thatShift->mMinimumRowIndex) {
610 modelIndexRow += thatShift->mShift;
615 invariant->d->setModelIndexRowAndRowMapperSerial(modelIndexRow, mCurrentShiftSerial);
617 mCurrentInvariantHash->insert(modelIndexRow, invariant);
620 if ((curIndex % 15) == 0) {
622 if ((elapsed > mLazyUpdateChunkInterval) || (elapsed < 0)) {
625 mUpdateTimer->start(mLazyUpdateIdleInterval);
642#include "moc_modelinvariantrowmapper.cpp"
An invariant index that can be ALWAYS used to reference an item inside a QAbstractItemModel.
QList< ModelInvariantIndex * > * modelIndexRowRangeToModelInvariantIndexList(int startIndexRow, int count)
This basically applies modelIndexRowToModelInvariantIndex() to a range of elements.
void createModelInvariantIndex(int modelIndexRow, ModelInvariantIndex *invariantToFill)
Binds a ModelInvariantIndex structure to the specified CURRENT modelIndexRow.
void modelRowsInserted(int modelIndexRowPosition, int count)
Call this function when rows are inserted to the underlying model BEFORE scanning the model for the n...
void modelReset()
Call this function from your handlers of reset() and layoutChanged() AFTER you ve last accessed the m...
QList< ModelInvariantIndex * > * modelRowsRemoved(int modelIndexRowPosition, int count)
Call this function when rows are removed from the underlying model AFTER accessing the removed rows f...
void setLazyUpdateChunkInterval(int chunkInterval)
Sets the maximum time we can spend inside a single lazy update step.
ModelInvariantIndex * modelIndexRowToModelInvariantIndex(int modelIndexRow)
Finds the existing ModelInvariantIndex that belongs to the specified CURRENT modelIndexRow.
void setLazyUpdateIdleInterval(int idleInterval)
Sets the idle time between two lazy updates in milliseconds.
int modelInvariantIndexToModelIndexRow(ModelInvariantIndex *invariant)
Maps a ModelInvariantIndex to the CURRENT associated row index in the model.
The implementation independent part of the MessageList library.
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
int msecsTo(QTime t) const const