Refactor and document QQuickChangeSet.
authorAndrew den Exter <andrew.den-exter@nokia.com>
Wed, 11 Jul 2012 03:30:38 +0000 (13:30 +1000)
committerQt by Nokia <qt-info@nokia.com>
Fri, 3 Aug 2012 05:44:47 +0000 (07:44 +0200)
Store an offset variable for moves so that an insert can be split
without the need to also split the corresponding remove, simplifying the
logic involved somewhat.

Change-Id: I1df19d431a04361a75e107bc4d149cbb80cd791d
Reviewed-by: Bea Lam <bea.lam@nokia.com>
src/quick/items/qquickvisualdatamodel.cpp
src/quick/util/qquickchangeset.cpp
src/quick/util/qquickchangeset_p.h
src/quick/util/qquicklistcompositor.cpp
src/quick/util/qquicklistcompositor_p.h
tests/auto/qml/qquickchangeset/tst_qquickchangeset.cpp

index 2ce6ead..832476e 100644 (file)
@@ -693,7 +693,7 @@ void QQuickVisualDataModelPrivate::updateFilterGroup()
         m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
 
         QQuickChangeSet changeSet;
-        changeSet.apply(removes, inserts);
+        changeSet.move(removes, inserts);
         emit q->modelUpdated(changeSet, false);
 
         if (changeSet.difference() != 0)
@@ -1062,7 +1062,7 @@ void QQuickVisualDataModelPrivate::itemsChanged(const QVector<Compositor::Change
     }
 
     for (int i = 1; i < m_groupCount; ++i)
-        QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedChanges.at(i));
+        QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.change(translatedChanges.at(i));
 }
 
 void QQuickVisualDataModel::_q_itemsChanged(int index, int count, const QVector<int> &roles)
@@ -1157,7 +1157,7 @@ void QQuickVisualDataModelPrivate::itemsInserted(const QVector<Compositor::Inser
         return;
 
     for (int i = 1; i < m_groupCount; ++i)
-        QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedInserts.at(i));
+        QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.insert(translatedInserts.at(i));
 }
 
 void QQuickVisualDataModel::_q_itemsInserted(int index, int count)
@@ -1274,7 +1274,7 @@ void QQuickVisualDataModelPrivate::itemsRemoved(const QVector<Compositor::Remove
         return;
 
     for (int i = 1; i < m_groupCount; ++i)
-       QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(translatedRemoves.at(i));
+       QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.remove(translatedRemoves.at(i));
 }
 
 void QQuickVisualDataModel::_q_itemsRemoved(int index, int count)
@@ -1316,7 +1316,7 @@ void QQuickVisualDataModelPrivate::itemsMoved(
         return;
 
     for (int i = 1; i < m_groupCount; ++i) {
-        QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.apply(
+        QQuickVisualDataGroupPrivate::get(m_groups[i])->changeSet.move(
                     translatedRemoves.at(i),
                     translatedInserts.at(i));
     }
@@ -2801,7 +2801,7 @@ void QQuickVisualPartsModel::updateFilterGroup()
         model->m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
 
         QQuickChangeSet changeSet;
-        changeSet.apply(removes, inserts);
+        changeSet.move(removes, inserts);
         if (!changeSet.isEmpty())
             emit modelUpdated(changeSet, false);
 
index c335408..23fa432 100644 (file)
 
 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();
index 04a1e77..31a9c7b 100644 (file)
@@ -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
 
index 25dbd98..e820a73 100644 (file)
@@ -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);
 }
 
index 718ffe0..5cf5190 100644 (file)
@@ -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,
index 4bd3df9..6ea4556 100644 (file)
 #include <qtest.h>
 #include <private/qquickchangeset_p.h>
 
-#define VERIFY_EXPECTED_OUTPUT
-
 class tst_qquickchangeset : public QObject
 {
     Q_OBJECT
+private slots:
+    void sequence_data();
+    void sequence();
+
+    void apply_data();
+    void apply();
+
+    void removeConsecutive_data();
+    void removeConsecutive();
+    void insertConsecutive_data();
+    void insertConsecutive();
+
+    // These create random sequences and verify a list with the reordered changes applied is the
+    // same as one with the unordered changes applied.
+private:
+    void random_data();
+    void random();
+
 public:
+    enum {
+        MoveOp = 0,
+        InsertOp = -1,
+        RemoveOp = -2
+    };
+
     struct Signal
     {
         int index;
         int count;
         int to;
         int moveId;
+        int offset;
 
         bool isInsert() const { return to == -1; }
         bool isRemove() const { return to == -2; }
-        bool isMove() const { return to >= 0; }
         bool isChange() const { return to == -3; }
+        bool isMove() const { return to >= 0; }
     };
 
-    static Signal Insert(int index, int count, int moveId = -1) { Signal signal = { index, count, -1, moveId }; return signal; }
-    static Signal Remove(int index, int count, int moveId = -1) { Signal signal = { index, count, -2, moveId }; return signal; }
-    static Signal Move(int from, int to, int count) { Signal signal = { from, count, to, -1 }; return signal; }
-    static Signal Change(int index, int count) { Signal signal = { index, count, -3, -1 }; return signal; }
+    static Signal Insert(int index, int count) {
+        Signal signal = { index, count, -1, -1, 0 }; return signal; }
+    static Signal Insert(int index, int count, int moveId, int moveOffset) {
+        Signal signal = { index, count, -1, moveId, moveOffset }; return signal; }
+    static Signal Remove(int index, int count) {
+        Signal signal = { index, count, -2, -1, 0 }; return signal; }
+    static Signal Remove(int index, int count, int moveId, int moveOffset) {
+        Signal signal = { index, count, -2, moveId, moveOffset }; return signal; }
+    static Signal Move(int from, int to, int count, int moveId) {
+        Signal signal = { from, count, to, moveId, 0 }; return signal; }
+    static Signal Change(int index, int count) {
+        Signal signal = { index, count, -3, -1, 0 }; return signal; }
 
     typedef QVector<Signal> SignalList;
-
-
-#ifdef VERIFY_EXPECTED_OUTPUT
+    typedef QVector<SignalList> SignalListList;
 
     template<typename T>
     void move(int from, int to, int n, T *items)
@@ -97,39 +126,58 @@ public:
             *t = *f;
     }
 
-    QVector<int> applyChanges(const QVector<int> &list, const QVector<Signal> &changes)
+    bool applyChanges(QVector<int> &list, const QVector<QVector<Signal> > &changes)
     {
-        QHash<int, QVector<int> > removedValues;
-        QVector<int> alteredList = list;
+        foreach (const SignalList &sl, changes) {
+            if (!applyChanges(list, sl))
+                return false;
+        }
+        return true;
+    }
+
+    bool applyChanges(QVector<int> &list, const QVector<Signal> &changes)
+    {
+        QHash<QQuickChangeSet::MoveKey, int> removedValues;
         foreach (const Signal &signal, changes) {
             if (signal.isInsert()) {
+                if (signal.index < 0 || signal.index > list.count()) {
+                    qDebug() << "insert out of range" << signal.index << list.count();
+                    return false;
+                }
                 if (signal.moveId != -1) {
-                    QVector<int> tail = alteredList.mid(signal.index);
-                    alteredList = alteredList.mid(0, signal.index) + removedValues.take(signal.moveId) + tail;
+                    QQuickChangeSet::Insert insert(signal.index, signal.count, signal.moveId, signal.offset);
+                    for (int i = insert.start(); i < insert.end(); ++i)
+                        list.insert(i, removedValues.take(insert.moveKey(i)));
                 } else {
-                    alteredList.insert(signal.index, signal.count, 100);
+                    list.insert(signal.index, signal.count, 100);
                 }
             } else if (signal.isRemove()) {
-                if (signal.moveId != -1)
-                    removedValues.insert(signal.moveId, alteredList.mid(signal.index, signal.count));
-                alteredList.erase(alteredList.begin() + signal.index, alteredList.begin() + signal.index + signal.count);
+                if (signal.index < 0 || signal.index + signal.count > list.count()) {
+                    qDebug() << "remove out of range" << signal.index << signal.count << list.count();
+                    return false;
+                }
+                if (signal.moveId != -1) {
+                    QQuickChangeSet::Remove remove(signal.index, signal.count, signal.moveId, signal.offset);
+                    for (int i = remove.start(); i < remove.end(); ++i)
+                        removedValues.insert(remove.moveKey(i), list.at(i));
+                }
+                list.erase(list.begin() + signal.index, list.begin() + signal.index + signal.count);
             } else if (signal.isMove()) {
-                move(signal.index, signal.to, signal.count, &alteredList);
-            } else if (signal.isChange()) {
-                for (int i = signal.index; i < signal.index + signal.count; ++i) {
-                    if (alteredList[i] < 100)
-                        alteredList[i] = 100;
+                if (signal.index < 0
+                        || signal.to < 0
+                        || signal.index + signal.count > list.count()
+                        || signal.to + signal.count > list.count()) {
+                    qDebug() << "move out of range" << signal.index << signal.to << signal.count << list.count();
+                    return false;
                 }
+                move(signal.index, signal.to, signal.count, &list);
+            } else if (signal.isChange()) {
+                for (int i = signal.index; i < signal.index + signal.count; ++i)
+                    list[i] = 100;
             }
         }
-        return alteredList;
+        return true;
     }
-
-#endif
-
-private slots:
-    void sequence_data();
-    void sequence();
 };
 
 bool operator ==(const tst_qquickchangeset::Signal &left, const tst_qquickchangeset::Signal &right)
@@ -137,24 +185,65 @@ bool operator ==(const tst_qquickchangeset::Signal &left, const tst_qquickchange
     return left.index == right.index
             && left.count == right.count
             && left.to == right.to
-            && ((left.moveId == -1 && right.moveId == -1) || (left.moveId != -1 && right.moveId != -1));
+            && left.moveId == right.moveId
+            && (left.moveId == -1 || left.offset == right.offset);
 }
 
-
 QDebug operator <<(QDebug debug, const tst_qquickchangeset::Signal &signal)
 {
-    if (signal.isInsert())
-        debug.nospace() << "Insert(" << signal.index << "," << signal.count << "," << signal.moveId << ")";
+    if (signal.isInsert() && signal.moveId == -1)
+        debug.nospace() << "Insert(" << signal.index << "," << signal.count << ")";
+    else if (signal.isInsert())
+        debug.nospace() << "Insert(" << signal.index << "," << signal.count << "," << signal.moveId << "," << signal.offset << ")";
+    else if (signal.isRemove() && signal.moveId == -1)
+        debug.nospace() << "Remove(" << signal.index << "," << signal.count << ")";
     else if (signal.isRemove())
-        debug.nospace() << "Remove(" << signal.index << "," << signal.count << "," << signal.moveId << ")";
+        debug.nospace() << "Remove(" << signal.index << "," << signal.count << "," << signal.moveId << "," << signal.offset << ")";
     else if (signal.isMove())
-        debug.nospace() << "Move(" << signal.index << "," << signal.to << "," << signal.count << ")";
+        debug.nospace() << "Move(" << signal.index << "," << signal.to << "," << signal.count << "," << signal.moveId << ")";
     else if (signal.isChange())
         debug.nospace() << "Change(" << signal.index << "," << signal.count << ")";
     return debug;
 }
 
 Q_DECLARE_METATYPE(tst_qquickchangeset::SignalList)
+Q_DECLARE_METATYPE(tst_qquickchangeset::SignalListList)
+
+#if 0
+# define VERIFY_EXPECTED_OUTPUT \
+    QVector<int> inputList; \
+    for (int i = 0; i < 40; ++i) \
+        inputList.append(i); \
+    QVector<int> outputList = inputList; \
+    if (!applyChanges(inputList, input)) { \
+        qDebug() << input; \
+        qDebug() << output; \
+        qDebug() << changes; \
+        QVERIFY(false); \
+    } else if (!applyChanges(outputList, output)) { \
+        qDebug() << input; \
+        qDebug() << output; \
+        qDebug() << changes; \
+        QVERIFY(false); \
+    } else if (outputList != inputList /* || changes != output*/) { \
+        qDebug() << input; \
+        qDebug() << output; \
+        qDebug() << changes; \
+        qDebug() << inputList; \
+        qDebug() << outputList; \
+        QVERIFY(false); \
+    } else if (changes != output) { \
+        qDebug() << output; \
+        qDebug() << changes; \
+        QCOMPARE(outputList, inputList); \
+    }
+#else
+# define VERIFY_EXPECTED_OUTPUT \
+    if (changes != output) { \
+        qDebug() << output; \
+        qDebug() << changes; \
+    }
+#endif
 
 void tst_qquickchangeset::sequence_data()
 {
@@ -200,178 +289,178 @@ void tst_qquickchangeset::sequence_data()
 
     // Move
     QTest::newRow("m(8-10,2)")
-            << (SignalList() << Move(8,10,2))
-            << (SignalList() << Remove(8,2,1) << Insert(10,2,1));
+            << (SignalList() << Move(8,10,2,0))
+            << (SignalList() << Remove(8,2,0,0) << Insert(10,2,0,0));
 
     QTest::newRow("m(23-12,6),m(13-15,5)")
-            << (SignalList() << Move(23,12,6) << Move(13,15,5))
-            << (SignalList() << Remove(23,1,0) << Remove(23,5,1) << Insert(12,1,0) << Insert(15,5,1));
+            << (SignalList() << Move(23,12,6,0) << Move(13,15,5,1))
+            << (SignalList() << Remove(23,6,0,0) << Insert(12,1,0,0) << Insert(15,5,0,1));
     QTest::newRow("m(23-12,6),m(13-15,2)")
-            << (SignalList() << Move(23,12,6) << Move(13,20,2))
-            << (SignalList() << Remove(23,1,0) << Remove(23,2,1) << Remove(23,3,2) << Insert(12,1,0) << Insert(13,3,2) << Insert(20,2,1));
+            << (SignalList() << Move(23,12,6,0) << Move(13,20,2,1))
+            << (SignalList() << Remove(23,6,0,0) << Insert(12,1,0,0) << Insert(13,3,0,3) << Insert(20,2,0,1));
     QTest::newRow("m(23-12,6),m(13-2,2)")
-            << (SignalList() << Move(23,12,6) << Move(13,2,2))
-            << (SignalList() << Remove(23,1,0) << Remove(23,2,1) << Remove(23,3,2) << Insert(2,2,1) << Insert(14,1,0) << Insert(15,3,2));
+            << (SignalList() << Move(23,12,6,0) << Move(13,2,2,1))
+            << (SignalList() << Remove(23,6,0,0) << Insert(2,2,0,1) << Insert(14,1,0,0) << Insert(15,3,0,3));
     QTest::newRow("m(23-12,6),m(12-6,5)")
-            << (SignalList() << Move(23,12,6) << Move(12,6,5))
-            << (SignalList() << Remove(23,5,0) << Remove(23,1,1) << Insert(6,5,0) << Insert(17,1,1));
+            << (SignalList() << Move(23,12,6,0) << Move(12,6,5,1))
+            << (SignalList() << Remove(23,6,0,0) << Insert(6,5,0,0) << Insert(17,1,0,5));
     QTest::newRow("m(23-12,6),m(10-5,4)")
-            << (SignalList() << Move(23,12,6) << Move(10,5,4))
-            << (SignalList() << Remove(10,2,0) << Remove(21,2,1) << Remove(21,4,2) << Insert(5,2,0) << Insert(7,2,1) << Insert(14,4,2));
+            << (SignalList() << Move(23,12,6,0) << Move(10,5,4,1))
+            << (SignalList() << Remove(10,2,1,0) << Remove(21,6,0,0) << Insert(5,2,1,0) << Insert(7,2,0,0) << Insert(14,4,0,2));
     QTest::newRow("m(23-12,6),m(16-5,4)")
-            << (SignalList() << Move(23,12,6) << Move(16,5,4))
-            << (SignalList() << Remove(12,2,0) << Remove(21,4,1) << Remove(21,2,2) << Insert(5,2,2) << Insert(7,2,0) << Insert(16,4,1));
+            << (SignalList() << Move(23,12,6,0) << Move(16,5,4,1))
+            << (SignalList() << Remove(12,2,1,2) << Remove(21,6,0,0) << Insert(5,2,0,4) << Insert(7,2,1,2) << Insert(16,4,0,0));
     QTest::newRow("m(23-12,6),m(13-5,4)")
-            << (SignalList() << Move(23,12,6) << Move(13,5,4))
-            << (SignalList() << Remove(23,1,0) << Remove(23,4,1) << Remove(23,1,2) << Insert(5,4,1) << Insert(16,1,0) << Insert(17,1,2));
+            << (SignalList() << Move(23,12,6,0) << Move(13,5,4,1))
+            << (SignalList() << Remove(23,6,0,0) << Insert(5,4,0,1) << Insert(16,1,0,0) << Insert(17,1,0,5));
     QTest::newRow("m(23-12,6),m(14-5,4)")
-            << (SignalList() << Move(23,12,6) << Move(14,5,4))
-            << (SignalList() << Remove(23,2,0) << Remove(23,4,1) << Insert(5,4,1) << Insert(16,2,0));
+            << (SignalList() << Move(23,12,6,0) << Move(14,5,4,1))
+            << (SignalList() << Remove(23,6,0,0) << Insert(5,4,0,2) << Insert(16,2,0,0));
     QTest::newRow("m(23-12,6),m(12-5,4)")
-            << (SignalList() << Move(23,12,6) << Move(12,5,4))
-            << (SignalList() << Remove(23,4,0) << Remove(23,2,1) << Insert(5,4,0) << Insert(16,2,1));
+            << (SignalList() << Move(23,12,6,0) << Move(12,5,4,1))
+            << (SignalList() << Remove(23,6,0,0) << Insert(5,4,0,0) << Insert(16,2,0,4));
     QTest::newRow("m(23-12,6),m(11-5,8)")
-            << (SignalList() << Move(23,12,6) << Move(11,5,8))
-            << (SignalList() << Remove(11,1,0) << Remove(11,1,1) << Remove(21,6,2) << Insert(5,1,0) << Insert(6,6,2) << Insert(12,1,1));
+            << (SignalList() << Move(23,12,6,0) << Move(11,5,8,1))
+            << (SignalList() << Remove(11,1,1,0) << Remove(11,1,1,7) << Remove(21,6,0,0) << Insert(5,1,1,0) << Insert(6,6,0,0) << Insert(12,1,1,7));
     QTest::newRow("m(23-12,6),m(8-5,4)")
-            << (SignalList() << Move(23,12,6) << Move(8,5,4))
-            << (SignalList() << Remove(8,4,0) << Remove(19,6,1) << Insert(5,4,0) << Insert(12,6,1));
+            << (SignalList() << Move(23,12,6,0) << Move(8,5,4,1))
+            << (SignalList() << Remove(8,4,1,0) << Remove(19,6,0,0) << Insert(5,4,1,0) << Insert(12,6,0,0));
     QTest::newRow("m(23-12,6),m(2-5,4)")
-            << (SignalList() << Move(23,12,6) << Move(2,5,4))
-            << (SignalList() << Remove(2,4,0) << Remove(19,6,1) << Insert(5,4,0) << Insert(12,6,1));
+            << (SignalList() << Move(23,12,6,0) << Move(2,5,4,1))
+            << (SignalList() << Remove(2,4,1,0) << Remove(19,6,0,0) << Insert(5,4,1,0) << Insert(12,6,0,0));
     QTest::newRow("m(23-12,6),m(18-5,4)")
-            << (SignalList() << Move(23,12,6) << Move(18,5,4))
-            << (SignalList() << Remove(12,4,0) << Remove(19,6,1) << Insert(5,4,0) << Insert(16,6,1));
+            << (SignalList() << Move(23,12,6,0) << Move(18,5,4,1))
+            << (SignalList() << Remove(12,4,1,0) << Remove(19,6,0,0) << Insert(5,4,1,0) << Insert(16,6,0,0));
     QTest::newRow("m(23-12,6),m(20-5,4)")
-            << (SignalList() << Move(23,12,6) << Move(20,5,4))
-            << (SignalList() << Remove(14,4,0) << Remove(19,6,1) << Insert(5,4,0) << Insert(16,6,1));
+            << (SignalList() << Move(23,12,6,0) << Move(20,5,4,1))
+            << (SignalList() << Remove(14,4,1,0) << Remove(19,6,0,0) << Insert(5,4,1,0) << Insert(16,6,0,0));
 
     QTest::newRow("m(23-12,6),m(5-13,11)")
-            << (SignalList() << Move(23,12,6) << Move(5,13,11))
-            << (SignalList() << Remove(5,7,0) << Remove(16,4,1) << Remove(16,2,2) << Insert(5,2,2) << Insert(13,7,0) << Insert(20,4,1));
+            << (SignalList() << Move(23,12,6,0) << Move(5,13,11,1))
+            << (SignalList() << Remove(5,7,1,0) << Remove(16,6,0,0) << Insert(5,2,0,4) << Insert(13,7,1,0) << Insert(20,4,0,0));
 
     QTest::newRow("m(23-12,6),m(12-23,6)")
-            << (SignalList() << Move(23,12,6) << Move(12,23,6))
-            << (SignalList() << Remove(23,6,0) << Insert(23,6,0));  // ### These cancel out.
+            << (SignalList() << Move(23,12,6,0) << Move(12,23,6,1))
+            << (SignalList() << Remove(23,6,0,0) << Insert(23,6,0,0));  // ### These cancel out.
     QTest::newRow("m(23-12,6),m(10-23,4)")
-            << (SignalList() << Move(23,12,6) << Move(10,23,4))
-            << (SignalList() << Remove(10,2 ,0) << Remove(21,2,1) << Remove(21,4,2) << Insert(10,4,2) << Insert(23,2,0) << Insert(25,2,1));
+            << (SignalList() << Move(23,12,6,0) << Move(10,23,4,1))
+            << (SignalList() << Remove(10,2,1,0) << Remove(21,6,0,0) << Insert(10,4,0,2) << Insert(23,2,1,0) << Insert(25,2,0,0));
     QTest::newRow("m(23-12,6),m(16-23.4)")
-            << (SignalList() << Move(23,12,6) << Move(16,23,4))
-            << (SignalList() << Remove(12,2,0) << Remove(21,4,1) << Remove(21,2,2) << Insert(12,4,1) << Insert(23,2,2) << Insert(25,2,0));
+            << (SignalList() << Move(23,12,6,0) << Move(16,23,4,1))
+            << (SignalList() << Remove(12,2,1,2) << Remove(21,6,0,0) << Insert(12,4,0,0) << Insert(23,2,0,4) << Insert(25,2,1,2));
     QTest::newRow("m(23-12,6),m(13-23,4)")
-            << (SignalList() << Move(23,12,6) << Move(13,23,4))
-            << (SignalList() << Remove(23,1,0) << Remove(23,4,1) << Remove(23,1,2) << Insert(12,1,0) << Insert(13,1,2) << Insert(23,4,1));
+            << (SignalList() << Move(23,12,6,0) << Move(13,23,4,1))
+            << (SignalList() << Remove(23,6,0,0) << Insert(12,1,0,0) << Insert(13,1,0,5) << Insert(23,4,0,1));
     QTest::newRow("m(23-12,6),m(14-23,)")
-            << (SignalList() << Move(23,12,6) << Move(14,23,4))
-            << (SignalList() << Remove(23,2,0) << Remove(23,4,1) << Insert(12,2,0) << Insert(23,4,1));
+            << (SignalList() << Move(23,12,6,0) << Move(14,23,4,1))
+            << (SignalList() << Remove(23,6,0,0) << Insert(12,2,0,0) << Insert(23,4,0,2));
     QTest::newRow("m(23-12,6),m(12-23,4)")
-            << (SignalList() << Move(23,12,6) << Move(12,23,4))
-            << (SignalList() << Remove(23,4,0) << Remove(23,2,1) << Insert(12,2,1) << Insert(23,4,0));
+            << (SignalList() << Move(23,12,6,0) << Move(12,23,4,1))
+            << (SignalList() << Remove(23,6,0,0) << Insert(12,2,0,4) << Insert(23,4,0,0));
     QTest::newRow("m(23-12,6),m(11-23,8)")
-            << (SignalList() << Move(23,12,6) << Move(11,23,8))
-            << (SignalList() << Remove(11,1,0) << Remove(11,1,1) << Remove(21,6,2) << Insert(23,1,0) << Insert(24,6,2) << Insert(30,1,1));
+            << (SignalList() << Move(23,12,6,0) << Move(11,23,8,1))
+            << (SignalList() << Remove(11,1,1,0) << Remove(11,1,1,7) << Remove(21,6,0,0) << Insert(23,1,1,0) << Insert(24,6,0,0) << Insert(30,1,1,7));
     QTest::newRow("m(23-12,6),m(8-23,4)")
-            << (SignalList() << Move(23,12,6) << Move(8,23,4))
-            << (SignalList() << Remove(8,4,0) << Remove(19,6,1) << Insert(8,6,1) << Insert(23,4,0));
+            << (SignalList() << Move(23,12,6,0) << Move(8,23,4,1))
+            << (SignalList() << Remove(8,4,1,0) << Remove(19,6,0,0) << Insert(8,6,0,0) << Insert(23,4,1,0));
     QTest::newRow("m(23-12,6),m(2-23,4)")
-            << (SignalList() << Move(23,12,6) << Move(2,23,4))
-            << (SignalList() << Remove(2,4,0) << Remove(19,6,1) << Insert(8,6,1) << Insert(23,4,0));
+            << (SignalList() << Move(23,12,6,0) << Move(2,23,4,1))
+            << (SignalList() << Remove(2,4,1,0) << Remove(19,6,0,0) << Insert(8,6,0,0) << Insert(23,4,1,0));
     QTest::newRow("m(23-12,6),m(18-23,4)")
-            << (SignalList() << Move(23,12,6) << Move(18,23,4))
-            << (SignalList() << Remove(12,4,0) << Remove(19,6,1) << Insert(12,6,1) << Insert(23,4,0));
+            << (SignalList() << Move(23,12,6,0) << Move(18,23,4,1))
+            << (SignalList() << Remove(12,4,1,0) << Remove(19,6,0,0) << Insert(12,6,0,0) << Insert(23,4,1,0));
     QTest::newRow("m(23-12,6),m(20-23,4)")
-            << (SignalList() << Move(23,12,6) << Move(20,23,4))
-            << (SignalList() << Remove(14,4,1) << Remove(19,6,0) << Insert(12,6,0) << Insert(23,4,1));
+            << (SignalList() << Move(23,12,6,0) << Move(20,23,4,1))
+            << (SignalList() << Remove(14,4,1,0) << Remove(19,6,0,0) << Insert(12,6,0,0) << Insert(23,4,1,0));
 
     QTest::newRow("m(23-12,6),m(11-23,10)")
-            << (SignalList() << Move(23,12,6) << Move(11,23,10))
-            << (SignalList() << Remove(11,1,3) << Remove(11,3,1) << Remove(19,6,2) << Insert(23,1,3) << Insert(24,6,2) << Insert(30,3,1));
+            << (SignalList() << Move(23,12,6,0) << Move(11,23,10,1))
+            << (SignalList() << Remove(11,1,1,0) << Remove(11,3,1,7) << Remove(19,6,0,0) << Insert(23,1,1,0) << Insert(24,6,0,0) << Insert(30,3,1,7));
 
     QTest::newRow("m(3-9,12),m(13-5,12)")
-            << (SignalList() << Move(3,9,12) << Move(13,15,5))
-            << (SignalList() << Remove(3,4,2) << Remove(3,5,1) << Remove(3,2,0) << Remove(3,1,3) << Insert(9,4,2) << Insert(13,2,0) << Insert(15,5,1) << Insert(20,1,3));
+            << (SignalList() << Move(3,9,12,0) << Move(13,15,5,1))
+            << (SignalList() << Remove(3,12,0,0) << Insert(9,4,0,0) << Insert(13,2,0,9) << Insert(15,5,0,4) << Insert(20,1,0,11));
     QTest::newRow("m(3-9,12),m(13-15,20)")
-            << (SignalList() << Move(3,9,12) << Move(13,15,20))
-            << (SignalList() << Remove(3,4,0) << Remove(3,8,1) << Remove(9,12,2) << Insert(9,4,0) << Insert(15,8,1) << Insert(23,12,2));
+            << (SignalList() << Move(3,9,12,0) << Move(13,15,20,1))
+            << (SignalList() << Remove(3,12,0,0) << Remove(9,12,1,8) << Insert(9,4,0,0) << Insert(15,8,0,4) << Insert(23,12,1,8));
     QTest::newRow("m(3-9,12),m(13-15,2)")
-            << (SignalList() << Move(3,9,12) << Move(13,15,2))
-            << (SignalList() << Remove(3,4,2) << Remove(3,2,1) << Remove(3,2,0) << Remove(3,4,3) << Insert(9,4,2) << Insert(13,2,0) << Insert(15,2,1) << Insert(17,4,3));
+            << (SignalList() << Move(3,9,12,0) << Move(13,15,2,1))
+            << (SignalList() << Remove(3,12,0,0) << Insert(9,4,0,0) << Insert(13,2,0,6) << Insert(15,2,0,4) << Insert(17,4,0,8));
     QTest::newRow("m(3-9,12),m(12-5,6)")
-            << (SignalList() << Move(3,9,12) << Move(12,5,6))
-            << (SignalList() << Remove(3,3,0) << Remove(3,6,1) << Remove(3,3,2) << Insert(5,6,1) << Insert(15,3,0) << Insert(18,3,2));
+            << (SignalList() << Move(3,9,12,0) << Move(12,5,6,1))
+            << (SignalList() << Remove(3,12,0,0) << Insert(5,6,0,3) << Insert(15,3,0,0) << Insert(18,3,0,9));
     QTest::newRow("m(3-9,12),m(10-14,5)")
-            << (SignalList() << Move(3,9,12) << Move(10,14,5))
-            << (SignalList() << Remove(3,1,2) << Remove(3,5,1) << Remove(3,4,0) << Remove(3,2,3) << Insert(9,1,2) << Insert(10,4,0) << Insert(14,5,1) << Insert(19,2,3));
+            << (SignalList() << Move(3,9,12,0) << Move(10,14,5,1))
+            << (SignalList() << Remove(3,12,0,0) << Insert(9,1,0,0) << Insert(10,4,0,6) << Insert(14,5,0,1) << Insert(19,2,0,10));
     QTest::newRow("m(3-9,12),m(16-20,5)")
-            << (SignalList() << Move(3,9,12) << Move(16,20,5))
-            << (SignalList() << Remove(3,7,0) << Remove(3,5,1) << Insert(9,7,0) << Insert(20,5,1));
+            << (SignalList() << Move(3,9,12,0) << Move(16,20,5,1))
+            << (SignalList() << Remove(3,12,0,0) << Insert(9,7,0,0) << Insert(20,5,0,7));
     QTest::newRow("m(3-9,12),m(13-17,5)")
-            << (SignalList() << Move(3,9,12) << Move(13,17,5))
-            << (SignalList() << Remove(3,4,0) << Remove(3,5,1) << Remove(3,3,2) << Insert(9,4,0) << Insert(13,3,2) << Insert(17,5,1));
+            << (SignalList() << Move(3,9,12,0) << Move(13,17,5,1))
+            << (SignalList() << Remove(3,12,0,0) << Insert(9,4,0,0) << Insert(13,3,0,9) << Insert(17,5,0,4));
     QTest::newRow("m(3-9,12),m(14-18,5)")
-            << (SignalList() << Move(3,9,12) << Move(14,18,5))
-            << (SignalList() << Remove(3,5,0) << Remove(3,5,1) << Remove(3,2,2) << Insert(9,5,0) << Insert(14,2,2) << Insert(18,5,1));
+            << (SignalList() << Move(3,9,12,0) << Move(14,18,5,1))
+            << (SignalList() << Remove(3,12,0,0) << Insert(9,5,0,0) << Insert(14,2,0,10) << Insert(18,5,0,5));
     QTest::newRow("m(3-9,12),m(12-16,5)")
-            << (SignalList() << Move(3,9,12) << Move(12,16,5))
-            << (SignalList() << Remove(3,3,2) << Remove(3,5,1) << Remove(3,4,0) << Insert(9,3,2) << Insert(12,4,0) << Insert(16,5,1));
+            << (SignalList() << Move(3,9,12,0) << Move(12,16,5,1))
+            << (SignalList() << Remove(3,12,0,0) << Insert(9,3,0,0) << Insert(12,4,0,8) << Insert(16,5,0,3));
     QTest::newRow("m(3-9,12),m(11-19,5)")
-            << (SignalList() << Move(3,9,12) << Move(11,19,5))
-            << (SignalList() << Remove(3,2,0) << Remove(3,5,1) << Remove(3,5,2) << Insert(9,2,0) << Insert(11,5,2) << Insert(19,5,1));
+            << (SignalList() << Move(3,9,12,0) << Move(11,19,5,1))
+            << (SignalList() << Remove(3,12,0,0) << Insert(9,2,0,0) << Insert(11,5,0,7) << Insert(19,5,0,2));
     QTest::newRow("m(3-9,12),m(8-12,5)")
-            << (SignalList() << Move(3,9,12) << Move(8,12,5))
-            << (SignalList() << Remove(3,4,1) << Remove(3,4,0) << Remove(3,4,4) << Remove(8,1,2) << Insert(8,4,0) << Insert(12,1,2) << Insert(13,4,1) << Insert(17,4,4));
+            << (SignalList() << Move(3,9,12,0) << Move(8,12,5,1))
+            << (SignalList() << Remove(3,12,0,0) << Remove(8,1,1,0) << Insert(8,4,0,4) << Insert(12,1,1,0) << Insert(13,4,0,0) << Insert(17,4,0,8));
     QTest::newRow("m(3-9,12),m(2-6,5)")
-            << (SignalList() << Move(3,9,12) << Move(2,6,5))
-            << (SignalList() <<  Remove(2,1,2) << Remove(2,2,0) << Remove(2,10,3) << Remove(2,4,1) << Insert(4,2,0) << Insert(6,1,2) << Insert(7,4,1) << Insert(11,10,3));
+            << (SignalList() << Move(3,9,12,0) << Move(2,6,5,1))
+            << (SignalList() <<  Remove(2,1,1,0) << Remove(2,12,0,0) << Remove(2,4,1,1) << Insert(4,2,0,0) << Insert(6,5,1,0) << Insert(11,10,0,2));
     QTest::newRow("m(3-9,12),m(18-22,5)")
-            << (SignalList() << Move(3,9,12) << Move(18,22,5))
-            << (SignalList() << Remove(3,9,0) << Remove(3,3,1) << Remove(9,2,2) << Insert(9,9,0) << Insert(22,3,1) << Insert(25,2,2));
+            << (SignalList() << Move(3,9,12,0) << Move(18,22,5,1))
+            << (SignalList() << Remove(3,12,0,0) << Remove(9,2,1,3) << Insert(9,9,0,0) << Insert(22,3,0,9) << Insert(25,2,1,3));
     QTest::newRow("m(3-9,12),m(20-24,5)")
-            << (SignalList() << Move(3,9,12) << Move(20,24,5))
-            << (SignalList() << Remove(3,11,0) << Remove(3,1,1) << Remove(9,4,2) << Insert(9,11,0) << Insert(24,1,1) << Insert(25,4,2));
+            << (SignalList() << Move(3,9,12,0) << Move(20,24,5,1))
+            << (SignalList() << Remove(3,12,0,0) << Remove(9,4,1,1) << Insert(9,11,0,0) << Insert(24,1,0,11) << Insert(25,4,1,1));
 
     QTest::newRow("m(3-9,12),m(5-11,8)")
-            << (SignalList() << Move(3,9,12) << Move(5,11,8))
-            << (SignalList() << Remove(3,4,1) << Remove(3,6,0) << Remove(3,2,3) << Remove(5,4,2) << Insert(5,6,0) << Insert(11,4,2) << Insert(15,2,3) << Insert(15,4,1));
+            << (SignalList() << Move(3,9,12,0) << Move(5,11,8,1))
+            << (SignalList() << Remove(3,12,0,0) << Remove(5,4,1,0) << Insert(5,6,0,4) << Insert(11,4,1,0) << Insert(15,4,0,0) << Insert(19,2,0,10));
 
     QTest::newRow("m(3-9,12),m(12-23,6)")
-            << (SignalList() << Move(3,9,12) << Move(12,23,6))
-            << (SignalList() << Remove(3,3,2) << Remove(3,6,1) << Remove(3,3,0) << Insert(9,3,2) << Insert(12,3,0) << Insert(23,6,1));
+            << (SignalList() << Move(3,9,12,0) << Move(12,23,6,1))
+            << (SignalList() << Remove(3,12,0,0) << Insert(9,3,0,0) << Insert(12,3,0,9) << Insert(23,6,0,3));
     QTest::newRow("m(3-9,12),m(10-23,4)")
-            << (SignalList() << Move(3,9,12) << Move(10,23,4))
-            << (SignalList() << Remove(3,1,2) << Remove(3,4,1) << Remove(3,7,0) << Insert(9,1,2) << Insert(10,7,0) << Insert(23,4,1));
+            << (SignalList() << Move(3,9,12,0) << Move(10,23,4,1))
+            << (SignalList() << Remove(3,12,0,0) << Insert(9,1,0,0) << Insert(10,7,0,5) << Insert(23,4,0,1));
     QTest::newRow("m(3-9,12),m(16-23,4)")
-            << (SignalList() << Move(3,9,12) << Move(16,23,4))
-            << (SignalList() << Remove(3,7,2) << Remove(3,4,1) << Remove(3,1,0) << Insert(9,7,2) << Insert(16,1,0) << Insert(23,4,1));
+            << (SignalList() << Move(3,9,12,0) << Move(16,23,4,1))
+            << (SignalList() << Remove(3,12,0,0) << Insert(9,7,0,0) << Insert(16,1,0,11) << Insert(23,4,0,7));
     QTest::newRow("m(3-9,12),m(13-23,4)")
-            << (SignalList() << Move(3,9,12) << Move(13,23,4))
-            << (SignalList() << Remove(3,4,2) << Remove(3,4,1) << Remove(3,4,0) << Insert(9,4,2) << Insert(13,4,0) << Insert(23,4,1));
+            << (SignalList() << Move(3,9,12,0) << Move(13,23,4,1))
+            << (SignalList() << Remove(3,12,0,0) << Insert(9,4,0,0) << Insert(13,4,0,8) << Insert(23,4,0,4));
     QTest::newRow("m(3-9,12),m(14-23,4)")
-            << (SignalList() << Move(3,9,12) << Move(14,23,4))
-            << (SignalList() << Remove(3,5,2) << Remove(3,4,1) << Remove(3,3,0) << Insert(9,5,2) << Insert(14,3,0) << Insert(23,4,1));
+            << (SignalList() << Move(3,9,12,0) << Move(14,23,4,1))
+            << (SignalList() << Remove(3,12,0,0) << Insert(9,5,0,0) << Insert(14,3,0,9) << Insert(23,4,0,5));
     QTest::newRow("m(3-9,12),m(12-23,4)")
-            << (SignalList() << Move(3,9,12) << Move(12,23,4))
-            << (SignalList() << Remove(3,3,2) << Remove(3,4,1) << Remove(3,5,0) << Insert(9,3,2) << Insert(12,5,0) << Insert(23,4,1));
+            << (SignalList() << Move(3,9,12,0) << Move(12,23,4,1))
+            << (SignalList() << Remove(3,12,0,0) << Insert(9,3,0,0) << Insert(12,5,0,7) << Insert(23,4,0,3));
     QTest::newRow("m(3-9,12),m(11-23,8)")
-            << (SignalList() << Move(3,9,12) << Move(11,23,8))
-            << (SignalList() << Remove(3,2,2) << Remove(3,8,1) << Remove(3,2,0) << Insert(9,2,2) << Insert(11,2,0) << Insert(23,8,1));
+            << (SignalList() << Move(3,9,12,0) << Move(11,23,8,1))
+            << (SignalList() << Remove(3,12,0,0) << Insert(9,2,0,0) << Insert(11,2,0,10) << Insert(23,8,0,2));
     QTest::newRow("m(3-9,12),m(8-23,4)")
-            << (SignalList() << Move(3,9,12) << Move(8,23,4))
-            << (SignalList() << Remove(3,3,1) << Remove(3,9,0) << Remove(8,1,2) << Insert(8,9,0) << Insert(23,1,2) << Insert(24,3,1));
+            << (SignalList() << Move(3,9,12,0) << Move(8,23,4,1))
+            << (SignalList() << Remove(3,12,0,0) << Remove(8,1,1,0) << Insert(8,9,0,3) << Insert(23,1,1,0) << Insert(24,3,0,0));
     QTest::newRow("m(3-9,12),m(2-23,4)")
-            << (SignalList() << Move(3,9,12) << Move(2,23,4))
-            << (SignalList() << Remove(2,1,2) << Remove(2,12,0) << Remove(2,3,1) << Insert(5,12,0) << Insert(23,1,2) << Insert(24,3,1));
+            << (SignalList() << Move(3,9,12,0) << Move(2,23,4,1))
+            << (SignalList() << Remove(2,1,1,0) << Remove(2,12,0,0) << Remove(2,3,1,1) << Insert(5,12,0,0) << Insert(23,4,1,0));
     QTest::newRow("m(3-9,12),m(18-23,4)")
-            << (SignalList() << Move(3,9,12) << Move(18,23,4))
-            << (SignalList() << Remove(3,9,3) << Remove(3,3,2) << Remove(9,1,1) << Insert(9,9,3) << Insert(23,3,2) << Insert(26,1,1));
+            << (SignalList() << Move(3,9,12,0) << Move(18,23,4,1))
+            << (SignalList() << Remove(3,12,0,0) << Remove(9,1,1,3) << Insert(9,9,0,0) << Insert(23,3,0,9) << Insert(26,1,1,3));
     QTest::newRow("m(3-9,12),m(20-23,4)")
-            << (SignalList() << Move(3,9,12) << Move(20,23,4))
-            << (SignalList() << Remove(3,11,3) << Remove(3,1,2) << Remove(9,3,1) << Insert(9,11,3) << Insert(23,1,2) << Insert(24,3,1));
+            << (SignalList() << Move(3,9,12,0) << Move(20,23,4,1))
+            << (SignalList() << Remove(3,12,0,0) << Remove(9,3,1,1) << Insert(9,11,0,0) << Insert(23,1,0,11) << Insert(24,3,1,1));
 
     QTest::newRow("m(3-9,12),m(11-23,10)")
-            << (SignalList() << Move(3,9,12) << Move(11,23,10))
-            << (SignalList() << Remove(3,2,2) << Remove(3,10,1) << Insert(9,2,2) << Insert(23,10,1));
+            << (SignalList() << Move(3,9,12,0) << Move(11,23,10,1))
+            << (SignalList() << Remove(3,12,0,0) << Insert(9,2,0,0) << Insert(23,10,0,2));
 
     // Change
     QTest::newRow("c(4,5)")
@@ -440,117 +529,117 @@ void tst_qquickchangeset::sequence_data()
             << (SignalList() << Insert(12,6) << Remove(20,4))
             << (SignalList() << Remove(14,4) << Insert(12,6));
 
+    // Insert,then change
+    QTest::newRow("i(12,6),c(12,6)")
+            << (SignalList() << Insert(12,6) << Change(12,6))
+            << (SignalList() << Insert(12,6));
+    QTest::newRow("i(12,6),c(10,6)")
+            << (SignalList() << Insert(12,6) << Change(10,6))
+            << (SignalList() << Insert(12,6) << Change(10,2));
+    QTest::newRow("i(12,6),c(16,4)")
+            << (SignalList() << Insert(12,6) << Change(16,4))
+            << (SignalList() << Insert(12,6) << Change(18,2));
+    QTest::newRow("i(12,6),c(13,4)")
+            << (SignalList() << Insert(12,6) << Change(13,4))
+            << (SignalList() << Insert(12,6));
+    QTest::newRow("i(12,6),c(14,4)")
+            << (SignalList() << Insert(12,6) << Change(14,4))
+            << (SignalList() << Insert(12,6));
+    QTest::newRow("i(12,6),c(12,4)")
+            << (SignalList() << Insert(12,6) << Change(12,4))
+            << (SignalList() << Insert(12,6));
+    QTest::newRow("i(12,6),c(11,8)")
+            << (SignalList() << Insert(12,6) << Change(11,8))
+            << (SignalList() << Insert(12,6) << Change(11,1) << Change(18,1));
+    QTest::newRow("i(12,6),c(8,4)")
+            << (SignalList() << Insert(12,6) << Change(8,4))
+            << (SignalList() << Insert(12,6) << Change(8,4));
+    QTest::newRow("i(12,6),c(2,4)")
+            << (SignalList() << Insert(12,6) << Change(2,4))
+            << (SignalList() << Insert(12,6) << Change(2,4));
+    QTest::newRow("i(12,6),c(18,4)")
+            << (SignalList() << Insert(12,6) << Change(18,4))
+            << (SignalList() << Insert(12,6) << Change(18,4));
+    QTest::newRow("i(12,6),c(20,4)")
+            << (SignalList() << Insert(12,6) << Change(20,4))
+            << (SignalList() << Insert(12,6) << Change(20,4));
+
     // Insert,then move
     QTest::newRow("i(12,6),m(12-5,6)")
-            << (SignalList() << Insert(12,6) << Move(12,5,6))
+            << (SignalList() << Insert(12,6) << Move(12,5,6,0))
             << (SignalList() << Insert(5,6));
     QTest::newRow("i(12,6),m(10-5,4)")
-            << (SignalList() << Insert(12,6) << Move(10,5,4))
-            << (SignalList() << Remove(10,2,0) << Insert(5,2,0) << Insert(7,2) << Insert(14,4));
+            << (SignalList() << Insert(12,6) << Move(10,5,4,0))
+            << (SignalList() << Remove(10,2,0,0) << Insert(5,2,0,0) << Insert(7,2) << Insert(14,4));
     QTest::newRow("i(12,6),m(16-5,4)")
-            << (SignalList() << Insert(12,6) << Move(16,5,4))
-            << (SignalList() << Remove(12,2,0) << Insert(5,2) << Insert(7,2,0) << Insert(16,4));
+            << (SignalList() << Insert(12,6) << Move(16,5,4,0))
+            << (SignalList() << Remove(12,2,0,2) << Insert(5,2) << Insert(7,2,0,2) << Insert(16,4));
     QTest::newRow("i(12,6),m(13-5,4)")
-            << (SignalList() << Insert(12,6) << Move(13,5,4))
+            << (SignalList() << Insert(12,6) << Move(13,5,4,0))
             << (SignalList() << Insert(5,4) << Insert(16,2));
     QTest::newRow("i(12,6),m(14-5,4)")
-            << (SignalList() << Insert(12,6) << Move(14,5,4))
+            << (SignalList() << Insert(12,6) << Move(14,5,4,0))
             << (SignalList() << Insert(5,4) << Insert(16,2));
     QTest::newRow("i(12,6),m(12-5,4)")
-            << (SignalList() << Insert(12,6) << Move(12,5,4))
+            << (SignalList() << Insert(12,6) << Move(12,5,4,0))
             << (SignalList() << Insert(5,4) << Insert(16,2));
     QTest::newRow("i(12,6),m(11-5,8)")
-            << (SignalList() << Insert(12,6) << Move(11,5,8))
-            << (SignalList() << Remove(11,1,0) << Remove(11,1,1) << Insert(5,1,0) << Insert(6,6) << Insert(12,1,1));
+            << (SignalList() << Insert(12,6) << Move(11,5,8,0))
+            << (SignalList() << Remove(11,1,0,0) << Remove(11,1,0,7) << Insert(5,1,0,0) << Insert(6,6) << Insert(12,1,0,7));
     QTest::newRow("i(12,6),m(8-5,4)")
-            << (SignalList() << Insert(12,6) << Move(8,5,4))
-            << (SignalList() << Remove(8,4,0) << Insert(5,4,0) << Insert(12,6));
+            << (SignalList() << Insert(12,6) << Move(8,5,4,0))
+            << (SignalList() << Remove(8,4,0,0) << Insert(5,4,0,0) << Insert(12,6));
     QTest::newRow("i(12,6),m(2-5,4)")
-            << (SignalList() << Insert(12,6) << Move(2,5,4))
-            << (SignalList() << Remove(2,4,0) << Insert(5,4,0) << Insert(12,6));
+            << (SignalList() << Insert(12,6) << Move(2,5,4,0))
+            << (SignalList() << Remove(2,4,0,0) << Insert(5,4,0,0) << Insert(12,6));
     QTest::newRow("i(12,6),m(18-5,4)")
-            << (SignalList() << Insert(12,6) << Move(18,5,4))
-            << (SignalList() << Remove(12,4,0) << Insert(5,4,0) << Insert(16,6));
+            << (SignalList() << Insert(12,6) << Move(18,5,4,0))
+            << (SignalList() << Remove(12,4,0,0) << Insert(5,4,0,0) << Insert(16,6));
     QTest::newRow("i(12,6),m(20-5,4)")
-            << (SignalList() << Insert(12,6) << Move(20,5,4))
-            << (SignalList() << Remove(14,4,0) << Insert(5,4,0) << Insert(16,6));
+            << (SignalList() << Insert(12,6) << Move(20,5,4,0))
+            << (SignalList() << Remove(14,4,0,0) << Insert(5,4,0,0) << Insert(16,6));
 
     QTest::newRow("i(12,6),m(5-13,11)")
-            << (SignalList() << Insert(12,6) << Move(5,11,8))
-            << (SignalList() << Remove(5,7,0) << Insert(5,5) << Insert(11,7,0) << Insert(18,1));
+            << (SignalList() << Insert(12,6) << Move(5,11,8,0))
+            << (SignalList() << Remove(5,7,0,0) << Insert(5,5) << Insert(11,7,0,0) << Insert(18,1));
 
     QTest::newRow("i(12,6),m(12-23,6)")
-            << (SignalList() << Insert(12,6) << Move(12,23,6))
+            << (SignalList() << Insert(12,6) << Move(12,23,6,0))
             << (SignalList() << Insert(23,6));
     QTest::newRow("i(12,6),m(10-23,4)")
-            << (SignalList() << Insert(12,6) << Move(10,23,4))
-            << (SignalList() << Remove(10,2,0) << Insert(10,4) << Insert(23,2,0) << Insert(25,2));
+            << (SignalList() << Insert(12,6) << Move(10,23,4,0))
+            << (SignalList() << Remove(10,2,0,0) << Insert(10,4) << Insert(23,2,0,0) << Insert(25,2));
     QTest::newRow("i(12,6),m(16-23,4)")
-            << (SignalList() << Insert(12,6) << Move(16,23,4))
-            << (SignalList() << Remove(12,2,0) << Insert(12,4) << Insert(23,2) << Insert(25,2,0));
+            << (SignalList() << Insert(12,6) << Move(16,23,4,0))
+            << (SignalList() << Remove(12,2,0,2) << Insert(12,4) << Insert(23,2) << Insert(25,2,0,2));
     QTest::newRow("i(12,6),m(13-23,4)")
-            << (SignalList() << Insert(12,6) << Move(13,23,4))
+            << (SignalList() << Insert(12,6) << Move(13,23,4,0))
             << (SignalList() << Insert(12,2) << Insert(23,4));
     QTest::newRow("i(12,6),m(14-23,4)")
-            << (SignalList() << Insert(12,6) << Move(14,23,4))
+            << (SignalList() << Insert(12,6) << Move(14,23,4,0))
             << (SignalList() << Insert(12,2) << Insert(23,4));
     QTest::newRow("i(12,6),m(12-23,4)")
-            << (SignalList() << Insert(12,6) << Move(12,23,4))
+            << (SignalList() << Insert(12,6) << Move(12,23,4,0))
             << (SignalList() << Insert(12,2) << Insert(23,4));
     QTest::newRow("i(12,6),m(11-23,8)")
-            << (SignalList() << Insert(12,6) << Move(11,23,8))
-            << (SignalList() << Remove(11,1,0) << Remove(11,1,1) << Insert(23,1,0)<< Insert(24,6) << Insert(30,1,1));
+            << (SignalList() << Insert(12,6) << Move(11,23,8,0))
+            << (SignalList() << Remove(11,1,0,0) << Remove(11,1,0,7) << Insert(23,1,0,0)<< Insert(24,6) << Insert(30,1,0,7));
     QTest::newRow("i(12,6),m(8-23,4)")
-            << (SignalList() << Insert(12,6) << Move(8,23,4))
-            << (SignalList() << Remove(8,4,0) << Insert(8,6) << Insert(23,4,0));
+            << (SignalList() << Insert(12,6) << Move(8,23,4,0))
+            << (SignalList() << Remove(8,4,0,0) << Insert(8,6) << Insert(23,4,0,0));
     QTest::newRow("i(12,6),m(2-23,4)")
-            << (SignalList() << Insert(12,6) << Move(2,23,4))
-            << (SignalList() << Remove(2,4,0) << Insert(8,6) << Insert(23,4,0));
+            << (SignalList() << Insert(12,6) << Move(2,23,4,0))
+            << (SignalList() << Remove(2,4,0,0) << Insert(8,6) << Insert(23,4,0,0));
     QTest::newRow("i(12,6),m(18-23,4)")
-            << (SignalList() << Insert(12,6) << Move(18,23,4))
-            << (SignalList() << Remove(12,4,0) << Insert(12,6) << Insert(23,4,0));
+            << (SignalList() << Insert(12,6) << Move(18,23,4,0))
+            << (SignalList() << Remove(12,4,0,0) << Insert(12,6) << Insert(23,4,0,0));
     QTest::newRow("i(12,6),m(20-23,4)")
-            << (SignalList() << Insert(12,6) << Move(20,23,4))
-            << (SignalList() << Remove(14,4,0) << Insert(12,6) << Insert(23,4,0));
+            << (SignalList() << Insert(12,6) << Move(20,23,4,0))
+            << (SignalList() << Remove(14,4,0,0) << Insert(12,6) << Insert(23,4,0,0));
 
     QTest::newRow("i(12,6),m(11-23,10)")
-            << (SignalList() << Insert(12,6) << Move(11,23,10))
-            << (SignalList() << Remove(11,1,0) << Remove(11,3,1) << Insert(23,1,0) << Insert(24,6) << Insert(30,3,1));
-
-    // Insert,then change
-    QTest::newRow("i(12,6),c(12,6)")
-            << (SignalList() << Insert(12,6) << Change(12,6))
-            << (SignalList() << Insert(12,6));
-    QTest::newRow("i(12,6),c(10,6)")
-            << (SignalList() << Insert(12,6) << Change(10,6))
-            << (SignalList() << Insert(12,6) << Change(10,2));
-    QTest::newRow("i(12,6),c(16,4)")
-            << (SignalList() << Insert(12,6) << Change(16,4))
-            << (SignalList() << Insert(12,6) << Change(18,2));
-    QTest::newRow("i(12,6),c(13,4)")
-            << (SignalList() << Insert(12,6) << Change(13,4))
-            << (SignalList() << Insert(12,6));
-    QTest::newRow("i(12,6),c(14,4)")
-            << (SignalList() << Insert(12,6) << Change(14,4))
-            << (SignalList() << Insert(12,6));
-    QTest::newRow("i(12,6),c(12,4)")
-            << (SignalList() << Insert(12,6) << Change(12,4))
-            << (SignalList() << Insert(12,6));
-    QTest::newRow("i(12,6),c(11,8)")
-            << (SignalList() << Insert(12,6) << Change(11,8))
-            << (SignalList() << Insert(12,6) << Change(11,1) << Change(18,1));
-    QTest::newRow("i(12,6),c(8,4)")
-            << (SignalList() << Insert(12,6) << Change(8,4))
-            << (SignalList() << Insert(12,6) << Change(8,4));
-    QTest::newRow("i(12,6),c(2,4)")
-            << (SignalList() << Insert(12,6) << Change(2,4))
-            << (SignalList() << Insert(12,6) << Change(2,4));
-    QTest::newRow("i(12,6),c(18,4)")
-            << (SignalList() << Insert(12,6) << Change(18,4))
-            << (SignalList() << Insert(12,6) << Change(18,4));
-    QTest::newRow("i(12,6),c(20,4)")
-            << (SignalList() << Insert(12,6) << Change(20,4))
-            << (SignalList() << Insert(12,6) << Change(20,4));
+            << (SignalList() << Insert(12,6) << Move(11,23,10,0))
+            << (SignalList() << Remove(11,1,0,0) << Remove(11,3,0,7) << Insert(23,1,0,0) << Insert(24,6) << Insert(30,3,0,7));
 
     // Remove,then insert
     QTest::newRow("r(12,6),i(12,6)")
@@ -589,144 +678,144 @@ void tst_qquickchangeset::sequence_data()
 
     // Move,then insert
     QTest::newRow("m(12-5,6),i(12,6)")
-            << (SignalList() << Move(12,5,6) << Insert(12,6))
-            << (SignalList() << Remove(12,6,0) << Insert(5,6,0) << Insert(12,6));
+            << (SignalList() << Move(12,5,6,0) << Insert(12,6))
+            << (SignalList() << Remove(12,6,0,0) << Insert(5,6,0,0) << Insert(12,6));
     QTest::newRow("m(12-5,6),i(10,4)")
-            << (SignalList() << Move(12,5,6) << Insert(10,4))
-            << (SignalList() << Remove(12,5,0) << Remove(12,1,1) << Insert(5,5,0) << Insert(10,4) << Insert(14,1,1));
+            << (SignalList() << Move(12,5,6,0) << Insert(10,4))
+            << (SignalList() << Remove(12,6,0,0) << Insert(5,5,0,0) << Insert(10,4) << Insert(14,1,0,5));
     QTest::newRow("m(12-5,6),i(16,4)")
-            << (SignalList() << Move(12,5,6) << Insert(16,4))
-            << (SignalList() << Remove(12,6,0) << Insert(5,6,0) << Insert(16,4));
+            << (SignalList() << Move(12,5,6,0) << Insert(16,4))
+            << (SignalList() << Remove(12,6,0,0) << Insert(5,6,0,0) << Insert(16,4));
     QTest::newRow("m(12-5,6),i(13,4)")
-            << (SignalList() << Move(12,5,6) << Insert(13,4))
-            << (SignalList() << Remove(12,6,0) << Insert(5,6,0) << Insert(13,4));
+            << (SignalList() << Move(12,5,6,0) << Insert(13,4))
+            << (SignalList() << Remove(12,6,0,0) << Insert(5,6,0,0) << Insert(13,4));
     QTest::newRow("m(12-5,6),i(14,4)")
-            << (SignalList() << Move(12,5,6) << Insert(14,4))
-            << (SignalList() << Remove(12,6,0) << Insert(5,6,0) << Insert(14,4));
+            << (SignalList() << Move(12,5,6,0) << Insert(14,4))
+            << (SignalList() << Remove(12,6,0,0) << Insert(5,6,0,0) << Insert(14,4));
     QTest::newRow("m(12-5,6),i(12,4)")
-            << (SignalList() << Move(12,5,6) << Insert(12,4))
-            << (SignalList() << Remove(12,6,0) << Insert(5,6,0) << Insert(12,4));
+            << (SignalList() << Move(12,5,6,0) << Insert(12,4))
+            << (SignalList() << Remove(12,6,0,0) << Insert(5,6,0,0) << Insert(12,4));
     QTest::newRow("m(12-5,6),i(11,8)")
-            << (SignalList() << Move(12,5,6) << Insert(11,8))
-            << (SignalList() << Remove(12,6,0) << Insert(5,6,0) << Insert(11,8));
+            << (SignalList() << Move(12,5,6,0) << Insert(11,8))
+            << (SignalList() << Remove(12,6,0,0) << Insert(5,6,0,0) << Insert(11,8));
     QTest::newRow("m(12-5,6),i(8,4)")
-            << (SignalList() << Move(12,5,6) << Insert(8,4))
-            << (SignalList() << Remove(12,3,0) << Remove(12,3,1) << Insert(5,3,0) << Insert(8,4) << Insert(12,3,1));
+            << (SignalList() << Move(12,5,6,0) << Insert(8,4))
+            << (SignalList() << Remove(12,6,0,0) << Insert(5,3,0,0) << Insert(8,4) << Insert(12,3,0,3));
     QTest::newRow("m(12-5,6),i(2,4)")
-            << (SignalList() << Move(12,5,6) << Insert(2,4))
-            << (SignalList() << Remove(12,6,0) << Insert(2,4) << Insert(9,6,0));
+            << (SignalList() << Move(12,5,6,0) << Insert(2,4))
+            << (SignalList() << Remove(12,6,0,0) << Insert(2,4) << Insert(9,6,0,0));
     QTest::newRow("m(12-5,6),i(18,4)")
-            << (SignalList() << Move(12,5,6) << Insert(18,4))
-            << (SignalList() << Remove(12,6,0) << Insert(5,6,0) << Insert(18,4));
+            << (SignalList() << Move(12,5,6,0) << Insert(18,4))
+            << (SignalList() << Remove(12,6,0,0) << Insert(5,6,0,0) << Insert(18,4));
     QTest::newRow("m(12-5,6),i(20,4)")
-            << (SignalList() << Move(12,5,6) << Insert(20,4))
-            << (SignalList() << Remove(12,6,0) << Insert(5,6,0) << Insert(20,4));
+            << (SignalList() << Move(12,5,6,0) << Insert(20,4))
+            << (SignalList() << Remove(12,6,0,0) << Insert(5,6,0,0) << Insert(20,4));
 
     QTest::newRow("m(12-23,6),i(12,6)")
-            << (SignalList() << Move(12,23,6) << Insert(12,6))
-            << (SignalList() << Remove(12,6,0) << Insert(12,6) << Insert(29,6,0));
+            << (SignalList() << Move(12,23,6,0) << Insert(12,6))
+            << (SignalList() << Remove(12,6,0,0) << Insert(12,6) << Insert(29,6,0,0));
     QTest::newRow("m(12-23,6),i(10,4)")
-            << (SignalList() << Move(12,23,6) << Insert(10,4))
-            << (SignalList() << Remove(12,6,0) << Insert(10,4) << Insert(27,6,0));
+            << (SignalList() << Move(12,23,6,0) << Insert(10,4))
+            << (SignalList() << Remove(12,6,0,0) << Insert(10,4) << Insert(27,6,0,0));
     QTest::newRow("m(12-23,6),i(16,4)")
-            << (SignalList() << Move(12,23,6) << Insert(16,4))
-            << (SignalList() << Remove(12,6,0) << Insert(16,4) << Insert(27,6,0));
+            << (SignalList() << Move(12,23,6,0) << Insert(16,4))
+            << (SignalList() << Remove(12,6,0,0) << Insert(16,4) << Insert(27,6,0,0));
     QTest::newRow("m(12-23,6),i(13,4)")
-            << (SignalList() << Move(12,23,6) << Insert(13,4))
-            << (SignalList() << Remove(12,6,0) << Insert(13,4) << Insert(27,6,0));
+            << (SignalList() << Move(12,23,6,0) << Insert(13,4))
+            << (SignalList() << Remove(12,6,0,0) << Insert(13,4) << Insert(27,6,0,0));
     QTest::newRow("m(12-23,6),i(14,4)")
-            << (SignalList() << Move(12,23,6) << Insert(14,4))
-            << (SignalList() << Remove(12,6,0) << Insert(14,4) << Insert(27,6,0));
+            << (SignalList() << Move(12,23,6,0) << Insert(14,4))
+            << (SignalList() << Remove(12,6,0,0) << Insert(14,4) << Insert(27,6,0,0));
     QTest::newRow("m(12-23,6),i(12,4)")
-            << (SignalList() << Move(12,23,6) << Insert(12,4))
-            << (SignalList() << Remove(12,6,0) << Insert(12,4) << Insert(27,6,0));
+            << (SignalList() << Move(12,23,6,0) << Insert(12,4))
+            << (SignalList() << Remove(12,6,0,0) << Insert(12,4) << Insert(27,6,0,0));
     QTest::newRow("m(12-23,6),i(11,8)")
-            << (SignalList() << Move(12,23,6) << Insert(11,8))
-            << (SignalList() << Remove(12,6,0) << Insert(11,8) << Insert(31,6,0));
+            << (SignalList() << Move(12,23,6,0) << Insert(11,8))
+            << (SignalList() << Remove(12,6,0,0) << Insert(11,8) << Insert(31,6,0,0));
     QTest::newRow("m(12-23,6),i(8,4)")
-            << (SignalList() << Move(12,23,6) << Insert(8,4))
-            << (SignalList() << Remove(12,6,0) << Insert(8,4) << Insert(27,6,0));
+            << (SignalList() << Move(12,23,6,0) << Insert(8,4))
+            << (SignalList() << Remove(12,6,0,0) << Insert(8,4) << Insert(27,6,0,0));
     QTest::newRow("m(12-23,6),i(2,4)")
-            << (SignalList() << Move(12,23,6) << Insert(2,4))
-            << (SignalList() << Remove(12,6,0) << Insert(2,4) << Insert(27,6,0));
+            << (SignalList() << Move(12,23,6,0) << Insert(2,4))
+            << (SignalList() << Remove(12,6,0,0) << Insert(2,4) << Insert(27,6,0,0));
     QTest::newRow("m(12-23,6),i(18,4)")
-            << (SignalList() << Move(12,23,6) << Insert(18,4))
-            << (SignalList() << Remove(12,6,0) << Insert(18,4) << Insert(27,6,0));
+            << (SignalList() << Move(12,23,6,0) << Insert(18,4))
+            << (SignalList() << Remove(12,6,0,0) << Insert(18,4) << Insert(27,6,0,0));
     QTest::newRow("m(12-23,6),i(20,4)")
-            << (SignalList() << Move(12,23,6) << Insert(20,4))
-            << (SignalList() << Remove(12,6,0) << Insert(20,4) << Insert(27,6,0));
+            << (SignalList() << Move(12,23,6,0) << Insert(20,4))
+            << (SignalList() << Remove(12,6,0,0) << Insert(20,4) << Insert(27,6,0,0));
 
     // Move,then remove
     QTest::newRow("m(12-5,6),r(12,6)")
-            << (SignalList() << Move(12,5,6) << Remove(12,6))
-            << (SignalList() << Remove(6,6) << Remove(6,6,0) << Insert(5,6,0));
+            << (SignalList() << Move(12,5,6,0) << Remove(12,6))
+            << (SignalList() << Remove(6,6) << Remove(6,6,0,0) << Insert(5,6,0,0));
     QTest::newRow("m(12-5,6),r(10,4)")
-            << (SignalList() << Move(12,5,6) << Remove(10,4))
-            << (SignalList() << Remove(5,3) << Remove(9,5,0) << Remove(9,1) << Insert(5,5,0));
+            << (SignalList() << Move(12,5,6,0) << Remove(10,4)) // ###
+            << (SignalList() << Remove(5,3) << Remove(9,6,0,0) << Insert(5,5,0,0));
     QTest::newRow("m(12-5,6),r(16,4)")
-            << (SignalList() << Move(12,5,6) << Remove(16,4))
-            << (SignalList() << Remove(10,2) << Remove(10,6,0) << Remove(10,2) << Insert(5,6,0));
+            << (SignalList() << Move(12,5,6,0) << Remove(16,4))
+            << (SignalList() << Remove(10,2) << Remove(10,6,0,0) << Remove(10,2) << Insert(5,6,0,0));
     QTest::newRow("m(12-5,6),r(13,4)")
-            << (SignalList() << Move(12,5,6) << Remove(13,4))
-            << (SignalList() << Remove(7,4) << Remove(8,6,0) << Insert(5,6,0));
+            << (SignalList() << Move(12,5,6,0) << Remove(13,4))
+            << (SignalList() << Remove(7,4) << Remove(8,6,0,0) << Insert(5,6,0,0));
     QTest::newRow("m(12-5,6),r(14,4)")
-            << (SignalList() << Move(12,5,6) << Remove(14,4))
-            << (SignalList() << Remove(8,4) << Remove(8,6,0) << Insert(5,6,0));
+            << (SignalList() << Move(12,5,6,0) << Remove(14,4))
+            << (SignalList() << Remove(8,4) << Remove(8,6,0,0) << Insert(5,6,0,0));
     QTest::newRow("m(12-5,6),r(12,4)")
-            << (SignalList() << Move(12,5,6) << Remove(12,4))
-            << (SignalList() << Remove(6,4) << Remove(8,6,0) << Insert(5,6,0));
+            << (SignalList() << Move(12,5,6,0) << Remove(12,4))
+            << (SignalList() << Remove(6,4) << Remove(8,6,0,0) << Insert(5,6,0,0));
     QTest::newRow("m(12-5,6),r(11,8)")
-            << (SignalList() << Move(12,5,6) << Remove(11,8))
-            << (SignalList() << Remove(5,7) << Remove(5,6,0) << Remove(5,1) << Insert(5,6,0));
+            << (SignalList() << Move(12,5,6,0) << Remove(11,8))
+            << (SignalList() << Remove(5,7) << Remove(5,6,0,0) << Remove(5,1) << Insert(5,6,0,0));
     QTest::newRow("m(12-5,6),r(8,4)")
-            << (SignalList() << Move(12,5,6) << Remove(8,4))
-            << (SignalList() << Remove(5,1) << Remove(11,3,0) << Remove(11,3) << Insert(5,3,0));
+            << (SignalList() << Move(12,5,6,0) << Remove(8,4)) // ###
+            << (SignalList() << Remove(5,1) << Remove(11,6,0,0) << Insert(5,3,0,0));
     QTest::newRow("m(12-5,6),r(2,4)")
-            << (SignalList() << Move(12,5,6) << Remove(2,4))
-            << (SignalList() << Remove(2,3) << Remove(9,1) << Remove(9,5,0) << Insert(2,5,0));
+            << (SignalList() << Move(12,5,6,0) << Remove(2,4))
+            << (SignalList() << Remove(2,3) << Remove(9,6,0,0) << Insert(2,5,0,1));
     QTest::newRow("m(12-5,6),r(6,4)")
-            << (SignalList() << Move(12,5,6) << Remove(6,4))
-            << (SignalList() << Remove(12,1,0) << Remove(12,4) << Remove(12,1,1) << Insert(5,1,0) << Insert(6,1,1));
+            << (SignalList() << Move(12,5,6,0) << Remove(6,4))
+            << (SignalList() << Remove(12,6,0,0) << Insert(5,1,0,0) << Insert(6,1,0,5));
     QTest::newRow("m(12-5,6),r(18,4)")
-            << (SignalList() << Move(12,5,6) << Remove(18,4))
-            << (SignalList() << Remove(12,6,0) << Remove(12,4) << Insert(5,6,0));
+            << (SignalList() << Move(12,5,6,0) << Remove(18,4))
+            << (SignalList() << Remove(12,6,0,0) << Remove(12,4) << Insert(5,6,0,0));
     QTest::newRow("m(12-5,6),r(20,4)")
-            << (SignalList() << Move(12,5,6) << Remove(20,4))
-            << (SignalList() << Remove(12,6,0) << Remove(14,4) << Insert(5,6,0));
+            << (SignalList() << Move(12,5,6,0) << Remove(20,4))
+            << (SignalList() << Remove(12,6,0,0) << Remove(14,4) << Insert(5,6,0,0));
 
     QTest::newRow("m(12-23,6),r(12,6)")
-            << (SignalList() << Move(12,23,6) << Remove(12,6))
-            << (SignalList() << Remove(12,6,0) << Remove(12,6) << Insert(17,6,0));
+            << (SignalList() << Move(12,23,6,0) << Remove(12,6))
+            << (SignalList() << Remove(12,6,0,0) << Remove(12,6) << Insert(17,6,0,0));
     QTest::newRow("m(12-23,6),r(10,4)")
-            << (SignalList() << Move(12,23,6) << Remove(10,4))
-            << (SignalList() << Remove(10,2) << Remove(10,6,0) << Remove(10,2) << Insert(19,6,0));
+            << (SignalList() << Move(12,23,6,0) << Remove(10,4))
+            << (SignalList() << Remove(10,2) << Remove(10,6,0,0) << Remove(10,2) << Insert(19,6,0,0));
     QTest::newRow("m(12-23,6),r(16,4)")
-            << (SignalList() << Move(12,23,6) << Remove(16,4))
-            << (SignalList() << Remove(12,6,0) << Remove(16,4) << Insert(19,6,0));
+            << (SignalList() << Move(12,23,6,0) << Remove(16,4))
+            << (SignalList() << Remove(12,6,0,0) << Remove(16,4) << Insert(19,6,0,0));
     QTest::newRow("m(12-23,6),r(13,4)")
-            << (SignalList() << Move(12,23,6) << Remove(13,4))
-            << (SignalList() << Remove(12,6,0) << Remove(13,4) << Insert(19,6,0));
+            << (SignalList() << Move(12,23,6,0) << Remove(13,4))
+            << (SignalList() << Remove(12,6,0,0) << Remove(13,4) << Insert(19,6,0,0));
     QTest::newRow("m(12-23,6),r(14,4)")
-            << (SignalList() << Move(12,23,6) << Remove(14,4))
-            << (SignalList() << Remove(12,6,0) << Remove(14,4) << Insert(19,6,0));
+            << (SignalList() << Move(12,23,6,0) << Remove(14,4))
+            << (SignalList() << Remove(12,6,0,0) << Remove(14,4) << Insert(19,6,0,0));
     QTest::newRow("m(12-23,6),r(12,4)")
-            << (SignalList() << Move(12,23,6) << Remove(12,4))
-            << (SignalList() << Remove(12,6,0) << Remove(12,4) << Insert(19,6,0));
+            << (SignalList() << Move(12,23,6,0) << Remove(12,4))
+            << (SignalList() << Remove(12,6,0,0) << Remove(12,4) << Insert(19,6,0,0));
     QTest::newRow("m(12-23,6),r(11,8)")
-            << (SignalList() << Move(12,23,6) << Remove(11,8))
-            << (SignalList() << Remove(11,1) << Remove(11,6,0) << Remove(11,7) << Insert(15,6,0));
+            << (SignalList() << Move(12,23,6,0) << Remove(11,8))
+            << (SignalList() << Remove(11,1) << Remove(11,6,0,0) << Remove(11,7) << Insert(15,6,0,0));
     QTest::newRow("m(12-23,6),r(8,4)")
-            << (SignalList() << Move(12,23,6) << Remove(8,4))
-            << (SignalList() << Remove(8,4) << Remove(8,6,0) << Insert(19,6,0));
+            << (SignalList() << Move(12,23,6,0) << Remove(8,4))
+            << (SignalList() << Remove(8,4) << Remove(8,6,0,0) << Insert(19,6,0,0));
     QTest::newRow("m(12-23,6),r(2,4)")
-            << (SignalList() << Move(12,23,6) << Remove(2,4))
-            << (SignalList() << Remove(2,4) << Remove(8,6,0) << Insert(19,6,0));
+            << (SignalList() << Move(12,23,6,0) << Remove(2,4))
+            << (SignalList() << Remove(2,4) << Remove(8,6,0,0) << Insert(19,6,0,0));
     QTest::newRow("m(12-23,6),r(18,4)")
-            << (SignalList() << Move(12,23,6) << Remove(18,4))
-            << (SignalList() << Remove(12,6,0) << Remove(18,4) << Insert(19,6,0));
+            << (SignalList() << Move(12,23,6,0) << Remove(18,4))
+            << (SignalList() << Remove(12,6,0,0) << Remove(18,4) << Insert(19,6,0,0));
     QTest::newRow("m(12-23,6),r(20,4)")
-            << (SignalList() << Move(12,23,6) << Remove(20,4))
-            << (SignalList() << Remove(12,1) << Remove(12,5,0) << Remove(20,3) << Insert(20,5,0));
+            << (SignalList() << Move(12,23,6,0) << Remove(20,4))
+            << (SignalList() << Remove(12,6,0,0) << Remove(20,3) << Insert(20,5,0,1));
 
 
     // Complex
@@ -746,9 +835,321 @@ void tst_qquickchangeset::sequence_data()
             << (SignalList() << Remove(15,1) << Remove(22,1) << Remove(25,1) << Remove(15,1) << Remove(13,1) << Remove(13,1))
             << (SignalList() << Remove(13,4) << Remove(19,1) << Remove(22,1));
     QTest::newRow("r(15,1),r(22,1),r(25,1),r(15,1),r(13,1),r(13,1),m(12,13,1)")
-            << (SignalList() << Remove(15,1) << Remove(22,1) << Remove(25,1) << Remove(15,1) << Remove(13,1) << Remove(13,1) << Move(12,13,1))
-            << (SignalList() << Remove(12,1,0) << Remove(12,4) << Remove(18,1) << Remove(21,1) << Insert(13,1,0));
+            << (SignalList() << Remove(15,1) << Remove(22,1) << Remove(25,1) << Remove(15,1) << Remove(13,1) << Remove(13,1) << Move(12,13,1,0))
+            << (SignalList() << Remove(12,1,0,0) << Remove(12,4) << Remove(18,1) << Remove(21,1) << Insert(13,1,0,0));
+
+    QTest::newRow("r(12,18),r(3,0)")
+            << (SignalList() << Remove(12,18) << Remove(3,0))
+            << (SignalList() << Remove(12,18));
+    QTest::newRow("r(12,18),r(3,0),r(1,2)")
+            << (SignalList() << Remove(12,18) << Remove(3,0) << Remove(1,2))
+            << (SignalList() << Remove(1,2) << Remove(10,18));
+    QTest::newRow("r(12,18),r(3,0),r(1,2),m(4,0,11)")
+            << (SignalList() << Remove(12,18) << Remove(3,0) << Remove(1,2) << Move(4,0,11,0))
+            << (SignalList() << Remove(1,2) << Remove(4,6,0,0) << Remove(4,18) << Remove(4,5,0,6) << Insert(0,11,0,0));
+    QTest::newRow("r(12,18),r(3,0),r(1,2),m(4,0,11),r(14,3)")
+            << (SignalList() << Remove(12,18) << Remove(3,0) << Remove(1,2) << Move(4,0,11,0) << Remove(14,3))
+            << (SignalList() << Remove(1,2) << Remove(3,1) << Remove(3,6,0,0) << Remove(3,18) << Remove(3,5,0,6) << Remove(3,2) << Insert(0,11,0,0));
+
+    QTest::newRow("m(9,11,14),i(16,1)")
+            << (SignalList() << Move(9,11,14,0) << Insert(16,1))
+            << (SignalList() << Remove(9,14,0,0) << Insert(11,5,0,0) << Insert(16,1) << Insert(17,9,0,5));
+    QTest::newRow("m(9,11,14),i(16,1),m(22,38,3)")
+            << (SignalList() << Move(9,11,14,0) << Insert(16,1) << Move(22,38,3,1))
+            << (SignalList() << Remove(9,14,0,0) << Insert(11,5,0,0) << Insert(16,1) << Insert(17,5,0,5) << Insert(22,1,0,13) << Insert(38,3,0,10));
+
+    QTest::newRow("i(28,2),m(7,5,22)")
+            << (SignalList() << Insert(28,2) << Move(7,5,22,0))
+            << (SignalList() << Remove(7,21,0,0) << Insert(5,21,0,0) << Insert(26,1) << Insert(29,1));
 
+    QTest::newRow("i(16,3),m(18,28,15)")
+            << (SignalList() << Insert(16,3) << Move(18,28,15,0))
+            << (SignalList() << Remove(16,14,0,1) << Insert(16,2) << Insert(28,1) << Insert(29,14,0,1));
+
+    QTest::newRow("m(33,12,6),m(18,20,20)")
+            << (SignalList() << Move(22,12,6,0) << Move(18,20,20,1))
+            << (SignalList() << Remove(12,10,1,0) << Remove(12,6,0,0) << Remove(12,10,1,10)
+                             << Insert(12,6,0,0) << Insert(20,20,1,0));
+    QTest::newRow("m(33,12,6),m(18,20,20),m(38,19,1)")
+            << (SignalList() << Move(22,12,6,0) << Move(18,20,20,1) << Move(28,19,1,2))
+            << (SignalList() << Remove(12,10,1,0) << Remove(12,6,0,0) << Remove(12,10,1,10)
+                             << Insert(12,6,0,0) << Insert(19,1,1,8) << Insert(21,8,1,0) << Insert(29,11,1,9));
+    QTest::newRow("m(33,12,6),m(18,20,20),m(38,19,1),r(34,4)")
+            << (SignalList() << Move(22,12,6,0) << Move(18,20,20,1) << Move(28,19,1,2) << Remove(34,4))
+            << (SignalList() << Remove(12,10,1,0) << Remove(12,6,0,0) << Remove(12,10,1,10)
+                             << Insert(12,6,0,0) << Insert(19,1,1,8) << Insert(21,8,1,0) << Insert(29,5,1,9) << Insert(34,2,1,18));
+    QTest::newRow("m(33,12,6),m(18,20,20),m(38,19,1),r(34,4),m(13,9,15)")
+            << (SignalList() << Move(22,12,6,0) << Move(18,20,20,1) << Move(28,19,1,2) << Remove(34,4) << Move(13,9,15,3))
+            << (SignalList() << Remove(12,10,1,0) << Remove(12,6,0,0) << Remove(12,10,1,10) << Remove(12,1,3,5) << Remove(12,1,3,7)
+                             << Insert(9,5,0,1) << Insert(14,1,3,5) << Insert(15,1,1,8) << Insert(16,1,3,7) << Insert(17,7,1,0) << Insert(27,1,0,0) << Insert(28,1,1,7) << Insert(29,5,1,9) << Insert(34,2,1,18));
+
+    QTest::newRow("i(8,5),m(14,26,14)")
+            << (SignalList() << Insert(8,5) << Move(14,26,14,0))
+            << (SignalList() << Remove(9,14,0,0) << Insert(8,5) << Insert(26,14,0,0));
+    QTest::newRow("i(8,5),m(14,26,14),r(45,0)")
+            << (SignalList() << Insert(8,5) << Move(14,26,14,0) << Remove(45,0))
+            << (SignalList() << Remove(9,14,0,0) << Insert(8,5) << Insert(26,14,0,0));
+    QTest::newRow("i(8,5),m(14,26,14),r(45,0),m(5,8,21)")
+            << (SignalList() << Insert(8,5) << Move(14,26,14,0) << Remove(45,0) << Move(5,8,21,1))
+            << (SignalList() << Remove(5,3,1,0) << Remove(5,1,1,8) << Remove(5,14,0,0) <<  Remove(5,12,1,9)
+                             << Insert(5,3,0,0) << Insert(8,3,1,0) << Insert(11,5) << Insert(16,13,1,8) << Insert(29,11,0,3));
+
+    QTest::newRow("i(35,1),r(5,31)")
+            << (SignalList() << Insert(35,1) << Remove(5,31))
+            << (SignalList() << Remove(5,30));
+    QTest::newRow("i(35,1),r(5,31),m(9,8,1)")
+            << (SignalList() << Insert(35,1) << Remove(5,31) << Move(9,8,1,0))
+            << (SignalList() << Remove(5,30) << Remove(9,1,0,0) << Insert(8,1,0,0));
+    QTest::newRow("i(35,1),r(5,31),m(9,8,1),i(7,2)")
+            << (SignalList() << Insert(35,1) << Remove(5,31) << Move(9,8,1,0) << Insert(7,2))
+            << (SignalList() << Remove(5,30) << Remove(9,1,0,0) << Insert(7,2) << Insert(10,1,0,0));
+    QTest::newRow("i(35,1),r(5,31),m(9,8,1),i(7,2),r(4,3)")
+            << (SignalList() << Insert(35,1) << Remove(5,31) << Move(9,8,1,0) << Insert(7,2) << Remove(4,3))
+            << (SignalList() << Remove(4,33) << Remove(6,1,0,0) << Insert(4,2) << Insert(7,1,0,0));
+
+    QTest::newRow("r(37,0),r(21,1)")
+            << (SignalList() << Remove(37,0) << Remove(21,1))
+            << (SignalList() << Remove(21,1));
+    QTest::newRow("r(37,0),r(21,1),m(27,35,2)")
+            << (SignalList() << Remove(37,0) << Remove(21,1) << Move(27,35,2,0))
+            << (SignalList() << Remove(21,1) << Remove(27,2,0,0) << Insert(35,2,0,0));
+    QTest::newRow("r(37,0),r(21,1),m(27,35,2),i(31,5)")
+            << (SignalList() << Remove(37,0) << Remove(21,1) << Move(27,35,2,0) << Insert(31,5))
+            << (SignalList() << Remove(21,1) << Remove(27,2,0,0) << Insert(31,5) << Insert(40,2,0,0));
+    QTest::newRow("r(37,0),r(21,1),m(27,35,2),i(31,5),r(10,31)")
+            << (SignalList() << Remove(37,0) << Remove(21,1) << Move(27,35,2,0) << Insert(31,5) << Remove(10,31))
+            << (SignalList() << Remove(10, 18) << Remove(10,2,0,0) << Remove(10,8) << Insert(10,1,0,1));
+
+    QTest::newRow("m(1,1,39),r(26,10)")
+            << (SignalList() << Move(1,1,39,0) << Remove(26,10))
+            << (SignalList() << Remove(1,39,0,0) << Insert(1,25,0,0) << Insert(26,4,0,35));
+    QTest::newRow("m(1,1,39),r(26,10),i(10,5)")
+            << (SignalList() << Move(1,1,39,0) << Remove(26,10) << Insert(10,5))
+            << (SignalList() << Remove(1,39,0,0) << Insert(1,9,0,0) << Insert(10,5) << Insert(15,16,0,9) << Insert(31,4,0,35));
+    QTest::newRow("m(1,1,39),r(26,10),i(10,5),i(27,3)")
+            << (SignalList() << Move(1,1,39,0) << Remove(26,10) << Insert(10,5) << Insert(27,3))
+            << (SignalList() << Remove(1,39,0,0)
+                             << Insert(1,9,0,0) << Insert(10,5) << Insert(15,12,0,9) << Insert(27,3) << Insert(30,4,0,21) << Insert(34,4,0,35));
+    QTest::newRow("m(1,1,39),r(26,10),i(10,5),i(27,3),r(28,5)")
+            << (SignalList() << Move(1,1,39,0) << Remove(26,10) << Insert(10,5) << Insert(27,3) << Remove(28,5))
+            << (SignalList() << Remove(1,39,0,0)
+                             << Insert(1,9,0,0) << Insert(10,5) << Insert(15,12,0,9) << Insert(27,1) << Insert(28,1,0,24) << Insert(29,4,0,35));
+
+    QTest::newRow("i(36,4)m(25,39,5)")
+            << (SignalList() << Insert(36,4) << Move(25,39,5,0))
+            << (SignalList() << Remove(25,5,0,0) << Insert(31,4) << Insert(39,5,0,0));
+    QTest::newRow("i(36,4)m(25,39,5),i(16,5)")
+            << (SignalList() << Insert(36,4) << Move(25,39,5,0) << Insert(16,5))
+            << (SignalList() << Remove(25,5,0,0) << Insert(16,5) << Insert(36,4) << Insert(44,5,0,0));
+    QTest::newRow("i(36,4)m(25,39,5),i(16,5),i(37,5)")
+            << (SignalList() << Insert(36,4) << Move(25,39,5,0) << Insert(16,5) << Insert(37,5))
+            << (SignalList() << Remove(25,5,0,0) << Insert(16,5) << Insert(36,9) << Insert(49,5,0,0));
+    QTest::newRow("i(36,4)m(25,39,5),i(16,5),i(37,5),m(40,21,11)")
+            << (SignalList() << Insert(36,4) << Move(25,39,5,0) << Insert(16,5) << Insert(37,5) << Move(40,21,11,1))
+            << (SignalList() << Remove(25,5,0,0) << Remove(31,4,1,5)
+                             << Insert(16,10) << Insert(26,4,1,5) << Insert(30,2,0,0) << Insert(47,4) << Insert(51,3,0,2));
+
+    QTest::newRow("i(24,1),r(33,4)")
+            << (SignalList() << Insert(24,1) << Remove(33,4))
+            << (SignalList() << Remove(32,4) << Insert(24,1));
+    QTest::newRow("i(24,1),r(33,4),r(15,15)")
+            << (SignalList() << Insert(24,1) << Remove(33,4) << Remove(15,15))
+            << (SignalList() << Remove(15,14) << Remove(18,4));
+    QTest::newRow("i(24,1),r(33,4),r(15,15),m(8,10,2)")
+            << (SignalList() << Insert(24,1) << Remove(33,4) << Remove(15,15) << Move(8,10,2,0))
+            << (SignalList() << Remove(8,2,0,0) << Remove(13,14) << Remove(16,4) << Insert(10,2,0,0));
+    QTest::newRow("i(24,1),r(33,4),r(15,15),m(8,10,2),r(2,19)")
+            << (SignalList() << Insert(24,1) << Remove(33,4) << Remove(15,15) << Move(8,10,2,0) << Remove(2,19))
+            << (SignalList() << Remove(2,6) << Remove(2,2,0,0) << Remove(2,29));
+
+    QTest::newRow("r(1,35),i(3,4),m(4,2,2)")
+            << (SignalList() << Remove(1,35) << Insert(3,4) << Move(4,2,2,0))
+            << (SignalList() << Remove(1,35) <<Insert(2,2) << Insert(5,2));
+    QTest::newRow("r(1,35),i(3,4),m(4,2,2),r(7,1)")
+            << (SignalList() << Remove(1,35) << Insert(3,4) << Move(4,2,2,0) << Remove(7,1))
+            << (SignalList() << Remove(1,35) << Remove(3,1) << Insert(2,2) << Insert(5,2));
+
+    QTest::newRow("i(30,4),m(7,28,16),m(6,7,13)")
+            << (SignalList() << Insert(30,4) << Move(7,28,16,0))
+            << (SignalList() << Remove(7,16,0,0) << Insert(14,4) << Insert(28,16,0,0));
+    QTest::newRow("(i(30,4),m(7,28,16),m(6,7,13),m(41,35,2)")
+            << (SignalList() << Insert(30,4) << Move(7,28,16,0) << Move(6,7,13,1) << Move(41,35,2,2))
+            << (SignalList() << Remove(6,1,1,0) << Remove(6,16,0,0) << Remove(6,7,1,1) << Remove(6,1,1,12)
+                             << Insert(7,8,1,0) << Insert(15,4) << Insert(19,1,1,12) << Insert(28,7,0,0) << Insert(35,2,0,13) << Insert(37,6,0,7) << Insert(43,1,0,15));
+
+    QTest::newRow("(i(35,2),r(39,0))(r(25,11))")
+            << (SignalList() << Insert(35,2) << Remove(39,0) << Remove(25,11))
+            << (SignalList() << Remove(25,10) << Insert(25,1));
+    QTest::newRow("(i(35,2),r(39,0))(r(25,11),m(28,8,7))")
+            << (SignalList() << Insert(35,2) << Remove(39,0) << Remove(25,11) << Move(24,8,7,0))
+            << (SignalList() << Remove(24,1,0,0) << Remove(24,10) << Remove(24,5,0,2)
+                << Insert(8,1,0,0) << Insert(9,1) << Insert(10,5,0,2));
+
+    QTest::newRow("i(26,1),i(39,1)")
+            << (SignalList() << Insert(26,1) << Insert(39,1))
+            << (SignalList() << Insert(26,1) << Insert(39,1));
+    QTest::newRow("i(26,1),i(39,1),m(31,34,2)")
+            << (SignalList() << Insert(26,1) << Insert(39,1) << Move(31,34,2,0))
+            << (SignalList() << Remove(30,2,0,0) << Insert(26,1) << Insert(34,2,0,0) << Insert(39,1));
+    QTest::newRow("i(26,1),i(39,1),m(31,34,2),r(15,27)")
+            << (SignalList() << Insert(26,1) << Insert(39,1) << Move(31,34,2,0) << Remove(15,27))
+            << (SignalList() << Remove(15,15) << Remove(15,2,0,0) << Remove(15,8));
+
+    QTest::newRow("i(19,1),i(2,3)")
+            << (SignalList() << Insert(19,1) << Insert(2,3))
+            << (SignalList() << Insert(2,3) << Insert(22,1));
+    QTest::newRow("i(19,1),i(2,3),r(38,4)")
+            << (SignalList() << Insert(19,1) << Insert(2,3) << Remove(38,4))
+            << (SignalList() << Remove(34,4) << Insert(2,3) << Insert(22,1));
+    QTest::newRow("i(19,1),(2,3),r(38,4),m(2,20,3")
+            << (SignalList() << Insert(19,1) << Insert(2,3) << Remove(38,4) << Move(2,20,3,0))
+            << (SignalList() << Remove(34,4) << Insert(19,4));
+
+    QTest::newRow("i(4,3),i(19,1)")
+            << (SignalList() << Insert(4,3) << Insert(19,1))
+            << (SignalList() << Insert(4,3) << Insert(19,1));
+    QTest::newRow("i(4,3),i(19,1),i(31,3)")
+            << (SignalList() << Insert(4,3) << Insert(19,1) << Insert(31,3))
+            << (SignalList() << Insert(4,3) << Insert(19,1) << Insert(31,3));
+    QTest::newRow("i(4,3),i(19,1),i(31,3),m(8,10,29)")
+            << (SignalList() << Insert(4,3) << Insert(19,1) << Insert(31,3) << Move(8,10,29,0))
+            << (SignalList() << Remove(5,11,0,0) << Remove(5,11,0,12) << Remove(5,3,0,26)
+                             << Insert(4,3) << Insert(10,11,0,0) << Insert(21,1) << Insert(22,11,0,12) << Insert(33,3) << Insert(36,3,0,26));
+
+    QTest::newRow("m(18,15,16),i(0,1)")
+            << (SignalList() << Move(18,15,16,0) << Insert(0,1))
+            << (SignalList() << Remove(18,16,0,0) << Insert(0,1) << Insert(16,16,0,0));
+    QTest::newRow("m(18,15,16),i(0,1),i(32,2)")
+            << (SignalList() << Move(18,15,16,0) << Insert(0,1) << Insert(32,2))
+            << (SignalList() << Remove(18,16,0,0) << Insert(0,1) << Insert(16,16,0,0) << Insert(32,2));
+    QTest::newRow("m(18,15,16),i(0,1),i(32,2),i(29,2)")
+            << (SignalList() << Move(18,15,16,0) << Insert(0,1) << Insert(32,2) << Insert(29,2))
+            << (SignalList() << Remove(18,16,0,0) << Insert(0,1) << Insert(16,13,0,0) << Insert(29,2) << Insert(31,3,0,13) << Insert(34,2));
+
+    QTest::newRow("i(38,5),i(12,5)")
+            << (SignalList() << Insert(38,5) << Insert(12,5))
+            << (SignalList() << Insert(12,5) << Insert(43,5));
+    QTest::newRow("i(38,5),i(12,5),i(48,3)")
+            << (SignalList() << Insert(38,5) << Insert(12,5) << Insert(48,3))
+            << (SignalList() << Insert(12,5) << Insert(43,8));
+    QTest::newRow("i(38,5),i(12,5),i(48,3),m(28,6,6)")
+            << (SignalList() << Insert(38,5) << Insert(12,5) << Insert(48,3) << Move(28,6,6,0))
+            << (SignalList() << Remove(23,6,0,0) << Insert(6,6,0,0) << Insert(18,5) << Insert(43,8));
+
+    QTest::newRow("r(8,9),m(7,10,18)")
+            << (SignalList() << Remove(8,9) << Move(7,10,18,0))
+            << (SignalList() << Remove(7,1,0,0) << Remove(7,9) << Remove(7,17,0,1) << Insert(10,18,0,0));
+    QTest::newRow("r(8,9),m(7,10,18),m(8,10,18)")
+            << (SignalList() << Remove(8,9) << Move(7,10,18,0) << Move(8,10,18,1))
+            << (SignalList() << Remove(7,1,0,0) << Remove(7,9) << Remove(7,17,0,1) << Remove(8,2,1,0) << Insert(8,2,0,16) << Insert(10,2,1,0) << Insert(12,16,0,0));
+    QTest::newRow("r(8,9),m(7,10,18),m(8,10,18),i(17,2)")
+            << (SignalList() << Remove(8,9) << Move(7,10,18,0) << Move(8,10,18,1) << Insert(17,2))
+            << (SignalList() << Remove(7,1,0,0) << Remove(7,9) << Remove(7,17,0,1) << Remove(8,2,1,0) << Insert(8,2,0,16) << Insert(10,2,1,0) << Insert(12,5,0,0) << Insert(17,2) << Insert(19,11,0,5));
+
+    QTest::newRow("r(39,0),m(18,1,21)")
+            << (SignalList() << Remove(39,0) << Move(18,1,21,0))
+            << (SignalList() << Remove(18,21,0,0) << Insert(1,21,0,0));
+    QTest::newRow("r(39,0),m(18,1,21),m(2,6,31)")
+            << (SignalList() << Remove(39,0) << Move(18,1,21,0) << Move(2,6,31,1))
+            << (SignalList() << Remove(1,11,1,20) << Remove(7,21,0,0) << Insert(1,1,0,0) << Insert(6,20,0,1) << Insert(26,11,1,20));
+    QTest::newRow("r(39,0),m(18,1,21),m(2,6,31),r(9,4)")
+            << (SignalList() << Remove(39,0) << Move(18,1,21,0) << Move(2,6,31,1) << Remove(9,4))
+            << (SignalList() << Remove(1,11,1,20) << Remove(7,21,0,0) << Insert(1,1,0,0) << Insert(6,3,0,1) << Insert(9,13,0,8) << Insert(22,11,1,20));
+
+    QTest::newRow("i(1,1),m(9,32,3)")
+            << (SignalList()
+                << Insert(1,1) << Move(9,32,3,0))
+            << (SignalList() << Remove(8,3,0,0) << Insert(1,1) << Insert(32,3,0,0));
+    QTest::newRow("i(1,1),m(9,32,3),r(22,1)")
+            << (SignalList()
+                << Insert(1,1) << Move(9,32,3,0) << Remove(22,1))
+            << (SignalList() << Remove(8,3,0,0) << Remove(21,1) << Insert(1,1) << Insert(31,3,0,0));
+    QTest::newRow("i(1,1),m(9,32,3),r(22,1),i(29,3)")
+            << (SignalList()
+                << Insert(1,1) << Move(9,32,3,0) << Remove(22,1) << Insert(29,3))
+            << (SignalList() << Remove(8,3,0,0) << Remove(21,1) << Insert(1,1) << Insert(29,3) << Insert(34,3,0,0));
+    QTest::newRow("i(1,1),m(9,32,3),r(22,1),i(29,3),m(7,15,23)")
+            << (SignalList()
+                << Insert(1,1) << Move(9,32,3,0) << Remove(22,1) << Insert(29,3) << Move(7,15,23,1))
+            << (SignalList() << Remove(6,2,1,0) << Remove(6,3,0,0) << Remove(6,13,1,2) << Remove(6,1) << Remove(6,7,1,15) << Insert(1,1) << Insert(7,2) << Insert(11,3,0,0) << Insert(15,22,1,0) << Insert(37,1));
+
+    QTest::newRow("r(36,4),m(3,2,14)")
+            << (SignalList() << Remove(36,4) << Move(3,2,14,0))
+            << (SignalList() << Remove(3,14,0,0) << Remove(22,4) << Insert(2,14,0,0));
+    QTest::newRow("r(36,4),m(3,2,14),i(36,3)")
+            << (SignalList() << Remove(36,4) << Move(3,2,14,0) << Insert(36,3))
+            << (SignalList() << Remove(3,14,0,0) << Remove(22,4) << Insert(2,14,0,0) << Insert(36,3));
+    QTest::newRow("r(36,4),m(3,2,14),i(36,3),r(30,7)")
+            << (SignalList() << Remove(36,4) << Move(3,2,14,0) << Insert(36,3)  << Remove(30,7))
+            << (SignalList() << Remove(3,14,0,0) << Remove(16,10) << Insert(2,14,0,0) << Insert(30,2));  // ###
+    QTest::newRow("r(36,4),m(3,2,14),i(36,3),r(30,7),i(3,5)")
+            << (SignalList() << Remove(36,4) << Move(3,2,14,0) << Insert(36,3)  << Remove(30,7) << Insert(3,5))
+            << (SignalList() << Remove(3,14,0,0) << Remove(16,10) << Insert(2,1,0,0) << Insert(3,5) << Insert(8,13,0,1) << Insert(35,2));    // ###
+
+    QTest::newRow("3*5 (10)")
+            << (SignalList()
+                << Remove(36,4) << Move(3,2,14,0) << Insert(36,3)  << Remove(30,7) << Insert(3,5)
+                << Insert(1,1) << Move(9,32,3,1) << Remove(22,1) << Insert(29,3) << Move(7,15,23,2))
+            << (SignalList()
+                << Remove(2,1,2,12) << Remove(2,14,0,0) << Remove(2,2,2,13) << Remove(2,1)
+                << Remove(2,7,2,15) << Remove(5,10) << Insert(1,1) << Insert(3,1,0,0)
+                << Insert(4,3) << Insert(7,2) << Insert(11,3,0,1) << Insert(15,2)
+                << Insert(17,10,0,4) << Insert(27,10,2,12) << Insert(37,3));
+    QTest::newRow("3*5 (11)")
+            << (SignalList()
+                << Remove(36,4) << Move(3,2,14,0) << Insert(36,3)  << Remove(30,7) << Insert(3,5)
+                << Insert(1,1) << Move(9,32,3,1) << Remove(22,1) << Insert(29,3) << Move(7,15,23,2)
+                << Move(38,23,1,3))
+            << (SignalList()
+                << Remove(2,1,2,12) << Remove(2,14,0,0) << Remove(2,2,2,13)
+                << Remove(2,1) << Remove(2,7,2,15) << Remove(5,10) << Insert(1,1)
+                << Insert(3,1,0,0) << Insert(4,3) << Insert(7,2) << Insert(11,3,0,1) << Insert(15,2)
+                << Insert(17,6,0,4) << Insert(23,1) << Insert(24,4,0,10) << Insert(28,10,2,12)
+                << Insert(38,2));
+    QTest::newRow("3*5 (12)")
+            << (SignalList()
+                << Remove(36,4) << Move(3,2,14,0) << Insert(36,3)  << Remove(30,7) << Insert(3,5)
+                << Insert(1,1) << Move(9,32,3,1) << Remove(22,1) << Insert(29,3) << Move(7,15,23,2)
+                << Move(38,23,1,3) << Move(38,31,0,4))
+            << (SignalList()
+                << Remove(2,1,2,12) << Remove(2,14,0,0) << Remove(2,2,2,13) << Remove(2,1)
+                << Remove(2,7,2,15) << Remove(5,10) << Insert(1,1) << Insert(3,1,0,0)
+                << Insert(4,3) << Insert(7,2) << Insert(11,3,0,1) << Insert(15,2) << Insert(17,6,0,4)
+                << Insert(23,1) << Insert(24,4,0,10) << Insert(28,10,2,12) << Insert(38,2));
+    QTest::newRow("3*5 (13)")
+            << (SignalList()
+                << Remove(36,4) << Move(3,2,14,0) << Insert(36,3)  << Remove(30,7) << Insert(3,5)
+                << Insert(1,1) << Move(9,32,3,1) << Remove(22,1) << Insert(29,3) << Move(7,15,23,2)
+                << Move(38,23,1,3) << Move(38,31,0,4) << Remove(26,11))
+            << (SignalList()
+                << Remove(2,1,2,12) << Remove(2,14,0,0) << Remove(2,2,2,13) << Remove(2,1)
+                << Remove(2,7,2,15) << Remove(5,10) << Insert(1,1) << Insert(3,1,0,0)
+                << Insert(4,3) << Insert(7,2) << Insert(11,3,0,1) << Insert(15,2) << Insert(17,6,0,4)
+                << Insert(23,1) << Insert(24,2,0,10) << Insert(26,1,2,21) << Insert(27,2));
+    QTest::newRow("3*5 (14)")
+            << (SignalList()
+                << Remove(36,4) << Move(3,2,14,0) << Insert(36,3)  << Remove(30,7) << Insert(3,5)
+                << Insert(1,1) << Move(9,32,3,1) << Remove(22,1) << Insert(29,3) << Move(7,15,23,2)
+                << Move(38,23,1,3) << Move(38,31,0,4) << Remove(26,11) << Move(5,7,18,5))
+            << (SignalList()
+                << Remove(2,1,2,12) << Remove(2,14,0,0) << Remove(2,2,2,13) << Remove(2,1)
+                << Remove(2,7,2,15) << Remove(2,2,5,4) << Remove(2,1,5,9) << Remove(2,10)
+                << Insert(1,1) << Insert(3,1,0,0) << Insert(4,1) << Insert(5,1)
+                << Insert(6,1,0,10) << Insert(7,4) << Insert(11,2,5,4)
+                << Insert(13,3,0,1) << Insert(16,1,5,9) << Insert(17,2) << Insert(19,6,0,4)
+                << Insert(25,1,0,11) << Insert(26,1,2,21) << Insert(27,2));
+    QTest::newRow("3*5 (15)")
+            << (SignalList()
+                << Remove(36,4) << Move(3,2,14,0) << Insert(36,3)  << Remove(30,7) << Insert(3,5)
+                << Insert(1,1) << Move(9,32,3,1) << Remove(22,1) << Insert(29,3) << Move(7,15,23,2)
+                << Move(38,23,1,3) << Move(38,31,0,4) << Remove(26,11) << Move(5,7,18,5) << Move(19,0,8,6))
+            << (SignalList()
+                << Remove(2,1,2,12) << Remove(2,14,0,0) << Remove(2,2,2,13) << Remove(2,1)
+                << Remove(2,7,2,15) << Remove(2,2,5,4) << Remove(2,1,5,9) << Remove(2,10)
+                << Insert(0,6,0,4) << Insert(6,1,0,11) << Insert(7,1,2,21) << Insert(9,1)
+                << Insert(11,1,0,0) << Insert(12,1) << Insert(13,1) << Insert(14,1,0,10)
+                << Insert(15,4) << Insert(19,2,5,4) << Insert(21,3,0,1)
+                << Insert(24,1,5,9) << Insert(25,2) << Insert(27,2));
 }
 
 void tst_qquickchangeset::sequence()
@@ -764,48 +1165,348 @@ void tst_qquickchangeset::sequence()
         else if (signal.isInsert())
             set.insert(signal.index, signal.count);
         else if (signal.isMove())
-            set.move(signal.index, signal.to, signal.count);
+            set.move(signal.index, signal.to, signal.count, signal.moveId);
         else if (signal.isChange())
             set.change(signal.index, signal.count);
     }
 
     SignalList changes;
     foreach (const QQuickChangeSet::Remove &remove, set.removes())
-        changes << Remove(remove.index, remove.count, remove.moveId);
+        changes << Remove(remove.index, remove.count, remove.moveId, remove.offset);
     foreach (const QQuickChangeSet::Insert &insert, set.inserts())
-        changes << Insert(insert.index, insert.count, insert.moveId);
+        changes << Insert(insert.index, insert.count, insert.moveId, insert.offset);
     foreach (const QQuickChangeSet::Change &change, set.changes())
         changes << Change(change.index, change.count);
 
-#ifdef VERIFY_EXPECTED_OUTPUT
-    QVector<int> list;
-    for (int i = 0; i < 40; ++i)
-        list.append(i);
-    QVector<int> inputList = applyChanges(list, input);
-    QVector<int> outputList = applyChanges(list, output);
-    if (outputList != inputList /* || changes != output*/) {
-        qDebug() << input;
-        qDebug() << output;
-        qDebug() << changes;
-        qDebug() << inputList;
-        qDebug() << outputList;
-    } else if (changes != output) {
-        qDebug() << output;
-        qDebug() << changes;
+    VERIFY_EXPECTED_OUTPUT
+    QCOMPARE(changes, output);
+}
+
+void tst_qquickchangeset::apply_data()
+{
+    QTest::addColumn<SignalListList>("input");
+
+    QTest::newRow("(r(1,35),i(3,4)),(m(4,2,2),r(7,1))")
+            << (SignalListList()
+                << (SignalList() << Remove(1,35) << Insert(3,4))
+                << (SignalList() << Move(4,2,2,0) << Remove(7,1)));
+
+    QTest::newRow("(i(30,4),m(7,28,16))(m(6,7,13),m(41,35,2))")
+            << (SignalListList()
+                << (SignalList() << Insert(30,4) << Move(7,28,16,0))
+                << (SignalList() << Move(6,7,13,1) << Move(41,35,2,2)));
+
+    QTest::newRow("(i(35,2),r(39,0))(r(25,11),m(24,8,7))")
+            << (SignalListList()
+                << (SignalList() << Insert(35,2) << Remove(39,0))
+                << (SignalList() << Remove(25,11) << Move(24,8,7,0)));
+
+    QTest::newRow("i(26,1),i(39,1),m(31,34,2),r(15,27)")
+            << (SignalListList()
+                << (SignalList() << Insert(26,1) << Insert(39,1))
+                << (SignalList() << Move(31,34,2,0) << Remove(15,27)));
+
+    QTest::newRow("i(19,1),(2,3),r(38,4),m(2,20,3)")
+            << (SignalListList()
+                << (SignalList() << Insert(19,1) << Insert(2,3))
+                << (SignalList() << Remove(38,4) << Move(2,20,3,0)));
+
+    QTest::newRow("i(4,3),i(19,1),i(31,3),m(8,10,29)")
+            << (SignalListList()
+                << (SignalList() << Insert(4,3) << Insert(19,1))
+                << (SignalList() << Insert(31,3) << Move(8,10,29,0)));
+
+    QTest::newRow("m(18,15,16),i(0,1),i(32,2),i(29,2)")
+            << (SignalListList()
+                << (SignalList() << Move(18,15,16,0) << Insert(0,1))
+                << (SignalList() << Insert(32,2) << Insert(29,2)));
+
+    QTest::newRow("i(38,5),i(12,5),i(48,3),m(28,6,6)")
+            << (SignalListList()
+                << (SignalList() << Insert(38,5) << Insert(12,5))
+                << (SignalList() << Insert(48,3) << Move(28,6,6,0)));
+
+    QTest::newRow("r(8,9),m(7,10,18),m(8,10,18),i(17,2)")
+            << (SignalListList()
+                << (SignalList() << Remove(8,9) << Move(7,10,18,0))
+                << (SignalList() << Move(8,10,18,1) << Insert(17,2)));
+
+    QTest::newRow("r(39,0),m(18,1,21),m(2,6,31),r(9,4)")
+            << (SignalListList()
+                << (SignalList() << Remove(39,0) << Move(18,1,21,0))
+                << (SignalList() << Move(2,6,31,1) << Remove(9,4)));
+
+    QTest::newRow("3*5 (5)")
+            << (SignalListList()
+                << (SignalList() << Remove(36,4) << Move(3,2,14,0) << Insert(36,3)  << Remove(30,7) << Insert(3,5)));
+    QTest::newRow("3*5 (6)")
+            << (SignalListList()
+                << (SignalList() << Remove(36,4) << Move(3,2,14,0) << Insert(36,3)  << Remove(30,7) << Insert(3,5))
+                << (SignalList() << Insert(1,1)));
+    QTest::newRow("3*5 (7)")
+            << (SignalListList()
+                << (SignalList() << Remove(36,4) << Move(3,2,14,0) << Insert(36,3)  << Remove(30,7) << Insert(3,5))
+                << (SignalList() << Insert(1,1) << Move(9,32,3,1)));
+    QTest::newRow("3*5 (8)")
+            << (SignalListList()
+                << (SignalList() << Remove(36,4) << Move(3,2,14,0) << Insert(36,3)  << Remove(30,7) << Insert(3,5))
+                << (SignalList() << Insert(1,1) << Move(9,32,3,1) << Remove(22,1)));
+    QTest::newRow("3*5 (9)")
+            << (SignalListList()
+                << (SignalList() << Remove(36,4) << Move(3,2,14,0) << Insert(36,3)  << Remove(30,7) << Insert(3,5))
+                << (SignalList() << Insert(1,1) << Move(9,32,3,1) << Remove(22,1) << Insert(29,3)));
+    QTest::newRow("3*5 (10)")
+            << (SignalListList()
+                << (SignalList() << Remove(36,4) << Move(3,2,14,0) << Insert(36,3)  << Remove(30,7) << Insert(3,5))
+                << (SignalList() << Insert(1,1) << Move(9,32,3,1) << Remove(22,1) << Insert(29,3) << Move(7,15,23,2)));
+    QTest::newRow("3*5 (11)")
+            << (SignalListList()
+                << (SignalList() << Remove(36,4) << Move(3,2,14,0) << Insert(36,3)  << Remove(30,7) << Insert(3,5))
+                << (SignalList() << Insert(1,1) << Move(9,32,3,1) << Remove(22,1) << Insert(29,3) << Move(7,15,23,2))
+                << (SignalList() << Move(38,23,1,3)));
+    QTest::newRow("3*5 (12)")
+            << (SignalListList()
+                << (SignalList() << Remove(36,4) << Move(3,2,14,0) << Insert(36,3)  << Remove(30,7) << Insert(3,5))
+                << (SignalList() << Insert(1,1) << Move(9,32,3,1) << Remove(22,1) << Insert(29,3) << Move(7,15,23,2))
+                << (SignalList() << Move(38,23,1,3) << Move(38,31,0,4)));
+    QTest::newRow("3*5 (13)")
+            << (SignalListList()
+                << (SignalList() << Remove(36,4) << Move(3,2,14,0) << Insert(36,3)  << Remove(30,7) << Insert(3,5))
+                << (SignalList() << Insert(1,1) << Move(9,32,3,1) << Remove(22,1) << Insert(29,3) << Move(7,15,23,2))
+                << (SignalList() << Move(38,23,1,3) << Move(38,31,0,4) << Remove(26,11)));
+    QTest::newRow("3*5 (14)")
+            << (SignalListList()
+                << (SignalList() << Remove(36,4) << Move(3,2,14,0) << Insert(36,3)  << Remove(30,7) << Insert(3,5))
+                << (SignalList() << Insert(1,1) << Move(9,32,3,1) << Remove(22,1) << Insert(29,3) << Move(7,15,23,2))
+                << (SignalList() << Move(38,23,1,3) << Move(38,31,0,4) << Remove(26,11) << Move(5,7,18,5)));
+    QTest::newRow("3*5 (15)")
+            << (SignalListList()
+                << (SignalList() << Remove(36,4) << Move(3,2,14,0) << Insert(36,3)  << Remove(30,7) << Insert(3,5))
+                << (SignalList() << Insert(1,1) << Move(9,32,3,1) << Remove(22,1) << Insert(29,3) << Move(7,15,23,2))
+                << (SignalList() << Move(38,23,1,3) << Move(38,31,0,4) << Remove(26,11) << Move(5,7,18,5) << Move(19,0,8,6)));
+}
+
+void tst_qquickchangeset::apply()
+{
+    QFETCH(SignalListList, input);
+
+    QQuickChangeSet set;
+    QQuickChangeSet linearSet;
+
+    foreach (const SignalList &list, input) {
+        QQuickChangeSet intermediateSet;
+        foreach (const Signal &signal, list) {
+            if (signal.isRemove()) {
+                intermediateSet.remove(signal.index, signal.count);
+                linearSet.remove(signal.index, signal.count);
+            } else if (signal.isInsert()) {
+                intermediateSet.insert(signal.index, signal.count);
+                linearSet.insert(signal.index, signal.count);
+            } else if (signal.isMove()) {
+                intermediateSet.move(signal.index, signal.to, signal.count, signal.moveId);
+                linearSet.move(signal.index, signal.to, signal.count, signal.moveId);
+            }
+        }
+        set.apply(intermediateSet);
     }
-    QCOMPARE(outputList, inputList);
-#else
 
-    if (changes != output) {
-        qDebug() << output;
-        qDebug() << changes;
+    SignalList changes;
+    foreach (const QQuickChangeSet::Remove &remove, set.removes())
+        changes << Remove(remove.index, remove.count, remove.moveId, remove.offset);
+    foreach (const QQuickChangeSet::Insert &insert, set.inserts())
+        changes << Insert(insert.index, insert.count, insert.moveId, insert.offset);
+
+    SignalList linearChanges;
+    foreach (const QQuickChangeSet::Remove &remove, linearSet.removes())
+        linearChanges << Remove(remove.index, remove.count, remove.moveId, remove.offset);
+    foreach (const QQuickChangeSet::Insert &insert, linearSet.inserts())
+        linearChanges << Insert(insert.index, insert.count, insert.moveId, insert.offset);
+
+    // The output in the failing tests isn't incorrect, merely sub-optimal.
+    QEXPECT_FAIL("3*5 (10)", "inserts not joined when dividing space removed", Abort);
+    QEXPECT_FAIL("3*5 (11)", "inserts not joined when dividing space removed", Abort);
+    QEXPECT_FAIL("3*5 (12)", "inserts not joined when dividing space removed", Abort);
+    QEXPECT_FAIL("3*5 (13)", "inserts not joined when dividing space removed", Abort);
+    QEXPECT_FAIL("3*5 (14)", "inserts not joined when dividing space removed", Abort);
+    QEXPECT_FAIL("3*5 (15)", "inserts not joined when dividing space removed", Abort);
+    QCOMPARE(changes, linearChanges);
+}
+
+void tst_qquickchangeset::removeConsecutive_data()
+{
+    QTest::addColumn<SignalList>("input");
+    QTest::addColumn<SignalList>("output");
+
+    QTest::newRow("at start")
+            << (SignalList() << Remove(0,2) << Remove(0,1) << Remove(0,5))
+            << (SignalList() << Remove(0,8));
+    QTest::newRow("offset")
+            << (SignalList() << Remove(3,2) << Remove(3,1) << Remove(3,5))
+            << (SignalList() << Remove(3,8));
+    QTest::newRow("with move")
+            << (SignalList() << Remove(0,2) << Remove(0,1,0,0) << Remove(0,5))
+            << (SignalList() << Remove(0,2) << Remove(0,1,0,0) << Remove(0,5));
+}
+
+void tst_qquickchangeset::removeConsecutive()
+{
+    QFETCH(SignalList, input);
+    QFETCH(SignalList, output);
+
+    QVector<QQuickChangeSet::Remove> removes;
+    foreach (const Signal &signal, input) {
+        QVERIFY(signal.isRemove());
+        removes.append(QQuickChangeSet::Remove(signal.index, signal.count, signal.moveId, signal.offset));
     }
 
-#endif
+    QQuickChangeSet set;
+    set.remove(removes);
+
+    SignalList changes;
+    foreach (const QQuickChangeSet::Remove &remove, set.removes())
+        changes << Remove(remove.index, remove.count, remove.moveId, remove.offset);
+    QVERIFY(set.inserts().isEmpty());
+    QVERIFY(set.changes().isEmpty());
+
+    VERIFY_EXPECTED_OUTPUT
+    QCOMPARE(changes, output);
+}
+
+void tst_qquickchangeset::insertConsecutive_data()
+{
+    QTest::addColumn<SignalList>("input");
+    QTest::addColumn<SignalList>("output");
+
+    QTest::newRow("at start")
+            << (SignalList() << Insert(0,2) << Insert(2,1) << Insert(3,5))
+            << (SignalList() << Insert(0,8));
+    QTest::newRow("offset")
+            << (SignalList() << Insert(3,2) << Insert(5,1) << Insert(6,5))
+            << (SignalList() << Insert(3,8));
+    QTest::newRow("with move")
+            << (SignalList() << Insert(0,2) << Insert(2,1,0,0) << Insert(3,5))
+            << (SignalList() << Insert(0,2) << Insert(2,1,0,0) << Insert(3,5));
+}
+
+void tst_qquickchangeset::insertConsecutive()
+{
+    QFETCH(SignalList, input);
+    QFETCH(SignalList, output);
 
+    QVector<QQuickChangeSet::Insert> inserts;
+    foreach (const Signal &signal, input) {
+        QVERIFY(signal.isInsert());
+        inserts.append(QQuickChangeSet::Insert(signal.index, signal.count, signal.moveId, signal.offset));
+    }
+
+    QQuickChangeSet set;
+    set.insert(inserts);
+
+    SignalList changes;
+    foreach (const QQuickChangeSet::Insert &insert, set.inserts())
+        changes << Insert(insert.index, insert.count, insert.moveId, insert.offset);
+    QVERIFY(set.removes().isEmpty());
+    QVERIFY(set.changes().isEmpty());
+
+    VERIFY_EXPECTED_OUTPUT
     QCOMPARE(changes, output);
 }
 
+void tst_qquickchangeset::random_data()
+{
+    QTest::addColumn<int>("seed");
+    QTest::addColumn<int>("combinations");
+    QTest::addColumn<int>("depth");
+    QTest::newRow("1*5") << 32 << 1 << 5;
+    QTest::newRow("2*2") << 32 << 2 << 2;
+    QTest::newRow("3*2") << 32 << 3 << 2;
+    QTest::newRow("3*5") << 32 << 3 << 5;
+}
+
+void tst_qquickchangeset::random()
+{
+    QFETCH(int, seed);
+    QFETCH(int, combinations);
+    QFETCH(int, depth);
+
+    qsrand(seed);
+
+    int failures = 0;
+    for (int i = 0; i < 20000; ++i) {
+        QQuickChangeSet accumulatedSet;
+        SignalList input;
+
+        int modelCount = 40;
+        int moveCount = 0;
+
+        for (int j = 0; j < combinations; ++j) {
+            QQuickChangeSet set;
+            for (int k = 0; k < depth; ++k) {
+                switch (-(qrand() % 3)) {
+                case InsertOp: {
+                    int index = qrand() % (modelCount + 1);
+                    int count = qrand() % 5 + 1;
+                    set.insert(index, count);
+                    input.append(Insert(index, count));
+                    modelCount += count;
+                    break;
+                }
+                case RemoveOp: {
+                    const int index = qrand() % (modelCount + 1);
+                    const int count = qrand() % (modelCount - index + 1);
+                    set.remove(index, count);
+                    input.append(Remove(index, count));
+                    modelCount -= count;
+                    break;
+                }
+                case MoveOp: {
+                    const int from = qrand() % (modelCount + 1);
+                    const int count = qrand() % (modelCount - from + 1);
+                    const int to = qrand() % (modelCount - count + 1);
+                    const int moveId = moveCount++;
+                    set.move(from, to, count, moveId);
+                    input.append(Move(from, to, count, moveId));
+                    break;
+                }
+                default:
+                    break;
+                }
+            }
+            accumulatedSet.apply(set);
+        }
+
+        SignalList output;
+        foreach (const QQuickChangeSet::Remove &remove, accumulatedSet.removes())
+            output << Remove(remove.index, remove.count, remove.moveId, remove.offset);
+        foreach (const QQuickChangeSet::Insert &insert, accumulatedSet.inserts())
+            output << Insert(insert.index, insert.count, insert.moveId, insert.offset);
+
+        QVector<int> inputList;
+        for (int i = 0; i < 40; ++i)
+            inputList.append(i);
+        QVector<int> outputList = inputList;
+        if (!applyChanges(inputList, input)) {
+            qDebug() << "Invalid input list";
+            qDebug() << input;
+            qDebug() << inputList;
+            ++failures;
+        } else if (!applyChanges(outputList, output)) {
+            qDebug() << "Invalid output list";
+            qDebug() << input;
+            qDebug() << output;
+            qDebug() << outputList;
+            ++failures;
+        } else if (outputList != inputList) {
+            qDebug() << "Input/output mismatch";
+            qDebug() << input;
+            qDebug() << output;
+            qDebug() << inputList;
+            qDebug() << outputList;
+            ++failures;
+        }
+    }
+    QCOMPARE(failures, 0);
+}
 
 QTEST_MAIN(tst_qquickchangeset)