QQuickListCompositor::iterator &QQuickListCompositor::iterator::operator +=(int difference)
{
- Q_ASSERT(difference >= 0);
- while (!(range->flags & groupFlag)) {
- incrementIndexes(range->count - offset);
- offset = 0;
- range = range->next;
- }
+ // Update all indexes to the start of the range.
decrementIndexes(offset);
+
+ // If the iterator group isn't a member of the current range ignore the current offset.
+ if (!(range->flags & groupFlag))
+ offset = 0;
+
offset += difference;
- while (offset >= range->count || !(range->flags & groupFlag)) {
- if (range->flags & groupFlag)
- offset -= range->count;
- incrementIndexes(range->count);
- range = range->next;
- }
- incrementIndexes(offset);
- return *this;
-}
-QQuickListCompositor::iterator &QQuickListCompositor::iterator::operator -=(int difference)
-{
- Q_ASSERT(difference >= 0);
- while (!(range->flags & groupFlag)) {
- decrementIndexes(offset);
- range = range->previous;
- offset = range->count;
- }
- decrementIndexes(offset);
- offset -= difference;
- while (offset < 0) {
+ // Iterate backwards looking for a range with a positive offset.
+ while (offset <= 0 && range->previous->flags) {
range = range->previous;
if (range->flags & groupFlag)
offset += range->count;
decrementIndexes(range->count);
}
- incrementIndexes(offset);
- return *this;
-}
-QQuickListCompositor::insert_iterator &QQuickListCompositor::insert_iterator::operator +=(int difference)
-{
- Q_ASSERT(difference >= 0);
- while (!(range->flags & groupFlag)) {
- incrementIndexes(range->count - offset);
- offset = 0;
- range = range->next;
- }
- decrementIndexes(offset);
- offset += difference;
- while (offset > range->count
- || (offset == range->count && !range->append() && offset > 0)
- || (!(range->flags & groupFlag) && offset > 0)) {
- Q_ASSERT(range->flags);
+ // Iterate forwards looking for the first range which contains both the offset and the
+ // iterator group.
+ while (range->flags && (offset >= range->count || !(range->flags & groupFlag))) {
if (range->flags & groupFlag)
offset -= range->count;
incrementIndexes(range->count);
range = range->next;
}
+
+ // Update all the indexes to inclue the remaining offset.
incrementIndexes(offset);
+
return *this;
}
-QQuickListCompositor::insert_iterator &QQuickListCompositor::insert_iterator::operator -=(int difference)
+QQuickListCompositor::insert_iterator &QQuickListCompositor::insert_iterator::operator +=(int difference)
{
- Q_ASSERT(difference >= 0);
- while (!(range->flags & groupFlag) && range->previous->flags) {
- decrementIndexes(offset);
- range = range->previous;
- offset = (range->flags & (GroupMask | CacheFlag)) ? range->count : 0;
- }
- decrementIndexes(offset);
- offset -= difference;
- while (offset < 0) {
+ iterator::operator +=(difference);
+
+ // If the previous range contains the append flag move the iterator to the tail of the previous
+ // range so that appended appear after the insert position.
+ if (offset == 0 && range->previous->append()) {
range = range->previous;
- if (range->flags & groupFlag)
- offset += range->count;
- decrementIndexes(range->count);
- }
- incrementIndexes(offset);
- for (Range *previous = range->previous; offset == 0 && previous->prepend(); previous = previous->previous) {
- if (previous->append() && previous->inGroup()) {
- offset = previous->count;
- range = previous;
- } else if (!previous->inGroup()) {
- break;
- }
+ offset = range->inGroup() ? range->count : 0;
}
return *this;
} else {
const int offset = index - m_cacheIt.index[group];
m_cacheIt.setGroup(group);
- if (offset > 0) {
- m_cacheIt += offset;
- } else if (offset < 0) {
- m_cacheIt -= -offset;
- } else if (offset == 0) {
- m_cacheIt -= 0;
- m_cacheIt += 0;
- }
+ m_cacheIt += offset;
}
Q_ASSERT(m_cacheIt.index[group] == index);
Q_ASSERT(m_cacheIt->inGroup(group));
const int offset = index - m_cacheIt.index[group];
it = m_cacheIt;
it.setGroup(group);
- if (offset > 0) {
- it += offset;
- } else if (offset < 0) {
- it -= -offset;
- } else if (offset == 0) {
- it -= 0;
- it += 0;
- }
+ it += offset;
}
Q_ASSERT(it.index[group] == index);
return it;
void QQuickListCompositor::setFlags(
Group fromGroup, int from, int count, Group group, int flags, QVector<Insert> *inserts)
{
- QT_QML_TRACE_LISTCOMPOSITOR(<< group << index << count << flags)
+ QT_QML_TRACE_LISTCOMPOSITOR(<< fromGroup << from << count << group << flags)
setFlags(find(fromGroup, from), count, group, flags, inserts);
}
void QQuickListCompositor::clearFlags(
Group fromGroup, int from, int count, Group group, uint flags, QVector<Remove> *removes)
{
- QT_QML_TRACE_LISTCOMPOSITOR(<< group << index << count << flags)
+ QT_QML_TRACE_LISTCOMPOSITOR(<< fromGroup << from << count << group << flags)
clearFlags(find(fromGroup, from), count, group, flags, removes);
}
return to >= 0 && to + count <= m_end.index[toGroup];
}
+/*!
+ \internal
+
+ Moves \a count items belonging to \a moveGroup from the index \a from in \a fromGroup
+ to the index \a to in \a toGroup.
+
+ If \a removes and \a inserts are not null they will be populated with per group notifications
+ of the items moved.
+ */
+
void QQuickListCompositor::move(
Group fromGroup,
int from,
Group toGroup,
int to,
int count,
- Group group,
+ Group moveGroup,
QVector<Remove> *removes,
QVector<Insert> *inserts)
{
QT_QML_TRACE_LISTCOMPOSITOR(<< fromGroup << from << toGroup << to << count)
- Q_ASSERT(count != 0);
- Q_ASSERT(from >=0 && from + count <= m_end.index[toGroup]);
- Q_ASSERT(verifyMoveTo(fromGroup, from, toGroup, to, count, group));
+ Q_ASSERT(count > 0);
+ Q_ASSERT(from >=0);
+ Q_ASSERT(verifyMoveTo(fromGroup, from, toGroup, to, count, moveGroup));
+ // Find the position of the first item to move.
iterator fromIt = find(fromGroup, from);
- if (fromIt != group) {
+
+ if (fromIt != moveGroup) {
+ // If the range at the from index doesn't contain items from the move group; skip
+ // to the next range.
fromIt.incrementIndexes(fromIt->count - fromIt.offset);
fromIt.offset = 0;
*fromIt = fromIt->next;
} else if (fromIt.offset > 0) {
+ // If the range at the from index contains items from the move group and the index isn't
+ // at the start of the range; split the range at the index and move the iterator to start
+ // of the second range.
*fromIt = insert(
*fromIt, fromIt->list, fromIt->index, fromIt.offset, fromIt->flags & ~AppendFlag)->next;
fromIt->index += fromIt.offset;
fromIt.offset = 0;
}
+ // Remove count items belonging to the move group from the list.
Range movedFlags;
for (int moveId = 0; count > 0;) {
- if (fromIt != group) {
+ if (fromIt != moveGroup) {
+ // Skip ranges not containing items from the move group.
fromIt.incrementIndexes(fromIt->count);
*fromIt = fromIt->next;
continue;
}
int difference = qMin(count, fromIt->count);
+ // Create a new static range containing the moved items from an existing range.
new Range(
&movedFlags,
fromIt->list,
fromIt->index,
difference,
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++));
count -= difference;
fromIt->count -= difference;
+ // If the existing range contains the prepend flag replace the removed items with
+ // a placeholder range for new items inserted into the source model.
int removeIndex = fromIt->index;
if (fromIt->prepend()
&& fromIt->previous != &m_ranges
&& fromIt->previous->flags == PrependFlag
&& fromIt->previous->list == fromIt->list
&& fromIt->previous->end() == fromIt->index) {
+ // Grow the previous range instead of creating a new one if possible.
fromIt->previous->count += difference;
} else if (fromIt->prepend()) {
*fromIt = insert(*fromIt, fromIt->list, removeIndex, difference, PrependFlag)->next;
fromIt->index += difference;
if (fromIt->count == 0) {
+ // If the existing range has no items remaining; remove it from the list.
if (fromIt->append())
fromIt->previous->flags |= AppendFlag;
*fromIt = erase(*fromIt);
+ // If the ranges before and after the removed range can be joined, do so.
if (*fromIt != m_ranges.next && fromIt->flags == PrependFlag
&& fromIt->previous != &m_ranges
&& fromIt->previous->flags == PrependFlag
}
}
+ // Try and join the range following the removed items to the range preceding it.
if (*fromIt != m_ranges.next
&& *fromIt != &m_ranges
&& fromIt->previous->list == fromIt->list
*fromIt = erase(*fromIt)->previous;
}
+ // Find the destination position of the move.
insert_iterator toIt = fromIt;
toIt.setGroup(toGroup);
+
const int difference = to - toIt.index[toGroup];
- if (difference > 0)
- toIt += difference;
- else
- toIt -= -difference;
+ toIt += difference;
+ // If the insert position is part way through a range; split it and move the iterator to the
+ // start of the second range.
if (toIt.offset > 0) {
*toIt = insert(*toIt, toIt->list, toIt->index, toIt.offset, toIt->flags & ~AppendFlag)->next;
toIt->index += toIt.offset;
toIt.offset = 0;
}
+ // Insert the moved ranges before the insert iterator, growing the previous range if that
+ // is an option.
for (Range *range = movedFlags.previous; range != &movedFlags; range = range->previous) {
if (*toIt != &m_ranges
&& range->list == toIt->list
}
}
+ // Try and join the range after the inserted ranges to the last range inserted.
if (*toIt != m_ranges.next
&& toIt->previous->list == toIt->list
&& (!toIt->list || (toIt->previous->end() == toIt->index && toIt->previous->flags == (toIt->flags & ~AppendFlag)))) {
toIt->previous->flags = toIt->flags;
*toIt = erase(*toIt)->previous;
}
+ // Create insert notification for the ranges moved.
Insert insert(toIt, 0, 0, 0);
for (Range *next, *range = movedFlags.next; range != &movedFlags; range = next) {
insert.count = range->count;
}
m_cacheIt = toIt;
+
QT_QML_VERIFY_LISTCOMPOSITOR
}
<< Range(a, 1, 1, int(C::AppendFlag | C::PrependFlag | C::CacheFlag))
<< Range(0, 0, 1, int(VisibleFlag| C::CacheFlag)))
<< Selection << 1
- << 1 << 0 << 1 << 1
- << uint(C::AppendFlag | C::PrependFlag | C::CacheFlag) << 1;
+ << 1 << 1 << 1 << 3
+ << uint(0) << 0;
}
void tst_qquicklistcompositor::findInsertPosition()
compositor.append(range.list, range.index, range.count, range.flags);
QQuickListCompositor::insert_iterator it = compositor.findInsertPosition(group, index);
+
QCOMPARE(it.index[C::Cache], cacheIndex);
QCOMPARE(it.index[C::Default], defaultIndex);
QCOMPARE(it.index[Visible], visibleIndex);
C::Default, 0, c, 6, 4, C::DefaultFlag);
const int indexes[] = {6,7,8,9,0,1,2,3,4,5,6,7,8,9,10,11,4,5,6,7,2,3};
const int *lists[] = {c,c,c,c,a,a,a,a,a,a,a,a,a,a, a, a,b,b,b,b,c,c};
- QCOMPARE(compositor.count(C::Default), lengthOf(indexes));
for (int i = 0; i < lengthOf(indexes); ++i) {
it = compositor.find(C::Default, i);
QCOMPARE(it.list<int>(), lists[i]);
<< IndexArray(defaultIndexes) << ListArray(defaultLists)
<< IndexArray() << ListArray()
<< IndexArray() << ListArray();
+ } { static const int cacheIndexes[] = {1,2,3,4,5,6,0,8,9};
+ static const void *cacheLists[] = {a,a,a,a,a,a,a,a,a};
+ static const int defaultIndexes[] = {1,2,3,4,5,6,0,8,9};
+ static const void *defaultLists[] = {a,a,a,a,a,a,a,a,a};
+ static const int visibleIndexes[] = {0,7,10};
+ static const void *visibleLists[] = {a,a, a};
+ QTest::newRow("0, 6, 3")
+ << (RangeList()
+ << Range(a, 0, 1, C::PrependFlag)
+ << Range(a, 1, 6, C::PrependFlag | C::DefaultFlag | C::CacheFlag)
+ << Range(a, 0, 1, VisibleFlag | C::DefaultFlag | C::CacheFlag)
+ << Range(a, 7, 1, VisibleFlag)
+ << Range(a,10, 1, VisibleFlag)
+ << Range(a, 7, 1, C::PrependFlag)
+ << Range(a, 8, 2, C::AppendFlag | C::PrependFlag | C::DefaultFlag | C::CacheFlag))
+ << Visible << 0 << C::Default << 6 << 3
+ << (RemoveList()
+ << Remove(0, 0, 6, 6, 1, VisibleFlag | C::DefaultFlag | C::CacheFlag, 0)
+ << Remove(0, 0, 6, 6, 1, VisibleFlag, 1)
+ << Remove(0, 0, 6, 6, 1, VisibleFlag, 2))
+ << (InsertList()
+ << Insert(0, 0, 6, 6, 1, VisibleFlag | C::DefaultFlag | C::CacheFlag, 0)
+ << Insert(0, 1, 7, 7, 1, VisibleFlag, 1)
+ << Insert(0, 2, 7, 7, 1, VisibleFlag, 2))
+ << IndexArray(cacheIndexes) << ListArray(cacheLists)
+ << IndexArray(defaultIndexes) << ListArray(defaultLists)
+ << IndexArray(visibleIndexes) << ListArray(visibleLists)
+ << IndexArray() << ListArray();
}
}