aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/util')
-rw-r--r--src/quick/util/qquickchangeset.cpp565
-rw-r--r--src/quick/util/qquickchangeset_p.h43
-rw-r--r--src/quick/util/qquicklistcompositor.cpp23
-rw-r--r--src/quick/util/qquicklistcompositor_p.h4
4 files changed, 390 insertions, 245 deletions
diff --git a/src/quick/util/qquickchangeset.cpp b/src/quick/util/qquickchangeset.cpp
index c335408c02..23fa432367 100644
--- a/src/quick/util/qquickchangeset.cpp
+++ b/src/quick/util/qquickchangeset.cpp
@@ -43,120 +43,159 @@
QT_BEGIN_NAMESPACE
+
+/*!
+ \class QQuickChangeSet
+ \brief The QQuickChangeSet class stores an ordered list of notifications about
+ changes to a linear data set.
+ \internal
+
+ QQuickChangeSet can be used to record a series of notications about items in an indexed list
+ being inserted, removed, moved, and changed. Notifications in the set are re-ordered so that
+ all notifications of a single type are grouped together and sorted in order of ascending index,
+ with remove notifications preceding all others, followed by insert notification, and then
+ change notifications.
+
+ Moves in a change set are represented by a remove notification paired with an insert
+ notification by way of a shared unique moveId. Re-ordering may result in one or both of the
+ paired notifications being divided, when this happens the offset member of the notification
+ will indicate the relative offset of the divided notification from the beginning of the
+ original.
+*/
+
+/*!
+ Constructs an empty change set.
+*/
+
QQuickChangeSet::QQuickChangeSet()
- : m_moveCounter(0)
- , m_difference(0)
+ : m_difference(0)
{
}
+/*!
+ Constructs a copy of a \a changeSet.
+*/
+
QQuickChangeSet::QQuickChangeSet(const QQuickChangeSet &changeSet)
: m_removes(changeSet.m_removes)
, m_inserts(changeSet.m_inserts)
, m_changes(changeSet.m_changes)
- , m_moveCounter(changeSet.m_moveCounter)
- , m_difference(0)
+ , m_difference(changeSet.m_difference)
{
}
+/*!
+ Destroys a change set.
+*/
+
QQuickChangeSet::~QQuickChangeSet()
{
}
+/*!
+ Assigns the value of a \a changeSet to another.
+*/
+
QQuickChangeSet &QQuickChangeSet::operator =(const QQuickChangeSet &changeSet)
{
m_removes = changeSet.m_removes;
m_inserts = changeSet.m_inserts;
m_changes = changeSet.m_changes;
- m_moveCounter = changeSet.m_moveCounter;
m_difference = changeSet.m_difference;
return *this;
}
+/*!
+ Appends a notification that \a count items were inserted at \a index.
+*/
+
void QQuickChangeSet::insert(int index, int count)
{
- applyInsertions(QVector<Insert>() << Insert(index, count));
+ insert(QVector<Insert>() << Insert(index, count));
}
+/*!
+ Appends a notification that \a count items were removed at \a index.
+*/
+
void QQuickChangeSet::remove(int index, int count)
{
- QVector<Insert> i;
- applyRemovals(QVector<Remove>() << Remove(index, count), i);
+ QVector<Remove> removes;
+ removes.append(Remove(index, count));
+ remove(&removes, 0);
}
-void QQuickChangeSet::move(int from, int to, int count)
+/*!
+ Appends a notification that \a count items were moved \a from one index \a to another.
+
+ The \a moveId must be unique across the lifetime of the change set and any related
+ change sets.
+*/
+
+void QQuickChangeSet::move(int from, int to, int count, int moveId)
{
- apply(QVector<Remove>() << Remove(from, count, -2), QVector<Insert>() << Insert(to, count, -2));
+ QVector<Remove> removes;
+ removes.append(Remove(from, count, moveId));
+ QVector<Insert> inserts;
+ inserts.append(Insert(to, count, moveId));
+ remove(&removes, &inserts);
+ insert(inserts);
}
+/*!
+ Appends a notification that \a count items were changed at \a index.
+*/
+
void QQuickChangeSet::change(int index, int count)
{
- applyChanges(QVector<Change>() << Change(index, count));
+ QVector<Change> changes;
+ changes.append(Change(index, count));
+ change(changes);
}
-void QQuickChangeSet::apply(const QQuickChangeSet &changeSet)
-{
- apply(changeSet.m_removes, changeSet.m_inserts, changeSet.m_changes);
-}
+/*!
+ Applies the changes in a \a changeSet to another.
+*/
-void QQuickChangeSet::apply(const QVector<Remove> &removals)
+void QQuickChangeSet::apply(const QQuickChangeSet &changeSet)
{
- QVector<Remove> r = removals;
- QVector<Insert> i;
- applyRemovals(r, i);
+ QVector<Remove> r = changeSet.m_removes;
+ QVector<Insert> i = changeSet.m_inserts;
+ QVector<Change> c = changeSet.m_changes;
+ remove(&r, &i);
+ insert(i);
+ change(c);
}
-void QQuickChangeSet::apply(const QVector<Insert> &insertions)
-{
- QVector<Insert> i = insertions;
- applyInsertions(i);
-}
+/*!
+ Applies a list of \a removes to a change set.
-void QQuickChangeSet::apply(const QVector<Change> &changes)
-{
- QVector<Change> c = changes;
- applyChanges(c);
-}
+ If a remove contains a moveId then any intersecting insert in the set will replace the
+ corresponding intersection in the optional \a inserts list.
+*/
-void QQuickChangeSet::apply(const QVector<Remove> &removals, const QVector<Insert> &insertions, const QVector<Change> &changes)
+void QQuickChangeSet::remove(const QVector<Remove> &removes, QVector<Insert> *inserts)
{
- QVector<Remove> r = removals;
- QVector<Insert> i = insertions;
- QVector<Change> c = changes;
- applyRemovals(r, i);
- applyInsertions(i);
- applyChanges(c);
+ QVector<Remove> r = removes;
+ remove(&r, inserts);
}
-void QQuickChangeSet::applyRemovals(QVector<Remove> &removals, QVector<Insert> &insertions)
+void QQuickChangeSet::remove(QVector<Remove> *removes, QVector<Insert> *inserts)
{
int removeCount = 0;
int insertCount = 0;
QVector<Insert>::iterator insert = m_inserts.begin();
QVector<Change>::iterator change = m_changes.begin();
- QVector<Remove>::iterator rit = removals.begin();
- for (; rit != removals.end(); ++rit) {
+ QVector<Remove>::iterator rit = removes->begin();
+ for (; rit != removes->end(); ++rit) {
int index = rit->index + removeCount;
int count = rit->count;
- QVector<Insert>::iterator iit = insertions.begin();
- for (; rit->moveId != -1 && iit != insertions.end() && iit->moveId != rit->moveId; ++iit) {}
-
- for (QVector<Remove>::iterator nrit = rit + 1; nrit != removals.end(); nrit = rit + 1) {
- if (nrit->index != rit->index || (rit->moveId == -1) != (nrit->moveId == -1))
- break;
- if (nrit->moveId != -1) {
- QVector<Insert>::iterator niit = iit + 1;
- if (niit->moveId != nrit->moveId || niit->index != iit->index + iit->count)
- break;
- niit->index = iit->index;
- niit->count += iit->count;
- iit = insertions.erase(iit);
- }
- nrit->count += rit->count;
- rit = removals.erase(rit);
- }
-
- for (; change != m_changes.end() && change->end() < rit->index; ++change) {}
+ // Decrement the accumulated remove count from the indexes of any changes prior to the
+ // current remove.
+ for (; change != m_changes.end() && change->end() < rit->index; ++change)
+ change->index -= removeCount;
+ // Remove any portion of a change notification that intersects the current remove.
for (; change != m_changes.end() && change->index > rit->end(); ++change) {
change->count -= qMin(change->end(), rit->end()) - qMax(change->index, rit->index);
if (change->count == 0) {
@@ -165,164 +204,185 @@ void QQuickChangeSet::applyRemovals(QVector<Remove> &removals, QVector<Insert> &
change->index = rit->index;
}
}
+
+ // Decrement the accumulated remove count from the indexes of any inserts prior to the
+ // current remove.
for (; insert != m_inserts.end() && insert->end() <= index; ++insert) {
insertCount += insert->count;
insert->index -= removeCount;
}
- for (; insert != m_inserts.end() && insert->index < index + count; ++insert) {
- const int offset = insert->index - index;
- const int difference = qMin(insert->end(), index + count) - qMax(insert->index, index);
- const int moveId = rit->moveId != -1 ? m_moveCounter++ : -1;
- if (insert->moveId != -1) {
- QVector<Remove>::iterator remove = m_removes.begin();
- for (; remove != m_removes.end() && remove->moveId != insert->moveId; ++remove) {}
- Q_ASSERT(remove != m_removes.end());
- const int offset = index - insert->index;
- if (rit->moveId != -1 && offset < 0) {
- const int moveId = m_moveCounter++;
- iit = insertions.insert(iit, Insert(iit->index, -offset, moveId));
- ++iit;
- iit->index += -offset;
- iit->count -= -offset;
- rit = removals.insert(rit, Remove(rit->index, -offset, moveId));
- ++rit;
- rit->count -= -offset;
- }
- if (offset > 0) {
- const int moveId = m_moveCounter++;
- insert = m_inserts.insert(insert, Insert(insert->index, offset, moveId));
- ++insert;
- insert->index += offset;
- insert->count -= offset;
- remove = m_removes.insert(remove, Remove(remove->index, offset, moveId));
- ++remove;
- remove->count -= offset;
- rit->index -= offset;
- index += offset;
- count -= offset;
- }
+ rit->index -= insertCount;
- if (remove->count == difference) {
- remove->moveId = moveId;
- } else {
- remove = m_removes.insert(remove, Remove(remove->index, difference, moveId));
- ++remove;
- remove->count -= difference;
- }
- } else if (rit->moveId != -1 && offset > 0) {
- const int moveId = m_moveCounter++;
- iit = insertions.insert(iit, Insert(iit->index, offset, moveId));
- ++iit;
- iit->index += offset;
- iit->count -= offset;
- rit = removals.insert(rit, Remove(rit->index, offset, moveId));
+ // Remove any portion of a insert notification that intersects the current remove.
+ while (insert != m_inserts.end() && insert->index < index + count) {
+ int offset = index - insert->index;
+ const int difference = qMin(insert->end(), index + count) - qMax(insert->index, index);
+
+ // If part of the remove or insert that precedes the intersection has a moveId create
+ // a new delta for that portion and subtract the size of that delta from the current
+ // one.
+ if (offset < 0 && rit->moveId != -1) {
+ rit = removes->insert(rit, Remove(
+ rit->index, -offset, rit->moveId, rit->offset));
++rit;
- rit->count -= offset;
- index += offset;
- count -= offset;
+ rit->count -= -offset;
+ rit->offset += -offset;
+ index += -offset;
+ count -= -offset;
+ removeCount += -offset;
+ offset = 0;
+ } else if (offset > 0 && insert->moveId != -1) {
+ insert = m_inserts.insert(insert, Insert(
+ insert->index - removeCount, offset, insert->moveId, insert->offset));
+ ++insert;
+ insert->index += offset;
+ insert->count -= offset;
+ insert->offset += offset;
+ rit->index -= offset;
+ insertCount += offset;
}
- if (rit->moveId != -1 && difference > 0) {
- iit = insertions.insert(iit, Insert(
- iit->index, difference, insert->moveId != -1 ? moveId : -1));
- ++iit;
- iit->index += difference;
- iit->count -= difference;
+ // If the current remove has a move id, find any inserts with the same move id and
+ // replace the corresponding sections with the insert removed from the change set.
+ if (rit->moveId != -1 && difference > 0 && inserts) {
+ for (QVector<Insert>::iterator iit = inserts->begin(); iit != inserts->end(); ++iit) {
+ if (iit->moveId != rit->moveId
+ || rit->offset > iit->offset + iit->count
+ || iit->offset > rit->offset + difference) {
+ continue;
+ }
+ // If the intersecting insert starts before the replacement one create
+ // a new insert for the portion prior to the replacement insert.
+ const int overlapOffset = rit->offset - iit->offset;
+ if (overlapOffset > 0) {
+ iit = inserts->insert(iit, Insert(
+ iit->index, overlapOffset, iit->moveId, iit->offset));
+ ++iit;
+ iit->index += overlapOffset;
+ iit->count -= overlapOffset;
+ iit->offset += overlapOffset;
+ }
+ if (iit->offset >= rit->offset
+ && iit->offset + iit->count <= rit->offset + difference) {
+ // If the replacement insert completely encapsulates the existing
+ // one just change the moveId.
+ iit->moveId = insert->moveId;
+ iit->offset = insert->offset + qMax(0, -overlapOffset);
+ } else {
+ // Create a new insertion before the intersecting one with the number of intersecting
+ // items and remove that number from that insert.
+ const int count
+ = qMin(iit->offset + iit->count, rit->offset + difference)
+ - qMax(iit->offset, rit->offset);
+ iit = inserts->insert(iit, Insert(
+ iit->index,
+ count,
+ insert->moveId,
+ insert->offset + qMax(0, -overlapOffset)));
+ ++iit;
+ iit->index += count;
+ iit->count -= count;
+ iit->offset += count;
+ }
+ }
}
+ // Subtract the number of intersecting items from the current remove and insert.
insert->count -= difference;
+ insert->offset += difference;
rit->count -= difference;
+ rit->offset += difference;
+
+ index += difference;
+ count -= difference;
+ removeCount += difference;
+
if (insert->count == 0) {
insert = m_inserts.erase(insert);
- --insert;
- } else if (index <= insert->index) {
- insert->index = rit->index;
+ } else if (rit->count == -offset || rit->count == 0) {
+ insert->index += difference;
+ break;
+ } else if (offset <= 0) {
+ insert->index = index - removeCount;
+ insertCount += insert->count;
+ ++insert;
} else {
+ insert->index -= removeCount - difference;
rit->index -= insert->count;
+ insertCount += insert->count;
+ ++insert;
}
- index += difference;
- count -= difference;
- removeCount += difference;
}
- rit->index -= insertCount;
removeCount += rit->count;
-
- if (rit->count == 0) {
- if (rit->moveId != -1 && iit->count == 0)
- insertions.erase(iit);
- rit = removals.erase(rit);
- --rit;
- } else if (rit->moveId != -1) {
- const int moveId = m_moveCounter++;
- rit->moveId = moveId;
- iit->moveId = moveId;
- }
}
- for (; change != m_changes.end(); ++change)
- change->index -= removeCount;
for (; insert != m_inserts.end(); ++insert)
insert->index -= removeCount;
removeCount = 0;
QVector<Remove>::iterator remove = m_removes.begin();
- for (rit = removals.begin(); rit != removals.end(); ++rit) {
- QVector<Insert>::iterator iit = insertions.begin();
+ for (rit = removes->begin(); rit != removes->end(); ++rit) {
+ if (rit->count == 0)
+ continue;
+ // Accumulate consecutive removes into a single delta before attempting to apply.
+ for (QVector<Remove>::iterator next = rit + 1; next != removes->end()
+ && next->index == rit->index
+ && next->moveId == -1
+ && rit->moveId == -1; ++next) {
+ next->count += rit->count;
+ rit = next;
+ }
int index = rit->index + removeCount;
- for (; rit->moveId != -1 && iit != insertions.end() && iit->moveId != rit->moveId; ++iit) {}
+ // Decrement the accumulated remove count from the indexes of any inserts prior to the
+ // current remove.
for (; remove != m_removes.end() && index > remove->index; ++remove)
remove->index -= removeCount;
- while (remove != m_removes.end() && index + rit->count > remove->index) {
+ while (remove != m_removes.end() && index + rit->count >= remove->index) {
int count = 0;
- const int offset = remove->index - index - removeCount;
+ const int offset = remove->index - index;
QVector<Remove>::iterator rend = remove;
for (; rend != m_removes.end()
&& rit->moveId == -1
&& rend->moveId == -1
- && rit->index + rit->count >= rend->index; ++rend) {
+ && index + rit->count >= rend->index; ++rend) {
count += rend->count;
}
if (remove != rend) {
- const int difference = rend == m_removes.end() || rit->index + rit->count < rend->index - removeCount
- ? rit->count
- : offset;
+ // Accumulate all existing non-move removes that are encapsulated by or immediately
+ // follow the current remove into it.
+ int difference = 0;
+ if (rend == m_removes.end())
+ difference = rit->count;
+ else if (rit->index + rit->count < rend->index - removeCount)
+ difference = rit->count;
+ else if (rend->moveId != -1) {
+ difference = rend->index - removeCount - rit->index;
+ index += difference;
+ } else if (offset > 0)
+ difference = offset;
count += difference;
- index += difference;
rit->count -= difference;
removeCount += difference;
remove->index = rit->index;
remove->count = count;
remove = m_removes.erase(++remove, rend);
- } else if (rit->moveId != -1) {
- if (offset > 0) {
- const int moveId = m_moveCounter++;
- iit = insertions.insert(iit, Insert(iit->index, offset, moveId));
- ++iit;
- iit->index += offset;
- iit->count -= offset;
- remove = m_removes.insert(remove, Remove(rit->index, offset, moveId));
- ++remove;
- rit->count -= offset;
- removeCount += offset;
- }
- remove->index = rit->index;
- index += offset;
-
- ++remove;
} else {
+ // Insert a remove for the portion of the unmergable current remove prior to the
+ // point of intersection.
if (offset > 0) {
- remove = m_removes.insert(remove, Remove(rit->index, offset));
+ remove = m_removes.insert(remove, Remove(
+ rit->index, offset, rit->moveId, rit->offset));
++remove;
rit->count -= offset;
+ rit->offset += offset;
removeCount += offset;
+ index += offset;
}
remove->index = rit->index;
- index += offset;
++remove;
}
- index += count;
}
if (rit->count > 0) {
@@ -336,78 +396,125 @@ void QQuickChangeSet::applyRemovals(QVector<Remove> &removals, QVector<Insert> &
m_difference -= removeCount;
}
-void QQuickChangeSet::applyInsertions(QVector<Insert> &insertions)
+/*!
+ Applies a list of \a inserts to a change set.
+*/
+
+void QQuickChangeSet::insert(const QVector<Insert> &inserts)
{
int insertCount = 0;
QVector<Insert>::iterator insert = m_inserts.begin();
QVector<Change>::iterator change = m_changes.begin();
- for (QVector<Insert>::iterator iit = insertions.begin(); iit != insertions.end(); ++iit) {
+ for (QVector<Insert>::const_iterator iit = inserts.begin(); iit != inserts.end(); ++iit) {
+ if (iit->count == 0)
+ continue;
int index = iit->index - insertCount;
- int count = iit->count;
+
+ Insert current = *iit;
+ // Accumulate consecutive inserts into a single delta before attempting to insert.
+ for (QVector<Insert>::const_iterator next = iit + 1; next != inserts.end()
+ && next->index == iit->index + iit->count
+ && next->moveId == -1
+ && iit->moveId == -1; ++next) {
+ current.count += next->count;
+ iit = next;
+ }
+
+ // Increment the index of any changes before the current insert by the accumlated insert
+ // count.
for (; change != m_changes.end() && change->index >= index; ++change)
change->index += insertCount;
- if (change != m_changes.end() && change->index < index + count) {
+ // If the current insert index is in the middle of a change split it in two at that
+ // point and increment the index of the latter half.
+ if (change != m_changes.end() && change->index < index + iit->count) {
int offset = index - change->index;
change = m_changes.insert(change, Change(change->index + insertCount, offset));
++change;
- change->index += count + offset;
+ change->index += iit->count + offset;
change->count -= offset;
}
- for (; insert != m_inserts.end() && iit->index > insert->index + insert->count; ++insert)
+
+ // Increment the index of any inserts before the current insert by the accumlated insert
+ // count.
+ for (; insert != m_inserts.end() && index > insert->index + insert->count; ++insert)
insert->index += insertCount;
if (insert == m_inserts.end()) {
- insert = m_inserts.insert(insert, *iit);
+ insert = m_inserts.insert(insert, current);
++insert;
- insertCount += iit->count;
} else {
const int offset = index - insert->index;
- if (offset < 0 || (offset == 0 && (iit->moveId != -1 || insert->moveId != -1))) {
- insert = m_inserts.insert(insert, *iit);
+
+ if (offset < 0) {
+ // If the current insert is before an existing insert and not adjacent just insert
+ // it into the list.
+ insert = m_inserts.insert(insert, current);
++insert;
} else if (iit->moveId == -1 && insert->moveId == -1) {
- insert->index -= iit->count;
- insert->count += iit->count;
+ // If neither the current nor existing insert has a moveId add the current insert
+ // to the existing one.
+ if (offset < insert->count) {
+ insert->index -= current.count;
+ insert->count += current.count;
+ } else {
+ insert->index += insertCount;
+ insert->count += current.count;
+ ++insert;
+ }
} else if (offset < insert->count) {
- const int moveId = insert->moveId != -1 ? m_moveCounter++ : -1;
- insert = m_inserts.insert(insert, Insert(insert->index + insertCount, offset, moveId));
- ++insert;
- insert->index += offset;
- insert->count -= offset;
- insert = m_inserts.insert(insert, *iit);
- ++insert;
-
- if (insert->moveId != -1) {
- QVector<Remove>::iterator remove = m_removes.begin();
- for (; remove != m_removes.end() && remove->moveId != insert->moveId; ++remove) {}
- Q_ASSERT(remove != m_removes.end());
- if (remove->count == offset) {
- remove->moveId = moveId;
- } else {
- remove = m_removes.insert(remove, Remove(remove->index, offset, moveId));
- ++remove;
- remove->count -= offset;
- }
+ // If either insert has a moveId then split the existing insert and insert the
+ // current one in the middle.
+ if (offset > 0) {
+ insert = m_inserts.insert(insert, Insert(
+ insert->index + insertCount, offset, insert->moveId, insert->offset));
+ ++insert;
+ insert->index += offset;
+ insert->count -= offset;
+ insert->offset += offset;
}
+ insert = m_inserts.insert(insert, current);
+ ++insert;
} else {
+ insert->index += insertCount;
++insert;
- insert = m_inserts.insert(insert, *iit);
+ insert = m_inserts.insert(insert, current);
++insert;
}
- insertCount += iit->count;
}
+ insertCount += current.count;
}
- for (; change != m_changes.end(); ++change)
- change->index += insertCount;
for (; insert != m_inserts.end(); ++insert)
insert->index += insertCount;
m_difference += insertCount;
}
-void QQuickChangeSet::applyChanges(QVector<Change> &changes)
+/*!
+ Applies a combined list of \a removes and \a inserts to a change set. This is equivalent
+ calling \l remove() followed by \l insert() with the same lists.
+*/
+
+void QQuickChangeSet::move(const QVector<Remove> &removes, const QVector<Insert> &inserts)
+{
+ QVector<Remove> r = removes;
+ QVector<Insert> i = inserts;
+ remove(&r, &i);
+ insert(i);
+}
+
+/*!
+ Applies a list of \a changes to a change set.
+*/
+
+void QQuickChangeSet::change(const QVector<Change> &changes)
+{
+ QVector<Change> c = changes;
+ change(&c);
+}
+
+void QQuickChangeSet::change(QVector<Change> *changes)
{
QVector<Insert>::iterator insert = m_inserts.begin();
QVector<Change>::iterator change = m_changes.begin();
- for (QVector<Change>::iterator cit = changes.begin(); cit != changes.end(); ++cit) {
+ for (QVector<Change>::iterator cit = changes->begin(); cit != changes->end(); ++cit) {
for (; insert != m_inserts.end() && insert->end() < cit->index; ++insert) {}
for (; insert != m_inserts.end() && insert->index < cit->end(); ++insert) {
const int offset = insert->index - cit->index;
@@ -416,7 +523,7 @@ void QQuickChangeSet::applyChanges(QVector<Change> &changes)
cit->index = insert->index + insert->count;
cit->count = count;
} else {
- cit = changes.insert(++cit, Change(insert->index + insert->count, count));
+ cit = changes->insert(++cit, Change(insert->index + insert->count, count));
--cit;
cit->count = offset;
}
@@ -436,14 +543,14 @@ void QQuickChangeSet::applyChanges(QVector<Change> &changes)
if (cit->index + cit->count > change->index + change->count) {
change->count = cit->index + cit->count - change->index;
- QVector<Change>::iterator rbegin = change;
- QVector<Change>::iterator rend = ++rbegin;
- for (; rend != m_changes.end() && rend->index <= change->index + change->count; ++rend) {
- if (rend->index + rend->count > change->index + change->count)
- change->count = rend->index + rend->count - change->index;
+ QVector<Change>::iterator cbegin = change;
+ QVector<Change>::iterator cend = ++cbegin;
+ for (; cend != m_changes.end() && cend->index <= change->index + change->count; ++cend) {
+ if (cend->index + cend->count > change->index + change->count)
+ change->count = cend->index + cend->count - change->index;
}
- if (rbegin != rend) {
- change = m_changes.erase(rbegin, rend);
+ if (cbegin != cend) {
+ change = m_changes.erase(cbegin, cend);
--change;
}
}
@@ -451,6 +558,10 @@ void QQuickChangeSet::applyChanges(QVector<Change> &changes)
}
}
+/*!
+ Prints the contents of a change \a set to the \a debug stream.
+*/
+
QDebug operator <<(QDebug debug, const QQuickChangeSet &set)
{
debug.nospace() << "QQuickChangeSet(";
@@ -460,16 +571,52 @@ QDebug operator <<(QDebug debug, const QQuickChangeSet &set)
return debug.nospace() << ')';
}
+/*!
+ Prints a \a remove to the \a debug stream.
+*/
+
QDebug operator <<(QDebug debug, const QQuickChangeSet::Remove &remove)
{
- return (debug.nospace() << "Remove(" << remove.index << ',' << remove.count << ',' << remove.moveId << ')').space();
+ if (remove.moveId == -1) {
+ return (debug.nospace()
+ << "Remove(" << remove.index
+ << ',' << remove.count
+ << ')').space();
+ } else {
+ return (debug.nospace()
+ << "Remove(" << remove.index
+ << ',' << remove.count
+ << ',' << remove.moveId
+ << ',' << remove.offset
+ << ')').space();
+ }
}
+/*!
+ Prints an \a insert to the \a debug stream.
+*/
+
QDebug operator <<(QDebug debug, const QQuickChangeSet::Insert &insert)
{
- return (debug.nospace() << "Insert(" << insert.index << ',' << insert.count << ',' << insert.moveId << ')').space();
+ if (insert.moveId == -1) {
+ return (debug.nospace()
+ << "Insert(" << insert.index
+ << ',' << insert.count
+ << ')').space();
+ } else {
+ return (debug.nospace()
+ << "Insert(" << insert.index
+ << ',' << insert.count
+ << ',' << insert.moveId
+ << ',' << insert.offset
+ << ')').space();
+ }
}
+/*!
+ Prints a \a change to the \a debug stream.
+*/
+
QDebug operator <<(QDebug debug, const QQuickChangeSet::Change &change)
{
return (debug.nospace() << "Change(" << change.index << ',' << change.count << ')').space();
diff --git a/src/quick/util/qquickchangeset_p.h b/src/quick/util/qquickchangeset_p.h
index 04a1e77c24..31a9c7bcbc 100644
--- a/src/quick/util/qquickchangeset_p.h
+++ b/src/quick/util/qquickchangeset_p.h
@@ -72,16 +72,18 @@ public:
struct Change
{
Change() : index(0), count(0), moveId(-1) {}
- Change(int index, int count) : index(index), count(count), moveId(-1) {}
- Change(int index, int count, int moveId) : index(index), count(count), moveId(moveId) {}
+ Change(int index, int count, int moveId = -1, int offset = 0)
+ : index(index), count(count), moveId(moveId), offset(offset) {}
int index;
int count;
int moveId;
+ int offset;
bool isMove() const { return moveId >= 0; }
- MoveKey moveKey(int index) const { return MoveKey(moveId, index - Change::index); }
+ MoveKey moveKey(int index) const {
+ return MoveKey(moveId, index - Change::index + offset); }
int start() const { return index; }
int end() const { return index + count; }
@@ -91,15 +93,15 @@ public:
struct Insert : public Change
{
Insert() {}
- Insert(int index, int count) : Change(index, count) {}
- Insert(int index, int count, int moveId) : Change(index, count, moveId) {}
+ Insert(int index, int count, int moveId = -1, int offset = 0)
+ : Change(index, count, moveId, offset) {}
};
struct Remove : public Change
{
Remove() {}
- Remove(int index, int count) : Change(index, count) {}
- Remove(int index, int count, int moveId) : Change(index, count, moveId) {}
+ Remove(int index, int count, int moveId = -1, int offset = 0)
+ : Change(index, count, moveId, offset) {}
};
QQuickChangeSet();
@@ -110,45 +112,38 @@ public:
const QVector<Remove> &removes() const { return m_removes; }
const QVector<Insert> &inserts() const { return m_inserts; }
- const QVector<Change> &changes() const {return m_changes; }
+ const QVector<Change> &changes() const { return m_changes; }
void insert(int index, int count);
void remove(int index, int count);
- void move(int from, int to, int count);
+ void move(int from, int to, int count, int moveId);
void change(int index, int count);
+ void insert(const QVector<Insert> &inserts);
+ void remove(const QVector<Remove> &removes, QVector<Insert> *inserts = 0);
+ void move(const QVector<Remove> &removes, const QVector<Insert> &inserts);
+ void change(const QVector<Change> &changes);
void apply(const QQuickChangeSet &changeSet);
- void apply(const QVector<Remove> &removals);
- void apply(const QVector<Insert> &insertions);
- void apply(const QVector<Change> &changes);
- void apply(
- const QVector<Remove> &removals,
- const QVector<Insert> &insertions,
- const QVector<Change> &changes = QVector<Change>());
- bool isEmpty() const { return m_removes.empty() && m_inserts.empty() && m_changes.empty(); }
+ bool isEmpty() const { return m_removes.empty() && m_inserts.empty() && m_changes.isEmpty(); }
void clear()
{
m_removes.clear();
m_inserts.clear();
m_changes.clear();
- m_moveCounter = 0;
m_difference = 0;
}
- int moveCounter() const { return m_moveCounter; }
int difference() const { return m_difference; }
private:
- void applyRemovals(QVector<Remove> &removals, QVector<Insert> &insertions);
- void applyInsertions(QVector<Insert> &insertions);
- void applyChanges(QVector<Change> &changes);
+ void remove(QVector<Remove> *removes, QVector<Insert> *inserts);
+ void change(QVector<Change> *changes);
QVector<Remove> m_removes;
QVector<Insert> m_inserts;
QVector<Change> m_changes;
- int m_moveCounter;
int m_difference;
};
@@ -161,10 +156,10 @@ inline uint qHash(const QQuickChangeSet::MoveKey &key) { return qHash(qMakePair(
inline bool operator ==(const QQuickChangeSet::MoveKey &l, const QQuickChangeSet::MoveKey &r) {
return l.moveId == r.moveId && l.offset == r.offset; }
-Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQuickChangeSet &change);
Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQuickChangeSet::Remove &remove);
Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQuickChangeSet::Insert &insert);
Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQuickChangeSet::Change &change);
+Q_AUTOTEST_EXPORT QDebug operator <<(QDebug debug, const QQuickChangeSet &change);
QT_END_NAMESPACE
diff --git a/src/quick/util/qquicklistcompositor.cpp b/src/quick/util/qquicklistcompositor.cpp
index 25dbd98c1e..e820a73ad2 100644
--- a/src/quick/util/qquicklistcompositor.cpp
+++ b/src/quick/util/qquicklistcompositor.cpp
@@ -210,6 +210,7 @@ QQuickListCompositor::QQuickListCompositor()
, m_groupCount(2)
, m_defaultFlags(PrependFlag | DefaultFlag)
, m_removeFlags(AppendFlag | PrependFlag | GroupMask)
+ , m_moveId(0)
{
}
@@ -586,7 +587,7 @@ void QQuickListCompositor::move(
// Remove count items belonging to the move group from the list.
Range movedFlags;
- for (int moveId = 0; count > 0;) {
+ for (int moveId = m_moveId; count > 0;) {
if (fromIt != moveGroup) {
// Skip ranges not containing items from the move group.
fromIt.incrementIndexes(fromIt->count);
@@ -604,7 +605,7 @@ void QQuickListCompositor::move(
fromIt->flags & ~(PrependFlag | AppendFlag));
// Remove moved items from the count, the existing range, and a remove notification.
if (removes)
- removes->append(Remove(fromIt, difference, fromIt->flags, moveId++));
+ removes->append(Remove(fromIt, difference, fromIt->flags, ++moveId));
count -= difference;
fromIt->count -= difference;
@@ -702,13 +703,15 @@ void QQuickListCompositor::move(
for (Range *next, *range = movedFlags.next; range != &movedFlags; range = next) {
insert.count = range->count;
insert.flags = range->flags;
- if (inserts)
+ if (inserts) {
+ insert.moveId = ++m_moveId;
inserts->append(insert);
+ }
for (int i = 0; i < m_groupCount; ++i) {
if (insert.inGroup(i))
insert.index[i] += range->count;
}
- ++insert.moveId;
+
next = range->next;
delete range;
}
@@ -823,7 +826,7 @@ void QQuickListCompositor::listItemsRemoved(
void *list,
QVector<QQuickChangeSet::Remove> *removals,
QVector<QQuickChangeSet::Insert> *insertions,
- QVector<MovedFlags> *movedFlags, int moveId)
+ QVector<MovedFlags> *movedFlags)
{
QT_QML_TRACE_LISTCOMPOSITOR(<< list << *removals)
@@ -856,7 +859,7 @@ void QQuickListCompositor::listItemsRemoved(
Q_ASSERT(insertion->count == removal->count);
if (relativeIndex < 0) {
- int splitMoveId = ++moveId;
+ int splitMoveId = ++m_moveId;
removal = removals->insert(removal, QQuickChangeSet::Remove(
removal->index, -relativeIndex, splitMoveId));
++removal;
@@ -870,8 +873,8 @@ void QQuickListCompositor::listItemsRemoved(
if (it->prepend()) {
removeFlags |= it->flags & CacheFlag;
- translatedRemoval.moveId = ++moveId;
- movedFlags->append(MovedFlags(moveId, it->flags & ~AppendFlag));
+ translatedRemoval.moveId = ++m_moveId;
+ movedFlags->append(MovedFlags(m_moveId, it->flags & ~AppendFlag));
if (removeCount < removal->count) {
removal = removals->insert(removal, QQuickChangeSet::Remove(
@@ -965,7 +968,7 @@ void QQuickListCompositor::listItemsRemoved(
QVector<QQuickChangeSet::Remove> removals;
removals.append(QQuickChangeSet::Remove(index, count));
- listItemsRemoved(translatedRemovals, list, &removals, 0, 0, 0);
+ listItemsRemoved(translatedRemovals, list, &removals, 0, 0);
}
void QQuickListCompositor::listItemsMoved(
@@ -985,7 +988,7 @@ void QQuickListCompositor::listItemsMoved(
removals.append(QQuickChangeSet::Remove(from, count, 0));
insertions.append(QQuickChangeSet::Insert(to, count, 0));
- listItemsRemoved(translatedRemovals, list, &removals, &insertions, &movedFlags, 0);
+ listItemsRemoved(translatedRemovals, list, &removals, &insertions, &movedFlags);
listItemsInserted(translatedInsertions, list, insertions, &movedFlags);
}
diff --git a/src/quick/util/qquicklistcompositor_p.h b/src/quick/util/qquicklistcompositor_p.h
index 718ffe0011..5cf5190d91 100644
--- a/src/quick/util/qquicklistcompositor_p.h
+++ b/src/quick/util/qquicklistcompositor_p.h
@@ -273,6 +273,7 @@ private:
int m_groupCount;
int m_defaultFlags;
int m_removeFlags;
+ int m_moveId;
inline Range *insert(Range *before, void *list, int index, int count, uint flags);
inline Range *erase(Range *range);
@@ -291,8 +292,7 @@ private:
void *list,
QVector<QQuickChangeSet::Remove> *removals,
QVector<QQuickChangeSet::Insert> *insertions = 0,
- QVector<MovedFlags> *movedFlags = 0,
- int moveId = 0);
+ QVector<MovedFlags> *movedFlags = 0);
void listItemsInserted(
QVector<Insert> *translatedInsertions,
void *list,