diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/kitemviews/kfileitemmodel.cpp | 20 | ||||
| -rw-r--r-- | src/kitemviews/kitemlistselectionmanager.cpp | 46 | ||||
| -rw-r--r-- | src/kitemviews/kitemlistselectionmanager.h | 1 | ||||
| -rw-r--r-- | src/kitemviews/kitemlistview.cpp | 13 | ||||
| -rw-r--r-- | src/kitemviews/kitemlistview.h | 1 | ||||
| -rw-r--r-- | src/kitemviews/kitemmodelbase.h | 17 | ||||
| -rw-r--r-- | src/tests/kfileitemmodeltest.cpp | 33 | ||||
| -rw-r--r-- | src/tests/kitemlistselectionmanagertest.cpp | 91 |
8 files changed, 189 insertions, 33 deletions
diff --git a/src/kitemviews/kfileitemmodel.cpp b/src/kitemviews/kfileitemmodel.cpp index 7874d3025..0d6f60336 100644 --- a/src/kitemviews/kfileitemmodel.cpp +++ b/src/kitemviews/kfileitemmodel.cpp @@ -732,6 +732,8 @@ void KFileItemModel::resortAllItems() return; } + const KFileItemList oldSortedItems = m_sortedItems; + KFileItemList sortedItems = m_sortedItems; m_sortedItems.clear(); m_items.clear(); @@ -748,12 +750,28 @@ void KFileItemModel::resortAllItems() ++index; } + bool emitItemsMoved = false; + QList<int> movedToIndexes; + movedToIndexes.reserve(sortedItems.count()); + for (int i = 0; i < itemCount; i++) { + const int newIndex = m_items.value(oldSortedItems.at(i).url()); + movedToIndexes.append(newIndex); + if (!emitItemsMoved && newIndex != i) { + emitItemsMoved = true; + } + } + + if (emitItemsMoved) { + // TODO: + // * Implement KItemListView::slotItemsMoved() (which should call KItemListSelectionManager::itemsMoved()) + // * Do not emit itemsRemoved()/itemsInserted() here. + emit itemsMoved(KItemRange(0, itemCount), movedToIndexes); + } emit itemsInserted(KItemRangeList() << KItemRange(0, itemCount)); } void KFileItemModel::removeExpandedItems() { - KFileItemList expandedItems; const int maxIndex = m_data.count() - 1; diff --git a/src/kitemviews/kitemlistselectionmanager.cpp b/src/kitemviews/kitemlistselectionmanager.cpp index 63306a3f2..131ee46e6 100644 --- a/src/kitemviews/kitemlistselectionmanager.cpp +++ b/src/kitemviews/kitemlistselectionmanager.cpp @@ -239,6 +239,7 @@ void KItemListSelectionManager::itemsInserted(const KItemRangeList& itemRanges) if (!m_selectedItems.isEmpty()) { const QSet<int> previous = m_selectedItems; m_selectedItems.clear(); + m_selectedItems.reserve(previous.count()); QSetIterator<int> it(previous); while (it.hasNext()) { const int index = it.next(); @@ -307,6 +308,7 @@ void KItemListSelectionManager::itemsRemoved(const KItemRangeList& itemRanges) if (!m_selectedItems.isEmpty()) { const QSet<int> previous = m_selectedItems; m_selectedItems.clear(); + m_selectedItems.reserve(previous.count()); QSetIterator<int> it(previous); while (it.hasNext()) { int index = it.next(); @@ -338,4 +340,48 @@ void KItemListSelectionManager::itemsRemoved(const KItemRangeList& itemRanges) } } +void KItemListSelectionManager::itemsMoved(const KItemRange& itemRange, const QList<int>& movedToIndexes) +{ + // Store the current selection (needed in the selectionChanged() signal) + const QSet<int> previousSelection = selectedItems(); + + // Update the current item + if (m_currentItem >= itemRange.index && m_currentItem < itemRange.index + itemRange.count) { + const int previousCurrentItem = m_currentItem; + const int newCurrentItem = movedToIndexes.at(previousCurrentItem - itemRange.index); + + // Calling setCurrentItem would trigger the selectionChanged signal, but we want to + // emit it only once in this function -> change the current item manually and emit currentChanged + m_currentItem = newCurrentItem; + emit currentChanged(newCurrentItem, previousCurrentItem); + } + + // Update the anchor item + if (m_anchorItem >= itemRange.index && m_anchorItem < itemRange.index + itemRange.count) { + m_anchorItem = movedToIndexes.at(m_anchorItem - itemRange.index); + } + + // Update the selections + if (!m_selectedItems.isEmpty()) { + const QSet<int> previous = m_selectedItems; + m_selectedItems.clear(); + m_selectedItems.reserve(previous.count()); + QSetIterator<int> it(previous); + while (it.hasNext()) { + const int index = it.next(); + if (index >= itemRange.index && index < itemRange.index + itemRange.count) { + m_selectedItems.insert(movedToIndexes.at(index - itemRange.index)); + } + else { + m_selectedItems.insert(index); + } + } + } + + const QSet<int> selection = selectedItems(); + if (selection != previousSelection) { + emit selectionChanged(selection, previousSelection); + } +} + #include "kitemlistselectionmanager.moc" diff --git a/src/kitemviews/kitemlistselectionmanager.h b/src/kitemviews/kitemlistselectionmanager.h index 8b3a121a6..a8ef5ca2d 100644 --- a/src/kitemviews/kitemlistselectionmanager.h +++ b/src/kitemviews/kitemlistselectionmanager.h @@ -73,6 +73,7 @@ private: void setModel(KItemModelBase* model); void itemsInserted(const KItemRangeList& itemRanges); void itemsRemoved(const KItemRangeList& itemRanges); + void itemsMoved(const KItemRange& itemRange, const QList<int>& movedToIndexes); private: int m_currentItem; diff --git a/src/kitemviews/kitemlistview.cpp b/src/kitemviews/kitemlistview.cpp index 988a45d40..63315b665 100644 --- a/src/kitemviews/kitemlistview.cpp +++ b/src/kitemviews/kitemlistview.cpp @@ -762,6 +762,15 @@ void KItemListView::slotItemsRemoved(const KItemRangeList& itemRanges) } } +void KItemListView::slotItemsMoved(const KItemRange& itemRange, const QList<int>& movedToIndexes) +{ + // TODO: + // * Implement KItemListView::slotItemsMoved() (which should call KItemListSelectionManager::itemsMoved()) + // * Do not emit itemsRemoved()/itemsInserted() in KFileItemModel::resortAllItems() + Q_UNUSED(itemRange); + Q_UNUSED(movedToIndexes); +} + void KItemListView::slotItemsChanged(const KItemRangeList& itemRanges, const QSet<QByteArray>& roles) { @@ -1031,6 +1040,8 @@ void KItemListView::setModel(KItemModelBase* model) this, SLOT(slotItemsInserted(KItemRangeList))); disconnect(m_model, SIGNAL(itemsRemoved(KItemRangeList)), this, SLOT(slotItemsRemoved(KItemRangeList))); + disconnect(m_model, SIGNAL(itemsMoved(KItemRangeList,QList<int>)), + this, SLOT(slotItemsMoved(KItemRangeList,QList<int>))); } m_model = model; @@ -1044,6 +1055,8 @@ void KItemListView::setModel(KItemModelBase* model) this, SLOT(slotItemsInserted(KItemRangeList))); connect(m_model, SIGNAL(itemsRemoved(KItemRangeList)), this, SLOT(slotItemsRemoved(KItemRangeList))); + connect(m_model, SIGNAL(itemsMoved(KItemRangeList,QList<int>)), + this, SLOT(slotItemsMoved(KItemRangeList,QList<int>))); } onModelChanged(model, previous); diff --git a/src/kitemviews/kitemlistview.h b/src/kitemviews/kitemlistview.h index 73b736bf7..e49dbe48d 100644 --- a/src/kitemviews/kitemlistview.h +++ b/src/kitemviews/kitemlistview.h @@ -246,6 +246,7 @@ protected: protected slots: virtual void slotItemsInserted(const KItemRangeList& itemRanges); virtual void slotItemsRemoved(const KItemRangeList& itemRanges); + virtual void slotItemsMoved(const KItemRange& itemRange, const QList<int>& movedToIndexes); virtual void slotItemsChanged(const KItemRangeList& itemRanges, const QSet<QByteArray>& roles); diff --git a/src/kitemviews/kitemmodelbase.h b/src/kitemviews/kitemmodelbase.h index 742bc2915..763a02efd 100644 --- a/src/kitemviews/kitemmodelbase.h +++ b/src/kitemviews/kitemmodelbase.h @@ -34,7 +34,7 @@ class QMimeData; struct KItemRange { - KItemRange(int index, int count); + KItemRange(int index = 0, int count = 0); int index; int count; @@ -180,20 +180,15 @@ signals: /** * Is emitted if one ore more items get moved. - * @param itemRanges Item-ranges that get moved to a new position. - * @param movedToIndexes New positions for each element of the item-ranges. + * @param itemRange Item-range that gets moved to a new position. + * @param movedToIndexes New positions for each element of the item-range. * * For example if the model has 10 items and the items 0 and 1 get exchanged * with the items 5 and 6 then the parameters look like this: - * - itemRanges: Contains two ranges. The first has the index 0 and a count of - * 2 and the second as the index 5 and a count of 2. - * - movedToIndexes: Contains the four values 5, 6, 0, 1 - * - * For the item-ranges it is assured that: - * - They don't overlap - * - The index of item-range n is smaller than the index of item-range n + 1. + * - itemRange: has the index 0 and a count of 7. + * - movedToIndexes: Contains the seven values 5, 6, 2, 3, 4, 0, 1 */ - void itemsMoved(const KItemRangeList& itemRanges, const QList<int> movedToIndexes); + void itemsMoved(const KItemRange& itemRange, const QList<int>& movedToIndexes); void itemsChanged(const KItemRangeList& itemRanges, const QSet<QByteArray>& roles); diff --git a/src/tests/kfileitemmodeltest.cpp b/src/tests/kfileitemmodeltest.cpp index ea8c19c05..f56ef9033 100644 --- a/src/tests/kfileitemmodeltest.cpp +++ b/src/tests/kfileitemmodeltest.cpp @@ -29,6 +29,7 @@ namespace { }; Q_DECLARE_METATYPE(KItemRangeList) +Q_DECLARE_METATYPE(QList<int>) class KFileItemModelTest : public QObject { @@ -65,6 +66,7 @@ private: void KFileItemModelTest::init() { + qRegisterMetaType<KItemRange>("KItemRange"); qRegisterMetaType<KItemRangeList>("KItemRangeList"); qRegisterMetaType<KFileItemList>("KFileItemList"); @@ -355,23 +357,31 @@ void KFileItemModelTest::testSorting() //QVERIFY(!m_model->showHiddenFiles()); QCOMPARE(itemsInModel(), QStringList() << "c" << "a" << "b" << "d" << "e"); + QSignalSpy spyItemsMoved(m_model, SIGNAL(itemsMoved(KItemRange,QList<int>))); + // Sort by Name, descending m_model->setSortOrder(Qt::DescendingOrder); QCOMPARE(m_model->sortRole(), QByteArray("name")); QCOMPARE(m_model->sortOrder(), Qt::DescendingOrder); QCOMPARE(itemsInModel(), QStringList() << "c" << "e" << "d" << "b" << "a"); + QCOMPARE(spyItemsMoved.count(), 1); + QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 0 << 4 << 3 << 2 << 1); - // Sort by Date, decending + // Sort by Date, descending m_model->setSortRole("date"); QCOMPARE(m_model->sortRole(), QByteArray("date")); QCOMPARE(m_model->sortOrder(), Qt::DescendingOrder); QCOMPARE(itemsInModel(), QStringList() << "c" << "b" << "d" << "a" << "e"); + QCOMPARE(spyItemsMoved.count(), 1); + QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 0 << 4 << 2 << 1 << 3); // Sort by Date, ascending m_model->setSortOrder(Qt::AscendingOrder); QCOMPARE(m_model->sortRole(), QByteArray("date")); QCOMPARE(m_model->sortOrder(), Qt::AscendingOrder); QCOMPARE(itemsInModel(), QStringList() << "c" << "e" << "a" << "d" << "b"); + QCOMPARE(spyItemsMoved.count(), 1); + QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 0 << 4 << 3 << 2 << 1); // Sort by Date, ascending, 'Sort Folders First' disabled m_model->setSortFoldersFirst(false); @@ -379,20 +389,33 @@ void KFileItemModelTest::testSorting() QCOMPARE(m_model->sortOrder(), Qt::AscendingOrder); QVERIFY(!m_model->sortFoldersFirst()); QCOMPARE(itemsInModel(), QStringList() << "e" << "a" << "c" << "d" << "b"); + QCOMPARE(spyItemsMoved.count(), 1); + QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 2 << 0 << 1 << 3 << 4); - // Default: Sort by Name, ascending, 'Sort Folders First' disabled + // Sort by Name, ascending, 'Sort Folders First' disabled m_model->setSortRole("name"); QCOMPARE(m_model->sortOrder(), Qt::AscendingOrder); QVERIFY(!m_model->sortFoldersFirst()); QCOMPARE(itemsInModel(), QStringList() << "a" << "b" << "c" << "d" << "e"); + QCOMPARE(spyItemsMoved.count(), 1); + QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 4 << 0 << 2 << 3 << 1); - // Sort by Size, ascending, 'Sort Folders First' enabled + // Sort by Size, ascending, 'Sort Folders First' disabled m_model->setSortRole("size"); + QCOMPARE(m_model->sortRole(), QByteArray("size")); + QCOMPARE(m_model->sortOrder(), Qt::AscendingOrder); + QVERIFY(!m_model->sortFoldersFirst()); + QCOMPARE(itemsInModel(), QStringList() << "c" << "a" << "b" << "e" << "d"); + QCOMPARE(spyItemsMoved.count(), 1); + QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 1 << 2 << 0 << 4 << 3); + + // In 'Sort by Size' mode, folders are always first -> changing 'Sort Folders First' does not resort the model m_model->setSortFoldersFirst(true); QCOMPARE(m_model->sortRole(), QByteArray("size")); QCOMPARE(m_model->sortOrder(), Qt::AscendingOrder); QVERIFY(m_model->sortFoldersFirst()); QCOMPARE(itemsInModel(), QStringList() << "c" << "a" << "b" << "e" << "d"); + QCOMPARE(spyItemsMoved.count(), 0); // Sort by Size, descending, 'Sort Folders First' enabled m_model->setSortOrder(Qt::DescendingOrder); @@ -400,8 +423,8 @@ void KFileItemModelTest::testSorting() QCOMPARE(m_model->sortOrder(), Qt::DescendingOrder); QVERIFY(m_model->sortFoldersFirst()); QCOMPARE(itemsInModel(), QStringList() << "c" << "d" << "e" << "b" << "a"); - - // TODO: How shall the sorting by size be done if 'Sort Folders First' is disabled? + QCOMPARE(spyItemsMoved.count(), 1); + QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 0 << 4 << 3 << 2 << 1); // TODO: Sort by other roles; show/hide hidden files } diff --git a/src/tests/kitemlistselectionmanagertest.cpp b/src/tests/kitemlistselectionmanagertest.cpp index c27096177..2a3601bb0 100644 --- a/src/tests/kitemlistselectionmanagertest.cpp +++ b/src/tests/kitemlistselectionmanagertest.cpp @@ -297,14 +297,44 @@ namespace { NoChange, InsertItems, RemoveItems, + MoveItems, EndAnchoredSelection, - ToggleSelected + SetSelected }; } Q_DECLARE_METATYPE(QSet<int>); Q_DECLARE_METATYPE(ChangeType); +Q_DECLARE_METATYPE(KItemRange); Q_DECLARE_METATYPE(KItemRangeList); +Q_DECLARE_METATYPE(KItemListSelectionManager::SelectionMode); +Q_DECLARE_METATYPE(QList<int>); + +/** + * The following function provides a generic way to test the selection functionality. + * + * The test is data-driven and takes the following arguments: + * + * \param initialSelection The selection at the beginning. + * \param anchor This item will be the anchor item. + * \param current This item will be the current item. + * \param expectedSelection Expected selection after anchor and current are set. + * \param changeType Type of the change that is done then: + * - NoChange + * - InsertItems -> data.at(0) provides the KItemRangeList. \sa KItemListSelectionManager::itemsInserted() + * - RemoveItems -> data.at(0) provides the KItemRangeList. \sa KItemListSelectionManager::itemsRemoved() + * - MoveItems -> data.at(0) provides the KItemRange containing the original indices, + * data.at(1) provides the list containing the new indices + * \sa KItemListSelectionManager::itemsMoved(), KItemModelBase::itemsMoved() + * - EndAnchoredSelection + * - SetSelected -> data.at(0) provides the index where the selection process starts, + * data.at(1) provides the number of indices to be selected, + * data.at(2) provides the selection mode. + * \sa KItemListSelectionManager::setSelected() + * \param data A list of QVariants which will be cast to the arguments needed for the chosen ChangeType (see above). + * \param finalSelection The expected final selection. + * + */ void KItemListSelectionManagerTest::testChangeSelection_data() { @@ -313,43 +343,68 @@ void KItemListSelectionManagerTest::testChangeSelection_data() QTest::addColumn<int>("current"); QTest::addColumn<QSet<int> >("expectedSelection"); QTest::addColumn<ChangeType>("changeType"); - QTest::addColumn<KItemRangeList>("changedItems"); + QTest::addColumn<QList<QVariant> >("data"); QTest::addColumn<QSet<int> >("finalSelection"); QTest::newRow("No change") << (QSet<int>() << 5 << 6) << 2 << 3 << (QSet<int>() << 2 << 3 << 5 << 6) - << NoChange << KItemRangeList() + << NoChange + << QList<QVariant>() << (QSet<int>() << 2 << 3 << 5 << 6); QTest::newRow("Insert Items") << (QSet<int>() << 5 << 6) << 2 << 3 << (QSet<int>() << 2 << 3 << 5 << 6) - << InsertItems << (KItemRangeList() << KItemRange(1, 1) << KItemRange(5, 2) << KItemRange(10, 5)) + << InsertItems + << (QList<QVariant>() << QVariant::fromValue(KItemRangeList() << KItemRange(1, 1) << KItemRange(5, 2) << KItemRange(10, 5))) << (QSet<int>() << 3 << 4 << 8 << 9); QTest::newRow("Remove Items") << (QSet<int>() << 5 << 6) << 2 << 3 << (QSet<int>() << 2 << 3 << 5 << 6) - << RemoveItems << (KItemRangeList() << KItemRange(1, 1) << KItemRange(3, 1) << KItemRange(10, 5)) + << RemoveItems + << (QList<QVariant>() << QVariant::fromValue(KItemRangeList() << KItemRange(1, 1) << KItemRange(3, 1) << KItemRange(10, 5))) << (QSet<int>() << 1 << 2 << 3 << 4); QTest::newRow("Empty Anchored Selection") << QSet<int>() << 2 << 2 << QSet<int>() - << EndAnchoredSelection << KItemRangeList() + << EndAnchoredSelection + << QList<QVariant>() << QSet<int>(); QTest::newRow("Toggle selection") << (QSet<int>() << 1 << 3 << 4) << 6 << 8 << (QSet<int>() << 1 << 3 << 4 << 6 << 7 << 8) - << ToggleSelected << (KItemRangeList() << KItemRange(0, 10)) + << SetSelected + << (QList<QVariant>() << 0 << 10 << QVariant::fromValue(KItemListSelectionManager::Toggle)) << (QSet<int>() << 0 << 2 << 5 << 9); + + // Swap items 2, 3 and 4, 5 + QTest::newRow("Move items") + << (QSet<int>() << 0 << 1 << 2 << 3) + << -1 << -1 + << (QSet<int>() << 0 << 1 << 2 << 3) + << MoveItems + << (QList<QVariant>() << QVariant::fromValue(KItemRange(2, 4)) + << QVariant::fromValue(QList<int>() << 4 << 5 << 2 << 3)) + << (QSet<int>() << 0 << 1 << 4 << 5); + + // Revert sort order + QTest::newRow("Revert sort order") + << (QSet<int>() << 0 << 1) + << 3 << 4 + << (QSet<int>() << 0 << 1 << 3 << 4) + << MoveItems + << (QList<QVariant>() << QVariant::fromValue(KItemRange(0, 10)) + << QVariant::fromValue(QList<int>() << 9 << 8 << 7 << 6 << 5 << 4 << 3 << 2 << 1 << 0)) + << (QSet<int>() << 5 << 6 << 8 << 9); } void KItemListSelectionManagerTest::testChangeSelection() @@ -357,10 +412,10 @@ void KItemListSelectionManagerTest::testChangeSelection() QFETCH(QSet<int>, initialSelection); QFETCH(int, anchor); QFETCH(int, current); - QFETCH(QSet<int> , expectedSelection); + QFETCH(QSet<int>, expectedSelection); QFETCH(ChangeType, changeType); - QFETCH(KItemRangeList, changedItems); - QFETCH(QSet<int> , finalSelection); + QFETCH(QList<QVariant>, data); + QFETCH(QSet<int>, finalSelection); QSignalSpy spySelectionChanged(m_selectionManager, SIGNAL(selectionChanged(QSet<int>,QSet<int>))); @@ -406,19 +461,23 @@ void KItemListSelectionManagerTest::testChangeSelection() // Change the model by inserting or removing items. switch (changeType) { case InsertItems: - m_selectionManager->itemsInserted(changedItems); + m_selectionManager->itemsInserted(data.at(0).value<KItemRangeList>()); break; case RemoveItems: - m_selectionManager->itemsRemoved(changedItems); + m_selectionManager->itemsRemoved(data.at(0).value<KItemRangeList>()); + break; + case MoveItems: + m_selectionManager->itemsMoved(data.at(0).value<KItemRange>(), + data.at(1).value<QList<int> >()); break; case EndAnchoredSelection: m_selectionManager->endAnchoredSelection(); QVERIFY(!m_selectionManager->isAnchoredSelectionActive()); break; - case ToggleSelected: - foreach(const KItemRange& range, changedItems) { - m_selectionManager->setSelected(range.index, range.count, KItemListSelectionManager::Toggle); - } + case SetSelected: + m_selectionManager->setSelected(data.at(0).value<int>(), // index + data.at(1).value<int>(), // count + data.at(2).value<KItemListSelectionManager::SelectionMode>()); break; case NoChange: break; |
