From fc2ab478989fb4effc14c06aa56fdb29d3143b35 Mon Sep 17 00:00:00 2001 From: Frank Reininghaus Date: Wed, 30 Oct 2013 23:21:09 +0100 Subject: [PATCH] Store the selected items in a more efficient way Since Dolphin 2.0, we have stored the selected items in a QSet, which is neither space-efficient nor particularly fast when inserting many items which are in a consecutive range. This commit replaces the QSet by a new class "KItemSet", which stores the items in a sorted list of ranges. For each range, we only store the first index and the length of the range, so we need a lot less memory for most common selection patterns, and we also save quite a few CPU cycles in many situations, because adding an item to the KItemSet will in many cases not need a memory allocation at all, and it's particularly easy when inserting sorted items into the KItemSet in a row. KItemSet contains a minimal subset of QSet's API which makes it suitable as a drop-in replacement for our needs. It also has iterators, such that the items can be iterated through easily, also with foreach. One advantage of KItemSet compared to QSet is that the items are always iterated through in ascending order. REVIEW: 113488 --- src/CMakeLists.txt | 1 + src/kitemviews/kfileitemlistview.cpp | 6 +- src/kitemviews/kfileitemlistview.h | 2 +- src/kitemviews/kfileitemmodel.cpp | 6 +- src/kitemviews/kfileitemmodel.h | 3 +- src/kitemviews/kitemlistcontroller.cpp | 16 +- src/kitemviews/kitemlistcontroller.h | 9 +- src/kitemviews/kitemlistselectionmanager.cpp | 57 +- src/kitemviews/kitemlistselectionmanager.h | 10 +- src/kitemviews/kitemlistview.cpp | 10 +- src/kitemviews/kitemlistview.h | 4 +- src/kitemviews/kitemlistviewaccessible.cpp | 2 +- src/kitemviews/kitemmodelbase.cpp | 2 +- src/kitemviews/kitemmodelbase.h | 4 +- src/kitemviews/kitemset.cpp | 348 +++++++++++ src/kitemviews/kitemset.h | 413 +++++++++++++ src/kitemviews/kstandarditemmodel.cpp | 2 +- src/kitemviews/kstandarditemmodel.h | 2 +- src/panels/places/placesitemmodel.cpp | 2 +- src/panels/places/placesitemmodel.h | 2 +- src/tests/CMakeLists.txt | 12 + src/tests/kitemlistcontrollertest.cpp | 202 +++--- src/tests/kitemlistselectionmanagertest.cpp | 100 +-- src/tests/kitemsettest.cpp | 612 +++++++++++++++++++ src/views/dolphinview.cpp | 29 +- src/views/dolphinview.h | 6 +- 26 files changed, 1617 insertions(+), 245 deletions(-) create mode 100644 src/kitemviews/kitemset.cpp create mode 100644 src/kitemviews/kitemset.h create mode 100644 src/tests/kitemsettest.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 48ea14c18e..7710ddf928 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -53,6 +53,7 @@ set(dolphinprivate_LIB_SRCS kitemviews/kitemlistviewaccessible.cpp kitemviews/kitemlistwidget.cpp kitemviews/kitemmodelbase.cpp + kitemviews/kitemset.cpp kitemviews/kstandarditem.cpp kitemviews/kstandarditemlistgroupheader.cpp kitemviews/kstandarditemlistwidget.cpp diff --git a/src/kitemviews/kfileitemlistview.cpp b/src/kitemviews/kfileitemlistview.cpp index 8950c9a1ee..fd01f2c4c2 100644 --- a/src/kitemviews/kfileitemlistview.cpp +++ b/src/kitemviews/kfileitemlistview.cpp @@ -119,7 +119,7 @@ QStringList KFileItemListView::enabledPlugins() const return m_modelRolesUpdater ? m_modelRolesUpdater->enabledPlugins() : QStringList(); } -QPixmap KFileItemListView::createDragPixmap(const QSet& indexes) const +QPixmap KFileItemListView::createDragPixmap(const KItemSet& indexes) const { if (!model()) { return QPixmap(); @@ -165,10 +165,8 @@ QPixmap KFileItemListView::createDragPixmap(const QSet& indexes) const QPainter painter(&dragPixmap); int x = 0; int y = 0; - QSetIterator it(indexes); - while (it.hasNext()) { - const int index = it.next(); + foreach (int index, indexes) { QPixmap pixmap = model()->data(index).value("iconPixmap").value(); if (pixmap.isNull()) { KIcon icon(model()->data(index).value("iconName").toString()); diff --git a/src/kitemviews/kfileitemlistview.h b/src/kitemviews/kfileitemlistview.h index bdc63b01bd..2fd21edbfd 100644 --- a/src/kitemviews/kfileitemlistview.h +++ b/src/kitemviews/kfileitemlistview.h @@ -73,7 +73,7 @@ public: QStringList enabledPlugins() const; /** @reimp */ - virtual QPixmap createDragPixmap(const QSet& indexes) const; + virtual QPixmap createDragPixmap(const KItemSet& indexes) const; protected: virtual KItemListWidgetCreatorBase* defaultWidgetCreator() const; diff --git a/src/kitemviews/kfileitemmodel.cpp b/src/kitemviews/kfileitemmodel.cpp index e2d0413a26..261b23046d 100644 --- a/src/kitemviews/kfileitemmodel.cpp +++ b/src/kitemviews/kfileitemmodel.cpp @@ -237,7 +237,7 @@ bool KFileItemModel::showDirectoriesOnly() const return m_dirLister->dirOnlyMode(); } -QMimeData* KFileItemModel::createMimeData(const QSet& indexes) const +QMimeData* KFileItemModel::createMimeData(const KItemSet& indexes) const { QMimeData* data = new QMimeData(); @@ -248,9 +248,7 @@ QMimeData* KFileItemModel::createMimeData(const QSet& indexes) const KUrl::List mostLocalUrls; bool canUseMostLocalUrls = true; - QSetIterator it(indexes); - while (it.hasNext()) { - const int index = it.next(); + foreach (int index, indexes) { const KFileItem item = fileItem(index); if (!item.isNull()) { urls << item.targetUrl(); diff --git a/src/kitemviews/kfileitemmodel.h b/src/kitemviews/kfileitemmodel.h index 4b50477d98..c57329fc85 100644 --- a/src/kitemviews/kfileitemmodel.h +++ b/src/kitemviews/kfileitemmodel.h @@ -27,6 +27,7 @@ #include #include +#include class KFileItemModelDirLister; class QTimer; @@ -99,7 +100,7 @@ public: bool showDirectoriesOnly() const; /** @reimp */ - virtual QMimeData* createMimeData(const QSet& indexes) const; + virtual QMimeData* createMimeData(const KItemSet& indexes) const; /** @reimp */ virtual int indexForKeyboardSearch(const QString& text, int startFromIndex = 0) const; diff --git a/src/kitemviews/kitemlistcontroller.cpp b/src/kitemviews/kitemlistcontroller.cpp index befb09713e..51a1f91b91 100644 --- a/src/kitemviews/kitemlistcontroller.cpp +++ b/src/kitemviews/kitemlistcontroller.cpp @@ -364,11 +364,11 @@ bool KItemListController::keyPressEvent(QKeyEvent* event) case Qt::Key_Enter: case Qt::Key_Return: { - const QSet selectedItems = m_selectionManager->selectedItems(); + const KItemSet selectedItems = m_selectionManager->selectedItems(); if (selectedItems.count() >= 2) { emit itemsActivated(selectedItems); } else if (selectedItems.count() == 1) { - emit itemActivated(selectedItems.toList().first()); + emit itemActivated(selectedItems.first()); } else { emit itemActivated(index); } @@ -378,14 +378,14 @@ bool KItemListController::keyPressEvent(QKeyEvent* event) case Qt::Key_Menu: { // Emit the signal itemContextMenuRequested() in case if at least one // item is selected. Otherwise the signal viewContextMenuRequested() will be emitted. - const QSet selectedItems = m_selectionManager->selectedItems(); + const KItemSet selectedItems = m_selectionManager->selectedItems(); int index = -1; if (selectedItems.count() >= 2) { const int currentItemIndex = m_selectionManager->currentItem(); index = selectedItems.contains(currentItemIndex) - ? currentItemIndex : selectedItems.toList().first(); + ? currentItemIndex : selectedItems.first(); } else if (selectedItems.count() == 1) { - index = selectedItems.toList().first(); + index = selectedItems.first(); } if (index >= 0) { @@ -1079,7 +1079,7 @@ void KItemListController::slotRubberBandChanged() } } - QSet selectedItems; + KItemSet selectedItems; // Select all visible items that intersect with the rubberband foreach (const KItemListWidget* widget, m_view->visibleItemListWidgets()) { @@ -1127,7 +1127,7 @@ void KItemListController::slotRubberBandChanged() // Therefore, the new selection contains: // 1. All previously selected items which are not inside the rubberband, and // 2. all items inside the rubberband which have not been selected previously. - m_selectionManager->setSelectedItems((m_oldSelection - selectedItems) + (selectedItems - m_oldSelection)); + m_selectionManager->setSelectedItems(m_oldSelection ^ selectedItems); } else { m_selectionManager->setSelectedItems(selectedItems + m_oldSelection); @@ -1140,7 +1140,7 @@ void KItemListController::startDragging() return; } - const QSet selectedItems = m_selectionManager->selectedItems(); + const KItemSet selectedItems = m_selectionManager->selectedItems(); if (selectedItems.isEmpty()) { return; } diff --git a/src/kitemviews/kitemlistcontroller.h b/src/kitemviews/kitemlistcontroller.h index bb72856e0c..e9b70cddaf 100644 --- a/src/kitemviews/kitemlistcontroller.h +++ b/src/kitemviews/kitemlistcontroller.h @@ -25,10 +25,11 @@ #include +#include "kitemset.h" + #include #include #include -#include class KItemModelBase; class KItemListKeyboardSearchManager; @@ -129,7 +130,7 @@ public: /** * If set to true, the signals itemActivated() and itemsActivated() are emitted - * after a single-click of the left mouse button. If set to false (the default), + * after a single-click of the left mouse button. If set to false (the default), * the setting from KGlobalSettings::singleClick() is used. */ void setSingleClickActivationEnforced(bool singleClick); @@ -165,7 +166,7 @@ signals: * Is emitted if more than one item has been activated by pressing Return/Enter * when having a selection. */ - void itemsActivated(const QSet& indexes); + void itemsActivated(const KItemSet& indexes); void itemMiddleClicked(int index); @@ -326,7 +327,7 @@ private: * the current selection it is remembered in m_oldSelection before the * rubberband gets activated. */ - QSet m_oldSelection; + KItemSet m_oldSelection; /** * Assuming a view is given with a vertical scroll-orientation, grouped items and diff --git a/src/kitemviews/kitemlistselectionmanager.cpp b/src/kitemviews/kitemlistselectionmanager.cpp index 833f7aad07..ebff1a30ed 100644 --- a/src/kitemviews/kitemlistselectionmanager.cpp +++ b/src/kitemviews/kitemlistselectionmanager.cpp @@ -43,7 +43,7 @@ KItemListSelectionManager::~KItemListSelectionManager() void KItemListSelectionManager::setCurrentItem(int current) { const int previous = m_currentItem; - const QSet previousSelection = selectedItems(); + const KItemSet previousSelection = selectedItems(); if (m_model && current >= 0 && current < m_model->count()) { m_currentItem = current; @@ -55,7 +55,7 @@ void KItemListSelectionManager::setCurrentItem(int current) emit currentChanged(m_currentItem, previous); if (m_isAnchoredSelectionActive) { - const QSet selection = selectedItems(); + const KItemSet selection = selectedItems(); if (selection != previousSelection) { emit selectionChanged(selection, previousSelection); } @@ -68,18 +68,18 @@ int KItemListSelectionManager::currentItem() const return m_currentItem; } -void KItemListSelectionManager::setSelectedItems(const QSet& items) +void KItemListSelectionManager::setSelectedItems(const KItemSet& items) { if (m_selectedItems != items) { - const QSet previous = m_selectedItems; + const KItemSet previous = m_selectedItems; m_selectedItems = items; emit selectionChanged(m_selectedItems, previous); } } -QSet KItemListSelectionManager::selectedItems() const +KItemSet KItemListSelectionManager::selectedItems() const { - QSet selectedItems = m_selectedItems; + KItemSet selectedItems = m_selectedItems; if (m_isAnchoredSelectionActive && m_anchorItem != m_currentItem) { Q_ASSERT(m_anchorItem >= 0); @@ -127,7 +127,7 @@ void KItemListSelectionManager::setSelected(int index, int count, SelectionMode } endAnchoredSelection(); - const QSet previous = selectedItems(); + const KItemSet previous = selectedItems(); count = qMin(count, m_model->count() - index); @@ -160,7 +160,7 @@ void KItemListSelectionManager::setSelected(int index, int count, SelectionMode break; } - const QSet selection = selectedItems(); + const KItemSet selection = selectedItems(); if (selection != previous) { emit selectionChanged(selection, previous); } @@ -168,11 +168,11 @@ void KItemListSelectionManager::setSelected(int index, int count, SelectionMode void KItemListSelectionManager::clearSelection() { - const QSet previous = selectedItems(); + const KItemSet previous = selectedItems(); if (!previous.isEmpty()) { m_selectedItems.clear(); m_isAnchoredSelectionActive = false; - emit selectionChanged(QSet(), previous); + emit selectionChanged(KItemSet(), previous); } } @@ -221,7 +221,7 @@ void KItemListSelectionManager::setModel(KItemModelBase* model) void KItemListSelectionManager::itemsInserted(const KItemRangeList& itemRanges) { // Store the current selection (needed in the selectionChanged() signal) - const QSet previousSelection = selectedItems(); + const KItemSet previousSelection = selectedItems(); // Update the current item if (m_currentItem < 0) { @@ -257,12 +257,10 @@ void KItemListSelectionManager::itemsInserted(const KItemRangeList& itemRanges) // Update the selections if (!m_selectedItems.isEmpty()) { - const QSet previous = m_selectedItems; + const KItemSet previous = m_selectedItems; m_selectedItems.clear(); - m_selectedItems.reserve(previous.count()); - QSetIterator it(previous); - while (it.hasNext()) { - const int index = it.next(); + + foreach (int index, previous) { int inc = 0; foreach (const KItemRange& itemRange, itemRanges) { if (index < itemRange.index) { @@ -274,7 +272,7 @@ void KItemListSelectionManager::itemsInserted(const KItemRangeList& itemRanges) } } - const QSet selection = selectedItems(); + const KItemSet selection = selectedItems(); if (selection != previousSelection) { emit selectionChanged(selection, previousSelection); } @@ -283,7 +281,7 @@ void KItemListSelectionManager::itemsInserted(const KItemRangeList& itemRanges) void KItemListSelectionManager::itemsRemoved(const KItemRangeList& itemRanges) { // Store the current selection (needed in the selectionChanged() signal) - const QSet previousSelection = selectedItems(); + const KItemSet previousSelection = selectedItems(); const int previousCurrent = m_currentItem; // Update the current item @@ -308,19 +306,18 @@ void KItemListSelectionManager::itemsRemoved(const KItemRangeList& itemRanges) // Update the selections and the anchor item if (!m_selectedItems.isEmpty()) { - const QSet previous = m_selectedItems; + const KItemSet previous = m_selectedItems; m_selectedItems.clear(); - m_selectedItems.reserve(previous.count()); - QSetIterator it(previous); - while (it.hasNext()) { - const int index = indexAfterRangesRemoving(it.next(), itemRanges, DiscardRemovedIndex); + + foreach (int oldIndex, previous) { + const int index = indexAfterRangesRemoving(oldIndex, itemRanges, DiscardRemovedIndex); if (index >= 0) { m_selectedItems.insert(index); } } } - const QSet selection = selectedItems(); + const KItemSet selection = selectedItems(); if (selection != previousSelection) { emit selectionChanged(selection, previousSelection); } @@ -332,7 +329,7 @@ void KItemListSelectionManager::itemsRemoved(const KItemRangeList& itemRanges) void KItemListSelectionManager::itemsMoved(const KItemRange& itemRange, const QList& movedToIndexes) { // Store the current selection (needed in the selectionChanged() signal) - const QSet previousSelection = selectedItems(); + const KItemSet previousSelection = selectedItems(); // Update the current item if (m_currentItem >= itemRange.index && m_currentItem < itemRange.index + itemRange.count) { @@ -352,12 +349,10 @@ void KItemListSelectionManager::itemsMoved(const KItemRange& itemRange, const QL // Update the selections if (!m_selectedItems.isEmpty()) { - const QSet previous = m_selectedItems; + const KItemSet previous = m_selectedItems; m_selectedItems.clear(); - m_selectedItems.reserve(previous.count()); - QSetIterator it(previous); - while (it.hasNext()) { - const int index = it.next(); + + foreach (int index, previous) { if (index >= itemRange.index && index < itemRange.index + itemRange.count) { m_selectedItems.insert(movedToIndexes.at(index - itemRange.index)); } @@ -367,7 +362,7 @@ void KItemListSelectionManager::itemsMoved(const KItemRange& itemRange, const QL } } - const QSet selection = selectedItems(); + const KItemSet selection = selectedItems(); if (selection != previousSelection) { emit selectionChanged(selection, previousSelection); } diff --git a/src/kitemviews/kitemlistselectionmanager.h b/src/kitemviews/kitemlistselectionmanager.h index c89b8a4b85..c4decd39eb 100644 --- a/src/kitemviews/kitemlistselectionmanager.h +++ b/src/kitemviews/kitemlistselectionmanager.h @@ -26,9 +26,9 @@ #include #include +#include #include -#include class KItemModelBase; @@ -57,8 +57,8 @@ public: void setCurrentItem(int current); int currentItem() const; - void setSelectedItems(const QSet& items); - QSet selectedItems() const; + void setSelectedItems(const KItemSet& items); + KItemSet selectedItems() const; bool isSelected(int index) const; bool hasSelection() const; @@ -73,7 +73,7 @@ public: signals: void currentChanged(int current, int previous); - void selectionChanged(const QSet& current, const QSet& previous); + void selectionChanged(const KItemSet& current, const KItemSet& previous); private: void setModel(KItemModelBase* model); @@ -91,7 +91,7 @@ private: private: int m_currentItem; int m_anchorItem; - QSet m_selectedItems; + KItemSet m_selectedItems; bool m_isAnchoredSelectionActive; KItemModelBase* m_model; diff --git a/src/kitemviews/kitemlistview.cpp b/src/kitemviews/kitemlistview.cpp index b3d805a917..7f497210cd 100644 --- a/src/kitemviews/kitemlistview.cpp +++ b/src/kitemviews/kitemlistview.cpp @@ -609,12 +609,12 @@ KItemListHeader* KItemListView::header() const return m_header; } -QPixmap KItemListView::createDragPixmap(const QSet& indexes) const +QPixmap KItemListView::createDragPixmap(const KItemSet& indexes) const { QPixmap pixmap; if (indexes.count() == 1) { - KItemListWidget* item = m_visibleItems.value(indexes.toList().first()); + KItemListWidget* item = m_visibleItems.value(indexes.first()); QGraphicsView* graphicsView = scene()->views()[0]; if (item && graphicsView) { pixmap = item->createDragPixmap(0, graphicsView); @@ -1305,7 +1305,7 @@ void KItemListView::slotCurrentChanged(int current, int previous) QAccessible::updateAccessibility(this, current+1, QAccessible::Focus); } -void KItemListView::slotSelectionChanged(const QSet& current, const QSet& previous) +void KItemListView::slotSelectionChanged(const KItemSet& current, const KItemSet& previous) { Q_UNUSED(previous); @@ -1502,7 +1502,7 @@ void KItemListView::setController(KItemListController* controller) if (previous) { KItemListSelectionManager* selectionManager = previous->selectionManager(); disconnect(selectionManager, SIGNAL(currentChanged(int,int)), this, SLOT(slotCurrentChanged(int,int))); - disconnect(selectionManager, SIGNAL(selectionChanged(QSet,QSet)), this, SLOT(slotSelectionChanged(QSet,QSet))); + disconnect(selectionManager, SIGNAL(selectionChanged(KItemSet,KItemSet)), this, SLOT(slotSelectionChanged(KItemSet,KItemSet))); } m_controller = controller; @@ -1510,7 +1510,7 @@ void KItemListView::setController(KItemListController* controller) if (controller) { KItemListSelectionManager* selectionManager = controller->selectionManager(); connect(selectionManager, SIGNAL(currentChanged(int,int)), this, SLOT(slotCurrentChanged(int,int))); - connect(selectionManager, SIGNAL(selectionChanged(QSet,QSet)), this, SLOT(slotSelectionChanged(QSet,QSet))); + connect(selectionManager, SIGNAL(selectionChanged(KItemSet,KItemSet)), this, SLOT(slotSelectionChanged(KItemSet,KItemSet))); } onControllerChanged(controller, previous); diff --git a/src/kitemviews/kitemlistview.h b/src/kitemviews/kitemlistview.h index 14360b02bb..dbe9230867 100644 --- a/src/kitemviews/kitemlistview.h +++ b/src/kitemviews/kitemlistview.h @@ -271,7 +271,7 @@ public: * @return Pixmap that is used for a drag operation based on the * items given by \a indexes. */ - virtual QPixmap createDragPixmap(const QSet& indexes) const; + virtual QPixmap createDragPixmap(const KItemSet& indexes) const; /** * Lets the user edit the role \a role for item with the index \a index. @@ -400,7 +400,7 @@ protected slots: virtual void slotSortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous); virtual void slotSortRoleChanged(const QByteArray& current, const QByteArray& previous); virtual void slotCurrentChanged(int current, int previous); - virtual void slotSelectionChanged(const QSet& current, const QSet& previous); + virtual void slotSelectionChanged(const KItemSet& current, const KItemSet& previous); private slots: void slotAnimationFinished(QGraphicsWidget* widget, diff --git a/src/kitemviews/kitemlistviewaccessible.cpp b/src/kitemviews/kitemlistviewaccessible.cpp index 565c2151ec..d9ddd58f84 100644 --- a/src/kitemviews/kitemlistviewaccessible.cpp +++ b/src/kitemviews/kitemlistviewaccessible.cpp @@ -109,7 +109,7 @@ int KItemListViewAccessible::rowCount() const int KItemListViewAccessible::selectedCellCount() const { - return view()->controller()->selectionManager()->selectedItems().size(); + return view()->controller()->selectionManager()->selectedItems().count(); } int KItemListViewAccessible::selectedColumnCount() const diff --git a/src/kitemviews/kitemmodelbase.cpp b/src/kitemviews/kitemmodelbase.cpp index edce95ece9..4312640e41 100644 --- a/src/kitemviews/kitemmodelbase.cpp +++ b/src/kitemviews/kitemmodelbase.cpp @@ -123,7 +123,7 @@ int KItemModelBase::expandedParentsCount(int index) const return 0; } -QMimeData* KItemModelBase::createMimeData(const QSet& indexes) const +QMimeData* KItemModelBase::createMimeData(const KItemSet& indexes) const { Q_UNUSED(indexes); return 0; diff --git a/src/kitemviews/kitemmodelbase.h b/src/kitemviews/kitemmodelbase.h index c5b9a0ca5f..283cfa5523 100644 --- a/src/kitemviews/kitemmodelbase.h +++ b/src/kitemviews/kitemmodelbase.h @@ -26,10 +26,10 @@ #include #include +#include #include #include -#include #include class QMimeData; @@ -149,7 +149,7 @@ public: * caller of this method. The method must be implemented if dragging of * items should be possible. */ - virtual QMimeData* createMimeData(const QSet& indexes) const; + virtual QMimeData* createMimeData(const KItemSet& indexes) const; /** * @return Reimplement this to return the index for the first item diff --git a/src/kitemviews/kitemset.cpp b/src/kitemviews/kitemset.cpp new file mode 100644 index 0000000000..f855368c14 --- /dev/null +++ b/src/kitemviews/kitemset.cpp @@ -0,0 +1,348 @@ +/*************************************************************************** + * Copyright (C) 2013 by Frank Reininghaus * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#include "kitemset.h" + +#include + +#include + +KItemSet::iterator KItemSet::insert(int i) +{ + if (m_itemRanges.empty()) { + m_itemRanges.push_back(KItemRange(i, 1)); + return iterator(m_itemRanges.begin(), 0); + } + + KItemRangeList::iterator rangeBegin = m_itemRanges.begin(); + if (i < rangeBegin->index) { + // The inserted index is smaller than all existing items. + if (i == rangeBegin->index - 1) { + // Move the beginning of the first range one item to the front. + --rangeBegin->index; + ++rangeBegin->count; + } else { + // Insert a new range at the beginning. + rangeBegin = m_itemRanges.insert(rangeBegin, KItemRange(i, 1)); + } + + return iterator(rangeBegin, 0); + } + + KItemRangeList::iterator rangeEnd = m_itemRanges.end(); + KItemRangeList::iterator lastRange = rangeEnd - 1; + if (i >= lastRange->index) { + // i either belongs to the last range, or it is larger than all existing items. + const int lastItemPlus1 = lastRange->index + lastRange->count; + if (i == lastItemPlus1) { + // Move the end of the last range one item to the back. + ++lastRange->count; + } else if (i > lastItemPlus1) { + // Append a new range. + lastRange = m_itemRanges.insert(rangeEnd, KItemRange(i, 1)); + } + + return iterator(lastRange, i - lastRange->index); + } + + // We know that i is between the smallest existing item and the first item + // of the last range. Find the lowest range whose 'index' is smaller than i. + KItemRangeList::iterator low = rangeBegin; + KItemRangeList::iterator high = lastRange; + + while (low + 1 != high) { + const int span = high - low; + Q_ASSERT(span >= 2); + + KItemRangeList::iterator mid = low + span / 2; + if (mid->index > i) { + high = mid; + } else { + low = mid; + } + } + + Q_ASSERT(low->index <= i && high->index > i); + + if (i == low->index + low->count) { + // i is just one item behind the range low. + if (i == high->index - 1) { + // i closes the gap between low and high. Merge the two ranges. + const int newRangeCount = low->count + 1 + high->count; + KItemRangeList::iterator behindNewRange = m_itemRanges.erase(high); + KItemRangeList::iterator newRange = behindNewRange - 1; + newRange->count = newRangeCount; + return iterator(newRange, i - newRange->index); + } else { + // Extend low by one item. + ++low->count; + return iterator(low, low->count - 1); + } + } else if (i > low->index + low->count) { + if (i == high->index - 1) { + // Extend high by one item to the front. + --high->index; + ++high->count; + return iterator(high, 0); + } else { + // Insert a new range between low and high. + KItemRangeList::iterator newRange = m_itemRanges.insert(high, KItemRange(i, 1)); + return iterator(newRange, 0); + } + } else { + // The range low already contains i. + return iterator(low, i - low->index); + } +} + +KItemSet::iterator KItemSet::erase(iterator it) +{ + KItemRangeList::iterator rangeIt = it.m_rangeIt; + + if (it.m_offset == 0) { + // Removed index is at the beginning of a range. + if (rangeIt->count > 1) { + ++rangeIt->index; + --rangeIt->count; + } else { + // The range only contains the removed index. + rangeIt = m_itemRanges.erase(rangeIt); + } + return iterator(rangeIt, 0); + } else if (it.m_offset == rangeIt->count - 1) { + // Removed index is at the end of a range. + --rangeIt->count; + ++rangeIt; + return iterator(rangeIt, 0); + } else { + // The removed index is in the middle of a range. + const int newRangeIndex = *it + 1; + const int newRangeCount = rangeIt->count - it.m_offset - 1; + const KItemRange newRange(newRangeIndex, newRangeCount); + + rangeIt->count = it.m_offset; + ++rangeIt; + rangeIt = m_itemRanges.insert(rangeIt, newRange); + + return iterator(rangeIt, 0); + } +} + +KItemSet KItemSet::operator+(const KItemSet& other) const +{ + KItemSet sum; + + KItemRangeList::const_iterator it1 = m_itemRanges.constBegin(); + KItemRangeList::const_iterator it2 = other.m_itemRanges.constBegin(); + + const KItemRangeList::const_iterator end1 = m_itemRanges.constEnd(); + const KItemRangeList::const_iterator end2 = other.m_itemRanges.constEnd(); + + while (it1 != end1 || it2 != end2) { + if (it1 == end1) { + // We are past the end of 'this' already. Append all remaining + // item ranges from 'other'. + while (it2 != end2) { + sum.m_itemRanges.append(*it2); + ++it2; + } + } else if (it2 == end2) { + // We are past the end of 'other' already. Append all remaining + // item ranges from 'this'. + while (it1 != end1) { + sum.m_itemRanges.append(*it1); + ++it1; + } + } else { + // Find the beginning of the next range. + int index = qMin(it1->index, it2->index); + int count = 0; + + do { + if (it1 != end1 && it1->index <= index + count) { + // The next range from 'this' overlaps with the current range in the sum. + count = qMax(count, it1->index + it1->count - index); + ++it1; + } + + if (it2 != end2 && it2->index <= index + count) { + // The next range from 'other' overlaps with the current range in the sum. + count = qMax(count, it2->index + it2->count - index); + ++it2; + } + } while ((it1 != end1 && it1->index <= index + count) + || (it2 != end2 && it2->index <= index + count)); + + sum.m_itemRanges.append(KItemRange(index, count)); + } + } + + return sum; +} + +KItemSet KItemSet::operator^(const KItemSet& other) const +{ + // We are looking for all ints which are either in *this or in other, + // but not in both. + KItemSet result; + + // When we go through all integers from INT_MIN to INT_MAX and start + // in the state "do not add to result", every beginning/end of a range + // of *this and other toggles the "add/do not add to result" state. + // Therefore, we just have to put ints where any range starts/ends to + // a sorted array, and then we can calculate the result quite easily. + QVector rangeBoundaries; + rangeBoundaries.resize(2 * (m_itemRanges.count() + other.m_itemRanges.count())); + const QVector::iterator begin = rangeBoundaries.begin(); + const QVector::iterator end = rangeBoundaries.end(); + QVector::iterator it = begin; + + foreach (const KItemRange& range, m_itemRanges) { + *it++ = range.index; + *it++ = range.index + range.count; + } + + const QVector::iterator middle = it; + + foreach (const KItemRange& range, other.m_itemRanges) { + *it++ = range.index; + *it++ = range.index + range.count; + } + Q_ASSERT(it == end); + + std::inplace_merge(begin, middle, end); + + it = begin; + while (it != end) { + const int rangeBegin = *it; + ++it; + + if (*it == rangeBegin) { + // It seems that ranges from both *this and other start at + // rangeBegin. Do not start a new range, but read the next int. + // + // Example: Consider the symmetric difference of the sets + // {1, 2, 3, 4} and {1, 2}. The sorted list of range boundaries is + // 1 1 3 5. Discarding the duplicate 1 yields the result + // rangeBegin = 3, rangeEnd = 5, which corresponds to the set {3, 4}. + ++it; + } else { + // The end of the current range is the next *single* int that we + // find. If an int appears twice in rangeBoundaries, the range does + // not end. + // + // Example: Consider the symmetric difference of the sets + // {1, 2, 3, 4, 8, 9, 10} and {5, 6, 7}. The sorted list of range + // boundaries is 1 5 5 8 8 11, and discarding all duplicates yields + // the result rangeBegin = 1, rangeEnd = 11, which corresponds to + // the set {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}. + bool foundEndOfRange = false; + int rangeEnd; + do { + rangeEnd = *it; + ++it; + + if (it == end || *it != rangeEnd) { + foundEndOfRange = true; + } else { + ++it; + } + } while (!foundEndOfRange); + + result.m_itemRanges.append(KItemRange(rangeBegin, rangeEnd - rangeBegin)); + } + } + + return result; +} + +bool KItemSet::isValid() const +{ + const KItemRangeList::const_iterator begin = m_itemRanges.constBegin(); + const KItemRangeList::const_iterator end = m_itemRanges.constEnd(); + + for (KItemRangeList::const_iterator it = begin; it != end; ++it) { + if (it->count <= 0) { + return false; + } + + if (it != begin) { + const KItemRangeList::const_iterator previous = it - 1; + if (previous->index + previous->count >= it->index) { + return false; + } + } + } + + return true; +} + +KItemRangeList::iterator KItemSet::rangeForItem(int i) +{ + const KItemRangeList::iterator end = m_itemRanges.end(); + KItemRangeList::iterator low = m_itemRanges.begin(); + KItemRangeList::iterator high = end; + + if (low == end || low->index > i) { + return end; + } + + while (low != high && low + 1 != high) { + KItemRangeList::iterator mid = low + (high - low) / 2; + if (mid->index > i) { + high = mid; + } else { + low = mid; + } + } + + Q_ASSERT(low->index <= i); + if (low->index + low->count > i) { + return low; + } + + return end; +} + +KItemRangeList::const_iterator KItemSet::constRangeForItem(int i) const +{ + const KItemRangeList::const_iterator end = m_itemRanges.constEnd(); + KItemRangeList::const_iterator low = m_itemRanges.constBegin(); + KItemRangeList::const_iterator high = end; + + if (low == end || low->index > i) { + return end; + } + + while (low != high && low + 1 != high) { + KItemRangeList::const_iterator mid = low + (high - low) / 2; + if (mid->index > i) { + high = mid; + } else { + low = mid; + } + } + + Q_ASSERT(low->index <= i); + if (low->index + low->count > i) { + return low; + } + + return end; +} diff --git a/src/kitemviews/kitemset.h b/src/kitemviews/kitemset.h new file mode 100644 index 0000000000..385010f7d6 --- /dev/null +++ b/src/kitemviews/kitemset.h @@ -0,0 +1,413 @@ +/*************************************************************************** + * Copyright (C) 2013 by Frank Reininghaus * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#ifndef KITEMSET_H +#define KITEMSET_H + +#include + +/** + * @brief Stores a set of integer numbers in a space-efficient way. + * + * This class is similar to QSet, but it has the following advantages: + * + * 1. It uses less memory than a QSet if many consecutive numbers are + * stored. This is achieved by not storing each number separately, but + * "ranges" of numbers. + * + * Example: The set {1, 2, 3, 4, 5} is represented by a single range which + * starts at 1 and has the length 5. + * + * 2. When iterating through a KItemSet using KItemSet::iterator or + * KItemSet::const_iterator, the numbers are traversed in ascending order. + * + * The complexity of most operations depends on the number of ranges. + */ + +class KItemSet +{ +public: + KItemSet(); + KItemSet(const KItemSet& other); + + /** + * Returns the number of items in the set. + * Complexity: O(log(number of ranges)). + */ + int count() const; + + bool isEmpty() const; + void clear(); + + bool operator==(const KItemSet& other) const; + bool operator!=(const KItemSet& other) const; + + class iterator + { + iterator(const KItemRangeList::iterator& rangeIt, int offset) : + m_rangeIt(rangeIt), + m_offset(offset) + { + } + + public: + iterator(const iterator& other) : + m_rangeIt(other.m_rangeIt), + m_offset(other.m_offset) + { + } + + iterator& operator=(const iterator& other) + { + m_rangeIt = other.m_rangeIt; + m_offset = other.m_offset; + return *this; + } + + int operator*() const + { + return m_rangeIt->index + m_offset; + } + + inline bool operator==(const iterator& other) const + { + return m_rangeIt == other.m_rangeIt && m_offset == other.m_offset; + } + + inline bool operator!=(const iterator& other) const + { + return !(*this == other); + } + + inline iterator& operator++() + { + ++m_offset; + + if (m_offset == m_rangeIt->count) { + ++m_rangeIt; + m_offset = 0; + } + + return *this; + } + + inline iterator operator++(int) + { + iterator r = *this; + ++(*this); + return r; + } + + inline iterator& operator--() + { + if (m_offset == 0) { + --m_rangeIt; + m_offset = m_rangeIt->count - 1; + } else { + --m_offset; + } + + return *this; + } + + inline iterator operator--(int) + { + iterator r = *this; + --(*this); + return r; + } + + private: + KItemRangeList::iterator m_rangeIt; + int m_offset; + + friend class const_iterator; + friend class KItemSet; + }; + + + class const_iterator + { + const_iterator(KItemRangeList::const_iterator rangeIt, int offset) : + m_rangeIt(rangeIt), + m_offset(offset) + { + } + + public: + const_iterator(const const_iterator& other) : + m_rangeIt(other.m_rangeIt), + m_offset(other.m_offset) + { + } + + const_iterator(const iterator& other) : + m_rangeIt(other.m_rangeIt), + m_offset(other.m_offset) + { + } + + const_iterator& operator=(const const_iterator& other) + { + m_rangeIt = other.m_rangeIt; + m_offset = other.m_offset; + return *this; + } + + int operator*() const + { + return m_rangeIt->index + m_offset; + } + + inline bool operator==(const const_iterator& other) const + { + return m_rangeIt == other.m_rangeIt && m_offset == other.m_offset; + } + + inline bool operator!=(const const_iterator& other) const + { + return !(*this == other); + } + + inline const_iterator& operator++() + { + ++m_offset; + + if (m_offset == m_rangeIt->count) { + ++m_rangeIt; + m_offset = 0; + } + + return *this; + } + + inline const_iterator operator++(int) + { + const_iterator r = *this; + ++(*this); + return r; + } + + inline const_iterator& operator--() + { + if (m_offset == 0) { + --m_rangeIt; + m_offset = m_rangeIt->count - 1; + } else { + --m_offset; + } + + return *this; + } + + inline const_iterator operator--(int) + { + const_iterator r = *this; + --(*this); + return r; + } + + private: + KItemRangeList::const_iterator m_rangeIt; + int m_offset; + + friend class KItemSet; + }; + + iterator begin(); + const_iterator begin() const; + const_iterator constBegin() const; + iterator end(); + const_iterator end() const; + const_iterator constEnd() const; + + int first() const; + int last() const; + + bool contains(int i) const; + iterator insert(int i); + iterator find(int i); + const_iterator constFind(int i) const; + bool remove(int i); + iterator erase(iterator it); + + /** + * Returns a new set which contains all items that are contained in this + * KItemSet, in \a other, or in both. + */ + KItemSet operator+(const KItemSet& other) const; + + /** + * Returns a new set which contains all items that are contained either in + * this KItemSet, or in \a other, but not in both (the symmetric difference + * of both KItemSets). + */ + KItemSet operator^(const KItemSet& other) const; + + KItemSet& operator<<(int i); + +private: + /** + * Returns true if the KItemSet is valid, and false otherwise. + * A valid KItemSet must store the item ranges in ascending order, and + * the ranges must not overlap. + */ + bool isValid() const; + + /** + * This function returns an iterator that points to the KItemRange which + * contains i, or m_itemRanges.end() if no such range exists. + */ + KItemRangeList::iterator rangeForItem(int i); + + /** + * This function returns an iterator that points to the KItemRange which + * contains i, or m_itemRanges.constEnd() if no such range exists. + */ + KItemRangeList::const_iterator constRangeForItem(int i) const; + + KItemRangeList m_itemRanges; + + friend class KItemSetTest; +}; + +inline KItemSet::KItemSet() : + m_itemRanges() +{ +} + +inline KItemSet::KItemSet(const KItemSet& other) : + m_itemRanges(other.m_itemRanges) +{ +} + +inline int KItemSet::count() const +{ + int result = 0; + foreach (const KItemRange& range, m_itemRanges) { + result += range.count; + } + return result; +} + +inline bool KItemSet::isEmpty() const +{ + return m_itemRanges.isEmpty(); +} + +inline void KItemSet::clear() +{ + m_itemRanges.clear(); +} + +inline bool KItemSet::operator==(const KItemSet& other) const +{ + return m_itemRanges == other.m_itemRanges; +} + +inline bool KItemSet::operator!=(const KItemSet& other) const +{ + return m_itemRanges != other.m_itemRanges; +} + +inline bool KItemSet::contains(int i) const +{ + const KItemRangeList::const_iterator it = constRangeForItem(i); + return it != m_itemRanges.end(); +} + +inline KItemSet::iterator KItemSet::find(int i) +{ + const KItemRangeList::iterator it = rangeForItem(i); + if (it != m_itemRanges.end()) { + return iterator(it, i - it->index); + } else { + return end(); + } +} + +inline KItemSet::const_iterator KItemSet::constFind(int i) const +{ + const KItemRangeList::const_iterator it = constRangeForItem(i); + if (it != m_itemRanges.constEnd()) { + return const_iterator(it, i - it->index); + } else { + return constEnd(); + } +} + +inline bool KItemSet::remove(int i) +{ + iterator it = find(i); + if (it != end()) { + erase(it); + return true; + } else { + return false; + } +} + +inline KItemSet::iterator KItemSet::begin() +{ + return iterator(m_itemRanges.begin(), 0); +} + +inline KItemSet::const_iterator KItemSet::begin() const +{ + return const_iterator(m_itemRanges.begin(), 0); +} + +inline KItemSet::const_iterator KItemSet::constBegin() const +{ + return const_iterator(m_itemRanges.constBegin(), 0); +} + +inline KItemSet::iterator KItemSet::end() +{ + return iterator(m_itemRanges.end(), 0); +} + +inline KItemSet::const_iterator KItemSet::end() const +{ + return const_iterator(m_itemRanges.end(), 0); +} + +inline KItemSet::const_iterator KItemSet::constEnd() const +{ + return const_iterator(m_itemRanges.constEnd(), 0); +} + +inline int KItemSet::first() const +{ + return m_itemRanges.first().index; +} + +inline int KItemSet::last() const +{ + const KItemRange& lastRange = m_itemRanges.last(); + return lastRange.index + lastRange.count - 1; +} + +inline KItemSet& KItemSet::operator<<(int i) +{ + insert(i); + return *this; +} + +#endif diff --git a/src/kitemviews/kstandarditemmodel.cpp b/src/kitemviews/kstandarditemmodel.cpp index 959d62cb8a..e8c1b62042 100644 --- a/src/kitemviews/kstandarditemmodel.cpp +++ b/src/kitemviews/kstandarditemmodel.cpp @@ -175,7 +175,7 @@ bool KStandardItemModel::setData(int index, const QHash& v return true; } -QMimeData* KStandardItemModel::createMimeData(const QSet& indexes) const +QMimeData* KStandardItemModel::createMimeData(const KItemSet& indexes) const { Q_UNUSED(indexes); return 0; diff --git a/src/kitemviews/kstandarditemmodel.h b/src/kitemviews/kstandarditemmodel.h index 0debd6a6fc..721e155299 100644 --- a/src/kitemviews/kstandarditemmodel.h +++ b/src/kitemviews/kstandarditemmodel.h @@ -72,7 +72,7 @@ public: virtual int count() const; virtual QHash data(int index) const; virtual bool setData(int index, const QHash& values); - virtual QMimeData* createMimeData(const QSet& indexes) const; + virtual QMimeData* createMimeData(const KItemSet& indexes) const; virtual int indexForKeyboardSearch(const QString& text, int startFromIndex = 0) const; virtual bool supportsDropping(int index) const; virtual QString roleDescription(const QByteArray& role) const; diff --git a/src/panels/places/placesitemmodel.cpp b/src/panels/places/placesitemmodel.cpp index eae2095c99..681479dfba 100644 --- a/src/panels/places/placesitemmodel.cpp +++ b/src/panels/places/placesitemmodel.cpp @@ -377,7 +377,7 @@ void PlacesItemModel::requestStorageSetup(int index) } } -QMimeData* PlacesItemModel::createMimeData(const QSet& indexes) const +QMimeData* PlacesItemModel::createMimeData(const KItemSet& indexes) const { KUrl::List urls; QByteArray itemData; diff --git a/src/panels/places/placesitemmodel.h b/src/panels/places/placesitemmodel.h index 6938360332..cd37e73535 100644 --- a/src/panels/places/placesitemmodel.h +++ b/src/panels/places/placesitemmodel.h @@ -118,7 +118,7 @@ public: void requestStorageSetup(int index); /** @reimp */ - virtual QMimeData* createMimeData(const QSet& indexes) const; + virtual QMimeData* createMimeData(const KItemSet& indexes) const; /** @reimp */ virtual bool supportsDropping(int index) const; diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index dd761fc90b..9b152ed07d 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -3,11 +3,21 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BUILD_DIR}/. # needed on windows to correctly use the files from dolphinprivate add_definitions(-DLIBDOLPHINPRIVATE_EXPORT=) + +# KItemSetTest +set(kitemsettest_SRCS + kitemsettest.cpp + ../kitemviews/kitemset.cpp +) +kde4_add_unit_test(kitemsettest TEST ${kitemsettest_SRCS}) +target_link_libraries(kitemsettest dolphinprivate ${KDE4_KIO_LIBS} ${QT_QTTEST_LIBRARY}) + # KItemListSelectionManagerTest set(kitemlistselectionmanagertest_SRCS kitemlistselectionmanagertest.cpp ../kitemviews/kitemlistselectionmanager.cpp ../kitemviews/kitemmodelbase.cpp + ../kitemviews/kitemset.cpp ) kde4_add_unit_test(kitemlistselectionmanagertest TEST ${kitemlistselectionmanagertest_SRCS}) target_link_libraries(kitemlistselectionmanagertest dolphinprivate ${KDE4_KIO_LIBS} ${QT_QTTEST_LIBRARY}) @@ -24,6 +34,7 @@ set(kitemlistcontrollertest_SRCS ../kitemviews/kitemlistcontainer.cpp ../kitemviews/kitemlistwidget.cpp ../kitemviews/kitemlistviewaccessible.cpp + ../kitemviews/kitemset.cpp ../kitemviews/kstandarditemlistview.cpp ../kitemviews/kstandarditemlistwidget.cpp ) @@ -41,6 +52,7 @@ set(kfileitemlistviewtest_SRCS ../kitemviews/kitemlistviewaccessible.cpp ../kitemviews/kitemlistcontainer.cpp ../kitemviews/kitemlistwidget.cpp + ../kitemviews/kitemset.cpp ../kitemviews/kstandarditemlistview.cpp ../kitemviews/kstandarditemlistwidget.cpp ) diff --git a/src/tests/kitemlistcontrollertest.cpp b/src/tests/kitemlistcontrollertest.cpp index 60e93e539a..7dd37bf0a3 100644 --- a/src/tests/kitemlistcontrollertest.cpp +++ b/src/tests/kitemlistcontrollertest.cpp @@ -41,7 +41,7 @@ namespace { Q_DECLARE_METATYPE(KFileItemListView::ItemLayout); Q_DECLARE_METATYPE(Qt::Orientation); Q_DECLARE_METATYPE(KItemListController::SelectionBehavior); -Q_DECLARE_METATYPE(QSet); +Q_DECLARE_METATYPE(KItemSet); class KItemListControllerTest : public QObject { @@ -81,7 +81,7 @@ private: */ void KItemListControllerTest::initTestCase() { - qRegisterMetaType >("QSet"); + qRegisterMetaType("KItemSet"); m_testDir = new TestDir(); m_model = new KFileItemModel(); @@ -159,14 +159,14 @@ struct KeyPress { */ struct ViewState { - ViewState(int current, const QSet selection, bool activated = false) : + ViewState(int current, const KItemSet selection, bool activated = false) : m_current(current), m_selection(selection), m_activated(activated) {} int m_current; - QSet m_selection; + KItemSet m_selection; bool m_activated; }; @@ -262,34 +262,34 @@ void KItemListControllerTest::testKeyboardNavigation_data() // First, key presses which should have the same effect // for any layout and any number of columns. testList - << qMakePair(KeyPress(nextItemKey), ViewState(1, QSet() << 1)) - << qMakePair(KeyPress(Qt::Key_Return), ViewState(1, QSet() << 1, true)) - << qMakePair(KeyPress(Qt::Key_Enter), ViewState(1, QSet() << 1, true)) - << qMakePair(KeyPress(nextItemKey), ViewState(2, QSet() << 2)) - << qMakePair(KeyPress(nextItemKey, Qt::ShiftModifier), ViewState(3, QSet() << 2 << 3)) - << qMakePair(KeyPress(Qt::Key_Return), ViewState(3, QSet() << 2 << 3, true)) - << qMakePair(KeyPress(previousItemKey, Qt::ShiftModifier), ViewState(2, QSet() << 2)) - << qMakePair(KeyPress(nextItemKey, Qt::ShiftModifier), ViewState(3, QSet() << 2 << 3)) - << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(4, QSet() << 2 << 3)) - << qMakePair(KeyPress(Qt::Key_Return), ViewState(4, QSet() << 2 << 3, true)) - << qMakePair(KeyPress(previousItemKey), ViewState(3, QSet() << 3)) - << qMakePair(KeyPress(Qt::Key_Home, Qt::ShiftModifier), ViewState(0, QSet() << 0 << 1 << 2 << 3)) - << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(1, QSet() << 0 << 1 << 2 << 3)) - << qMakePair(KeyPress(Qt::Key_Space, Qt::ControlModifier), ViewState(1, QSet() << 0 << 2 << 3)) - << qMakePair(KeyPress(Qt::Key_Space, Qt::ControlModifier), ViewState(1, QSet() << 0 << 1 << 2 << 3)) - << qMakePair(KeyPress(Qt::Key_End), ViewState(19, QSet() << 19)) - << qMakePair(KeyPress(previousItemKey, Qt::ShiftModifier), ViewState(18, QSet() << 18 << 19)) - << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, QSet() << 0)) - << qMakePair(KeyPress(Qt::Key_Space, Qt::ControlModifier), ViewState(0, QSet())) - << qMakePair(KeyPress(Qt::Key_Enter), ViewState(0, QSet(), true)) - << qMakePair(KeyPress(Qt::Key_Space, Qt::ControlModifier), ViewState(0, QSet() << 0)) - << qMakePair(KeyPress(Qt::Key_Space, Qt::ControlModifier), ViewState(0, QSet())) - << qMakePair(KeyPress(Qt::Key_Space), ViewState(0, QSet() << 0)) - << qMakePair(KeyPress(Qt::Key_E), ViewState(13, QSet() << 13)) - << qMakePair(KeyPress(Qt::Key_Space), ViewState(14, QSet() << 14)) - << qMakePair(KeyPress(Qt::Key_3), ViewState(15, QSet() << 15)) - << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, QSet() << 0)) - << qMakePair(KeyPress(Qt::Key_Escape), ViewState(0, QSet())); + << qMakePair(KeyPress(nextItemKey), ViewState(1, KItemSet() << 1)) + << qMakePair(KeyPress(Qt::Key_Return), ViewState(1, KItemSet() << 1, true)) + << qMakePair(KeyPress(Qt::Key_Enter), ViewState(1, KItemSet() << 1, true)) + << qMakePair(KeyPress(nextItemKey), ViewState(2, KItemSet() << 2)) + << qMakePair(KeyPress(nextItemKey, Qt::ShiftModifier), ViewState(3, KItemSet() << 2 << 3)) + << qMakePair(KeyPress(Qt::Key_Return), ViewState(3, KItemSet() << 2 << 3, true)) + << qMakePair(KeyPress(previousItemKey, Qt::ShiftModifier), ViewState(2, KItemSet() << 2)) + << qMakePair(KeyPress(nextItemKey, Qt::ShiftModifier), ViewState(3, KItemSet() << 2 << 3)) + << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(4, KItemSet() << 2 << 3)) + << qMakePair(KeyPress(Qt::Key_Return), ViewState(4, KItemSet() << 2 << 3, true)) + << qMakePair(KeyPress(previousItemKey), ViewState(3, KItemSet() << 3)) + << qMakePair(KeyPress(Qt::Key_Home, Qt::ShiftModifier), ViewState(0, KItemSet() << 0 << 1 << 2 << 3)) + << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(1, KItemSet() << 0 << 1 << 2 << 3)) + << qMakePair(KeyPress(Qt::Key_Space, Qt::ControlModifier), ViewState(1, KItemSet() << 0 << 2 << 3)) + << qMakePair(KeyPress(Qt::Key_Space, Qt::ControlModifier), ViewState(1, KItemSet() << 0 << 1 << 2 << 3)) + << qMakePair(KeyPress(Qt::Key_End), ViewState(19, KItemSet() << 19)) + << qMakePair(KeyPress(previousItemKey, Qt::ShiftModifier), ViewState(18, KItemSet() << 18 << 19)) + << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, KItemSet() << 0)) + << qMakePair(KeyPress(Qt::Key_Space, Qt::ControlModifier), ViewState(0, KItemSet())) + << qMakePair(KeyPress(Qt::Key_Enter), ViewState(0, KItemSet(), true)) + << qMakePair(KeyPress(Qt::Key_Space, Qt::ControlModifier), ViewState(0, KItemSet() << 0)) + << qMakePair(KeyPress(Qt::Key_Space, Qt::ControlModifier), ViewState(0, KItemSet())) + << qMakePair(KeyPress(Qt::Key_Space), ViewState(0, KItemSet() << 0)) + << qMakePair(KeyPress(Qt::Key_E), ViewState(13, KItemSet() << 13)) + << qMakePair(KeyPress(Qt::Key_Space), ViewState(14, KItemSet() << 14)) + << qMakePair(KeyPress(Qt::Key_3), ViewState(15, KItemSet() << 15)) + << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, KItemSet() << 0)) + << qMakePair(KeyPress(Qt::Key_Escape), ViewState(0, KItemSet())); // Next, we test combinations of key presses which only work for a // particular number of columns and either enabled or disabled grouping. @@ -297,12 +297,12 @@ void KItemListControllerTest::testKeyboardNavigation_data() // One column. if (columnCount == 1) { testList - << qMakePair(KeyPress(nextRowKey), ViewState(1, QSet() << 1)) - << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(2, QSet() << 1 << 2)) - << qMakePair(KeyPress(nextRowKey, Qt::ControlModifier), ViewState(3, QSet() << 1 << 2)) - << qMakePair(KeyPress(previousRowKey), ViewState(2, QSet() << 2)) - << qMakePair(KeyPress(previousItemKey), ViewState(1, QSet() << 1)) - << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, QSet() << 0)); + << qMakePair(KeyPress(nextRowKey), ViewState(1, KItemSet() << 1)) + << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(2, KItemSet() << 1 << 2)) + << qMakePair(KeyPress(nextRowKey, Qt::ControlModifier), ViewState(3, KItemSet() << 1 << 2)) + << qMakePair(KeyPress(previousRowKey), ViewState(2, KItemSet() << 2)) + << qMakePair(KeyPress(previousItemKey), ViewState(1, KItemSet() << 1)) + << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, KItemSet() << 0)); } // Multiple columns: we test both 3 and 5 columns with grouping @@ -321,26 +321,26 @@ void KItemListControllerTest::testKeyboardNavigation_data() // e3 e4 e5 | 15 16 17 // e6 e7 | 18 19 testList - << qMakePair(KeyPress(nextRowKey), ViewState(3, QSet() << 3)) - << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(4, QSet() << 3)) - << qMakePair(KeyPress(nextRowKey), ViewState(7, QSet() << 7)) - << qMakePair(KeyPress(nextItemKey, Qt::ShiftModifier), ViewState(8, QSet() << 7 << 8)) - << qMakePair(KeyPress(nextItemKey, Qt::ShiftModifier), ViewState(9, QSet() << 7 << 8 << 9)) - << qMakePair(KeyPress(previousItemKey, Qt::ShiftModifier), ViewState(8, QSet() << 7 << 8)) - << qMakePair(KeyPress(previousItemKey, Qt::ShiftModifier), ViewState(7, QSet() << 7)) - << qMakePair(KeyPress(previousItemKey, Qt::ShiftModifier), ViewState(6, QSet() << 6 << 7)) - << qMakePair(KeyPress(previousItemKey, Qt::ShiftModifier), ViewState(5, QSet() << 5 << 6 << 7)) - << qMakePair(KeyPress(nextItemKey, Qt::ShiftModifier), ViewState(6, QSet() << 6 << 7)) - << qMakePair(KeyPress(nextItemKey, Qt::ShiftModifier), ViewState(7, QSet() << 7)) - << qMakePair(KeyPress(nextRowKey), ViewState(10, QSet() << 10)) - << qMakePair(KeyPress(nextItemKey), ViewState(11, QSet() << 11)) - << qMakePair(KeyPress(nextRowKey), ViewState(14, QSet() << 14)) - << qMakePair(KeyPress(nextRowKey), ViewState(17, QSet() << 17)) - << qMakePair(KeyPress(nextRowKey), ViewState(19, QSet() << 19)) - << qMakePair(KeyPress(previousRowKey), ViewState(17, QSet() << 17)) - << qMakePair(KeyPress(Qt::Key_End), ViewState(19, QSet() << 19)) - << qMakePair(KeyPress(previousRowKey), ViewState(16, QSet() << 16)) - << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, QSet() << 0)); + << qMakePair(KeyPress(nextRowKey), ViewState(3, KItemSet() << 3)) + << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(4, KItemSet() << 3)) + << qMakePair(KeyPress(nextRowKey), ViewState(7, KItemSet() << 7)) + << qMakePair(KeyPress(nextItemKey, Qt::ShiftModifier), ViewState(8, KItemSet() << 7 << 8)) + << qMakePair(KeyPress(nextItemKey, Qt::ShiftModifier), ViewState(9, KItemSet() << 7 << 8 << 9)) + << qMakePair(KeyPress(previousItemKey, Qt::ShiftModifier), ViewState(8, KItemSet() << 7 << 8)) + << qMakePair(KeyPress(previousItemKey, Qt::ShiftModifier), ViewState(7, KItemSet() << 7)) + << qMakePair(KeyPress(previousItemKey, Qt::ShiftModifier), ViewState(6, KItemSet() << 6 << 7)) + << qMakePair(KeyPress(previousItemKey, Qt::ShiftModifier), ViewState(5, KItemSet() << 5 << 6 << 7)) + << qMakePair(KeyPress(nextItemKey, Qt::ShiftModifier), ViewState(6, KItemSet() << 6 << 7)) + << qMakePair(KeyPress(nextItemKey, Qt::ShiftModifier), ViewState(7, KItemSet() << 7)) + << qMakePair(KeyPress(nextRowKey), ViewState(10, KItemSet() << 10)) + << qMakePair(KeyPress(nextItemKey), ViewState(11, KItemSet() << 11)) + << qMakePair(KeyPress(nextRowKey), ViewState(14, KItemSet() << 14)) + << qMakePair(KeyPress(nextRowKey), ViewState(17, KItemSet() << 17)) + << qMakePair(KeyPress(nextRowKey), ViewState(19, KItemSet() << 19)) + << qMakePair(KeyPress(previousRowKey), ViewState(17, KItemSet() << 17)) + << qMakePair(KeyPress(Qt::Key_End), ViewState(19, KItemSet() << 19)) + << qMakePair(KeyPress(previousRowKey), ViewState(16, KItemSet() << 16)) + << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, KItemSet() << 0)); } if (columnCount == 5 && !groupingEnabled) { @@ -351,17 +351,17 @@ void KItemListControllerTest::testKeyboardNavigation_data() // d2 d3 d4 e1 e2 | 10 11 12 13 14 // e3 e4 e5 e6 e7 | 15 16 17 18 19 testList - << qMakePair(KeyPress(nextRowKey), ViewState(5, QSet() << 5)) - << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(6, QSet() << 5)) - << qMakePair(KeyPress(nextRowKey), ViewState(11, QSet() << 11)) - << qMakePair(KeyPress(nextItemKey), ViewState(12, QSet() << 12)) - << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(17, QSet() << 12 << 13 << 14 << 15 << 16 << 17)) - << qMakePair(KeyPress(previousRowKey, Qt::ShiftModifier), ViewState(12, QSet() << 12)) - << qMakePair(KeyPress(previousRowKey, Qt::ShiftModifier), ViewState(7, QSet() << 7 << 8 << 9 << 10 << 11 << 12)) - << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(12, QSet() << 12)) - << qMakePair(KeyPress(Qt::Key_End, Qt::ControlModifier), ViewState(19, QSet() << 12)) - << qMakePair(KeyPress(previousRowKey), ViewState(14, QSet() << 14)) - << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, QSet() << 0)); + << qMakePair(KeyPress(nextRowKey), ViewState(5, KItemSet() << 5)) + << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(6, KItemSet() << 5)) + << qMakePair(KeyPress(nextRowKey), ViewState(11, KItemSet() << 11)) + << qMakePair(KeyPress(nextItemKey), ViewState(12, KItemSet() << 12)) + << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(17, KItemSet() << 12 << 13 << 14 << 15 << 16 << 17)) + << qMakePair(KeyPress(previousRowKey, Qt::ShiftModifier), ViewState(12, KItemSet() << 12)) + << qMakePair(KeyPress(previousRowKey, Qt::ShiftModifier), ViewState(7, KItemSet() << 7 << 8 << 9 << 10 << 11 << 12)) + << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(12, KItemSet() << 12)) + << qMakePair(KeyPress(Qt::Key_End, Qt::ControlModifier), ViewState(19, KItemSet() << 12)) + << qMakePair(KeyPress(previousRowKey), ViewState(14, KItemSet() << 14)) + << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, KItemSet() << 0)); } if (columnCount == 3 && groupingEnabled) { @@ -377,19 +377,19 @@ void KItemListControllerTest::testKeyboardNavigation_data() // e4 e5 e6 | 16 17 18 // e7 | 19 testList - << qMakePair(KeyPress(nextItemKey), ViewState(1, QSet() << 1)) - << qMakePair(KeyPress(nextItemKey), ViewState(2, QSet() << 2)) - << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(3, QSet() << 2 << 3)) - << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(6, QSet() << 2 << 3 << 4 << 5 << 6)) - << qMakePair(KeyPress(nextRowKey), ViewState(8, QSet() << 8)) - << qMakePair(KeyPress(nextRowKey), ViewState(11, QSet() << 11)) - << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(12, QSet() << 11)) - << qMakePair(KeyPress(nextRowKey), ViewState(13, QSet() << 13)) - << qMakePair(KeyPress(nextRowKey), ViewState(16, QSet() << 16)) - << qMakePair(KeyPress(nextItemKey), ViewState(17, QSet() << 17)) - << qMakePair(KeyPress(nextRowKey), ViewState(19, QSet() << 19)) - << qMakePair(KeyPress(previousRowKey), ViewState(17, QSet() << 17)) - << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, QSet() << 0)); + << qMakePair(KeyPress(nextItemKey), ViewState(1, KItemSet() << 1)) + << qMakePair(KeyPress(nextItemKey), ViewState(2, KItemSet() << 2)) + << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(3, KItemSet() << 2 << 3)) + << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(6, KItemSet() << 2 << 3 << 4 << 5 << 6)) + << qMakePair(KeyPress(nextRowKey), ViewState(8, KItemSet() << 8)) + << qMakePair(KeyPress(nextRowKey), ViewState(11, KItemSet() << 11)) + << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(12, KItemSet() << 11)) + << qMakePair(KeyPress(nextRowKey), ViewState(13, KItemSet() << 13)) + << qMakePair(KeyPress(nextRowKey), ViewState(16, KItemSet() << 16)) + << qMakePair(KeyPress(nextItemKey), ViewState(17, KItemSet() << 17)) + << qMakePair(KeyPress(nextRowKey), ViewState(19, KItemSet() << 19)) + << qMakePair(KeyPress(previousRowKey), ViewState(17, KItemSet() << 17)) + << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, KItemSet() << 0)); } if (columnCount == 5 && groupingEnabled) { @@ -402,19 +402,19 @@ void KItemListControllerTest::testKeyboardNavigation_data() // e1 e2 e3 e4 e5 | 13 14 15 16 17 // e6 e7 | 18 19 testList - << qMakePair(KeyPress(nextItemKey), ViewState(1, QSet() << 1)) - << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(3, QSet() << 1 << 2 << 3)) - << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(5, QSet() << 1 << 2 << 3 << 4 << 5)) - << qMakePair(KeyPress(nextItemKey), ViewState(6, QSet() << 6)) - << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(7, QSet() << 6)) - << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(8, QSet() << 6)) - << qMakePair(KeyPress(nextRowKey), ViewState(12, QSet() << 12)) - << qMakePair(KeyPress(nextRowKey), ViewState(17, QSet() << 17)) - << qMakePair(KeyPress(nextRowKey), ViewState(19, QSet() << 19)) - << qMakePair(KeyPress(previousRowKey), ViewState(17, QSet() << 17)) - << qMakePair(KeyPress(Qt::Key_End, Qt::ShiftModifier), ViewState(19, QSet() << 17 << 18 << 19)) - << qMakePair(KeyPress(previousRowKey, Qt::ShiftModifier), ViewState(14, QSet() << 14 << 15 << 16 << 17)) - << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, QSet() << 0)); + << qMakePair(KeyPress(nextItemKey), ViewState(1, KItemSet() << 1)) + << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(3, KItemSet() << 1 << 2 << 3)) + << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(5, KItemSet() << 1 << 2 << 3 << 4 << 5)) + << qMakePair(KeyPress(nextItemKey), ViewState(6, KItemSet() << 6)) + << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(7, KItemSet() << 6)) + << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(8, KItemSet() << 6)) + << qMakePair(KeyPress(nextRowKey), ViewState(12, KItemSet() << 12)) + << qMakePair(KeyPress(nextRowKey), ViewState(17, KItemSet() << 17)) + << qMakePair(KeyPress(nextRowKey), ViewState(19, KItemSet() << 19)) + << qMakePair(KeyPress(previousRowKey), ViewState(17, KItemSet() << 17)) + << qMakePair(KeyPress(Qt::Key_End, Qt::ShiftModifier), ViewState(19, KItemSet() << 17 << 18 << 19)) + << qMakePair(KeyPress(previousRowKey, Qt::ShiftModifier), ViewState(14, KItemSet() << 14 << 15 << 16 << 17)) + << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, KItemSet() << 0)); } const QString testName = @@ -470,14 +470,14 @@ void KItemListControllerTest::testKeyboardNavigation() QCOMPARE(m_view->m_layouter->m_columnCount, columnCount); QSignalSpy spySingleItemActivated(m_controller, SIGNAL(itemActivated(int))); - QSignalSpy spyMultipleItemsActivated(m_controller, SIGNAL(itemsActivated(QSet))); + QSignalSpy spyMultipleItemsActivated(m_controller, SIGNAL(itemsActivated(KItemSet))); while (!testList.isEmpty()) { const QPair test = testList.takeFirst(); const Qt::Key key = test.first.m_key; const Qt::KeyboardModifiers modifier = test.first.m_modifier; const int current = test.second.m_current; - const QSet selection = test.second.m_selection; + const KItemSet selection = test.second.m_selection; const bool activated = test.second.m_activated; QTest::keyClick(m_container, key, modifier); @@ -485,7 +485,7 @@ void KItemListControllerTest::testKeyboardNavigation() QCOMPARE(m_selectionManager->currentItem(), current); switch (selectionBehavior) { case KItemListController::NoSelection: QVERIFY(m_selectionManager->selectedItems().isEmpty()); break; - case KItemListController::SingleSelection: QCOMPARE(m_selectionManager->selectedItems(), QSet() << current); break; + case KItemListController::SingleSelection: QCOMPARE(m_selectionManager->selectedItems(), KItemSet() << current); break; case KItemListController::MultiSelection: QCOMPARE(m_selectionManager->selectedItems(), selection); break; } @@ -496,12 +496,12 @@ void KItemListControllerTest::testKeyboardNavigation() // The selected items should be activated. if (selection.count() == 1) { QVERIFY(!spySingleItemActivated.isEmpty()); - QCOMPARE(qvariant_cast(spySingleItemActivated.takeFirst().at(0)), selection.toList().at(0)); + QCOMPARE(qvariant_cast(spySingleItemActivated.takeFirst().at(0)), selection.first()); QVERIFY(spyMultipleItemsActivated.isEmpty()); } else { QVERIFY(spySingleItemActivated.isEmpty()); QVERIFY(!spyMultipleItemsActivated.isEmpty()); - QCOMPARE(qvariant_cast >(spyMultipleItemsActivated.takeFirst().at(0)), selection); + QCOMPARE(qvariant_cast(spyMultipleItemsActivated.takeFirst().at(0)), selection); } break; } @@ -641,7 +641,7 @@ void KItemListControllerTest::testMouseClickActivation() group.writeEntry("SingleClick", restoreKGlobalSettingsSingleClick, KConfig::Persistent|KConfig::Global); config.sync(); KGlobalSettings::self()->emitChange(KGlobalSettings::SettingsChanged, KGlobalSettings::SETTINGS_MOUSE); - + iterations = 0; while (KGlobalSettings::singleClick() != restoreKGlobalSettingsSingleClick && iterations < maxIterations) { QTest::qWait(50); diff --git a/src/tests/kitemlistselectionmanagertest.cpp b/src/tests/kitemlistselectionmanagertest.cpp index 302985a5f4..af2610d8c2 100644 --- a/src/tests/kitemlistselectionmanagertest.cpp +++ b/src/tests/kitemlistselectionmanagertest.cpp @@ -80,7 +80,7 @@ private slots: void testDeleteCurrentItem(); private: - void verifySelectionChange(QSignalSpy& spy, const QSet& currentSelection, const QSet& previousSelection) const; + void verifySelectionChange(QSignalSpy& spy, const KItemSet& currentSelection, const KItemSet& previousSelection) const; KItemListSelectionManager* m_selectionManager; DummyModel* m_model; @@ -127,7 +127,7 @@ void KItemListSelectionManagerTest::testCurrentItemAnchorItem() QCOMPARE(m_selectionManager->m_anchorItem, 5); // Items between current and anchor should be selected now - QCOMPARE(m_selectionManager->selectedItems(), QSet() << 4 << 5); + QCOMPARE(m_selectionManager->selectedItems(), KItemSet() << 4 << 5); QVERIFY(m_selectionManager->hasSelection()); // Change current item again and check the selection @@ -138,7 +138,7 @@ void KItemListSelectionManagerTest::testCurrentItemAnchorItem() QCOMPARE(qvariant_cast(spyCurrent.at(0).at(1)), 4); spyCurrent.takeFirst(); - QCOMPARE(m_selectionManager->selectedItems(), QSet() << 2 << 3 << 4 << 5); + QCOMPARE(m_selectionManager->selectedItems(), KItemSet() << 2 << 3 << 4 << 5); QVERIFY(m_selectionManager->hasSelection()); // Inserting items should update current item and anchor item. @@ -155,7 +155,7 @@ void KItemListSelectionManagerTest::testCurrentItemAnchorItem() QCOMPARE(m_selectionManager->m_anchorItem, 8); - QCOMPARE(m_selectionManager->selectedItems(), QSet() << 5 << 6 << 7 << 8); + QCOMPARE(m_selectionManager->selectedItems(), KItemSet() << 5 << 6 << 7 << 8); QVERIFY(m_selectionManager->hasSelection()); // Removing items should update current item and anchor item. @@ -172,12 +172,12 @@ void KItemListSelectionManagerTest::testCurrentItemAnchorItem() QCOMPARE(m_selectionManager->m_anchorItem, 5); - QCOMPARE(m_selectionManager->selectedItems(), QSet() << 2 << 3 << 4 << 5); + QCOMPARE(m_selectionManager->selectedItems(), KItemSet() << 2 << 3 << 4 << 5); QVERIFY(m_selectionManager->hasSelection()); // Verify that clearSelection() also clears the anchored selection. m_selectionManager->clearSelection(); - QCOMPARE(m_selectionManager->selectedItems(), QSet()); + QCOMPARE(m_selectionManager->selectedItems(), KItemSet()); QVERIFY(!m_selectionManager->hasSelection()); m_selectionManager->endAnchoredSelection(); @@ -212,7 +212,7 @@ void KItemListSelectionManagerTest::testItemsInserted() { // Select items 10 to 12 m_selectionManager->setSelected(10, 3); - QSet selectedItems = m_selectionManager->selectedItems(); + KItemSet selectedItems = m_selectionManager->selectedItems(); QCOMPARE(selectedItems.count(), 3); QVERIFY(selectedItems.contains(10)); QVERIFY(selectedItems.contains(11)); @@ -242,7 +242,7 @@ void KItemListSelectionManagerTest::testItemsRemoved() { // Select items 10 to 15 m_selectionManager->setSelected(10, 6); - QSet selectedItems = m_selectionManager->selectedItems(); + KItemSet selectedItems = m_selectionManager->selectedItems(); QCOMPARE(selectedItems.count(), 6); for (int i = 10; i <= 15; ++i) { QVERIFY(selectedItems.contains(i)); @@ -276,20 +276,20 @@ void KItemListSelectionManagerTest::testAnchoredSelection() m_selectionManager->setCurrentItem(6); QCOMPARE(m_selectionManager->currentItem(), 6); - QCOMPARE(m_selectionManager->selectedItems(), QSet() << 5 << 6); + QCOMPARE(m_selectionManager->selectedItems(), KItemSet() << 5 << 6); m_selectionManager->setCurrentItem(4); QCOMPARE(m_selectionManager->currentItem(), 4); - QCOMPARE(m_selectionManager->selectedItems(), QSet() << 4 << 5); + QCOMPARE(m_selectionManager->selectedItems(), KItemSet() << 4 << 5); m_selectionManager->setCurrentItem(7); QCOMPARE(m_selectionManager->currentItem(), 7); - QCOMPARE(m_selectionManager->selectedItems(), QSet() << 5 << 6 << 7); + QCOMPARE(m_selectionManager->selectedItems(), KItemSet() << 5 << 6 << 7); // Ending the anchored selection should not change the selected items. m_selectionManager->endAnchoredSelection(); QVERIFY(!m_selectionManager->isAnchoredSelectionActive()); - QCOMPARE(m_selectionManager->selectedItems(), QSet() << 5 << 6 << 7); + QCOMPARE(m_selectionManager->selectedItems(), KItemSet() << 5 << 6 << 7); // Start a new anchored selection that overlaps the previous one m_selectionManager->beginAnchoredSelection(9); @@ -298,15 +298,15 @@ void KItemListSelectionManagerTest::testAnchoredSelection() m_selectionManager->setCurrentItem(6); QCOMPARE(m_selectionManager->currentItem(), 6); - QCOMPARE(m_selectionManager->selectedItems(), QSet() << 5 << 6 << 7 << 8 << 9); + QCOMPARE(m_selectionManager->selectedItems(), KItemSet() << 5 << 6 << 7 << 8 << 9); m_selectionManager->setCurrentItem(10); QCOMPARE(m_selectionManager->currentItem(), 10); - QCOMPARE(m_selectionManager->selectedItems(), QSet() << 5 << 6 << 7 << 9 << 10); + QCOMPARE(m_selectionManager->selectedItems(), KItemSet() << 5 << 6 << 7 << 9 << 10); m_selectionManager->endAnchoredSelection(); QVERIFY(!m_selectionManager->isAnchoredSelectionActive()); - QCOMPARE(m_selectionManager->selectedItems(), QSet() << 5 << 6 << 7 << 9 << 10); + QCOMPARE(m_selectionManager->selectedItems(), KItemSet() << 5 << 6 << 7 << 9 << 10); } namespace { @@ -320,7 +320,7 @@ namespace { }; } -Q_DECLARE_METATYPE(QSet); +Q_DECLARE_METATYPE(KItemSet); Q_DECLARE_METATYPE(ChangeType); Q_DECLARE_METATYPE(KItemRange); Q_DECLARE_METATYPE(KItemRangeList); @@ -355,86 +355,86 @@ Q_DECLARE_METATYPE(QList); void KItemListSelectionManagerTest::testChangeSelection_data() { - QTest::addColumn >("initialSelection"); + QTest::addColumn("initialSelection"); QTest::addColumn("anchor"); QTest::addColumn("current"); - QTest::addColumn >("expectedSelection"); + QTest::addColumn("expectedSelection"); QTest::addColumn("changeType"); QTest::addColumn >("data"); - QTest::addColumn >("finalSelection"); + QTest::addColumn("finalSelection"); QTest::newRow("No change") - << (QSet() << 5 << 6) + << (KItemSet() << 5 << 6) << 2 << 3 - << (QSet() << 2 << 3 << 5 << 6) + << (KItemSet() << 2 << 3 << 5 << 6) << NoChange << QList() - << (QSet() << 2 << 3 << 5 << 6); + << (KItemSet() << 2 << 3 << 5 << 6); QTest::newRow("Insert Items") - << (QSet() << 5 << 6) + << (KItemSet() << 5 << 6) << 2 << 3 - << (QSet() << 2 << 3 << 5 << 6) + << (KItemSet() << 2 << 3 << 5 << 6) << InsertItems << (QList() << QVariant::fromValue(KItemRangeList() << KItemRange(1, 1) << KItemRange(5, 2) << KItemRange(10, 5))) - << (QSet() << 3 << 4 << 8 << 9); + << (KItemSet() << 3 << 4 << 8 << 9); QTest::newRow("Remove Items") - << (QSet() << 5 << 6) + << (KItemSet() << 5 << 6) << 2 << 3 - << (QSet() << 2 << 3 << 5 << 6) + << (KItemSet() << 2 << 3 << 5 << 6) << RemoveItems << (QList() << QVariant::fromValue(KItemRangeList() << KItemRange(1, 1) << KItemRange(3, 1) << KItemRange(10, 5))) - << (QSet() << 1 << 2 << 3 << 4); + << (KItemSet() << 1 << 2 << 3 << 4); QTest::newRow("Empty Anchored Selection") - << QSet() + << KItemSet() << 2 << 2 - << QSet() + << KItemSet() << EndAnchoredSelection << QList() - << QSet(); + << KItemSet(); QTest::newRow("Toggle selection") - << (QSet() << 1 << 3 << 4) + << (KItemSet() << 1 << 3 << 4) << 6 << 8 - << (QSet() << 1 << 3 << 4 << 6 << 7 << 8) + << (KItemSet() << 1 << 3 << 4 << 6 << 7 << 8) << SetSelected << (QList() << 0 << 10 << QVariant::fromValue(KItemListSelectionManager::Toggle)) - << (QSet() << 0 << 2 << 5 << 9); + << (KItemSet() << 0 << 2 << 5 << 9); // Swap items 2, 3 and 4, 5 QTest::newRow("Move items") - << (QSet() << 0 << 1 << 2 << 3) + << (KItemSet() << 0 << 1 << 2 << 3) << -1 << -1 - << (QSet() << 0 << 1 << 2 << 3) + << (KItemSet() << 0 << 1 << 2 << 3) << MoveItems << (QList() << QVariant::fromValue(KItemRange(2, 4)) << QVariant::fromValue(QList() << 4 << 5 << 2 << 3)) - << (QSet() << 0 << 1 << 4 << 5); + << (KItemSet() << 0 << 1 << 4 << 5); // Revert sort order QTest::newRow("Revert sort order") - << (QSet() << 0 << 1) + << (KItemSet() << 0 << 1) << 3 << 4 - << (QSet() << 0 << 1 << 3 << 4) + << (KItemSet() << 0 << 1 << 3 << 4) << MoveItems << (QList() << QVariant::fromValue(KItemRange(0, 10)) << QVariant::fromValue(QList() << 9 << 8 << 7 << 6 << 5 << 4 << 3 << 2 << 1 << 0)) - << (QSet() << 5 << 6 << 8 << 9); + << (KItemSet() << 5 << 6 << 8 << 9); } void KItemListSelectionManagerTest::testChangeSelection() { - QFETCH(QSet, initialSelection); + QFETCH(KItemSet, initialSelection); QFETCH(int, anchor); QFETCH(int, current); - QFETCH(QSet, expectedSelection); + QFETCH(KItemSet, expectedSelection); QFETCH(ChangeType, changeType); QFETCH(QList, data); - QFETCH(QSet, finalSelection); + QFETCH(KItemSet, finalSelection); - QSignalSpy spySelectionChanged(m_selectionManager, SIGNAL(selectionChanged(QSet,QSet))); + QSignalSpy spySelectionChanged(m_selectionManager, SIGNAL(selectionChanged(KItemSet,KItemSet))); // Initial selection should be empty QVERIFY(!m_selectionManager->hasSelection()); @@ -443,7 +443,7 @@ void KItemListSelectionManagerTest::testChangeSelection() // Perform the initial selectiion m_selectionManager->setSelectedItems(initialSelection); - verifySelectionChange(spySelectionChanged, initialSelection, QSet()); + verifySelectionChange(spySelectionChanged, initialSelection, KItemSet()); // Perform an anchored selection. // Note that current and anchor index are equal first because this is the case in typical uses of the @@ -486,7 +486,7 @@ void KItemListSelectionManagerTest::testChangeSelection() // Finally, clear the selection m_selectionManager->clearSelection(); - verifySelectionChange(spySelectionChanged, QSet(), finalSelection); + verifySelectionChange(spySelectionChanged, KItemSet(), finalSelection); } void KItemListSelectionManagerTest::testDeleteCurrentItem_data() @@ -520,8 +520,8 @@ void KItemListSelectionManagerTest::testDeleteCurrentItem() } void KItemListSelectionManagerTest::verifySelectionChange(QSignalSpy& spy, - const QSet& currentSelection, - const QSet& previousSelection) const + const KItemSet& currentSelection, + const KItemSet& previousSelection) const { QCOMPARE(m_selectionManager->selectedItems(), currentSelection); QCOMPARE(m_selectionManager->hasSelection(), !currentSelection.isEmpty()); @@ -540,8 +540,8 @@ void KItemListSelectionManagerTest::verifySelectionChange(QSignalSpy& spy, else { QCOMPARE(spy.count(), 1); QList arguments = spy.takeFirst(); - QCOMPARE(qvariant_cast >(arguments.at(0)), currentSelection); - QCOMPARE(qvariant_cast >(arguments.at(1)), previousSelection); + QCOMPARE(qvariant_cast(arguments.at(0)), currentSelection); + QCOMPARE(qvariant_cast(arguments.at(1)), previousSelection); } } diff --git a/src/tests/kitemsettest.cpp b/src/tests/kitemsettest.cpp new file mode 100644 index 0000000000..2832596ba6 --- /dev/null +++ b/src/tests/kitemsettest.cpp @@ -0,0 +1,612 @@ +/*************************************************************************** + * Copyright (C) 2013 by Frank Reininghaus * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#include + +#include "kitemviews/kitemset.h" + +#include + +Q_DECLARE_METATYPE(KItemRangeList); + +/** + * Converts a KItemRangeList to a KItemSet. + */ +KItemSet KItemRangeList2KItemSet(const KItemRangeList& itemRanges) +{ + KItemSet result; + foreach (const KItemRange& range, itemRanges) { + for (int i = range.index; i < range.index + range.count; ++i) { + result.insert(i); + } + } + return result; +} + +/** + * Converts a KItemRangeList to a QSet. + */ +QSet KItemRangeList2QSet(const KItemRangeList& itemRanges) +{ + QSet result; + foreach (const KItemRange& range, itemRanges) { + for (int i = range.index; i < range.index + range.count; ++i) { + result.insert(i); + } + } + return result; +} + +/** + * Converts a KItemRangeList to a QVector. + */ +QVector KItemRangeList2QVector(const KItemRangeList& itemRanges) +{ + QVector result; + foreach (const KItemRange& range, itemRanges) { + for (int i = range.index; i < range.index + range.count; ++i) { + result.append(i); + } + } + return result; +} + +/** + * Converts a KItemSet to a QSet. + */ +static QSet KItemSet2QSet(const KItemSet& itemSet) +{ + QSet result; + foreach (int i, itemSet) { + result.insert(i); + } + + // Check that the conversion was successful. + Q_ASSERT(itemSet.count() == result.count()); + + foreach (int i, itemSet) { + Q_ASSERT(result.contains(i)); + } + + foreach (int i, result) { + Q_ASSERT(itemSet.contains(i)); + } + + return result; +} + + +/** + * The main test class. + */ +class KItemSetTest : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + + void testConstruction_data(); + void testConstruction(); + void testIterators_data(); + void testIterators(); + void testFind_data(); + void testFind(); + void testChangingOneItem_data(); + void testChangingOneItem(); + void testAddSets_data(); + void testAddSets(); + /* + void testSubtractSets_data(); + void testSubtractSets(); + */ + void testSymmetricDifference_data(); + void testSymmetricDifference(); + +private: + QHash m_testCases; +}; + +void KItemSetTest::initTestCase() +{ + m_testCases.insert("empty", KItemRangeList()); + m_testCases.insert("[0]", KItemRangeList() << KItemRange(0, 1)); + m_testCases.insert("[1]", KItemRangeList() << KItemRange(1, 1)); + m_testCases.insert("[1, 2]", KItemRangeList() << KItemRange(1, 2)); + m_testCases.insert("[1, 2] [5]", KItemRangeList() << KItemRange(1, 2) << KItemRange(5, 1)); + m_testCases.insert("[1] [4, 5]", KItemRangeList() << KItemRange(1, 1) << KItemRange(4, 2)); + m_testCases.insert("[1, 2] [4, 5]", KItemRangeList() << KItemRange(1, 2) << KItemRange(4, 2)); + m_testCases.insert("[1, 5]", KItemRangeList() << KItemRange(1, 5)); + m_testCases.insert("[1, 2] [4, 5] [7] [9, 10] [13] [20, 25] [30]", + KItemRangeList() << KItemRange(1, 2) << KItemRange(4, 2) << KItemRange(7, 1) << KItemRange(9, 2) << KItemRange(20, 6) << KItemRange(30, 1)); + m_testCases.insert("[-10, -1]", KItemRangeList() << KItemRange(-10, 10)); + m_testCases.insert("[-10, 0]", KItemRangeList() << KItemRange(-10, 11)); + m_testCases.insert("[-10, 1]", KItemRangeList() << KItemRange(-10, 12)); + m_testCases.insert("[0, 9]", KItemRangeList() << KItemRange(0, 10)); + m_testCases.insert("[0, 19]", KItemRangeList() << KItemRange(0, 10)); +} + +void KItemSetTest::testConstruction_data() +{ + QTest::addColumn("itemRanges"); + + QHash::const_iterator it = m_testCases.constBegin(); + const QHash::const_iterator end = m_testCases.constEnd(); + + while (it != end) { + QTest::newRow(it.key()) << it.value(); + ++it; + } +} + +void KItemSetTest::testConstruction() +{ + QFETCH(KItemRangeList, itemRanges); + + KItemSet itemSet = KItemRangeList2KItemSet(itemRanges); + QSet itemsQSet = KItemRangeList2QSet(itemRanges); + + QVERIFY(itemSet.isValid()); + QVERIFY(itemSet.count() == itemsQSet.count()); + QCOMPARE(KItemSet2QSet(itemSet), itemsQSet); + + // Test copy constructor. + KItemSet copy(itemSet); + QCOMPARE(itemSet, copy); + copy.clear(); + QVERIFY(itemSet != copy || itemSet.isEmpty()); + + // Clear the set. + itemSet.clear(); + QVERIFY(itemSet.isEmpty()); + QCOMPARE(itemSet.count(), 0); +} + +void KItemSetTest::testIterators_data() +{ + QTest::addColumn("itemRanges"); + + QHash::const_iterator it = m_testCases.constBegin(); + const QHash::const_iterator end = m_testCases.constEnd(); + + while (it != end) { + QTest::newRow(it.key()) << it.value(); + ++it; + } +} + +/** + * Verify that the iterators work exactly like their counterparts for the + * equivalent QVector. + */ +void KItemSetTest::testIterators() +{ + QFETCH(KItemRangeList, itemRanges); + + KItemSet itemSet = KItemRangeList2KItemSet(itemRanges); + QVector itemsQVector = KItemRangeList2QVector(itemRanges); + + QVERIFY(itemSet.isValid()); + QVERIFY(itemSet.count() == itemsQVector.count()); + + if (itemSet.count() == 0) { + QVERIFY(itemSet.isEmpty()); + QVERIFY(itemSet.begin() == itemSet.end()); + QVERIFY(itemSet.constBegin() == itemSet.constEnd()); + } else { + QVERIFY(!itemSet.isEmpty()); + QVERIFY(itemSet.begin() != itemSet.end()); + QVERIFY(itemSet.constBegin() != itemSet.constEnd()); + + const int min = itemsQVector.first(); + const int max = itemsQVector.last(); + + QCOMPARE(*itemSet.begin(), min); + QCOMPARE(*itemSet.constBegin(), min); + QCOMPARE(itemSet.first(), min); + + QCOMPARE(*(--itemSet.end()), max); + QCOMPARE(*(--itemSet.constEnd()), max); + QCOMPARE(itemSet.last(), max); + } + + // Test iterating using the different iterators. + QVector testQVector; + for (KItemSet::iterator it = itemSet.begin(), end = itemSet.end(); it != end; ++it) { + testQVector.append(*it); + } + QCOMPARE(testQVector, itemsQVector); + + testQVector.clear(); + for (KItemSet::const_iterator it = itemSet.constBegin(), end = itemSet.constEnd(); it != end; ++it) { + testQVector.append(*it); + } + QCOMPARE(testQVector, itemsQVector); + + testQVector.clear(); + foreach (int i, itemSet) { + testQVector.append(i); + } + QCOMPARE(testQVector, itemsQVector); + + // Verify that both variants of the (const)iterator's operator++ and + // operator-- functions behave exactly like their QVector equivalents. + KItemSet::iterator it1 = itemSet.begin(); + KItemSet::iterator it2 = itemSet.begin(); + KItemSet::const_iterator constIt1 = itemSet.constBegin(); + KItemSet::const_iterator constIt2 = itemSet.constBegin(); + QVector::iterator vectorIt1 = itemsQVector.begin(); + QVector::iterator vectorIt2 = itemsQVector.begin(); + QVector::const_iterator vectorConstIt1 = itemsQVector.constBegin(); + QVector::const_iterator vectorConstIt2 = itemsQVector.constBegin(); + + while (it1 != itemSet.end()) { + if (it1 != --itemSet.end()) { + QCOMPARE(*(++it1), *(++vectorIt1)); + QCOMPARE(*(++constIt1), *(++vectorConstIt1)); + } else { + QCOMPARE(++it1, itemSet.end()); + QCOMPARE(++vectorIt1, itemsQVector.end()); + QCOMPARE(++constIt1, itemSet.constEnd()); + QCOMPARE(++vectorConstIt1, itemsQVector.constEnd()); + } + + QCOMPARE(*(it2++), *(vectorIt2++)); + QCOMPARE(*(constIt2++), *(vectorConstIt2++)); + + QCOMPARE(it1, it2); + QCOMPARE(constIt1, constIt2); + QCOMPARE(KItemSet::const_iterator(it1), constIt1); + } + + QCOMPARE(it1, itemSet.end()); + QCOMPARE(it2, itemSet.end()); + QCOMPARE(constIt1, itemSet.constEnd()); + QCOMPARE(constIt2, itemSet.constEnd()); + QCOMPARE(vectorIt1, itemsQVector.end()); + QCOMPARE(vectorIt2, itemsQVector.end()); + QCOMPARE(vectorConstIt1, itemsQVector.constEnd()); + QCOMPARE(vectorConstIt2, itemsQVector.constEnd()); + + while (it1 != itemSet.begin()) { + QCOMPARE(*(--it1), *(--vectorIt1)); + QCOMPARE(*(--constIt1), *(--vectorConstIt1)); + + if (it2 != itemSet.end()) { + QCOMPARE(*(it2--), *(vectorIt2--)); + QCOMPARE(*(constIt2--), *(vectorConstIt2--)); + } else { + QCOMPARE(it2--, itemSet.end()); + QCOMPARE(vectorIt2--, itemsQVector.end()); + QCOMPARE(constIt2--, itemSet.constEnd()); + QCOMPARE(vectorConstIt2--, itemsQVector.constEnd()); + } + + QCOMPARE(it1, it2); + QCOMPARE(constIt1, constIt2); + QCOMPARE(KItemSet::const_iterator(it1), constIt1); + } + + QCOMPARE(it1, itemSet.begin()); + QCOMPARE(it2, itemSet.begin()); + QCOMPARE(constIt1, itemSet.constBegin()); + QCOMPARE(constIt2, itemSet.constBegin()); + QCOMPARE(vectorIt1, itemsQVector.begin()); + QCOMPARE(vectorIt2, itemsQVector.begin()); + QCOMPARE(vectorConstIt1, itemsQVector.constBegin()); + QCOMPARE(vectorConstIt2, itemsQVector.constBegin()); +} + +void KItemSetTest::testFind_data() +{ + QTest::addColumn("itemRanges"); + + QHash::const_iterator it = m_testCases.constBegin(); + const QHash::const_iterator end = m_testCases.constEnd(); + + while (it != end) { + QTest::newRow(it.key()) << it.value(); + ++it; + } +} + +/** + * Test all functions that find items: + * contais(int), find(int), constFind(int) + */ +void KItemSetTest::testFind() +{ + QFETCH(KItemRangeList, itemRanges); + + KItemSet itemSet = KItemRangeList2KItemSet(itemRanges); + QSet itemsQSet = KItemRangeList2QSet(itemRanges); + + QVERIFY(itemSet.isValid()); + QVERIFY(itemSet.count() == itemsQSet.count()); + + // Find the minimum and maximum items. + int min; + int max; + + if (itemSet.count() == 0) { + // Use some arbitrary values for the upcoming tests. + min = 0; + max = 5; + } else { + min = *itemSet.begin(); + max = *(--itemSet.end()); + } + + // Test contains(int), find(int), and constFind(int) + // for items between min - 2 and max + 2. + for (int i = min - 2; i <= max + 2; ++i) { + const KItemSet::iterator it = itemSet.find(i); + const KItemSet::const_iterator constIt = itemSet.constFind(i); + QCOMPARE(KItemSet::const_iterator(it), constIt); + + if (itemsQSet.contains(i)) { + QVERIFY(itemSet.contains(i)); + QCOMPARE(*it, i); + QCOMPARE(*constIt, i); + } else { + QVERIFY(!itemSet.contains(i)); + QCOMPARE(it, itemSet.end()); + QCOMPARE(constIt, itemSet.constEnd()); + } + } +} + +void KItemSetTest::testChangingOneItem_data() +{ + QTest::addColumn("itemRanges"); + + QHash::const_iterator it = m_testCases.constBegin(); + const QHash::const_iterator end = m_testCases.constEnd(); + + while (it != end) { + QTest::newRow(it.key()) << it.value(); + ++it; + } +} + +/** + * Test all functions that change a single item: + * insert(int), remove(int), erase(KItemSet::iterator) + */ +void KItemSetTest::testChangingOneItem() +{ + QFETCH(KItemRangeList, itemRanges); + + KItemSet itemSet = KItemRangeList2KItemSet(itemRanges); + QSet itemsQSet = KItemRangeList2QSet(itemRanges); + + QVERIFY(itemSet.isValid()); + QVERIFY(itemSet.count() == itemsQSet.count()); + + // Find the minimum and maximum items. + int min; + int max; + + if (itemSet.count() == 0) { + // Use some arbitrary values for the upcoming tests. + min = 0; + max = 5; + } else { + min = *itemSet.begin(); + max = *(--itemSet.end()); + } + + // Test insert(int), remove(int), and erase(KItemSet::iterator) + // for items between min - 2 and max + 2. + for (int i = min - 2; i <= max + 2; ++i) { + + // Test insert(int). + { + KItemSet tmp(itemSet); + const KItemSet::iterator insertedIt = tmp.insert(i); + QCOMPARE(*insertedIt, i); + + QVERIFY(tmp.isValid()); + QVERIFY(tmp.contains(i)); + + QSet expectedQSet = itemsQSet; + expectedQSet.insert(i); + QCOMPARE(KItemSet2QSet(tmp), expectedQSet); + + if (!itemSet.contains(i)) { + QVERIFY(itemSet != tmp); + QCOMPARE(tmp.count(), itemSet.count() + 1); + } else { + QCOMPARE(itemSet, tmp); + } + + QCOMPARE(i, *tmp.find(i)); + QCOMPARE(i, *tmp.constFind(i)); + + // Erase the new item and check that we get the old KItemSet back. + tmp.erase(tmp.find(i)); + QVERIFY(tmp.isValid()); + QVERIFY(!tmp.contains(i)); + + if (!itemSet.contains(i)) { + QCOMPARE(itemSet, tmp); + } + + expectedQSet.remove(i); + QCOMPARE(KItemSet2QSet(tmp), expectedQSet); + } + + // Test remove(int). + { + KItemSet tmp(itemSet); + const bool removed = tmp.remove(i); + + QCOMPARE(removed, itemSet.contains(i)); + + QVERIFY(tmp.isValid()); + QVERIFY(!tmp.contains(i)); + + QSet expectedQSet = itemsQSet; + expectedQSet.remove(i); + QCOMPARE(KItemSet2QSet(tmp), expectedQSet); + + if (itemSet.contains(i)) { + QVERIFY(itemSet != tmp); + QCOMPARE(tmp.count(), itemSet.count() - 1); + } else { + QCOMPARE(itemSet, tmp); + } + + QCOMPARE(tmp.end(), tmp.find(i)); + QCOMPARE(tmp.constEnd(), tmp.constFind(i)); + } + + // Test erase(KItemSet::iterator). + if (itemSet.contains(i)) { + KItemSet tmp(itemSet); + KItemSet::iterator it = tmp.find(i); + it = tmp.erase(it); + + QVERIFY(tmp.isValid()); + QVERIFY(!tmp.contains(i)); + + QSet expectedQSet = itemsQSet; + expectedQSet.remove(i); + QCOMPARE(KItemSet2QSet(tmp), expectedQSet); + + if (itemSet.contains(i)) { + QVERIFY(itemSet != tmp); + QCOMPARE(tmp.count(), itemSet.count() - 1); + } else { + QCOMPARE(itemSet, tmp); + } + + QCOMPARE(tmp.end(), tmp.find(i)); + QCOMPARE(tmp.constEnd(), tmp.constFind(i)); + + // Check the returen value, now contained in 'it'. + if (i == max) { + QCOMPARE(it, tmp.end()); + } else { + // it now points to the next item. + QVERIFY(tmp.contains(*it)); + for (int j = i; j < *it; ++j) { + QVERIFY(!tmp.contains(j)); + } + } + } + } + + // Clear the set. + itemSet.clear(); + QVERIFY(itemSet.isEmpty()); + QCOMPARE(itemSet.count(), 0); +} + +void KItemSetTest::testAddSets_data() +{ + QTest::addColumn("itemRanges1"); + QTest::addColumn("itemRanges2"); + + QHash::const_iterator it1 = m_testCases.constBegin(); + const QHash::const_iterator end = m_testCases.constEnd(); + + while (it1 != end) { + QHash::const_iterator it2 = m_testCases.constBegin(); + + while (it2 != end) { + QByteArray name = it1.key() + QByteArray(" + ") + it2.key(); + QTest::newRow(name) << it1.value() << it2.value(); + ++it2; + } + + ++it1; + } +} + +void KItemSetTest::testAddSets() +{ + QFETCH(KItemRangeList, itemRanges1); + QFETCH(KItemRangeList, itemRanges2); + + KItemSet itemSet1 = KItemRangeList2KItemSet(itemRanges1); + QSet itemsQSet1 = KItemRangeList2QSet(itemRanges1); + + KItemSet itemSet2 = KItemRangeList2KItemSet(itemRanges2); + QSet itemsQSet2 = KItemRangeList2QSet(itemRanges2); + + KItemSet sum = itemSet1 + itemSet2; + QSet sumQSet = itemsQSet1 + itemsQSet2; + + QCOMPARE(sum.count(), sumQSet.count()); + QCOMPARE(KItemSet2QSet(sum), sumQSet); +} + +void KItemSetTest::testSymmetricDifference_data() +{ + QTest::addColumn("itemRanges1"); + QTest::addColumn("itemRanges2"); + + QHash::const_iterator it1 = m_testCases.constBegin(); + const QHash::const_iterator end = m_testCases.constEnd(); + + while (it1 != end) { + QHash::const_iterator it2 = m_testCases.constBegin(); + + while (it2 != end) { + QByteArray name = it1.key() + QByteArray(" ^ ") + it2.key(); + QTest::newRow(name) << it1.value() << it2.value(); + ++it2; + } + + ++it1; + } +} + +void KItemSetTest::testSymmetricDifference() +{ + QFETCH(KItemRangeList, itemRanges1); + QFETCH(KItemRangeList, itemRanges2); + + KItemSet itemSet1 = KItemRangeList2KItemSet(itemRanges1); + QSet itemsQSet1 = KItemRangeList2QSet(itemRanges1); + + KItemSet itemSet2 = KItemRangeList2KItemSet(itemRanges2); + QSet itemsQSet2 = KItemRangeList2QSet(itemRanges2); + + KItemSet symmetricDifference = itemSet1 ^ itemSet2; + QSet symmetricDifferenceQSet = (itemsQSet1 - itemsQSet2) + (itemsQSet2 - itemsQSet1); + + QCOMPARE(symmetricDifference.count(), symmetricDifferenceQSet.count()); + QCOMPARE(KItemSet2QSet(symmetricDifference), symmetricDifferenceQSet); + + // Check commutativity. + QCOMPARE(itemSet2 ^ itemSet1, symmetricDifference); + + // Some more checks: + // itemSet1 ^ symmetricDifference == itemSet2, + // itemSet2 ^ symmetricDifference == itemSet1. + QCOMPARE(itemSet1 ^ symmetricDifference, itemSet2); + QCOMPARE(itemSet2 ^ symmetricDifference, itemSet1); +} + + +QTEST_KDEMAIN(KItemSetTest, NoGUI) + +#include "kitemsettest.moc" diff --git a/src/views/dolphinview.cpp b/src/views/dolphinview.cpp index fd149e0f6a..d0a85b3e26 100644 --- a/src/views/dolphinview.cpp +++ b/src/views/dolphinview.cpp @@ -145,7 +145,7 @@ DolphinView::DolphinView(const KUrl& url, QWidget* parent) : controller->setSelectionBehavior(KItemListController::MultiSelection); connect(controller, SIGNAL(itemActivated(int)), this, SLOT(slotItemActivated(int))); - connect(controller, SIGNAL(itemsActivated(QSet)), this, SLOT(slotItemsActivated(QSet))); + connect(controller, SIGNAL(itemsActivated(KItemSet)), this, SLOT(slotItemsActivated(KItemSet))); connect(controller, SIGNAL(itemMiddleClicked(int)), this, SLOT(slotItemMiddleClicked(int))); connect(controller, SIGNAL(itemContextMenuRequested(int,QPointF)), this, SLOT(slotItemContextMenuRequested(int,QPointF))); connect(controller, SIGNAL(viewContextMenuRequested(QPointF)), this, SLOT(slotViewContextMenuRequested(QPointF))); @@ -184,8 +184,8 @@ DolphinView::DolphinView(const KUrl& url, QWidget* parent) : this, SLOT(slotHeaderColumnWidthChanged(QByteArray,qreal,qreal))); KItemListSelectionManager* selectionManager = controller->selectionManager(); - connect(selectionManager, SIGNAL(selectionChanged(QSet,QSet)), - this, SLOT(slotSelectionChanged(QSet,QSet))); + connect(selectionManager, SIGNAL(selectionChanged(KItemSet,KItemSet)), + this, SLOT(slotSelectionChanged(KItemSet,KItemSet))); m_toolTipManager = new ToolTipManager(this); @@ -350,14 +350,9 @@ int DolphinView::itemsCount() const KFileItemList DolphinView::selectedItems() const { const KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager(); - QList selectedIndexes = selectionManager->selectedItems().toList(); - - qSort(selectedIndexes); KFileItemList selectedItems; - QListIterator it(selectedIndexes); - while (it.hasNext()) { - const int index = it.next(); + foreach (int index, selectionManager->selectedItems()) { selectedItems.append(m_model->fileItem(index)); } return selectedItems; @@ -390,9 +385,9 @@ void DolphinView::selectItems(const QRegExp& pattern, bool enabled) for (int index = 0; index < m_model->count(); index++) { const KFileItem item = m_model->fileItem(index); if (pattern.exactMatch(item.text())) { - // An alternative approach would be to store the matching items in a QSet and + // An alternative approach would be to store the matching items in a KItemSet and // select them in one go after the loop, but we'd need a new function - // KItemListSelectionManager::setSelected(QSet, SelectionMode mode) + // KItemListSelectionManager::setSelected(KItemSet, SelectionMode mode) // for that. selectionManager->setSelected(index, 1, mode); } @@ -803,7 +798,7 @@ void DolphinView::slotItemActivated(int index) } } -void DolphinView::slotItemsActivated(const QSet& indexes) +void DolphinView::slotItemsActivated(const KItemSet& indexes) { Q_ASSERT(indexes.count() >= 2); @@ -818,9 +813,7 @@ void DolphinView::slotItemsActivated(const QSet& indexes) KFileItemList items; items.reserve(indexes.count()); - QSetIterator it(indexes); - while (it.hasNext()) { - const int index = it.next(); + foreach (int index, indexes) { KFileItem item = m_model->fileItem(index); const KUrl& url = openItemAsFolderUrl(item); @@ -1104,7 +1097,7 @@ void DolphinView::slotAboutToCreate(const KUrl::List& urls) } } -void DolphinView::slotSelectionChanged(const QSet& current, const QSet& previous) +void DolphinView::slotSelectionChanged(const KItemSet& current, const KItemSet& previous) { const int currentCount = current.count(); const int previousCount = previous.count(); @@ -1323,7 +1316,7 @@ void DolphinView::updateViewState() m_clearSelectionBeforeSelectingNewItems = false; } - QSet selectedItems = selectionManager->selectedItems(); + KItemSet selectedItems = selectionManager->selectedItems(); QList::iterator it = m_selectedUrls.begin(); while (it != m_selectedUrls.end()) { @@ -1659,7 +1652,7 @@ KUrl::List DolphinView::simplifiedSelectedUrls() const QMimeData* DolphinView::selectionMimeData() const { const KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager(); - const QSet selectedIndexes = selectionManager->selectedItems(); + const KItemSet selectedIndexes = selectionManager->selectedItems(); return m_model->createMimeData(selectedIndexes); } diff --git a/src/views/dolphinview.h b/src/views/dolphinview.h index a6f969bc1b..b43957f226 100644 --- a/src/views/dolphinview.h +++ b/src/views/dolphinview.h @@ -34,7 +34,6 @@ #include #include #include -#include #include typedef KIO::FileUndoManager::CommandType CommandType; @@ -45,6 +44,7 @@ class KActionCollection; class KFileItemModel; class KItemListContainer; class KItemModelBase; +class KItemSet; class KUrl; class ToolTipManager; class VersionControlObserver; @@ -563,7 +563,7 @@ private slots: void activate(); void slotItemActivated(int index); - void slotItemsActivated(const QSet& indexes); + void slotItemsActivated(const KItemSet& indexes); void slotItemMiddleClicked(int index); void slotItemContextMenuRequested(int index, const QPointF& pos); void slotViewContextMenuRequested(const QPointF& pos); @@ -587,7 +587,7 @@ private slots: * the signal is emitted only after no selection change has been done * within a small delay. */ - void slotSelectionChanged(const QSet& current, const QSet& previous); + void slotSelectionChanged(const KItemSet& current, const KItemSet& previous); /** * Is called by emitDelayedSelectionChangedSignal() and emits the