kitemviews/kitemlistviewaccessible.cpp
kitemviews/kitemlistwidget.cpp
kitemviews/kitemmodelbase.cpp
+ kitemviews/kitemset.cpp
kitemviews/kstandarditem.cpp
kitemviews/kstandarditemlistgroupheader.cpp
kitemviews/kstandarditemlistwidget.cpp
kitemviews/kstandarditemlistview.cpp
kitemviews/kstandarditemmodel.cpp
+ kitemviews/private/kdirectorycontentscounter.cpp
+ kitemviews/private/kdirectorycontentscounterworker.cpp
kitemviews/private/kfileitemclipboard.cpp
kitemviews/private/kfileitemmodeldirlister.cpp
kitemviews/private/kfileitemmodelfilter.cpp
views/viewproperties.cpp
views/zoomlevelinfo.cpp
dolphinremoveaction.cpp
+ dolphinnewfilemenu.cpp
)
if(HAVE_NEPOMUK)
if (m_selectedItems.count() == 1) {
if (m_fileInfo.isDir()) {
// setup 'Create New' menu
- DolphinNewFileMenu* newFileMenu = new DolphinNewFileMenu(m_mainWindow);
+ DolphinNewFileMenu* newFileMenu = new DolphinNewFileMenu(m_mainWindow->actionCollection(), this);
const DolphinView* view = m_mainWindow->activeViewContainer()->view();
newFileMenu->setViewShowsHiddenFiles(view->hiddenFilesShown());
newFileMenu->checkUpToDate();
#include <QStyle>
+namespace {
+ // Disable the 'Floatable' feature, i.e., the possibility to drag the
+ // dock widget out of the main window. This works around problems like
+ // https://bugs.kde.org/show_bug.cgi?id=288629
+ // https://bugs.kde.org/show_bug.cgi?id=322299
+ const QDockWidget::DockWidgetFeatures DefaultDockWidgetFeatures = QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable;
+}
+
// Empty titlebar for the dock widgets when "Lock Layout" has been activated.
class DolphinDockTitleBar : public QWidget
{
m_locked(false),
m_dockTitleBar(0)
{
+ setFeatures(DefaultDockWidgetFeatures);
}
DolphinDockWidget::DolphinDockWidget(QWidget* parent, Qt::WindowFlags flags) :
m_locked(false),
m_dockTitleBar(0)
{
+ setFeatures(DefaultDockWidgetFeatures);
}
DolphinDockWidget::~DolphinDockWidget()
setFeatures(QDockWidget::NoDockWidgetFeatures);
} else {
setTitleBarWidget(0);
- setFeatures(QDockWidget::DockWidgetMovable |
- QDockWidget::DockWidgetFloatable |
- QDockWidget::DockWidgetClosable);
+ setFeatures(DefaultDockWidgetFeatures);
}
}
}
#include "views/dolphinremoteencoding.h"
#include "views/draganddrophelper.h"
#include "views/viewproperties.h"
+#include "views/dolphinnewfilemenuobserver.h"
#ifndef Q_OS_WIN
#include "panels/terminal/terminalpanel.h"
ViewTab& viewTab = m_viewTab[m_tabIndex];
viewTab.wasActive = true; // The first opened tab is automatically active
+ connect(&DolphinNewFileMenuObserver::instance(), SIGNAL(errorMessage(QString)),
+ this, SLOT(showErrorMessage(QString)));
+
KIO::FileUndoManager* undoManager = KIO::FileUndoManager::self();
undoManager->setUiInterface(new UndoUiInterface());
// Open each directory inside a new tab. If the "split view" option has been enabled,
// always show two directories within one tab.
- QList<KUrl>::const_iterator it = dirs.begin();
- while (it != dirs.end()) {
+ QList<KUrl>::const_iterator it = dirs.constBegin();
+ while (it != dirs.constEnd()) {
openNewTab(*it);
++it;
- if (hasSplitView && (it != dirs.end())) {
+ if (hasSplitView && (it != dirs.constEnd())) {
const int tabIndex = m_viewTab.count() - 1;
m_viewTab[tabIndex].secondaryView->setUrl(*it);
++it;
void DolphinMainWindow::setupActions()
{
// setup 'File' menu
- m_newFileMenu = new DolphinNewFileMenu(this);
+ m_newFileMenu = new DolphinNewFileMenu(actionCollection(), this);
KMenu* menu = m_newFileMenu->menu();
menu->setTitle(i18nc("@title:menu Create new folder, file, link, etc.", "Create New"));
menu->setIcon(KIcon("document-new"));
#include "dolphinnewfilemenu.h"
-#include "dolphinmainwindow.h"
-#include "dolphinviewcontainer.h"
#include "views/dolphinnewfilemenuobserver.h"
-#include "views/dolphinview.h"
#include <KActionCollection>
#include <KIO/Job>
-DolphinNewFileMenu::DolphinNewFileMenu(DolphinMainWindow* parent) :
- KNewFileMenu(parent->actionCollection(), "create_new", parent),
- m_mainWin(parent)
+DolphinNewFileMenu::DolphinNewFileMenu(KActionCollection* collection, QObject* parent) :
+ KNewFileMenu(collection, "new_menu", parent)
{
DolphinNewFileMenuObserver::instance().attach(this);
}
void DolphinNewFileMenu::slotResult(KJob* job)
{
if (job->error()) {
- DolphinViewContainer* container = m_mainWin->activeViewContainer();
- container->showMessage(job->errorString(), DolphinViewContainer::Error);
+ emit errorMessage(job->errorString());
} else {
KNewFileMenu::slotResult(job);
}
#include <KNewFileMenu>
-class DolphinMainWindow;
+#include "libdolphin_export.h"
+
class KJob;
/**
* All errors are shown in the status bar of Dolphin
* instead as modal error dialog with an OK button.
*/
-class DolphinNewFileMenu : public KNewFileMenu
+class LIBDOLPHINPRIVATE_EXPORT DolphinNewFileMenu : public KNewFileMenu
{
Q_OBJECT
public:
- DolphinNewFileMenu(DolphinMainWindow* parent);
+ DolphinNewFileMenu(KActionCollection* collection, QObject* parent);
virtual ~DolphinNewFileMenu();
+signals:
+ void errorMessage(const QString& error);
+
protected slots:
/** @see KNewFileMenu::slotResult() */
virtual void slotResult(KJob* job);
-
-private:
- DolphinMainWindow* m_mainWin;
};
#endif
#include <KIO/NetAccess>
#include <KToolInvocation>
#include <kauthorized.h>
-#include <KNewFileMenu>
#include <KMenu>
#include <KInputDialog>
#include <KProtocolInfo>
#include "dolphinpart_ext.h"
#endif
+#include "dolphinnewfilemenu.h"
#include "views/dolphinview.h"
#include "views/dolphinviewactionhandler.h"
#include "views/dolphinnewfilemenuobserver.h"
m_view->setTabsForFilesEnabled(true);
setWidget(m_view);
+ connect(&DolphinNewFileMenuObserver::instance(), SIGNAL(errorMessage(QString)),
+ this, SLOT(slotErrorMessage(QString)));
+
connect(m_view, SIGNAL(directoryLoadingCompleted()), this, SIGNAL(completed()));
connect(m_view, SIGNAL(directoryLoadingProgress(int)), this, SLOT(updateProgress(int)));
connect(m_view, SIGNAL(errorMessage(QString)), this, SLOT(slotErrorMessage(QString)));
DolphinPart::~DolphinPart()
{
- DolphinNewFileMenuObserver::instance().detach(m_newFileMenu);
}
void DolphinPart::createActions()
{
// Edit menu
- m_newFileMenu = new KNewFileMenu(actionCollection(), "new_menu", this);
+ m_newFileMenu = new DolphinNewFileMenu(actionCollection(), this);
m_newFileMenu->setParentWidget(widget());
- DolphinNewFileMenuObserver::instance().attach(m_newFileMenu);
connect(m_newFileMenu->menu(), SIGNAL(aboutToShow()),
this, SLOT(updateNewMenu()));
void DolphinPart::updateStatusBar()
{
- emit ReadOnlyPart::setStatusBarText(m_view->statusBarText());
+ const QString escapedText = Qt::convertFromPlainText(m_view->statusBarText());
+ emit ReadOnlyPart::setStatusBarText(QString("<qt>%1</qt>").arg(escapedText));
}
void DolphinPart::updateProgress(int percent)
return KParts::ReadOnlyPart::eventFilter(obj, event);
}
-////
-
-void DolphinPartBrowserExtension::restoreState(QDataStream &stream)
-{
- KParts::BrowserExtension::restoreState(stream);
- m_part->view()->restoreState(stream);
-}
-
-void DolphinPartBrowserExtension::saveState(QDataStream &stream)
-{
- KParts::BrowserExtension::saveState(stream);
- m_part->view()->saveState(stream);
-}
-
-void DolphinPartBrowserExtension::cut()
-{
- m_part->view()->cutSelectedItems();
-}
-
-void DolphinPartBrowserExtension::copy()
-{
- m_part->view()->copySelectedItems();
-}
-
-void DolphinPartBrowserExtension::paste()
-{
- m_part->view()->paste();
-}
-
-void DolphinPartBrowserExtension::pasteTo(const KUrl&)
-{
- m_part->view()->pasteIntoFolder();
-}
-
-void DolphinPartBrowserExtension::reparseConfiguration()
-{
- m_part->view()->readSettings();
-}
-
-////
-
-DolphinPartFileInfoExtension::DolphinPartFileInfoExtension(DolphinPart* part)
- : KParts::FileInfoExtension(part)
-{
-}
-
-DolphinPart* DolphinPartFileInfoExtension::part() const
-{
- return static_cast<DolphinPart*>(parent());
-}
-
-bool DolphinPartFileInfoExtension::hasSelection() const
-{
- return part()->view()->selectedItemsCount() > 0;
-}
-
-KParts::FileInfoExtension::QueryModes DolphinPartFileInfoExtension::supportedQueryModes() const
-{
- return (KParts::FileInfoExtension::AllItems | KParts::FileInfoExtension::SelectedItems);
-}
-
-KFileItemList DolphinPartFileInfoExtension::queryFor(KParts::FileInfoExtension::QueryMode mode) const
-{
- KFileItemList list;
-
- if (mode == KParts::FileInfoExtension::None)
- return list;
-
- if (!(supportedQueryModes() & mode))
- return list;
-
- switch (mode) {
- case KParts::FileInfoExtension::SelectedItems:
- if (hasSelection())
- return part()->view()->selectedItems();
- break;
- case KParts::FileInfoExtension::AllItems:
- return part()->view()->items();
- default:
- break;
- }
-
- return list;
-}
-
#include "dolphinpart.moc"
[Desktop Action compact]
Name=Compact
Name[ar]=مضغوط
+Name[bg]=Компактно
Name[bs]=Sabij
Name[ca]=Compacte
Name[ca@valencia]=Compacte
Name[tg]=Тафсилотҳо
Name[th]=รายละเอียด
Name[tr]=Ayrıntılar
-Name[ug]=تÛ\95پسÙ\89Ù\84اتÙ\89
+Name[ug]=تÛ\95پسÙ\89Ù\84اتÙ\84ار
Name[uk]=Подробиці
Name[uz]=Tafsilotlar
Name[uz@cyrillic]=Тафсилотлар
#define DOLPHINPART_H
#include <kparts/part.h>
-#include <kparts/browserextension.h>
-#include <kparts/fileinfoextension.h>
#include <QItemSelectionModel>
-class KNewFileMenu;
+class DolphinNewFileMenu;
class DolphinViewActionHandler;
class QActionGroup;
class KAction;
DolphinViewActionHandler* m_actionHandler;
DolphinRemoteEncoding* m_remoteEncoding;
DolphinPartBrowserExtension* m_extension;
- KNewFileMenu* m_newFileMenu;
+ DolphinNewFileMenu* m_newFileMenu;
KAction* m_findFileAction;
KAction* m_openTerminalAction;
QString m_nameFilter;
Q_DISABLE_COPY(DolphinPart)
};
-class DolphinPartBrowserExtension : public KParts::BrowserExtension
-{
- Q_OBJECT
-public:
- DolphinPartBrowserExtension( DolphinPart* part )
- : KParts::BrowserExtension( part ), m_part(part) {}
-
- virtual void restoreState(QDataStream &stream);
- virtual void saveState(QDataStream &stream);
-
-public Q_SLOTS:
- void cut();
- void copy();
- void paste();
- void pasteTo(const KUrl&);
- void reparseConfiguration();
-
-private:
- DolphinPart* m_part;
-};
-
-
-class DolphinPartFileInfoExtension : public KParts::FileInfoExtension
-{
- Q_OBJECT
-
-public:
- DolphinPartFileInfoExtension(DolphinPart* part);
-
- virtual QueryModes supportedQueryModes() const;
- virtual bool hasSelection() const;
-
- virtual KFileItemList queryFor(QueryMode mode) const;
-protected:
- DolphinPart* part() const;
-};
-
#endif /* DOLPHINPART_H */
#include <KFileItemList>
+
+DolphinPartBrowserExtension::DolphinPartBrowserExtension(DolphinPart* part)
+ :KParts::BrowserExtension( part )
+ ,m_part(part)
+{
+
+}
+
+void DolphinPartBrowserExtension::restoreState(QDataStream &stream)
+{
+ KParts::BrowserExtension::restoreState(stream);
+ m_part->view()->restoreState(stream);
+}
+
+void DolphinPartBrowserExtension::saveState(QDataStream &stream)
+{
+ KParts::BrowserExtension::saveState(stream);
+ m_part->view()->saveState(stream);
+}
+
+void DolphinPartBrowserExtension::cut()
+{
+ m_part->view()->cutSelectedItems();
+}
+
+void DolphinPartBrowserExtension::copy()
+{
+ m_part->view()->copySelectedItems();
+}
+
+void DolphinPartBrowserExtension::paste()
+{
+ m_part->view()->paste();
+}
+
+void DolphinPartBrowserExtension::pasteTo(const KUrl&)
+{
+ m_part->view()->pasteIntoFolder();
+}
+
+void DolphinPartBrowserExtension::reparseConfiguration()
+{
+ m_part->view()->readSettings();
+}
+
+
+DolphinPartFileInfoExtension::DolphinPartFileInfoExtension(DolphinPart* part)
+ :KParts::FileInfoExtension(part)
+ ,m_part(part)
+{
+}
+
+bool DolphinPartFileInfoExtension::hasSelection() const
+{
+ return m_part->view()->selectedItemsCount() > 0;
+}
+
+KParts::FileInfoExtension::QueryModes DolphinPartFileInfoExtension::supportedQueryModes() const
+{
+ return (KParts::FileInfoExtension::AllItems | KParts::FileInfoExtension::SelectedItems);
+}
+
+KFileItemList DolphinPartFileInfoExtension::queryFor(KParts::FileInfoExtension::QueryMode mode) const
+{
+ KFileItemList list;
+
+ if (mode == KParts::FileInfoExtension::None)
+ return list;
+
+ if (!(supportedQueryModes() & mode))
+ return list;
+
+ switch (mode) {
+ case KParts::FileInfoExtension::SelectedItems:
+ if (hasSelection())
+ return m_part->view()->selectedItems();
+ break;
+ case KParts::FileInfoExtension::AllItems:
+ return m_part->view()->items();
+ default:
+ break;
+ }
+
+ return list;
+}
+
DolphinPartListingFilterExtension::DolphinPartListingFilterExtension(DolphinPart* part)
: KParts::ListingFilterExtension(part)
, m_part(part)
#ifndef DOLPHINPART_EXT_H
#define DOLPHINPART_EXT_H
-
+#include <kparts/browserextension.h>
+#include <kparts/fileinfoextension.h>
#include <kparts/listingextension.h>
class DolphinPart;
+class DolphinPartBrowserExtension : public KParts::BrowserExtension
+{
+ Q_OBJECT
+public:
+ DolphinPartBrowserExtension( DolphinPart* part );
+ virtual void restoreState(QDataStream &stream);
+ virtual void saveState(QDataStream &stream);
+
+public Q_SLOTS:
+ void cut();
+ void copy();
+ void paste();
+ void pasteTo(const KUrl&);
+ void reparseConfiguration();
+
+private:
+ DolphinPart* m_part;
+};
+
+class DolphinPartFileInfoExtension : public KParts::FileInfoExtension
+{
+ Q_OBJECT
+
+public:
+ DolphinPartFileInfoExtension(DolphinPart* part);
+
+ virtual QueryModes supportedQueryModes() const;
+ virtual bool hasSelection() const;
+
+ virtual KFileItemList queryFor(QueryMode mode) const;
+
+private:
+ DolphinPart* m_part;
+};
+
class DolphinPartListingFilterExtension : public KParts::ListingFilterExtension
{
Q_OBJECT
<kpartgui name="dolphin" version="14">
<MenuBar>
<Menu name="file">
- <Action name="create_new" />
+ <Action name="new_menu" />
<Action name="new_window" />
<Action name="new_tab" />
<Action name="close_tab" />
if (item.isNull()) {
m_statusBar->resetToDefaultText();
} else {
- const QString text = item.isDir() ? item.text() : item.getStatusBarInfo();
- m_statusBar->setText(text);
+ m_statusBar->setText(item.getStatusBarInfo());
}
}
return m_modelRolesUpdater ? m_modelRolesUpdater->enabledPlugins() : QStringList();
}
-QPixmap KFileItemListView::createDragPixmap(const QSet<int>& indexes) const
+QPixmap KFileItemListView::createDragPixmap(const KItemSet& indexes) const
{
if (!model()) {
return QPixmap();
QPainter painter(&dragPixmap);
int x = 0;
int y = 0;
- QSetIterator<int> it(indexes);
- while (it.hasNext()) {
- const int index = it.next();
+ foreach (int index, indexes) {
QPixmap pixmap = model()->data(index).value("iconPixmap").value<QPixmap>();
if (pixmap.isNull()) {
KIcon icon(model()->data(index).value("iconName").toString());
void KFileItemListView::onItemLayoutChanged(ItemLayout current, ItemLayout previous)
{
- if (previous == DetailsLayout || current == DetailsLayout) {
- // The details-layout requires some invisible roles that
- // must be added to the model if the new layout is "details".
- // If the old layout was "details" the roles will get removed.
- applyRolesToModel();
- }
KStandardItemListView::onItemLayoutChanged(current, previous);
triggerVisibleIndexRangeUpdate();
}
QStringList enabledPlugins() const;
/** @reimp */
- virtual QPixmap createDragPixmap(const QSet<int>& indexes) const;
+ virtual QPixmap createDragPixmap(const KItemSet& indexes) const;
protected:
virtual KItemListWidgetCreatorBase* defaultWidgetCreator() const;
***************************************************************************/
#include "kfileitemlistwidget.h"
+#include "kfileitemmodel.h"
+#include "kitemlistview.h"
#include <kmimetype.h>
#include <KDebug>
{
}
+QString KFileItemListWidgetInformant::itemText(int index, const KItemListView* view) const
+{
+ Q_ASSERT(qobject_cast<KFileItemModel*>(view->model()));
+ KFileItemModel* fileItemModel = static_cast<KFileItemModel*>(view->model());
+
+ const KFileItem item = fileItemModel->fileItem(index);
+ return item.text();
+}
+
QString KFileItemListWidgetInformant::roleText(const QByteArray& role,
const QHash<QByteArray, QVariant>& values) const
{
virtual ~KFileItemListWidgetInformant();
protected:
+ virtual QString itemText(int index, const KItemListView* view) const;
virtual QString roleText(const QByteArray& role, const QHash<QByteArray, QVariant>& values) const;
};
QHash<QByteArray, QVariant> KFileItemModel::data(int index) const
{
if (index >= 0 && index < count()) {
- return m_itemData.at(index)->values;
+ ItemData* data = m_itemData.at(index);
+ if (data->values.isEmpty()) {
+ data->values = retrieveData(data->item, data->parent);
+ }
+
+ return data->values;
}
return QHash<QByteArray, QVariant>();
}
return false;
}
- QHash<QByteArray, QVariant> currentValues = m_itemData.at(index)->values;
+ QHash<QByteArray, QVariant> currentValues = data(index);
// Determine which roles have been changed
QSet<QByteArray> changedRoles;
return m_dirLister->dirOnlyMode();
}
-QMimeData* KFileItemModel::createMimeData(const QSet<int>& indexes) const
+QMimeData* KFileItemModel::createMimeData(const KItemSet& indexes) const
{
QMimeData* data = new QMimeData();
KUrl::List mostLocalUrls;
bool canUseMostLocalUrls = true;
- QSetIterator<int> 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();
{
startFromIndex = qMax(0, startFromIndex);
for (int i = startFromIndex; i < count(); ++i) {
- if (data(i)["text"].toString().startsWith(text, Qt::CaseInsensitive)) {
+ if (fileItem(i).text().startsWith(text, Qt::CaseInsensitive)) {
return i;
}
}
for (int i = 0; i < startFromIndex; ++i) {
- if (data(i)["text"].toString().startsWith(text, Qt::CaseInsensitive)) {
+ if (fileItem(i).text().startsWith(text, Qt::CaseInsensitive)) {
return i;
}
}
if (expanded) {
m_expandedDirs.insert(targetUrl, url);
m_dirLister->openUrl(url, KDirLister::Keep);
+
+ const KUrl::List previouslyExpandedChildren = m_itemData.at(index)->values.value("previouslyExpandedChildren").value<KUrl::List>();
+ foreach (const KUrl& url, previouslyExpandedChildren) {
+ m_urlsToExpand.insert(url);
+ }
} else {
m_expandedDirs.remove(targetUrl);
m_dirLister->stop(url);
- removeFilteredChildren(KFileItemList() << item);
+ const int parentLevel = expandedParentsCount(index);
+ const int itemCount = m_itemData.count();
+ const int firstChildIndex = index + 1;
+
+ KUrl::List expandedChildren;
+
+ int childIndex = firstChildIndex;
+ while (childIndex < itemCount && expandedParentsCount(childIndex) > parentLevel) {
+ ItemData* itemData = m_itemData.at(childIndex);
+ if (itemData->values.value("isExpanded").toBool()) {
+ const KUrl targetUrl = itemData->item.targetUrl();
+ m_expandedDirs.remove(targetUrl);
+ expandedChildren.append(targetUrl);
+ }
+ ++childIndex;
+ }
+ const int childrenCount = childIndex - firstChildIndex;
- const KFileItemList itemsToRemove = childItems(item);
- removeFilteredChildren(itemsToRemove);
- removeItems(itemsToRemove, DeleteItemData);
+ removeFilteredChildren(KItemRangeList() << KItemRange(index, 1 + childrenCount));
+ removeItems(KItemRangeList() << KItemRange(firstChildIndex, childrenCount), DeleteItemData);
+
+ m_itemData.at(index)->values.insert("previouslyExpandedChildren", expandedChildren);
}
return true;
bool KFileItemModel::isExpandable(int index) const
{
if (index >= 0 && index < count()) {
- return m_itemData.at(index)->values.value("isExpandable").toBool();
+ // Call data (instead of accessing m_itemData directly)
+ // to ensure that the value is initialized.
+ return data(index).value("isExpandable").toBool();
}
return false;
}
int KFileItemModel::expandedParentsCount(int index) const
{
if (index >= 0 && index < count()) {
- const int parentsCount = m_itemData.at(index)->values.value("expandedParentsCount").toInt();
- if (parentsCount > 0) {
- return parentsCount;
- }
+ return expandedParentsCount(m_itemData.at(index));
}
return 0;
}
{
// Check which shown items from m_itemData must get
// hidden and hence moved to m_filteredItems.
- KFileItemList newFilteredItems;
+ QVector<int> newFilteredIndexes;
+
+ const int itemCount = m_itemData.count();
+ for (int index = 0; index < itemCount; ++index) {
+ ItemData* itemData = m_itemData.at(index);
- foreach (ItemData* itemData, m_itemData) {
// Only filter non-expanded items as child items may never
// exist without a parent item
if (!itemData->values.value("isExpanded").toBool()) {
const KFileItem item = itemData->item;
if (!m_filter.matches(item)) {
- newFilteredItems.append(item);
+ newFilteredIndexes.append(index);
m_filteredItems.insert(item, itemData);
}
}
}
- removeItems(newFilteredItems, KeepItemData);
+ const KItemRangeList removedRanges = KItemRangeList::fromSortedContainer(newFilteredIndexes);
+ removeItems(removedRanges, KeepItemData);
// Check which hidden items from m_filteredItems should
// get visible again and hence removed from m_filteredItems.
insertItems(newVisibleItems);
}
-void KFileItemModel::removeFilteredChildren(const KFileItemList& parentsList)
+void KFileItemModel::removeFilteredChildren(const KItemRangeList& itemRanges)
{
- if (m_filteredItems.isEmpty()) {
+ if (m_filteredItems.isEmpty() || !m_requestRole[ExpandedParentsCountRole]) {
+ // There are either no filtered items, or it is not possible to expand
+ // folders -> there cannot be any filtered children.
return;
}
- // First, we put the parent items into a set to provide fast lookup
- // while iterating over m_filteredItems and prevent quadratic
- // complexity if there are N parents and N filtered items.
- const QSet<KFileItem> parents = parentsList.toSet();
+ QSet<ItemData*> parents;
+ foreach (const KItemRange& range, itemRanges) {
+ for (int index = range.index; index < range.index + range.count; ++index) {
+ parents.insert(m_itemData.at(index));
+ }
+ }
QHash<KFileItem, ItemData*>::iterator it = m_filteredItems.begin();
while (it != m_filteredItems.end()) {
- const ItemData* parent = it.value()->parent;
-
- if (parent && parents.contains(parent->item)) {
+ if (parents.contains(it.value()->parent)) {
delete it.value();
it = m_filteredItems.erase(it);
} else {
oldUrls.append(itemData->item.url());
}
- m_groups.clear();
m_items.clear();
// Resort the items
m_items.insert(m_itemData.at(i)->item.url(), i);
}
- // Determine the indexes that have been moved
- QList<int> movedToIndexes;
- movedToIndexes.reserve(itemCount);
- for (int i = 0; i < itemCount; i++) {
- const int newIndex = m_items.value(oldUrls.at(i));
- movedToIndexes.append(newIndex);
+ // Determine the first index that has been moved.
+ int firstMovedIndex = 0;
+ while (firstMovedIndex < itemCount
+ && firstMovedIndex == m_items.value(oldUrls.at(firstMovedIndex))) {
+ ++firstMovedIndex;
}
- // Don't check whether items have really been moved and always emit a
- // itemsMoved() signal after resorting: In case of grouped items
- // the groups might change even if the items themselves don't change their
- // position. Let the receiver of the signal decide whether a check for moved
- // items makes sense.
- emit itemsMoved(KItemRange(0, itemCount), movedToIndexes);
+ const bool itemsHaveMoved = firstMovedIndex < itemCount;
+ if (itemsHaveMoved) {
+ m_groups.clear();
+
+ int lastMovedIndex = itemCount - 1;
+ while (lastMovedIndex > firstMovedIndex
+ && lastMovedIndex == m_items.value(oldUrls.at(lastMovedIndex))) {
+ --lastMovedIndex;
+ }
+
+ Q_ASSERT(firstMovedIndex <= lastMovedIndex);
+
+ // Create a list movedToIndexes, which has the property that
+ // movedToIndexes[i] is the new index of the item with the old index
+ // firstMovedIndex + i.
+ const int movedItemsCount = lastMovedIndex - firstMovedIndex + 1;
+ QList<int> movedToIndexes;
+ movedToIndexes.reserve(movedItemsCount);
+ for (int i = firstMovedIndex; i <= lastMovedIndex; ++i) {
+ const int newIndex = m_items.value(oldUrls.at(i));
+ movedToIndexes.append(newIndex);
+ }
+
+ emit itemsMoved(KItemRange(firstMovedIndex, movedItemsCount), movedToIndexes);
+ } else if (groupedSorting()) {
+ // The groups might have changed even if the order of the items has not.
+ const QList<QPair<int, QVariant> > oldGroups = m_groups;
+ m_groups.clear();
+ if (groups() != oldGroups) {
+ emit groupsChanged();
+ }
+ }
#ifdef KFILEITEMMODEL_DEBUG
kDebug() << "[TIME] Resorting of" << itemCount << "items:" << timer.elapsed();
{
dispatchPendingItemsToInsert();
- KFileItemList itemsToRemove = items;
- if (m_requestRole[ExpandedParentsCountRole]) {
- // Assure that removing a parent item also results in removing all children
- foreach (const KFileItem& item, items) {
- itemsToRemove.append(childItems(item));
- }
- }
+ QVector<int> indexesToRemove;
+ indexesToRemove.reserve(items.count());
- if (!m_filteredItems.isEmpty()) {
- foreach (const KFileItem& item, itemsToRemove) {
+ foreach (const KFileItem& item, items) {
+ const KUrl url = item.url();
+ const int index = m_items.value(url, -1);
+ if (index >= 0) {
+ indexesToRemove.append(index);
+ } else {
+ // Probably the item has been filtered.
QHash<KFileItem, ItemData*>::iterator it = m_filteredItems.find(item);
if (it != m_filteredItems.end()) {
delete it.value();
m_filteredItems.erase(it);
}
}
+ }
+
+ std::sort(indexesToRemove.begin(), indexesToRemove.end());
- if (m_requestRole[ExpandedParentsCountRole]) {
- removeFilteredChildren(itemsToRemove);
+ if (m_requestRole[ExpandedParentsCountRole] && !m_expandedDirs.isEmpty()) {
+ // Assure that removing a parent item also results in removing all children
+ QVector<int> indexesToRemoveWithChildren;
+ indexesToRemoveWithChildren.reserve(m_items.count());
+
+ const int itemCount = m_itemData.count();
+ foreach (int index, indexesToRemove) {
+ indexesToRemoveWithChildren.append(index);
+
+ const int parentLevel = expandedParentsCount(index);
+ int childIndex = index + 1;
+ while (childIndex < itemCount && expandedParentsCount(childIndex) > parentLevel) {
+ indexesToRemoveWithChildren.append(childIndex);
+ ++childIndex;
+ }
}
+
+ indexesToRemove = indexesToRemoveWithChildren;
}
- removeItems(itemsToRemove, DeleteItemData);
+ const KItemRangeList itemRanges = KItemRangeList::fromSortedContainer(indexesToRemove);
+ removeFilteredChildren(itemRanges);
+ removeItems(itemRanges, DeleteItemData);
}
void KFileItemModel::slotRefreshItems(const QList<QPair<KFileItem, KFileItem> >& items)
// Extract the item-ranges out of the changed indexes
qSort(indexes);
-
- KItemRangeList itemRangeList;
- int previousIndex = indexes.at(0);
- int rangeIndex = previousIndex;
- int rangeCount = 1;
-
- const int maxIndex = indexes.count() - 1;
- for (int i = 1; i <= maxIndex; ++i) {
- const int currentIndex = indexes.at(i);
- if (currentIndex == previousIndex + 1) {
- ++rangeCount;
- } else {
- itemRangeList.append(KItemRange(rangeIndex, rangeCount));
-
- rangeIndex = currentIndex;
- rangeCount = 1;
- }
- previousIndex = currentIndex;
- }
-
- if (rangeCount > 0) {
- itemRangeList.append(KItemRange(rangeIndex, rangeCount));
- }
-
+ const KItemRangeList itemRangeList = KItemRangeList::fromSortedContainer(indexes);
emitItemsChangedAndTriggerResorting(itemRangeList, changedRoles);
}
m_groups.clear();
+ if (m_sortRole == NameRole && m_naturalSorting) {
+ // Natural sorting of items can be very slow. However, it becomes much
+ // faster if the input sequence is already mostly sorted. Therefore, we
+ // first sort 'newItems' according to the QStrings returned by
+ // KFileItem::text() using QString::operator<(), which is quite fast.
+ parallelMergeSort(newItems.begin(), newItems.end(), nameLessThan, QThread::idealThreadCount());
+ }
+
sort(newItems.begin(), newItems.end());
#ifdef KFILEITEMMODEL_DEBUG
#endif
}
-static KItemRangeList sortedIndexesToKItemRangeList(const QList<int>& sortedNumbers)
+void KFileItemModel::removeItems(const KItemRangeList& itemRanges, RemoveItemsBehavior behavior)
{
- if (sortedNumbers.empty()) {
- return KItemRangeList();
- }
-
- KItemRangeList result;
-
- QList<int>::const_iterator it = sortedNumbers.begin();
- int index = *it;
- int count = 1;
-
- ++it;
-
- QList<int>::const_iterator end = sortedNumbers.end();
- while (it != end) {
- if (*it == index + count) {
- ++count;
- } else {
- result << KItemRange(index, count);
- index = *it;
- count = 1;
- }
- ++it;
+ if (itemRanges.isEmpty()) {
+ return;
}
- result << KItemRange(index, count);
- return result;
-}
-
-void KFileItemModel::removeItems(const KFileItemList& items, RemoveItemsBehavior behavior)
-{
-#ifdef KFILEITEMMODEL_DEBUG
- kDebug() << "Removing " << items.count() << "items";
-#endif
-
m_groups.clear();
- // Step 1: Determine the indexes of the removed items, remove them from
- // the hash m_items, and free the ItemData.
- QList<int> indexesToRemove;
- indexesToRemove.reserve(items.count());
- foreach (const KFileItem& item, items) {
- const KUrl url = item.url();
- const int index = m_items.value(url, -1);
- if (index >= 0) {
- indexesToRemove.append(index);
+ // Step 1: Remove the items from the hash m_items, and free the ItemData.
+ int removedItemsCount = 0;
+ foreach (const KItemRange& range, itemRanges) {
+ removedItemsCount += range.count;
+
+ for (int index = range.index; index < range.index + range.count; ++index) {
+ const KUrl url = m_itemData.at(index)->item.url();
// Prevent repeated expensive rehashing by using QHash::erase(),
// rather than QHash::remove().
}
}
- if (indexesToRemove.isEmpty()) {
- return;
- }
-
- std::sort(indexesToRemove.begin(), indexesToRemove.end());
-
// Step 2: Remove the ItemData pointers from the list m_itemData.
- const KItemRangeList itemRanges = sortedIndexesToKItemRangeList(indexesToRemove);
int target = itemRanges.at(0).index;
int source = itemRanges.at(0).index + itemRanges.at(0).count;
int nextRange = 1;
}
}
- m_itemData.erase(m_itemData.end() - indexesToRemove.count(), m_itemData.end());
+ m_itemData.erase(m_itemData.end() - removedItemsCount, m_itemData.end());
// Step 3: Adjust indexes in the hash m_items, starting from the
// index of the first removed item.
foreach (const KFileItem& item, items) {
ItemData* itemData = new ItemData();
itemData->item = item;
- itemData->values = retrieveData(item, parentItem);
itemData->parent = parentItem;
itemDataList.append(itemData);
}
+ switch (m_sortRole) {
+ case PermissionsRole:
+ case OwnerRole:
+ case GroupRole:
+ case DestinationRole:
+ case PathRole:
+ // These roles can be determined with retrieveData, and they have to be stored
+ // in the QHash "values" for the sorting.
+ foreach (ItemData* itemData, itemDataList) {
+ itemData->values = retrieveData(itemData->item, parentItem);
+ }
+ break;
+
+ case TypeRole:
+ // At least store the data including the file type for items with known MIME type.
+ foreach (ItemData* itemData, itemDataList) {
+ const KFileItem item = itemData->item;
+ if (item.isDir() || item.isMimeTypeKnown()) {
+ itemData->values = retrieveData(itemData->item, parentItem);
+ }
+ }
+ break;
+
+ default:
+ // The other roles are either resolved by KFileItemModelRolesUpdater
+ // (this includes the SizeRole for directories), or they do not need
+ // to be stored in the QHash "values" for sorting because the data can
+ // be retrieved directly from the KFileItem (NameRole, SiezRole for files,
+ // DateRole).
+ break;
+ }
+
return itemDataList;
}
+int KFileItemModel::expandedParentsCount(const ItemData* data)
+{
+ // The hash 'values' is only guaranteed to contain the key "expandedParentsCount"
+ // if the corresponding item is expanded, and it is not a top-level item.
+ const ItemData* parent = data->parent;
+ if (parent) {
+ if (parent->parent) {
+ Q_ASSERT(parent->values.contains("expandedParentsCount"));
+ return parent->values.value("expandedParentsCount").toInt() + 1;
+ } else {
+ return 1;
+ }
+ } else {
+ return 0;
+ }
+}
+
void KFileItemModel::removeExpandedItems()
{
- KFileItemList expandedItems;
+ QVector<int> indexesToRemove;
const int maxIndex = m_itemData.count() - 1;
for (int i = 0; i <= maxIndex; ++i) {
const ItemData* itemData = m_itemData.at(i);
- if (itemData->values.value("expandedParentsCount").toInt() > 0) {
- expandedItems.append(itemData->item);
+ if (itemData->parent) {
+ indexesToRemove.append(i);
}
}
- // The m_expandedParentsCountRoot may not get reset before all items with
- // a bigger count have been removed.
- removeItems(expandedItems, DeleteItemData);
-
+ removeItems(KItemRangeList::fromSortedContainer(indexesToRemove), DeleteItemData);
m_expandedDirs.clear();
// Also remove all filtered items which have a parent.
if (m_requestRole[ExpandedParentsCountRole]) {
if (parent) {
- const int level = parent->values["expandedParentsCount"].toInt() + 1;
+ const int level = expandedParentsCount(parent) + 1;
data.insert(sharedValue("expandedParentsCount"), level);
}
}
int result = 0;
if (a->parent != b->parent) {
- const int expansionLevelA = a->values.value("expandedParentsCount").toInt();
- const int expansionLevelB = b->values.value("expandedParentsCount").toInt();
+ const int expansionLevelA = expandedParentsCount(a);
+ const int expansionLevelB = expandedParentsCount(b);
// If b has a higher expansion level than a, check if a is a parent
// of b, and make sure that both expansion levels are equal otherwise.
a = a->parent;
}
- Q_ASSERT(a->values.value("expandedParentsCount").toInt() == b->values.value("expandedParentsCount").toInt());
+ Q_ASSERT(expandedParentsCount(a) == expandedParentsCount(b));
// Compare the last parents of a and b which are different.
while (a->parent != b->parent) {
continue;
}
- const QString name = m_itemData.at(i)->values.value("text").toString();
+ const QString name = m_itemData.at(i)->item.text();
// Use the first character of the name as group indication
QChar newFirstChar = name.at(0).toUpper();
return groups;
}
-KFileItemList KFileItemModel::childItems(const KFileItem& item) const
-{
- KFileItemList items;
-
- int index = m_items.value(item.url(), -1);
- if (index >= 0) {
- const int parentLevel = m_itemData.at(index)->values.value("expandedParentsCount").toInt();
- ++index;
- while (index < m_itemData.count() && m_itemData.at(index)->values.value("expandedParentsCount").toInt() > parentLevel) {
- items.append(m_itemData.at(index)->item);
- ++index;
- }
- }
-
- return items;
-}
-
void KFileItemModel::emitSortProgress(int resolvedCount)
{
// Be tolerant against a resolvedCount with a wrong range.
const ItemData* data = m_itemData.at(i);
const ItemData* parent = data->parent;
if (parent) {
- if (data->values.value("expandedParentsCount").toInt() != parent->values.value("expandedParentsCount").toInt() + 1) {
+ if (expandedParentsCount(data) != expandedParentsCount(parent) + 1) {
qWarning() << "expandedParentsCount is inconsistent for parent" << parent->item << "and child" << data->item;
return false;
}
#include <kitemviews/private/kfileitemmodelfilter.h>
#include <QHash>
+#include <QSet>
class KFileItemModelDirLister;
class QTimer;
bool showDirectoriesOnly() const;
/** @reimp */
- virtual QMimeData* createMimeData(const QSet<int>& indexes) const;
+ virtual QMimeData* createMimeData(const KItemSet& indexes) const;
/** @reimp */
virtual int indexForKeyboardSearch(const QString& text, int startFromIndex = 0) const;
};
void insertItems(QList<ItemData*>& items);
- void removeItems(const KFileItemList& items, RemoveItemsBehavior behavior);
+ void removeItems(const KItemRangeList& itemRanges, RemoveItemsBehavior behavior);
/**
* Helper method for insertItems() and removeItems(): Creates
*/
QList<ItemData*> createItemDataList(const KUrl& parentUrl, const KFileItemList& items) const;
+ static int expandedParentsCount(const ItemData* data);
+
void removeExpandedItems();
/**
QHash<QByteArray, QVariant> retrieveData(const KFileItem& item, const ItemData* parent) const;
+ /**
+ * @return True if \a a has a KFileItem whose text is 'less than' the one
+ * of \a b according to QString::operator<(const QString&).
+ */
+ static bool nameLessThan(const ItemData* a, const ItemData* b);
+
/**
* @return True if the item-data \a a should be ordered before the item-data
* \b. The item-data may have different parent-items.
*/
bool isChildItem(int index) const;
- /**
- * @return Recursive list of child items that have \a item as upper most parent.
- */
- KFileItemList childItems(const KFileItem& item) const;
-
/**
* Is invoked by KFileItemModelRolesUpdater and results in emitting the
* sortProgress signal with a percent-value of the progress.
* Removes filtered items whose expanded parents have been deleted
* or collapsed via setExpanded(parentIndex, false).
*/
- void removeFilteredChildren(const KFileItemList& parentsList);
+ void removeFilteredChildren(const KItemRangeList& parents);
/**
* Maps the QByteArray-roles to RoleTypes and provides translation- and
friend class DolphinPart; // Accesses m_dirLister
};
+inline bool KFileItemModel::nameLessThan(const ItemData* a, const ItemData* b)
+{
+ return a->item.text() < b->item.text();
+}
+
+
inline bool KFileItemModel::isChildItem(int index) const
{
- return m_requestRole[ExpandedParentsCountRole] && m_itemData.at(index)->values.value("expandedParentsCount").toInt() > 0;
+ if (m_itemData.at(index)->parent) {
+ return true;
+ } else {
+ return false;
+ }
}
#endif
#include <KConfig>
#include <KConfigGroup>
#include <KDebug>
-#include <KDirWatch>
#include <KFileItem>
#include <KGlobal>
#include <KIO/JobUiDelegate>
#include <KIO/PreviewJob>
#include "private/kpixmapmodifier.h"
+#include "private/kdirectorycontentscounter.h"
#include <QApplication>
#include <QPainter>
#include <Nepomuk2/ResourceManager>
#endif
-// Required includes for subItemsCount():
-#ifdef Q_WS_WIN
- #include <QDir>
-#else
- #include <dirent.h>
- #include <QFile>
-#endif
-
// #define KFILEITEMMODELROLESUPDATER_DEBUG
namespace {
m_recentlyChangedItemsTimer(0),
m_recentlyChangedItems(),
m_changedItems(),
- m_dirWatcher(0),
- m_watchedDirs()
+ m_directoryContentsCounter(0)
#ifdef HAVE_NEPOMUK
, m_nepomukResourceWatcher(0),
m_nepomukUriItems()
m_resolvableRoles += KNepomukRolesProvider::instance().roles();
#endif
- // When folders are expandable or the item-count is shown for folders, it is necessary
- // to watch the number of items of the sub-folder to be able to react on changes.
- m_dirWatcher = new KDirWatch(this);
- connect(m_dirWatcher, SIGNAL(dirty(QString)), this, SLOT(slotDirWatchDirty(QString)));
+ m_directoryContentsCounter = new KDirectoryContentsCounter(m_model, this);
+ connect(m_directoryContentsCounter, SIGNAL(result(QString,int)),
+ this, SLOT(slotDirectoryContentsCountReceived(QString,int)));
}
KFileItemModelRolesUpdater::~KFileItemModelRolesUpdater()
const bool allItemsRemoved = (m_model->count() == 0);
- if (!m_watchedDirs.isEmpty()) {
- // Don't let KDirWatch watch for removed items
- if (allItemsRemoved) {
- foreach (const QString& path, m_watchedDirs) {
- m_dirWatcher->removeDir(path);
- }
- m_watchedDirs.clear();
- } else {
- QMutableSetIterator<QString> it(m_watchedDirs);
- while (it.hasNext()) {
- const QString& path = it.next();
- if (m_model->index(KUrl(path)) < 0) {
- m_dirWatcher->removeDir(path);
- it.remove();
- }
- }
- }
- }
-
#ifdef HAVE_NEPOMUK
if (m_nepomukResourceWatcher) {
// Don't let the ResourceWatcher watch for removed items
#endif
}
-void KFileItemModelRolesUpdater::slotDirWatchDirty(const QString& path)
+void KFileItemModelRolesUpdater::slotDirectoryContentsCountReceived(const QString& path, int count)
{
const bool getSizeRole = m_roles.contains("size");
const bool getIsExpandableRole = m_roles.contains("isExpandable");
if (getSizeRole || getIsExpandableRole) {
const int index = m_model->index(KUrl(path));
if (index >= 0) {
- if (!m_model->fileItem(index).isDir()) {
- // If INotify is used, KDirWatch issues the dirty() signal
- // also for changed files inside the directory, even if we
- // don't enable this behavior explicitly (see bug 309740).
- return;
- }
QHash<QByteArray, QVariant> data;
- const int count = subItemsCount(path);
if (getSizeRole) {
data.insert("size", count);
}
data.insert("isExpandable", count > 0);
}
- // Note that we do not block the itemsChanged signal here.
- // This ensures that a new preview will be generated.
+ disconnect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet<QByteArray>)),
+ this, SLOT(slotItemsChanged(KItemRangeList,QSet<QByteArray>)));
m_model->setData(index, data);
+ connect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet<QByteArray>)),
+ this, SLOT(slotItemsChanged(KItemRangeList,QSet<QByteArray>)));
}
}
}
data.insert("type", item.mimeComment());
} else if (m_model->sortRole() == "size" && item.isLocalFile() && item.isDir()) {
const QString path = item.localPath();
- data.insert("size", subItemsCount(path));
+ data.insert("size", m_directoryContentsCounter->countDirectoryContentsSynchronously(path));
} else {
// Probably the sort role is a Nepomuk role - just determine all roles.
data = rolesData(item);
return false;
}
-QHash<QByteArray, QVariant> KFileItemModelRolesUpdater::rolesData(const KFileItem& item) const
+QHash<QByteArray, QVariant> KFileItemModelRolesUpdater::rolesData(const KFileItem& item)
{
QHash<QByteArray, QVariant> data;
if ((getSizeRole || getIsExpandableRole) && item.isDir()) {
if (item.isLocalFile()) {
+ // Tell m_directoryContentsCounter that we want to count the items
+ // inside the directory. The result will be received in slotDirectoryContentsCountReceived.
const QString path = item.localPath();
- const int count = subItemsCount(path);
- if (getSizeRole) {
- data.insert("size", count);
- }
- if (getIsExpandableRole) {
- data.insert("isExpandable", count > 0);
- }
-
- if (!m_dirWatcher->contains(path)) {
- m_dirWatcher->addDir(path);
- m_watchedDirs.insert(path);
- }
+ m_directoryContentsCounter->addDirectory(path);
} else if (getSizeRole) {
data.insert("size", -1); // -1 indicates an unknown number of items
}
return data;
}
-int KFileItemModelRolesUpdater::subItemsCount(const QString& path) const
-{
- const bool countHiddenFiles = m_model->showHiddenFiles();
- const bool showFoldersOnly = m_model->showDirectoriesOnly();
-
-#ifdef Q_WS_WIN
- QDir dir(path);
- QDir::Filters filters = QDir::NoDotAndDotDot | QDir::System;
- if (countHiddenFiles) {
- filters |= QDir::Hidden;
- }
- if (showFoldersOnly) {
- filters |= QDir::Dirs;
- } else {
- filters |= QDir::AllEntries;
- }
- return dir.entryList(filters).count();
-#else
- // Taken from kdelibs/kio/kio/kdirmodel.cpp
- // Copyright (C) 2006 David Faure <faure@kde.org>
-
- int count = -1;
- DIR* dir = ::opendir(QFile::encodeName(path));
- if (dir) { // krazy:exclude=syscalls
- count = 0;
- struct dirent *dirEntry = 0;
- while ((dirEntry = ::readdir(dir))) {
- if (dirEntry->d_name[0] == '.') {
- if (dirEntry->d_name[1] == '\0' || !countHiddenFiles) {
- // Skip "." or hidden files
- continue;
- }
- if (dirEntry->d_name[1] == '.' && dirEntry->d_name[2] == '\0') {
- // Skip ".."
- continue;
- }
- }
-
- // If only directories are counted, consider an unknown file type and links also
- // as directory instead of trying to do an expensive stat()
- // (see bugs 292642 and 299997).
- const bool countEntry = !showFoldersOnly ||
- dirEntry->d_type == DT_DIR ||
- dirEntry->d_type == DT_LNK ||
- dirEntry->d_type == DT_UNKNOWN;
- if (countEntry) {
- ++count;
- }
- }
- ::closedir(dir);
- }
- return count;
-#endif
-}
-
void KFileItemModelRolesUpdater::updateAllPreviews()
{
if (m_state == Paused) {
#include <QSize>
#include <QStringList>
-class KDirWatch;
+class KDirectoryContentsCounter;
class KFileItemModel;
class KJob;
class QPixmap;
void applyChangedNepomukRoles(const Nepomuk2::Resource& resource, const Nepomuk2::Types::Property& property);
- /**
- * Is invoked if a directory watched by KDirWatch got dirty. Updates
- * the "isExpandable"- and "size"-roles of the item that matches to
- * the given path.
- */
- void slotDirWatchDirty(const QString& path);
+ void slotDirectoryContentsCountReceived(const QString& path, int count);
private:
/**
ResolveAll
};
bool applyResolvedRoles(const KFileItem& item, ResolveHint hint);
- QHash<QByteArray, QVariant> rolesData(const KFileItem& item) const;
+ QHash<QByteArray, QVariant> rolesData(const KFileItem& item);
/**
* @return The number of items of the path \a path.
// Items which have not been changed repeatedly recently.
QSet<KFileItem> m_changedItems;
- KDirWatch* m_dirWatcher;
- mutable QSet<QString> m_watchedDirs; // Required as sadly KDirWatch does not offer a getter method
- // to get all watched directories.
+ KDirectoryContentsCounter* m_directoryContentsCounter;
+
#ifdef HAVE_NEPOMUK
Nepomuk2::ResourceWatcher* m_nepomukResourceWatcher;
mutable QHash<QUrl, KUrl> m_nepomukUriItems;
case Qt::Key_Enter:
case Qt::Key_Return: {
- const QSet<int> 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);
}
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<int> 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) {
m_selectionManager->clearSelection();
}
m_keyboardManager->cancelSearch();
+ emit escapePressed();
break;
case Qt::Key_Space:
}
}
- QSet<int> selectedItems;
+ KItemSet selectedItems;
// Select all visible items that intersect with the rubberband
foreach (const KItemListWidget* widget, m_view->visibleItemListWidgets()) {
// 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);
return;
}
- const QSet<int> selectedItems = m_selectionManager->selectedItems();
+ const KItemSet selectedItems = m_selectionManager->selectedItems();
if (selectedItems.isEmpty()) {
return;
}
#include <libdolphin_export.h>
+#include "kitemset.h"
+
#include <QObject>
#include <QPixmap>
#include <QPointF>
-#include <QSet>
class KItemModelBase;
class KItemListKeyboardSearchManager;
/**
* 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);
* Is emitted if more than one item has been activated by pressing Return/Enter
* when having a selection.
*/
- void itemsActivated(const QSet<int>& indexes);
+ void itemsActivated(const KItemSet& indexes);
void itemMiddleClicked(int index);
*/
void aboveItemDropEvent(int index, QGraphicsSceneDragDropEvent* event);
+ /**
+ * Is emitted if the Escape key is pressed.
+ */
+ void escapePressed();
+
void modelChanged(KItemModelBase* current, KItemModelBase* previous);
void viewChanged(KItemListView* current, KItemListView* previous);
* the current selection it is remembered in m_oldSelection before the
* rubberband gets activated.
*/
- QSet<int> m_oldSelection;
+ KItemSet m_oldSelection;
/**
* Assuming a view is given with a vertical scroll-orientation, grouped items and
void KItemListSelectionManager::setCurrentItem(int current)
{
const int previous = m_currentItem;
- const QSet<int> previousSelection = selectedItems();
+ const KItemSet previousSelection = selectedItems();
if (m_model && current >= 0 && current < m_model->count()) {
m_currentItem = current;
emit currentChanged(m_currentItem, previous);
if (m_isAnchoredSelectionActive) {
- const QSet<int> selection = selectedItems();
+ const KItemSet selection = selectedItems();
if (selection != previousSelection) {
emit selectionChanged(selection, previousSelection);
}
return m_currentItem;
}
-void KItemListSelectionManager::setSelectedItems(const QSet<int>& items)
+void KItemListSelectionManager::setSelectedItems(const KItemSet& items)
{
if (m_selectedItems != items) {
- const QSet<int> previous = m_selectedItems;
+ const KItemSet previous = m_selectedItems;
m_selectedItems = items;
emit selectionChanged(m_selectedItems, previous);
}
}
-QSet<int> KItemListSelectionManager::selectedItems() const
+KItemSet KItemListSelectionManager::selectedItems() const
{
- QSet<int> selectedItems = m_selectedItems;
+ KItemSet selectedItems = m_selectedItems;
if (m_isAnchoredSelectionActive && m_anchorItem != m_currentItem) {
Q_ASSERT(m_anchorItem >= 0);
}
endAnchoredSelection();
- const QSet<int> previous = selectedItems();
+ const KItemSet previous = selectedItems();
count = qMin(count, m_model->count() - index);
break;
}
- const QSet<int> selection = selectedItems();
+ const KItemSet selection = selectedItems();
if (selection != previous) {
emit selectionChanged(selection, previous);
}
void KItemListSelectionManager::clearSelection()
{
- const QSet<int> previous = selectedItems();
+ const KItemSet previous = selectedItems();
if (!previous.isEmpty()) {
m_selectedItems.clear();
m_isAnchoredSelectionActive = false;
- emit selectionChanged(QSet<int>(), previous);
+ emit selectionChanged(KItemSet(), previous);
}
}
void KItemListSelectionManager::itemsInserted(const KItemRangeList& itemRanges)
{
// Store the current selection (needed in the selectionChanged() signal)
- const QSet<int> previousSelection = selectedItems();
+ const KItemSet previousSelection = selectedItems();
// Update the current item
if (m_currentItem < 0) {
// Update the selections
if (!m_selectedItems.isEmpty()) {
- const QSet<int> previous = m_selectedItems;
+ const KItemSet previous = m_selectedItems;
m_selectedItems.clear();
- m_selectedItems.reserve(previous.count());
- QSetIterator<int> 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) {
}
}
- const QSet<int> selection = selectedItems();
+ const KItemSet selection = selectedItems();
if (selection != previousSelection) {
emit selectionChanged(selection, previousSelection);
}
void KItemListSelectionManager::itemsRemoved(const KItemRangeList& itemRanges)
{
// Store the current selection (needed in the selectionChanged() signal)
- const QSet<int> previousSelection = selectedItems();
+ const KItemSet previousSelection = selectedItems();
const int previousCurrent = m_currentItem;
// Update the current item
// Update the selections and the anchor item
if (!m_selectedItems.isEmpty()) {
- const QSet<int> previous = m_selectedItems;
+ const KItemSet previous = m_selectedItems;
m_selectedItems.clear();
- m_selectedItems.reserve(previous.count());
- QSetIterator<int> 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<int> selection = selectedItems();
+ const KItemSet selection = selectedItems();
if (selection != previousSelection) {
emit selectionChanged(selection, previousSelection);
}
void KItemListSelectionManager::itemsMoved(const KItemRange& itemRange, const QList<int>& movedToIndexes)
{
// Store the current selection (needed in the selectionChanged() signal)
- const QSet<int> previousSelection = selectedItems();
+ const KItemSet previousSelection = selectedItems();
// Update the current item
if (m_currentItem >= itemRange.index && m_currentItem < itemRange.index + itemRange.count) {
// Update the selections
if (!m_selectedItems.isEmpty()) {
- const QSet<int> previous = m_selectedItems;
+ const KItemSet previous = m_selectedItems;
m_selectedItems.clear();
- m_selectedItems.reserve(previous.count());
- QSetIterator<int> 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));
}
}
}
- const QSet<int> selection = selectedItems();
+ const KItemSet selection = selectedItems();
if (selection != previousSelection) {
emit selectionChanged(selection, previousSelection);
}
#include <libdolphin_export.h>
#include <kitemviews/kitemmodelbase.h>
+#include <kitemviews/kitemset.h>
#include <QObject>
-#include <QSet>
class KItemModelBase;
void setCurrentItem(int current);
int currentItem() const;
- void setSelectedItems(const QSet<int>& items);
- QSet<int> selectedItems() const;
+ void setSelectedItems(const KItemSet& items);
+ KItemSet selectedItems() const;
bool isSelected(int index) const;
bool hasSelection() const;
signals:
void currentChanged(int current, int previous);
- void selectionChanged(const QSet<int>& current, const QSet<int>& previous);
+ void selectionChanged(const KItemSet& current, const KItemSet& previous);
private:
void setModel(KItemModelBase* model);
private:
int m_currentItem;
int m_anchorItem;
- QSet<int> m_selectedItems;
+ KItemSet m_selectedItems;
bool m_isAnchoredSelectionActive;
KItemModelBase* m_model;
return m_header;
}
-QPixmap KItemListView::createDragPixmap(const QSet<int>& 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);
QAccessible::updateAccessibility(this, 0, QAccessible::TableModelChanged);
}
+void KItemListView::slotGroupsChanged()
+{
+ updateVisibleGroupHeaders();
+ doLayout(NoAnimation);
+ updateSiblingsInformation();
+}
+
void KItemListView::slotGroupedSortingChanged(bool current)
{
m_grouped = current;
QAccessible::updateAccessibility(this, current+1, QAccessible::Focus);
}
-void KItemListView::slotSelectionChanged(const QSet<int>& current, const QSet<int>& previous)
+void KItemListView::slotSelectionChanged(const KItemSet& current, const KItemSet& previous)
{
Q_UNUSED(previous);
if (previous) {
KItemListSelectionManager* selectionManager = previous->selectionManager();
disconnect(selectionManager, SIGNAL(currentChanged(int,int)), this, SLOT(slotCurrentChanged(int,int)));
- disconnect(selectionManager, SIGNAL(selectionChanged(QSet<int>,QSet<int>)), this, SLOT(slotSelectionChanged(QSet<int>,QSet<int>)));
+ disconnect(selectionManager, SIGNAL(selectionChanged(KItemSet,KItemSet)), this, SLOT(slotSelectionChanged(KItemSet,KItemSet)));
}
m_controller = controller;
if (controller) {
KItemListSelectionManager* selectionManager = controller->selectionManager();
connect(selectionManager, SIGNAL(currentChanged(int,int)), this, SLOT(slotCurrentChanged(int,int)));
- connect(selectionManager, SIGNAL(selectionChanged(QSet<int>,QSet<int>)), this, SLOT(slotSelectionChanged(QSet<int>,QSet<int>)));
+ connect(selectionManager, SIGNAL(selectionChanged(KItemSet,KItemSet)), this, SLOT(slotSelectionChanged(KItemSet,KItemSet)));
}
onControllerChanged(controller, previous);
this, SLOT(slotItemsRemoved(KItemRangeList)));
disconnect(m_model, SIGNAL(itemsMoved(KItemRange,QList<int>)),
this, SLOT(slotItemsMoved(KItemRange,QList<int>)));
+ disconnect(m_model, SIGNAL(groupsChanged()),
+ this, SLOT(slotGroupsChanged()));
disconnect(m_model, SIGNAL(groupedSortingChanged(bool)),
this, SLOT(slotGroupedSortingChanged(bool)));
disconnect(m_model, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)),
this, SLOT(slotItemsRemoved(KItemRangeList)));
connect(m_model, SIGNAL(itemsMoved(KItemRange,QList<int>)),
this, SLOT(slotItemsMoved(KItemRange,QList<int>)));
+ connect(m_model, SIGNAL(groupsChanged()),
+ this, SLOT(slotGroupsChanged()));
connect(m_model, SIGNAL(groupedSortingChanged(bool)),
this, SLOT(slotGroupedSortingChanged(bool)));
connect(m_model, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)),
* @return Pixmap that is used for a drag operation based on the
* items given by \a indexes.
*/
- virtual QPixmap createDragPixmap(const QSet<int>& indexes) const;
+ virtual QPixmap createDragPixmap(const KItemSet& indexes) const;
/**
* Lets the user edit the role \a role for item with the index \a index.
virtual void slotItemsMoved(const KItemRange& itemRange, const QList<int>& movedToIndexes);
virtual void slotItemsChanged(const KItemRangeList& itemRanges,
const QSet<QByteArray>& roles);
+ virtual void slotGroupsChanged();
virtual void slotGroupedSortingChanged(bool current);
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<int>& current, const QSet<int>& previous);
+ virtual void slotSelectionChanged(const KItemSet& current, const KItemSet& previous);
private slots:
void slotAnimationFinished(QGraphicsWidget* widget,
int KItemListViewAccessible::selectedCellCount() const
{
- return view()->controller()->selectionManager()->selectedItems().size();
+ return view()->controller()->selectionManager()->selectedItems().count();
}
int KItemListViewAccessible::selectedColumnCount() const
#include "kitemmodelbase.h"
-KItemRange::KItemRange(int index, int count) :
- index(index),
- count(count)
-{
-}
-
-bool KItemRange::operator == (const KItemRange& other) const
-{
- return index == other.index && count == other.count;
-}
-
KItemModelBase::KItemModelBase(QObject* parent) :
QObject(parent),
m_groupedSorting(false),
return 0;
}
-QMimeData* KItemModelBase::createMimeData(const QSet<int>& indexes) const
+QMimeData* KItemModelBase::createMimeData(const KItemSet& indexes) const
{
Q_UNUSED(indexes);
return 0;
#include <libdolphin_export.h>
+#include <kitemviews/kitemrange.h>
+#include <kitemviews/kitemset.h>
+
#include <QHash>
#include <QObject>
-#include <QSet>
#include <QVariant>
class QMimeData;
-struct KItemRange
-{
- KItemRange(int index = 0, int count = 0);
- int index;
- int count;
-
- bool operator == (const KItemRange& other) const;
-};
-typedef QList<KItemRange> KItemRangeList;
-
/**
* @brief Base class for model implementations used by KItemListView and KItemListController.
*
* caller of this method. The method must be implemented if dragging of
* items should be possible.
*/
- virtual QMimeData* createMimeData(const QSet<int>& indexes) const;
+ virtual QMimeData* createMimeData(const KItemSet& indexes) const;
/**
* @return Reimplement this to return the index for the first item
* with the items 5 and 6 then the parameters look like this:
* - itemRange: has the index 0 and a count of 7.
* - movedToIndexes: Contains the seven values 5, 6, 2, 3, 4, 0, 1
+ *
+ * This signal implies that the groups might have changed. Therefore,
+ * gropusChanged() is not emitted if this signal is emitted.
*/
void itemsMoved(const KItemRange& itemRange, const QList<int>& movedToIndexes);
void itemsChanged(const KItemRangeList& itemRanges, const QSet<QByteArray>& roles);
+ /**
+ * Is emitted if the groups have changed, even though the order of the
+ * items has not been modified.
+ */
+ void groupsChanged();
+
void groupedSortingChanged(bool current);
void sortRoleChanged(const QByteArray& current, const QByteArray& previous);
void sortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous);
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * Copyright (C) 2013 by Frank Reininghaus <frank78ac@googlemail.com> *
+ * *
+ * Based on the Itemviews NG project from Trolltech Labs: *
+ * http://qt.gitorious.org/qt-labs/itemviews-ng *
+ * *
+ * 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 KITEMRANGE_H
+#define KITEMRANGE_H
+
+#include <QList>
+
+struct KItemRange
+{
+ KItemRange(int index = 0, int count = 0);
+ int index;
+ int count;
+
+ bool operator == (const KItemRange& other) const;
+};
+
+inline KItemRange::KItemRange(int index, int count) :
+ index(index),
+ count(count)
+{
+}
+
+inline bool KItemRange::operator == (const KItemRange& other) const
+{
+ return index == other.index && count == other.count;
+}
+
+
+class KItemRangeList : public QList<KItemRange>
+{
+public:
+ KItemRangeList() : QList<KItemRange>() {}
+ KItemRangeList(const QList<KItemRange>& list) : QList<KItemRange>(list) {}
+
+ template<class Container>
+ static KItemRangeList fromSortedContainer(const Container& container);
+
+ KItemRangeList& operator<<(const KItemRange& range)
+ {
+ append(range);
+ return *this;
+ }
+};
+
+template<class Container>
+KItemRangeList KItemRangeList::fromSortedContainer(const Container& container)
+{
+ typename Container::const_iterator it = container.constBegin();
+ const typename Container::const_iterator end = container.constEnd();
+
+ if (it == end) {
+ return KItemRangeList();
+ }
+
+ KItemRangeList result;
+
+ int index = *it;
+ int count = 1;
+
+ ++it;
+
+ while (it != end) {
+ if (*it == index + count) {
+ ++count;
+ } else {
+ result << KItemRange(index, count);
+ index = *it;
+ count = 1;
+ }
+ ++it;
+ }
+
+ result << KItemRange(index, count);
+ return result;
+}
+
+#endif
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2013 by Frank Reininghaus <frank78ac@googlemail.com> *
+ * *
+ * 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 <QVector>
+
+#include <algorithm>
+
+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<int> rangeBoundaries;
+ rangeBoundaries.resize(2 * (m_itemRanges.count() + other.m_itemRanges.count()));
+ const QVector<int>::iterator begin = rangeBoundaries.begin();
+ const QVector<int>::iterator end = rangeBoundaries.end();
+ QVector<int>::iterator it = begin;
+
+ foreach (const KItemRange& range, m_itemRanges) {
+ *it++ = range.index;
+ *it++ = range.index + range.count;
+ }
+
+ const QVector<int>::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;
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2013 by Frank Reininghaus <frank78ac@googlemail.com> *
+ * *
+ * 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 <kitemviews/kitemrange.h>
+
+/**
+ * @brief Stores a set of integer numbers in a space-efficient way.
+ *
+ * This class is similar to QSet<int>, but it has the following advantages:
+ *
+ * 1. It uses less memory than a QSet<int> 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
const ItemLayout previous = m_itemLayout;
m_itemLayout = layout;
- switch (layout) {
- case IconsLayout:
- setScrollOrientation(Qt::Vertical);
- setSupportsItemExpanding(false);
- break;
- case DetailsLayout:
- setScrollOrientation(Qt::Vertical);
- setSupportsItemExpanding(true);
- break;
- case CompactLayout:
- setScrollOrientation(Qt::Horizontal);
- setSupportsItemExpanding(false);
- break;
- default:
- Q_ASSERT(false);
- break;
- }
+ setSupportsItemExpanding(itemLayoutSupportsItemExpanding(layout));
+ setScrollOrientation(layout == CompactLayout ? Qt::Horizontal : Qt::Vertical);
onItemLayoutChanged(layout, previous);
return false;
}
+bool KStandardItemListView::itemLayoutSupportsItemExpanding(ItemLayout layout) const
+{
+ return layout == DetailsLayout;
+}
+
void KStandardItemListView::onItemLayoutChanged(ItemLayout current, ItemLayout previous)
{
Q_UNUSED(current);
virtual KItemListGroupHeaderCreatorBase* defaultGroupHeaderCreator() const;
virtual void initializeItemListWidget(KItemListWidget* item);
virtual bool itemSizeHintUpdateRequired(const QSet<QByteArray>& changedRoles) const;
+ virtual bool itemLayoutSupportsItemExpanding(ItemLayout layout) const;
virtual void onItemLayoutChanged(ItemLayout current, ItemLayout previous);
virtual void onScrollOrientationChanged(Qt::Orientation current, Qt::Orientation previous);
virtual void onSupportsItemExpandingChanged(bool supportsExpanding);
QSizeF KStandardItemListWidgetInformant::itemSizeHint(int index, const KItemListView* view) const
{
- const QHash<QByteArray, QVariant> values = view->model()->data(index);
const KItemListStyleOption& option = view->styleOption();
const int additionalRolesCount = qMax(view->visibleRoles().count() - 1, 0);
switch (static_cast<const KStandardItemListView*>(view)->itemLayout()) {
case KStandardItemListWidget::IconsLayout: {
- const QString text = KStringHandler::preProcessWrap(values["text"].toString());
+ const QString text = KStringHandler::preProcessWrap(itemText(index, view));
const qreal itemWidth = view->itemSize().width();
const qreal maxWidth = itemWidth - 2 * option.padding;
// to show all roles without horizontal clipping.
qreal maximumRequiredWidth = 0.0;
+ const QHash<QByteArray, QVariant> values = view->model()->data(index);
foreach (const QByteArray& role, view->visibleRoles()) {
const QString text = roleText(role, values);
const qreal requiredWidth = option.fontMetrics.width(text);
return width;
}
+QString KStandardItemListWidgetInformant::itemText(int index, const KItemListView* view) const
+{
+ return view->model()->data(index).value("text").toString();
+}
+
QString KStandardItemListWidgetInformant::roleText(const QByteArray& role,
const QHash<QByteArray, QVariant>& values) const
{
const QHash<QByteArray, QVariant> values = data();
const int expandedParentsCount = values.value("expandedParentsCount", 0).toInt();
if (expandedParentsCount >= 0) {
+ const KItemListStyleOption& option = styleOption();
const qreal widgetHeight = size().height();
- const qreal inc = (widgetHeight - KIconLoader::SizeSmall) / 2;
+ const qreal inc = (widgetHeight - option.iconSize) / 2;
const qreal x = expandedParentsCount * widgetHeight + inc;
const qreal y = inc;
- m_expansionArea = QRectF(x, y, KIconLoader::SizeSmall, KIconLoader::SizeSmall);
+ m_expansionArea = QRectF(x, y, option.iconSize, option.iconSize);
return;
}
}
int index,
const KItemListView* view) const;
protected:
+ /**
+ * @return The value of the "text" role. The default implementation returns
+ * view->model()->data(index)["text"]. If a derived class can
+ * prevent the (possibly expensive) construction of the
+ * QHash<QByteArray, QVariant> returned by KItemModelBase::data(int),
+ * it can reimplement this function.
+ */
+ virtual QString itemText(int index, const KItemListView* view) const;
+
/**
* @return String representation of the role \a role. The representation of
* a role might depend on other roles, so the values of all roles
return true;
}
-QMimeData* KStandardItemModel::createMimeData(const QSet<int>& indexes) const
+QMimeData* KStandardItemModel::createMimeData(const KItemSet& indexes) const
{
Q_UNUSED(indexes);
return 0;
virtual int count() const;
virtual QHash<QByteArray, QVariant> data(int index) const;
virtual bool setData(int index, const QHash<QByteArray, QVariant>& values);
- virtual QMimeData* createMimeData(const QSet<int>& 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;
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * Copyright (C) 2013 by Frank Reininghaus <frank78ac@googlemail.com> *
+ * *
+ * 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 "kdirectorycontentscounter.h"
+
+#include "kdirectorycontentscounterworker.h"
+#include <kitemviews/kfileitemmodel.h>
+
+#include <KDirWatch>
+#include <QThread>
+
+KDirectoryContentsCounter::KDirectoryContentsCounter(KFileItemModel* model, QObject* parent) :
+ QObject(parent),
+ m_model(model),
+ m_queue(),
+ m_workerThread(0),
+ m_worker(0),
+ m_workerIsBusy(false),
+ m_dirWatcher(0),
+ m_watchedDirs()
+{
+ connect(m_model, SIGNAL(itemsRemoved(KItemRangeList)),
+ this, SLOT(slotItemsRemoved()));
+
+ m_workerThread = new QThread(this);
+ m_worker = new KDirectoryContentsCounterWorker();
+ m_worker->moveToThread(m_workerThread);
+
+ connect(this, SIGNAL(requestDirectoryContentsCount(QString,KDirectoryContentsCounterWorker::Options)),
+ m_worker, SLOT(countDirectoryContents(QString,KDirectoryContentsCounterWorker::Options)));
+ connect(m_worker, SIGNAL(result(QString,int)),
+ this, SLOT(slotResult(QString,int)));
+
+ m_workerThread->start();
+
+ m_dirWatcher = new KDirWatch(this);
+ connect(m_dirWatcher, SIGNAL(dirty(QString)), this, SLOT(slotDirWatchDirty(QString)));
+}
+
+KDirectoryContentsCounter::~KDirectoryContentsCounter()
+{
+ m_workerThread->quit();
+ m_workerThread->wait();
+
+ delete m_worker;
+}
+
+void KDirectoryContentsCounter::addDirectory(const QString& path)
+{
+ startWorker(path);
+}
+
+int KDirectoryContentsCounter::countDirectoryContentsSynchronously(const QString& path)
+{
+ if (!m_dirWatcher->contains(path)) {
+ m_dirWatcher->addDir(path);
+ m_watchedDirs.insert(path);
+ }
+
+ KDirectoryContentsCounterWorker::Options options;
+
+ if (m_model->showHiddenFiles()) {
+ options |= KDirectoryContentsCounterWorker::CountHiddenFiles;
+ }
+
+ if (m_model->showDirectoriesOnly()) {
+ options |= KDirectoryContentsCounterWorker::CountDirectoriesOnly;
+ }
+
+ return KDirectoryContentsCounterWorker::subItemsCount(path, options);
+}
+
+void KDirectoryContentsCounter::slotResult(const QString& path, int count)
+{
+ m_workerIsBusy = false;
+
+ if (!m_dirWatcher->contains(path)) {
+ m_dirWatcher->addDir(path);
+ m_watchedDirs.insert(path);
+ }
+
+ if (!m_queue.isEmpty()) {
+ startWorker(m_queue.dequeue());
+ }
+
+ emit result(path, count);
+}
+
+void KDirectoryContentsCounter::slotDirWatchDirty(const QString& path)
+{
+ const int index = m_model->index(KUrl(path));
+ if (index >= 0) {
+ if (!m_model->fileItem(index).isDir()) {
+ // If INotify is used, KDirWatch issues the dirty() signal
+ // also for changed files inside the directory, even if we
+ // don't enable this behavior explicitly (see bug 309740).
+ return;
+ }
+
+ startWorker(path);
+ }
+}
+
+void KDirectoryContentsCounter::slotItemsRemoved()
+{
+ const bool allItemsRemoved = (m_model->count() == 0);
+
+ if (!m_watchedDirs.isEmpty()) {
+ // Don't let KDirWatch watch for removed items
+ if (allItemsRemoved) {
+ foreach (const QString& path, m_watchedDirs) {
+ m_dirWatcher->removeDir(path);
+ }
+ m_watchedDirs.clear();
+ m_queue.clear();
+ } else {
+ QMutableSetIterator<QString> it(m_watchedDirs);
+ while (it.hasNext()) {
+ const QString& path = it.next();
+ if (m_model->index(KUrl(path)) < 0) {
+ m_dirWatcher->removeDir(path);
+ it.remove();
+ }
+ }
+ }
+ }
+}
+
+void KDirectoryContentsCounter::startWorker(const QString& path)
+{
+ if (m_workerIsBusy) {
+ m_queue.enqueue(path);
+ } else {
+ KDirectoryContentsCounterWorker::Options options;
+
+ if (m_model->showHiddenFiles()) {
+ options |= KDirectoryContentsCounterWorker::CountHiddenFiles;
+ }
+
+ if (m_model->showDirectoriesOnly()) {
+ options |= KDirectoryContentsCounterWorker::CountDirectoriesOnly;
+ }
+
+ emit requestDirectoryContentsCount(path, options);
+ m_workerIsBusy = true;
+ }
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * Copyright (C) 2013 by Frank Reininghaus <frank78ac@googlemail.com> *
+ * *
+ * 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 KDIRECTORYCONTENTSCOUNTER_H
+#define KDIRECTORYCONTENTSCOUNTER_H
+
+#include "kdirectorycontentscounterworker.h"
+
+#include <QSet>
+#include <QQueue>
+
+class KDirWatch;
+class KFileItemModel;
+class QString;
+
+class KDirectoryContentsCounter : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit KDirectoryContentsCounter(KFileItemModel* model, QObject* parent = 0);
+ ~KDirectoryContentsCounter();
+
+ /**
+ * Requests the number of items inside the directory \a path. The actual
+ * counting is done asynchronously, and the result is announced via the
+ * signal \a result.
+ *
+ * The directory \a path is watched for changes, and the signal is emitted
+ * again if a change occurs.
+ */
+ void addDirectory(const QString& path);
+
+ /**
+ * In contrast to \a addDirectory, this function counts the items inside
+ * the directory \a path synchronously and returns the result.
+ *
+ * The directory is watched for changes, and the signal \a result is
+ * emitted if a change occurs.
+ */
+ int countDirectoryContentsSynchronously(const QString& path);
+
+signals:
+ /**
+ * Signals that the directory \a path contains \a count items.
+ */
+ void result(const QString& path, int count);
+
+ void requestDirectoryContentsCount(const QString& path, KDirectoryContentsCounterWorker::Options options);
+
+private slots:
+ void slotResult(const QString& path, int count);
+ void slotDirWatchDirty(const QString& path);
+ void slotItemsRemoved();
+
+private:
+ void startWorker(const QString& path);
+
+private:
+ KFileItemModel* m_model;
+
+ QQueue<QString> m_queue;
+
+ QThread* m_workerThread;
+ KDirectoryContentsCounterWorker* m_worker;
+ bool m_workerIsBusy;
+
+ KDirWatch* m_dirWatcher;
+ QSet<QString> m_watchedDirs; // Required as sadly KDirWatch does not offer a getter method
+ // to get all watched directories.
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * Copyright (C) 2013 by Frank Reininghaus <frank78ac@googlemail.com> *
+ * *
+ * 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 "kdirectorycontentscounterworker.h"
+
+// Required includes for subItemsCount():
+#ifdef Q_WS_WIN
+ #include <QDir>
+#else
+ #include <dirent.h>
+ #include <QFile>
+#endif
+
+KDirectoryContentsCounterWorker::KDirectoryContentsCounterWorker(QObject* parent) :
+ QObject(parent)
+{
+ qRegisterMetaType<KDirectoryContentsCounterWorker::Options>();
+}
+
+int KDirectoryContentsCounterWorker::subItemsCount(const QString& path, Options options)
+{
+ const bool countHiddenFiles = options & CountHiddenFiles;
+ const bool countDirectoriesOnly = options & CountDirectoriesOnly;
+
+#ifdef Q_WS_WIN
+ QDir dir(path);
+ QDir::Filters filters = QDir::NoDotAndDotDot | QDir::System;
+ if (countHiddenFiles) {
+ filters |= QDir::Hidden;
+ }
+ if (countDirectoriesOnly) {
+ filters |= QDir::Dirs;
+ } else {
+ filters |= QDir::AllEntries;
+ }
+ return dir.entryList(filters).count();
+#else
+ // Taken from kdelibs/kio/kio/kdirmodel.cpp
+ // Copyright (C) 2006 David Faure <faure@kde.org>
+
+ int count = -1;
+ DIR* dir = ::opendir(QFile::encodeName(path));
+ if (dir) { // krazy:exclude=syscalls
+ count = 0;
+ struct dirent *dirEntry = 0;
+ while ((dirEntry = ::readdir(dir))) {
+ if (dirEntry->d_name[0] == '.') {
+ if (dirEntry->d_name[1] == '\0' || !countHiddenFiles) {
+ // Skip "." or hidden files
+ continue;
+ }
+ if (dirEntry->d_name[1] == '.' && dirEntry->d_name[2] == '\0') {
+ // Skip ".."
+ continue;
+ }
+ }
+
+ // If only directories are counted, consider an unknown file type and links also
+ // as directory instead of trying to do an expensive stat()
+ // (see bugs 292642 and 299997).
+ const bool countEntry = !countDirectoriesOnly ||
+ dirEntry->d_type == DT_DIR ||
+ dirEntry->d_type == DT_LNK ||
+ dirEntry->d_type == DT_UNKNOWN;
+ if (countEntry) {
+ ++count;
+ }
+ }
+ ::closedir(dir);
+ }
+ return count;
+#endif
+}
+
+void KDirectoryContentsCounterWorker::countDirectoryContents(const QString& path, Options options)
+{
+ emit result(path, subItemsCount(path, options));
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2013 by Frank Reininghaus <frank78ac@googlemail.com> *
+ * *
+ * 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 KDIRECTORYCONTENTENTSCOUNTERWORKER_H
+#define KDIRECTORYCONTENTENTSCOUNTERWORKER_H
+
+#include <QFlags>
+#include <QMetaType>
+#include <QObject>
+
+class QString;
+
+class KDirectoryContentsCounterWorker : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum Option {
+ NoOptions = 0x0,
+ CountHiddenFiles = 0x1,
+ CountDirectoriesOnly = 0x2
+ };
+ Q_DECLARE_FLAGS(Options, Option)
+
+ explicit KDirectoryContentsCounterWorker(QObject* parent = 0);
+
+ /**
+ * Counts the items inside the directory \a path using the options
+ * \a options.
+ *
+ * @return The number of items.
+ */
+ static int subItemsCount(const QString& path, Options options);
+
+signals:
+ /**
+ * Signals that the directory \a path contains \a count items.
+ */
+ void result(const QString& path, int count);
+
+public slots:
+ /**
+ * Requests the number of items inside the directory \a path using the
+ * options \a options. The result is announced via the signal \a result.
+ */
+ // Note that the full type name KDirectoryContentsCounterWorker::Options
+ // is needed here. Just using 'Options' is OK for the compiler, but
+ // confuses moc.
+ void countDirectoryContents(const QString& path, KDirectoryContentsCounterWorker::Options options);
+};
+
+Q_DECLARE_METATYPE(KDirectoryContentsCounterWorker::Options)
+Q_DECLARE_OPERATORS_FOR_FLAGS(KDirectoryContentsCounterWorker::Options)
+
+#endif
const int movedRangeEnd = range.index + range.count;
for (int i = range.index; i < movedRangeEnd; ++i) {
- const int newIndex = movedToIndexes.at(i);
+ const int newIndex = movedToIndexes.at(i - range.index);
newSizeHintCache[newIndex] = m_sizeHintCache.at(i);
}
void KItemListSizeHintResolver::clearCache()
{
- const int count = m_sizeHintCache.count();
- for (int i = 0; i < count; ++i) {
- m_sizeHintCache[i] = QSizeF();
- }
+ m_sizeHintCache.fill(QSizeF());
}
return QRectF();
}
+ QSizeF sizeHint;
+ if (m_sizeHintResolver) {
+ sizeHint = m_sizeHintResolver->sizeHint(index);
+ } else {
+ sizeHint = m_itemSize;
+ }
+
if (m_scrollOrientation == Qt::Horizontal) {
// Rotate the logical direction which is always vertical by 90°
// to get the physical horizontal direction
- const QRectF& b = m_itemInfos[index].rect;
- QRectF bounds(b.y(), b.x(), b.height(), b.width());
- QPointF pos = bounds.topLeft();
+ const QPointF logicalPos = m_itemInfos[index].pos;
+ QPointF pos(logicalPos.y(), logicalPos.x());
pos.rx() -= m_scrollOffset;
- bounds.moveTo(pos);
- return bounds;
+ return QRectF(pos, sizeHint);
}
- QRectF bounds = m_itemInfos[index].rect;
- bounds.moveTo(bounds.topLeft() - QPointF(m_itemOffset, m_scrollOffset));
- return bounds;
+ if (sizeHint.width() <= 0) {
+ // In Details View, a size hint with negative width is used internally.
+ sizeHint.rwidth() = m_itemSize.width();
+ }
+
+ QPointF pos = m_itemInfos[index].pos;
+ pos -= QPointF(m_itemOffset, m_scrollOffset);
+ return QRectF(pos, sizeHint);
}
QRectF KItemListViewLayouter::groupHeaderRect(int index) const
// current column. As the scroll-direction is
// Qt::Horizontal and m_itemRects is accessed directly,
// the logical height represents the visual width.
- qreal width = minimumGroupHeaderWidth();
- const qreal y = m_itemInfos[index].rect.y();
+ qreal headerWidth = minimumGroupHeaderWidth();
+ const qreal y = m_itemInfos[index].pos.y();
const int maxIndex = m_itemInfos.count() - 1;
while (index <= maxIndex) {
- QRectF bounds = m_itemInfos[index].rect;
- if (bounds.y() != y) {
+ const QPointF pos = m_itemInfos[index].pos;
+ if (pos.y() != y) {
break;
}
- if (bounds.height() > width) {
- width = bounds.height();
+ qreal itemWidth;
+ if (m_sizeHintResolver) {
+ itemWidth = m_sizeHintResolver->sizeHint(index).width();
+ } else {
+ itemWidth = m_itemSize.width();
+ }
+
+ if (itemWidth > headerWidth) {
+ headerWidth = itemWidth;
}
++index;
}
- size = QSizeF(width, m_size.height());
+ size = QSizeF(headerWidth, m_size.height());
}
return QRectF(pos, size);
}
if (horizontalScrolling) {
// Flip everything so that the layout logically can work like having
// a vertical scrolling
- itemSize.setWidth(m_itemSize.height());
- itemSize.setHeight(m_itemSize.width());
- itemMargin.setWidth(m_itemMargin.height());
- itemMargin.setHeight(m_itemMargin.width());
- size.setWidth(m_size.height());
- size.setHeight(m_size.width());
+ itemSize.transpose();
+ itemMargin.transpose();
+ size.transpose();
if (grouped) {
// In the horizontal scrolling case all groups are aligned
}
}
- int rowCount = itemCount / m_columnCount;
- if (itemCount % m_columnCount != 0) {
- ++rowCount;
- }
-
- m_itemInfos.reserve(itemCount);
+ m_itemInfos.resize(itemCount);
qreal y = m_headerHeight + itemMargin.height();
int row = 0;
}
}
- const QRectF bounds(x, y, itemSize.width(), requiredItemHeight);
- if (index < m_itemInfos.count()) {
- m_itemInfos[index].rect = bounds;
- m_itemInfos[index].column = column;
- m_itemInfos[index].row = row;
- } else {
- ItemInfo itemInfo;
- itemInfo.rect = bounds;
- itemInfo.column = column;
- itemInfo.row = row;
- m_itemInfos.append(itemInfo);
- }
+ ItemInfo& itemInfo = m_itemInfos[index];
+ itemInfo.pos = QPointF(x, y);
+ itemInfo.column = column;
+ itemInfo.row = row;
if (grouped && horizontalScrolling) {
// When grouping is enabled in the horizontal mode, the header alignment
y += maxItemHeight + itemMargin.height();
++row;
}
- if (m_itemInfos.count() > itemCount) {
- m_itemInfos.erase(m_itemInfos.begin() + itemCount,
- m_itemInfos.end());
- }
if (itemCount > 0) {
- // Calculate the maximum y-range of the last row for m_maximumScrollOffset
- m_maximumScrollOffset = m_itemInfos.last().rect.bottom();
- const qreal rowY = m_itemInfos.last().rect.y();
-
- int index = m_itemInfos.count() - 2;
- while (index >= 0 && m_itemInfos[index].rect.bottom() >= rowY) {
- m_maximumScrollOffset = qMax(m_maximumScrollOffset, m_itemInfos[index].rect.bottom());
- --index;
- }
-
- m_maximumScrollOffset += itemMargin.height();
-
+ m_maximumScrollOffset = y;
m_maximumItemOffset = m_columnCount * m_columnWidth;
} else {
m_maximumScrollOffset = 0;
int mid = 0;
do {
mid = (min + max) / 2;
- if (m_itemInfos[mid].rect.top() < m_scrollOffset) {
+ if (m_itemInfos[mid].pos.y() < m_scrollOffset) {
min = mid + 1;
} else {
max = mid - 1;
if (mid > 0) {
// Include the row before the first fully visible index, as it might
// be partly visible
- if (m_itemInfos[mid].rect.top() >= m_scrollOffset) {
+ if (m_itemInfos[mid].pos.y() >= m_scrollOffset) {
--mid;
- Q_ASSERT(m_itemInfos[mid].rect.top() < m_scrollOffset);
+ Q_ASSERT(m_itemInfos[mid].pos.y() < m_scrollOffset);
}
- const qreal rowTop = m_itemInfos[mid].rect.top();
- while (mid > 0 && m_itemInfos[mid - 1].rect.top() == rowTop) {
+ const qreal rowTop = m_itemInfos[mid].pos.y();
+ while (mid > 0 && m_itemInfos[mid - 1].pos.y() == rowTop) {
--mid;
}
}
max = maxIndex;
do {
mid = (min + max) / 2;
- if (m_itemInfos[mid].rect.y() <= bottom) {
+ if (m_itemInfos[mid].pos.y() <= bottom) {
min = mid + 1;
} else {
max = mid - 1;
}
} while (min <= max);
- while (mid > 0 && m_itemInfos[mid].rect.y() > bottom) {
+ while (mid > 0 && m_itemInfos[mid].pos.y() > bottom) {
--mid;
}
m_lastVisibleIndex = mid;
qreal m_groupHeaderMargin;
struct ItemInfo {
- QRectF rect;
+ QPointF pos;
int column;
int row;
};
}
}
-QMimeData* PlacesItemModel::createMimeData(const QSet<int>& indexes) const
+QMimeData* PlacesItemModel::createMimeData(const KItemSet& indexes) const
{
KUrl::List urls;
QByteArray itemData;
void requestStorageSetup(int index);
/** @reimp */
- virtual QMimeData* createMimeData(const QSet<int>& indexes) const;
+ virtual QMimeData* createMimeData(const KItemSet& indexes) const;
/** @reimp */
virtual bool supportsDropping(int index) const;
Comment[zh_TW]=設定一般檔案管理員
X-KDE-Keywords=file manager
X-KDE-Keywords[ar]=مدير الملفات
+X-KDE-Keywords[bg]=преглед на файлове
X-KDE-Keywords[bs]=upravitelj datoteka
X-KDE-Keywords[ca]=gestor de fitxers
X-KDE-Keywords[ca@valencia]=gestor de fitxers
Comment[zh_TW]=設定檔案管理員導覽
X-KDE-Keywords=file manager
X-KDE-Keywords[ar]=مدير الملفات
+X-KDE-Keywords[bg]=преглед на файлове
X-KDE-Keywords[bs]=upravitelj datoteka
X-KDE-Keywords[ca]=gestor de fitxers
X-KDE-Keywords[ca@valencia]=gestor de fitxers
Comment[zh_TW]=設定檔案管理員服務
X-KDE-Keywords=file manager
X-KDE-Keywords[ar]=مدير الملفات
+X-KDE-Keywords[bg]=преглед на файлове
X-KDE-Keywords[bs]=upravitelj datoteka
X-KDE-Keywords[ca]=gestor de fitxers
X-KDE-Keywords[ca@valencia]=gestor de fitxers
Comment[zh_TW]=設定檔案管理員檢視模式
X-KDE-Keywords=file manager
X-KDE-Keywords[ar]=مدير الملفات
+X-KDE-Keywords[bg]=преглед на файлове
X-KDE-Keywords[bs]=upravitelj datoteka
X-KDE-Keywords[ca]=gestor de fitxers
X-KDE-Keywords[ca@valencia]=gestor de fitxers
# 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})
../kitemviews/kitemlistcontainer.cpp
../kitemviews/kitemlistwidget.cpp
../kitemviews/kitemlistviewaccessible.cpp
+ ../kitemviews/kitemset.cpp
../kitemviews/kstandarditemlistview.cpp
../kitemviews/kstandarditemlistwidget.cpp
)
../kitemviews/kitemlistviewaccessible.cpp
../kitemviews/kitemlistcontainer.cpp
../kitemviews/kitemlistwidget.cpp
+ ../kitemviews/kitemset.cpp
../kitemviews/kstandarditemlistview.cpp
../kitemviews/kstandarditemlistwidget.cpp
)
QCOMPARE(model.count(), initialItems.count() + newItems.count());
if (!removedItems.isEmpty()) {
- model.removeItems(removedItems, KFileItemModel::DeleteItemData);
+ model.slotItemsDeleted(removedItems);
}
QCOMPARE(model.count(), initialItems.count() + newItems.count() - removedItems.count());
}
const int DefaultTimeout = 5000;
};
+Q_DECLARE_METATYPE(KItemRange)
Q_DECLARE_METATYPE(KItemRangeList)
Q_DECLARE_METATYPE(QList<int>)
void testGeneralParentChildRelationships();
void testNameRoleGroups();
void testNameRoleGroupsWithExpandedItems();
+ void testInconsistentModel();
private:
QStringList itemsInModel() const;
// KFileItemModel::expansionLevelsCompare(const KFileItem& a, const KFileItem& b)
// yields the correct result for "a/a/1" and "a/a-1/", whis is non-trivial because they share the
// first three characters.
- QSet<QByteArray> modelRoles = m_model->roles();
+ QSet<QByteArray> originalModelRoles = m_model->roles();
+ QSet<QByteArray> modelRoles = originalModelRoles;
modelRoles << "isExpanded" << "isExpandable" << "expandedParentsCount";
m_model->setRoles(modelRoles);
QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(directoryLoadingCompleted()), DefaultTimeout));
QCOMPARE(m_model->count(), 5); // 5 items: "a/", "a/a/", "a/a/1", "a/a-1/", "a/a-1/1"
QCOMPARE(m_model->expandedDirectories(), allFolders);
+
+ // Remove all expanded items by changing the roles
+ spyRemoved.clear();
+ m_model->setRoles(originalModelRoles);
+ QVERIFY(!m_model->isExpanded(0));
+ QCOMPARE(m_model->count(), 1);
+ QVERIFY(!m_model->expandedDirectories().contains(KUrl(m_testDir->name() + 'a')));
+
+ QCOMPARE(spyRemoved.count(), 1);
+ itemRangeList = spyRemoved.takeFirst().at(0).value<KItemRangeList>();
+ QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(1, 4)); // 4 items removed
+ QVERIFY(m_model->isConsistent());
}
void KFileItemModelTest::testExpandParentItems()
QVERIFY(m_model->isExpanded(3));
QVERIFY(!m_model->isExpanded(4));
QVERIFY(m_model->isConsistent());
+
+ // Expand "a 1/b1/".
+ m_model->setExpanded(1, true);
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(directoryLoadingCompleted()), DefaultTimeout));
+ QCOMPARE(m_model->count(), 6);
+ QVERIFY(m_model->isExpanded(0));
+ QVERIFY(m_model->isExpanded(1));
+ QVERIFY(!m_model->isExpanded(2));
+ QVERIFY(m_model->isExpanded(3));
+ QVERIFY(m_model->isExpanded(4));
+ QVERIFY(!m_model->isExpanded(5));
+ QVERIFY(m_model->isConsistent());
+
+ // Collapse "a 1/b1/" again, and verify that the previous state is restored.
+ m_model->setExpanded(1, false);
+ QCOMPARE(m_model->count(), 5);
+ QVERIFY(m_model->isExpanded(0));
+ QVERIFY(!m_model->isExpanded(1));
+ QVERIFY(m_model->isExpanded(2));
+ QVERIFY(m_model->isExpanded(3));
+ QVERIFY(!m_model->isExpanded(4));
+ QVERIFY(m_model->isConsistent());
}
/**
QCOMPARE(m_model->sortOrder(), Qt::AscendingOrder);
QCOMPARE(itemsInModel(), QStringList() << "a" << "b" << "c" << "c-1" << "c-2" << "c-3" << "d" << "e");
QCOMPARE(spyItemsMoved.count(), 1);
- QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 2 << 4 << 5 << 3 << 0 << 1 << 6 << 7);
+ QCOMPARE(spyItemsMoved.first().at(0).value<KItemRange>(), KItemRange(0, 6));
+ QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 2 << 4 << 5 << 3 << 0 << 1);
// Sort by Name, descending
m_model->setSortDirectoriesFirst(true);
QCOMPARE(m_model->sortOrder(), Qt::DescendingOrder);
QCOMPARE(itemsInModel(), QStringList() << "c" << "c-2" << "c-3" << "c-1" << "e" << "d" << "b" << "a");
QCOMPARE(spyItemsMoved.count(), 2);
- QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 4 << 5 << 0 << 3 << 1 << 2 << 6 << 7);
- QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 0 << 1 << 2 << 3 << 7 << 6 << 5 << 4);
+ QCOMPARE(spyItemsMoved.first().at(0).value<KItemRange>(), KItemRange(0, 6));
+ QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 4 << 5 << 0 << 3 << 1 << 2);
+ QCOMPARE(spyItemsMoved.first().at(0).value<KItemRange>(), KItemRange(4, 4));
+ QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 7 << 6 << 5 << 4);
// Sort by Date, descending
m_model->setSortDirectoriesFirst(true);
QCOMPARE(m_model->sortOrder(), Qt::DescendingOrder);
QCOMPARE(itemsInModel(), QStringList() << "c" << "c-2" << "c-3" << "c-1" << "b" << "d" << "a" << "e");
QCOMPARE(spyItemsMoved.count(), 1);
- QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 0 << 1 << 2 << 3 << 7 << 5 << 4 << 6);
+ QCOMPARE(spyItemsMoved.first().at(0).value<KItemRange>(), KItemRange(4, 4));
+ QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 7 << 5 << 4 << 6);
// Sort by Date, ascending
m_model->setSortOrder(Qt::AscendingOrder);
QCOMPARE(m_model->sortOrder(), Qt::AscendingOrder);
QCOMPARE(itemsInModel(), QStringList() << "c" << "c-2" << "c-3" << "c-1" << "e" << "a" << "d" << "b");
QCOMPARE(spyItemsMoved.count(), 1);
- QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 0 << 1 << 2 << 3 << 7 << 6 << 5 << 4);
+ QCOMPARE(spyItemsMoved.first().at(0).value<KItemRange>(), KItemRange(4, 4));
+ QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 7 << 6 << 5 << 4);
// Sort by Date, ascending, 'Sort Folders First' disabled
m_model->setSortDirectoriesFirst(false);
QVERIFY(!m_model->sortDirectoriesFirst());
QCOMPARE(itemsInModel(), QStringList() << "e" << "a" << "c" << "c-1" << "c-2" << "c-3" << "d" << "b");
QCOMPARE(spyItemsMoved.count(), 1);
- QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 2 << 4 << 5 << 3 << 0 << 1 << 6 << 7);
+ QCOMPARE(spyItemsMoved.first().at(0).value<KItemRange>(), KItemRange(0, 6));
+ QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 2 << 4 << 5 << 3 << 0 << 1);
// Sort by Name, ascending, 'Sort Folders First' disabled
m_model->setSortRole("text");
QVERIFY(!m_model->sortDirectoriesFirst());
QCOMPARE(itemsInModel(), QStringList() << "a" << "b" << "c" << "c-1" << "c-2" << "c-3" << "d" << "e");
QCOMPARE(spyItemsMoved.count(), 1);
+ QCOMPARE(spyItemsMoved.first().at(0).value<KItemRange>(), KItemRange(0, 8));
QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 7 << 0 << 2 << 3 << 4 << 5 << 6 << 1);
// Sort by Size, ascending, 'Sort Folders First' disabled
QVERIFY(!m_model->sortDirectoriesFirst());
QCOMPARE(itemsInModel(), QStringList() << "c" << "c-2" << "c-3" << "c-1" << "a" << "b" << "e" << "d");
QCOMPARE(spyItemsMoved.count(), 1);
+ QCOMPARE(spyItemsMoved.first().at(0).value<KItemRange>(), KItemRange(0, 8));
QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 4 << 5 << 0 << 3 << 1 << 2 << 7 << 6);
- QSKIP("2 tests of testSorting() are temporary deactivated as in KFileItemModel resortAllItems() "
- "always emits a itemsMoved() signal. Before adjusting the tests think about probably introducing "
- "another signal", SkipSingle);
- // Internal note: Check comment in KFileItemModel::resortAllItems() for details.
-
// In 'Sort by Size' mode, folders are always first -> changing 'Sort Folders First' does not resort the model
m_model->setSortDirectoriesFirst(true);
QCOMPARE(m_model->sortRole(), QByteArray("size"));
QCOMPARE(m_model->sortOrder(), Qt::AscendingOrder);
QVERIFY(m_model->sortDirectoriesFirst());
- QCOMPARE(itemsInModel(), QStringList() << "c" << "a" << "b" << "e" << "d");
+ QCOMPARE(itemsInModel(), QStringList() << "c" << "c-2" << "c-3" << "c-1" << "a" << "b" << "e" << "d");
QCOMPARE(spyItemsMoved.count(), 0);
// Sort by Size, descending, 'Sort Folders First' enabled
QCOMPARE(m_model->sortRole(), QByteArray("size"));
QCOMPARE(m_model->sortOrder(), Qt::DescendingOrder);
QVERIFY(m_model->sortDirectoriesFirst());
- QCOMPARE(itemsInModel(), QStringList() << "c" << "d" << "e" << "b" << "a");
+ QCOMPARE(itemsInModel(), QStringList() << "c" << "c-2" << "c-3" << "c-1" << "d" << "e" << "b" << "a");
QCOMPARE(spyItemsMoved.count(), 1);
- QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 0 << 4 << 3 << 2 << 1);
+ QCOMPARE(spyItemsMoved.first().at(0).value<KItemRange>(), KItemRange(4, 4));
+ QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 7 << 6 << 5 << 4);
// TODO: Sort by other roles; show/hide hidden files
}
// Rename c.txt to d.txt.
data.insert("text", "d.txt");
m_model->setData(2, data);
- QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsMoved(KItemRange,QList<int>)), DefaultTimeout));
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(groupsChanged()), DefaultTimeout));
QCOMPARE(itemsInModel(), QStringList() << "a.txt" << "b.txt" << "d.txt" << "e.txt");
expectedGroups.clear();
fileItemC.setUrl(urlC);
m_model->slotRefreshItems(QList<QPair<KFileItem, KFileItem> >() << qMakePair(fileItemD, fileItemC));
- QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsMoved(KItemRange,QList<int>)), DefaultTimeout));
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(groupsChanged()), DefaultTimeout));
QCOMPARE(itemsInModel(), QStringList() << "a.txt" << "b.txt" << "c.txt" << "e.txt");
expectedGroups.clear();
QCOMPARE(m_model->groups(), expectedGroups);
}
+void KFileItemModelTest::testInconsistentModel()
+{
+ QSet<QByteArray> modelRoles = m_model->roles();
+ modelRoles << "isExpanded" << "isExpandable" << "expandedParentsCount";
+ m_model->setRoles(modelRoles);
+
+ QStringList files;
+ files << "a/b/c1.txt" << "a/b/c2.txt";
+
+ m_testDir->createFiles(files);
+
+ m_model->loadDirectory(m_testDir->url());
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+ QCOMPARE(itemsInModel(), QStringList() << "a");
+
+ // Expand "a/" and "a/b/".
+ m_model->setExpanded(0, true);
+ QVERIFY(m_model->isExpanded(0));
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+ QCOMPARE(itemsInModel(), QStringList() << "a" << "b");
+
+ m_model->setExpanded(1, true);
+ QVERIFY(m_model->isExpanded(1));
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+ QCOMPARE(itemsInModel(), QStringList() << "a" << "b" << "c1.txt" << "c2.txt");
+
+ // Add the files "c1.txt" and "c2.txt" to the model also as top-level items.
+ // Such a thing can in principle happen when performing a search, and there
+ // are files which
+ // (a) match the search string, and
+ // (b) are children of a folder that matches the search string and is expanded.
+ //
+ // Note that the first item in the list of added items must be new (i.e., not
+ // in the model yet). Otherwise, KFileItemModel::slotItemsAdded() will see that
+ // it receives items that are in the model already and ignore them.
+ KUrl url(m_model->directory().url() + "/a2");
+ KFileItem newItem(KFileItem::Unknown, KFileItem::Unknown, url);
+
+ KFileItemList items;
+ items << newItem << m_model->fileItem(2) << m_model->fileItem(3);
+ m_model->slotItemsAdded(m_model->directory(), items);
+ m_model->slotCompleted();
+ QCOMPARE(itemsInModel(), QStringList() << "a" << "b" << "c1.txt" << "c2.txt" << "a2" << "c1.txt" << "c2.txt");
+
+ m_model->setExpanded(0, false);
+
+ // Test that the right items have been removed, see
+ // https://bugs.kde.org/show_bug.cgi?id=324371
+ QCOMPARE(itemsInModel(), QStringList() << "a" << "a2" << "c1.txt" << "c2.txt");
+
+ // Test that resorting does not cause a crash, see
+ // https://bugs.kde.org/show_bug.cgi?id=325359
+ // The crash is not 100% reproducible, but Valgrind will report an invalid memory access.
+ m_model->resortAllItems();
+
+}
+
QStringList KFileItemModelTest::itemsInModel() const
{
QStringList items;
Q_DECLARE_METATYPE(KFileItemListView::ItemLayout);
Q_DECLARE_METATYPE(Qt::Orientation);
Q_DECLARE_METATYPE(KItemListController::SelectionBehavior);
-Q_DECLARE_METATYPE(QSet<int>);
+Q_DECLARE_METATYPE(KItemSet);
class KItemListControllerTest : public QObject
{
*/
void KItemListControllerTest::initTestCase()
{
- qRegisterMetaType<QSet<int> >("QSet<int>");
+ qRegisterMetaType<KItemSet>("KItemSet");
m_testDir = new TestDir();
m_model = new KFileItemModel();
*/
struct ViewState {
- ViewState(int current, const QSet<int> 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<int> m_selection;
+ KItemSet m_selection;
bool m_activated;
};
// First, key presses which should have the same effect
// for any layout and any number of columns.
testList
- << qMakePair(KeyPress(nextItemKey), ViewState(1, QSet<int>() << 1))
- << qMakePair(KeyPress(Qt::Key_Return), ViewState(1, QSet<int>() << 1, true))
- << qMakePair(KeyPress(Qt::Key_Enter), ViewState(1, QSet<int>() << 1, true))
- << qMakePair(KeyPress(nextItemKey), ViewState(2, QSet<int>() << 2))
- << qMakePair(KeyPress(nextItemKey, Qt::ShiftModifier), ViewState(3, QSet<int>() << 2 << 3))
- << qMakePair(KeyPress(Qt::Key_Return), ViewState(3, QSet<int>() << 2 << 3, true))
- << qMakePair(KeyPress(previousItemKey, Qt::ShiftModifier), ViewState(2, QSet<int>() << 2))
- << qMakePair(KeyPress(nextItemKey, Qt::ShiftModifier), ViewState(3, QSet<int>() << 2 << 3))
- << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(4, QSet<int>() << 2 << 3))
- << qMakePair(KeyPress(Qt::Key_Return), ViewState(4, QSet<int>() << 2 << 3, true))
- << qMakePair(KeyPress(previousItemKey), ViewState(3, QSet<int>() << 3))
- << qMakePair(KeyPress(Qt::Key_Home, Qt::ShiftModifier), ViewState(0, QSet<int>() << 0 << 1 << 2 << 3))
- << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(1, QSet<int>() << 0 << 1 << 2 << 3))
- << qMakePair(KeyPress(Qt::Key_Space, Qt::ControlModifier), ViewState(1, QSet<int>() << 0 << 2 << 3))
- << qMakePair(KeyPress(Qt::Key_Space, Qt::ControlModifier), ViewState(1, QSet<int>() << 0 << 1 << 2 << 3))
- << qMakePair(KeyPress(Qt::Key_End), ViewState(19, QSet<int>() << 19))
- << qMakePair(KeyPress(previousItemKey, Qt::ShiftModifier), ViewState(18, QSet<int>() << 18 << 19))
- << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, QSet<int>() << 0))
- << qMakePair(KeyPress(Qt::Key_Space, Qt::ControlModifier), ViewState(0, QSet<int>()))
- << qMakePair(KeyPress(Qt::Key_Enter), ViewState(0, QSet<int>(), true))
- << qMakePair(KeyPress(Qt::Key_Space, Qt::ControlModifier), ViewState(0, QSet<int>() << 0))
- << qMakePair(KeyPress(Qt::Key_Space, Qt::ControlModifier), ViewState(0, QSet<int>()))
- << qMakePair(KeyPress(Qt::Key_Space), ViewState(0, QSet<int>() << 0))
- << qMakePair(KeyPress(Qt::Key_E), ViewState(13, QSet<int>() << 13))
- << qMakePair(KeyPress(Qt::Key_Space), ViewState(14, QSet<int>() << 14))
- << qMakePair(KeyPress(Qt::Key_3), ViewState(15, QSet<int>() << 15))
- << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, QSet<int>() << 0))
- << qMakePair(KeyPress(Qt::Key_Escape), ViewState(0, QSet<int>()));
+ << 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.
// One column.
if (columnCount == 1) {
testList
- << qMakePair(KeyPress(nextRowKey), ViewState(1, QSet<int>() << 1))
- << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(2, QSet<int>() << 1 << 2))
- << qMakePair(KeyPress(nextRowKey, Qt::ControlModifier), ViewState(3, QSet<int>() << 1 << 2))
- << qMakePair(KeyPress(previousRowKey), ViewState(2, QSet<int>() << 2))
- << qMakePair(KeyPress(previousItemKey), ViewState(1, QSet<int>() << 1))
- << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, QSet<int>() << 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
// e3 e4 e5 | 15 16 17
// e6 e7 | 18 19
testList
- << qMakePair(KeyPress(nextRowKey), ViewState(3, QSet<int>() << 3))
- << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(4, QSet<int>() << 3))
- << qMakePair(KeyPress(nextRowKey), ViewState(7, QSet<int>() << 7))
- << qMakePair(KeyPress(nextItemKey, Qt::ShiftModifier), ViewState(8, QSet<int>() << 7 << 8))
- << qMakePair(KeyPress(nextItemKey, Qt::ShiftModifier), ViewState(9, QSet<int>() << 7 << 8 << 9))
- << qMakePair(KeyPress(previousItemKey, Qt::ShiftModifier), ViewState(8, QSet<int>() << 7 << 8))
- << qMakePair(KeyPress(previousItemKey, Qt::ShiftModifier), ViewState(7, QSet<int>() << 7))
- << qMakePair(KeyPress(previousItemKey, Qt::ShiftModifier), ViewState(6, QSet<int>() << 6 << 7))
- << qMakePair(KeyPress(previousItemKey, Qt::ShiftModifier), ViewState(5, QSet<int>() << 5 << 6 << 7))
- << qMakePair(KeyPress(nextItemKey, Qt::ShiftModifier), ViewState(6, QSet<int>() << 6 << 7))
- << qMakePair(KeyPress(nextItemKey, Qt::ShiftModifier), ViewState(7, QSet<int>() << 7))
- << qMakePair(KeyPress(nextRowKey), ViewState(10, QSet<int>() << 10))
- << qMakePair(KeyPress(nextItemKey), ViewState(11, QSet<int>() << 11))
- << qMakePair(KeyPress(nextRowKey), ViewState(14, QSet<int>() << 14))
- << qMakePair(KeyPress(nextRowKey), ViewState(17, QSet<int>() << 17))
- << qMakePair(KeyPress(nextRowKey), ViewState(19, QSet<int>() << 19))
- << qMakePair(KeyPress(previousRowKey), ViewState(17, QSet<int>() << 17))
- << qMakePair(KeyPress(Qt::Key_End), ViewState(19, QSet<int>() << 19))
- << qMakePair(KeyPress(previousRowKey), ViewState(16, QSet<int>() << 16))
- << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, QSet<int>() << 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) {
// 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<int>() << 5))
- << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(6, QSet<int>() << 5))
- << qMakePair(KeyPress(nextRowKey), ViewState(11, QSet<int>() << 11))
- << qMakePair(KeyPress(nextItemKey), ViewState(12, QSet<int>() << 12))
- << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(17, QSet<int>() << 12 << 13 << 14 << 15 << 16 << 17))
- << qMakePair(KeyPress(previousRowKey, Qt::ShiftModifier), ViewState(12, QSet<int>() << 12))
- << qMakePair(KeyPress(previousRowKey, Qt::ShiftModifier), ViewState(7, QSet<int>() << 7 << 8 << 9 << 10 << 11 << 12))
- << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(12, QSet<int>() << 12))
- << qMakePair(KeyPress(Qt::Key_End, Qt::ControlModifier), ViewState(19, QSet<int>() << 12))
- << qMakePair(KeyPress(previousRowKey), ViewState(14, QSet<int>() << 14))
- << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, QSet<int>() << 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) {
// e4 e5 e6 | 16 17 18
// e7 | 19
testList
- << qMakePair(KeyPress(nextItemKey), ViewState(1, QSet<int>() << 1))
- << qMakePair(KeyPress(nextItemKey), ViewState(2, QSet<int>() << 2))
- << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(3, QSet<int>() << 2 << 3))
- << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(6, QSet<int>() << 2 << 3 << 4 << 5 << 6))
- << qMakePair(KeyPress(nextRowKey), ViewState(8, QSet<int>() << 8))
- << qMakePair(KeyPress(nextRowKey), ViewState(11, QSet<int>() << 11))
- << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(12, QSet<int>() << 11))
- << qMakePair(KeyPress(nextRowKey), ViewState(13, QSet<int>() << 13))
- << qMakePair(KeyPress(nextRowKey), ViewState(16, QSet<int>() << 16))
- << qMakePair(KeyPress(nextItemKey), ViewState(17, QSet<int>() << 17))
- << qMakePair(KeyPress(nextRowKey), ViewState(19, QSet<int>() << 19))
- << qMakePair(KeyPress(previousRowKey), ViewState(17, QSet<int>() << 17))
- << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, QSet<int>() << 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) {
// e1 e2 e3 e4 e5 | 13 14 15 16 17
// e6 e7 | 18 19
testList
- << qMakePair(KeyPress(nextItemKey), ViewState(1, QSet<int>() << 1))
- << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(3, QSet<int>() << 1 << 2 << 3))
- << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(5, QSet<int>() << 1 << 2 << 3 << 4 << 5))
- << qMakePair(KeyPress(nextItemKey), ViewState(6, QSet<int>() << 6))
- << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(7, QSet<int>() << 6))
- << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(8, QSet<int>() << 6))
- << qMakePair(KeyPress(nextRowKey), ViewState(12, QSet<int>() << 12))
- << qMakePair(KeyPress(nextRowKey), ViewState(17, QSet<int>() << 17))
- << qMakePair(KeyPress(nextRowKey), ViewState(19, QSet<int>() << 19))
- << qMakePair(KeyPress(previousRowKey), ViewState(17, QSet<int>() << 17))
- << qMakePair(KeyPress(Qt::Key_End, Qt::ShiftModifier), ViewState(19, QSet<int>() << 17 << 18 << 19))
- << qMakePair(KeyPress(previousRowKey, Qt::ShiftModifier), ViewState(14, QSet<int>() << 14 << 15 << 16 << 17))
- << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, QSet<int>() << 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 =
QCOMPARE(m_view->m_layouter->m_columnCount, columnCount);
QSignalSpy spySingleItemActivated(m_controller, SIGNAL(itemActivated(int)));
- QSignalSpy spyMultipleItemsActivated(m_controller, SIGNAL(itemsActivated(QSet<int>)));
+ QSignalSpy spyMultipleItemsActivated(m_controller, SIGNAL(itemsActivated(KItemSet)));
while (!testList.isEmpty()) {
const QPair<KeyPress, ViewState> 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<int> 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);
QCOMPARE(m_selectionManager->currentItem(), current);
switch (selectionBehavior) {
case KItemListController::NoSelection: QVERIFY(m_selectionManager->selectedItems().isEmpty()); break;
- case KItemListController::SingleSelection: QCOMPARE(m_selectionManager->selectedItems(), QSet<int>() << current); break;
+ case KItemListController::SingleSelection: QCOMPARE(m_selectionManager->selectedItems(), KItemSet() << current); break;
case KItemListController::MultiSelection: QCOMPARE(m_selectionManager->selectedItems(), selection); break;
}
// The selected items should be activated.
if (selection.count() == 1) {
QVERIFY(!spySingleItemActivated.isEmpty());
- QCOMPARE(qvariant_cast<int>(spySingleItemActivated.takeFirst().at(0)), selection.toList().at(0));
+ QCOMPARE(qvariant_cast<int>(spySingleItemActivated.takeFirst().at(0)), selection.first());
QVERIFY(spyMultipleItemsActivated.isEmpty());
} else {
QVERIFY(spySingleItemActivated.isEmpty());
QVERIFY(!spyMultipleItemsActivated.isEmpty());
- QCOMPARE(qvariant_cast<QSet<int> >(spyMultipleItemsActivated.takeFirst().at(0)), selection);
+ QCOMPARE(qvariant_cast<KItemSet>(spyMultipleItemsActivated.takeFirst().at(0)), selection);
}
break;
}
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);
void testDeleteCurrentItem();
private:
- void verifySelectionChange(QSignalSpy& spy, const QSet<int>& currentSelection, const QSet<int>& previousSelection) const;
+ void verifySelectionChange(QSignalSpy& spy, const KItemSet& currentSelection, const KItemSet& previousSelection) const;
KItemListSelectionManager* m_selectionManager;
DummyModel* m_model;
QCOMPARE(m_selectionManager->m_anchorItem, 5);
// Items between current and anchor should be selected now
- QCOMPARE(m_selectionManager->selectedItems(), QSet<int>() << 4 << 5);
+ QCOMPARE(m_selectionManager->selectedItems(), KItemSet() << 4 << 5);
QVERIFY(m_selectionManager->hasSelection());
// Change current item again and check the selection
QCOMPARE(qvariant_cast<int>(spyCurrent.at(0).at(1)), 4);
spyCurrent.takeFirst();
- QCOMPARE(m_selectionManager->selectedItems(), QSet<int>() << 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.
QCOMPARE(m_selectionManager->m_anchorItem, 8);
- QCOMPARE(m_selectionManager->selectedItems(), QSet<int>() << 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.
QCOMPARE(m_selectionManager->m_anchorItem, 5);
- QCOMPARE(m_selectionManager->selectedItems(), QSet<int>() << 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<int>());
+ QCOMPARE(m_selectionManager->selectedItems(), KItemSet());
QVERIFY(!m_selectionManager->hasSelection());
m_selectionManager->endAnchoredSelection();
{
// Select items 10 to 12
m_selectionManager->setSelected(10, 3);
- QSet<int> selectedItems = m_selectionManager->selectedItems();
+ KItemSet selectedItems = m_selectionManager->selectedItems();
QCOMPARE(selectedItems.count(), 3);
QVERIFY(selectedItems.contains(10));
QVERIFY(selectedItems.contains(11));
{
// Select items 10 to 15
m_selectionManager->setSelected(10, 6);
- QSet<int> selectedItems = m_selectionManager->selectedItems();
+ KItemSet selectedItems = m_selectionManager->selectedItems();
QCOMPARE(selectedItems.count(), 6);
for (int i = 10; i <= 15; ++i) {
QVERIFY(selectedItems.contains(i));
m_selectionManager->setCurrentItem(6);
QCOMPARE(m_selectionManager->currentItem(), 6);
- QCOMPARE(m_selectionManager->selectedItems(), QSet<int>() << 5 << 6);
+ QCOMPARE(m_selectionManager->selectedItems(), KItemSet() << 5 << 6);
m_selectionManager->setCurrentItem(4);
QCOMPARE(m_selectionManager->currentItem(), 4);
- QCOMPARE(m_selectionManager->selectedItems(), QSet<int>() << 4 << 5);
+ QCOMPARE(m_selectionManager->selectedItems(), KItemSet() << 4 << 5);
m_selectionManager->setCurrentItem(7);
QCOMPARE(m_selectionManager->currentItem(), 7);
- QCOMPARE(m_selectionManager->selectedItems(), QSet<int>() << 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<int>() << 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);
m_selectionManager->setCurrentItem(6);
QCOMPARE(m_selectionManager->currentItem(), 6);
- QCOMPARE(m_selectionManager->selectedItems(), QSet<int>() << 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<int>() << 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<int>() << 5 << 6 << 7 << 9 << 10);
+ QCOMPARE(m_selectionManager->selectedItems(), KItemSet() << 5 << 6 << 7 << 9 << 10);
}
namespace {
};
}
-Q_DECLARE_METATYPE(QSet<int>);
+Q_DECLARE_METATYPE(KItemSet);
Q_DECLARE_METATYPE(ChangeType);
Q_DECLARE_METATYPE(KItemRange);
Q_DECLARE_METATYPE(KItemRangeList);
void KItemListSelectionManagerTest::testChangeSelection_data()
{
- QTest::addColumn<QSet<int> >("initialSelection");
+ QTest::addColumn<KItemSet>("initialSelection");
QTest::addColumn<int>("anchor");
QTest::addColumn<int>("current");
- QTest::addColumn<QSet<int> >("expectedSelection");
+ QTest::addColumn<KItemSet>("expectedSelection");
QTest::addColumn<ChangeType>("changeType");
QTest::addColumn<QList<QVariant> >("data");
- QTest::addColumn<QSet<int> >("finalSelection");
+ QTest::addColumn<KItemSet>("finalSelection");
QTest::newRow("No change")
- << (QSet<int>() << 5 << 6)
+ << (KItemSet() << 5 << 6)
<< 2 << 3
- << (QSet<int>() << 2 << 3 << 5 << 6)
+ << (KItemSet() << 2 << 3 << 5 << 6)
<< NoChange
<< QList<QVariant>()
- << (QSet<int>() << 2 << 3 << 5 << 6);
+ << (KItemSet() << 2 << 3 << 5 << 6);
QTest::newRow("Insert Items")
- << (QSet<int>() << 5 << 6)
+ << (KItemSet() << 5 << 6)
<< 2 << 3
- << (QSet<int>() << 2 << 3 << 5 << 6)
+ << (KItemSet() << 2 << 3 << 5 << 6)
<< InsertItems
<< (QList<QVariant>() << QVariant::fromValue(KItemRangeList() << KItemRange(1, 1) << KItemRange(5, 2) << KItemRange(10, 5)))
- << (QSet<int>() << 3 << 4 << 8 << 9);
+ << (KItemSet() << 3 << 4 << 8 << 9);
QTest::newRow("Remove Items")
- << (QSet<int>() << 5 << 6)
+ << (KItemSet() << 5 << 6)
<< 2 << 3
- << (QSet<int>() << 2 << 3 << 5 << 6)
+ << (KItemSet() << 2 << 3 << 5 << 6)
<< RemoveItems
<< (QList<QVariant>() << QVariant::fromValue(KItemRangeList() << KItemRange(1, 1) << KItemRange(3, 1) << KItemRange(10, 5)))
- << (QSet<int>() << 1 << 2 << 3 << 4);
+ << (KItemSet() << 1 << 2 << 3 << 4);
QTest::newRow("Empty Anchored Selection")
- << QSet<int>()
+ << KItemSet()
<< 2 << 2
- << QSet<int>()
+ << KItemSet()
<< EndAnchoredSelection
<< QList<QVariant>()
- << QSet<int>();
+ << KItemSet();
QTest::newRow("Toggle selection")
- << (QSet<int>() << 1 << 3 << 4)
+ << (KItemSet() << 1 << 3 << 4)
<< 6 << 8
- << (QSet<int>() << 1 << 3 << 4 << 6 << 7 << 8)
+ << (KItemSet() << 1 << 3 << 4 << 6 << 7 << 8)
<< SetSelected
<< (QList<QVariant>() << 0 << 10 << QVariant::fromValue(KItemListSelectionManager::Toggle))
- << (QSet<int>() << 0 << 2 << 5 << 9);
+ << (KItemSet() << 0 << 2 << 5 << 9);
// Swap items 2, 3 and 4, 5
QTest::newRow("Move items")
- << (QSet<int>() << 0 << 1 << 2 << 3)
+ << (KItemSet() << 0 << 1 << 2 << 3)
<< -1 << -1
- << (QSet<int>() << 0 << 1 << 2 << 3)
+ << (KItemSet() << 0 << 1 << 2 << 3)
<< MoveItems
<< (QList<QVariant>() << QVariant::fromValue(KItemRange(2, 4))
<< QVariant::fromValue(QList<int>() << 4 << 5 << 2 << 3))
- << (QSet<int>() << 0 << 1 << 4 << 5);
+ << (KItemSet() << 0 << 1 << 4 << 5);
// Revert sort order
QTest::newRow("Revert sort order")
- << (QSet<int>() << 0 << 1)
+ << (KItemSet() << 0 << 1)
<< 3 << 4
- << (QSet<int>() << 0 << 1 << 3 << 4)
+ << (KItemSet() << 0 << 1 << 3 << 4)
<< MoveItems
<< (QList<QVariant>() << QVariant::fromValue(KItemRange(0, 10))
<< QVariant::fromValue(QList<int>() << 9 << 8 << 7 << 6 << 5 << 4 << 3 << 2 << 1 << 0))
- << (QSet<int>() << 5 << 6 << 8 << 9);
+ << (KItemSet() << 5 << 6 << 8 << 9);
}
void KItemListSelectionManagerTest::testChangeSelection()
{
- QFETCH(QSet<int>, initialSelection);
+ QFETCH(KItemSet, initialSelection);
QFETCH(int, anchor);
QFETCH(int, current);
- QFETCH(QSet<int>, expectedSelection);
+ QFETCH(KItemSet, expectedSelection);
QFETCH(ChangeType, changeType);
QFETCH(QList<QVariant>, data);
- QFETCH(QSet<int>, finalSelection);
+ QFETCH(KItemSet, finalSelection);
- QSignalSpy spySelectionChanged(m_selectionManager, SIGNAL(selectionChanged(QSet<int>,QSet<int>)));
+ QSignalSpy spySelectionChanged(m_selectionManager, SIGNAL(selectionChanged(KItemSet,KItemSet)));
// Initial selection should be empty
QVERIFY(!m_selectionManager->hasSelection());
// Perform the initial selectiion
m_selectionManager->setSelectedItems(initialSelection);
- verifySelectionChange(spySelectionChanged, initialSelection, QSet<int>());
+ 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
// Finally, clear the selection
m_selectionManager->clearSelection();
- verifySelectionChange(spySelectionChanged, QSet<int>(), finalSelection);
+ verifySelectionChange(spySelectionChanged, KItemSet(), finalSelection);
}
void KItemListSelectionManagerTest::testDeleteCurrentItem_data()
}
void KItemListSelectionManagerTest::verifySelectionChange(QSignalSpy& spy,
- const QSet<int>& currentSelection,
- const QSet<int>& previousSelection) const
+ const KItemSet& currentSelection,
+ const KItemSet& previousSelection) const
{
QCOMPARE(m_selectionManager->selectedItems(), currentSelection);
QCOMPARE(m_selectionManager->hasSelection(), !currentSelection.isEmpty());
else {
QCOMPARE(spy.count(), 1);
QList<QVariant> arguments = spy.takeFirst();
- QCOMPARE(qvariant_cast<QSet<int> >(arguments.at(0)), currentSelection);
- QCOMPARE(qvariant_cast<QSet<int> >(arguments.at(1)), previousSelection);
+ QCOMPARE(qvariant_cast<KItemSet>(arguments.at(0)), currentSelection);
+ QCOMPARE(qvariant_cast<KItemSet>(arguments.at(1)), previousSelection);
}
}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2013 by Frank Reininghaus <frank78ac@googlemail.com> *
+ * *
+ * 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 <qtest_kde.h>
+
+#include "kitemviews/kitemset.h"
+
+#include <QVector>
+
+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<int>.
+ */
+QSet<int> KItemRangeList2QSet(const KItemRangeList& itemRanges)
+{
+ QSet<int> 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<int>.
+ */
+QVector<int> KItemRangeList2QVector(const KItemRangeList& itemRanges)
+{
+ QVector<int> 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<int>.
+ */
+static QSet<int> KItemSet2QSet(const KItemSet& itemSet)
+{
+ QSet<int> 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<const char*, KItemRangeList> 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<KItemRangeList>("itemRanges");
+
+ QHash<const char*, KItemRangeList>::const_iterator it = m_testCases.constBegin();
+ const QHash<const char*, KItemRangeList>::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<int> 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<KItemRangeList>("itemRanges");
+
+ QHash<const char*, KItemRangeList>::const_iterator it = m_testCases.constBegin();
+ const QHash<const char*, KItemRangeList>::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<int>.
+ */
+void KItemSetTest::testIterators()
+{
+ QFETCH(KItemRangeList, itemRanges);
+
+ KItemSet itemSet = KItemRangeList2KItemSet(itemRanges);
+ QVector<int> 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<int> 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<int>::iterator vectorIt1 = itemsQVector.begin();
+ QVector<int>::iterator vectorIt2 = itemsQVector.begin();
+ QVector<int>::const_iterator vectorConstIt1 = itemsQVector.constBegin();
+ QVector<int>::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<KItemRangeList>("itemRanges");
+
+ QHash<const char*, KItemRangeList>::const_iterator it = m_testCases.constBegin();
+ const QHash<const char*, KItemRangeList>::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<int> 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<KItemRangeList>("itemRanges");
+
+ QHash<const char*, KItemRangeList>::const_iterator it = m_testCases.constBegin();
+ const QHash<const char*, KItemRangeList>::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<int> 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<int> 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<int> 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<int> 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<KItemRangeList>("itemRanges1");
+ QTest::addColumn<KItemRangeList>("itemRanges2");
+
+ QHash<const char*, KItemRangeList>::const_iterator it1 = m_testCases.constBegin();
+ const QHash<const char*, KItemRangeList>::const_iterator end = m_testCases.constEnd();
+
+ while (it1 != end) {
+ QHash<const char*, KItemRangeList>::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<int> itemsQSet1 = KItemRangeList2QSet(itemRanges1);
+
+ KItemSet itemSet2 = KItemRangeList2KItemSet(itemRanges2);
+ QSet<int> itemsQSet2 = KItemRangeList2QSet(itemRanges2);
+
+ KItemSet sum = itemSet1 + itemSet2;
+ QSet<int> sumQSet = itemsQSet1 + itemsQSet2;
+
+ QCOMPARE(sum.count(), sumQSet.count());
+ QCOMPARE(KItemSet2QSet(sum), sumQSet);
+}
+
+void KItemSetTest::testSymmetricDifference_data()
+{
+ QTest::addColumn<KItemRangeList>("itemRanges1");
+ QTest::addColumn<KItemRangeList>("itemRanges2");
+
+ QHash<const char*, KItemRangeList>::const_iterator it1 = m_testCases.constBegin();
+ const QHash<const char*, KItemRangeList>::const_iterator end = m_testCases.constEnd();
+
+ while (it1 != end) {
+ QHash<const char*, KItemRangeList>::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<int> itemsQSet1 = KItemRangeList2QSet(itemRanges1);
+
+ KItemSet itemSet2 = KItemRangeList2KItemSet(itemRanges2);
+ QSet<int> itemsQSet2 = KItemRangeList2QSet(itemRanges2);
+
+ KItemSet symmetricDifference = itemSet1 ^ itemSet2;
+ QSet<int> 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"
beginTransaction();
setEnabledSelectionToggles(GeneralSettings::showSelectionToggle());
-
- const bool expandableFolders = (itemLayout() == KFileItemListView::DetailsLayout) &&
- DetailsModeSettings::expandableFolders();
- setSupportsItemExpanding(expandableFolders);
+ setSupportsItemExpanding(itemLayoutSupportsItemExpanding(itemLayout()));
updateFont();
updateGridSize();
return new KItemListWidgetCreator<DolphinFileItemListWidget>();
}
-void DolphinItemListView::onItemLayoutChanged(ItemLayout current, ItemLayout previous)
+bool DolphinItemListView::itemLayoutSupportsItemExpanding(ItemLayout layout) const
{
- Q_UNUSED(previous);
+ return layout == DetailsLayout && DetailsModeSettings::expandableFolders();
+}
- if (current == DetailsLayout) {
- setSupportsItemExpanding(DetailsModeSettings::expandableFolders());
- setHeaderVisible(true);
- } else {
- setHeaderVisible(false);
- }
+void DolphinItemListView::onItemLayoutChanged(ItemLayout current, ItemLayout previous)
+{
+ setHeaderVisible(current == DetailsLayout);
updateFont();
updateGridSize();
+
+ KFileItemListView::onItemLayoutChanged(current, previous);
}
void DolphinItemListView::onPreviewsShownChanged(bool shown)
protected:
virtual KItemListWidgetCreatorBase* defaultWidgetCreator() const;
+ virtual bool itemLayoutSupportsItemExpanding(ItemLayout layout) const;
virtual void onItemLayoutChanged(ItemLayout current, ItemLayout previous);
virtual void onPreviewsShownChanged(bool shown);
virtual void onVisibleRolesChanged(const QList<QByteArray>& current,
#include "dolphinnewfilemenuobserver.h"
#include <KGlobal>
-#include <KNewFileMenu>
+#include "dolphinnewfilemenu.h"
class DolphinNewFileMenuObserverSingleton
{
return s_DolphinNewFileMenuObserver->instance;
}
-void DolphinNewFileMenuObserver::attach(const KNewFileMenu* menu)
+void DolphinNewFileMenuObserver::attach(const DolphinNewFileMenu* menu)
{
connect(menu, SIGNAL(fileCreated(KUrl)),
this, SIGNAL(itemCreated(KUrl)));
connect(menu, SIGNAL(directoryCreated(KUrl)),
this, SIGNAL(itemCreated(KUrl)));
+ connect(menu, SIGNAL(errorMessage(QString)),
+ this, SIGNAL(errorMessage(QString)));
}
-void DolphinNewFileMenuObserver::detach(const KNewFileMenu* menu)
+void DolphinNewFileMenuObserver::detach(const DolphinNewFileMenu* menu)
{
disconnect(menu, SIGNAL(fileCreated(KUrl)),
this, SIGNAL(itemCreated(KUrl)));
disconnect(menu, SIGNAL(directoryCreated(KUrl)),
this, SIGNAL(itemCreated(KUrl)));
+ disconnect(menu, SIGNAL(errorMessage(QString)),
+ this, SIGNAL(errorMessage(QString)));
}
DolphinNewFileMenuObserver::DolphinNewFileMenuObserver() :
#include "libdolphin_export.h"
-class KNewFileMenu;
+class DolphinNewFileMenu;
class KUrl;
/**
public:
static DolphinNewFileMenuObserver& instance();
- void attach(const KNewFileMenu* menu);
- void detach(const KNewFileMenu* menu);
+ void attach(const DolphinNewFileMenu* menu);
+ void detach(const DolphinNewFileMenu* menu);
signals:
void itemCreated(const KUrl& url);
+ void errorMessage(const QString& error);
private:
DolphinNewFileMenuObserver();
controller->setSelectionBehavior(KItemListController::MultiSelection);
connect(controller, SIGNAL(itemActivated(int)), this, SLOT(slotItemActivated(int)));
- connect(controller, SIGNAL(itemsActivated(QSet<int>)), this, SLOT(slotItemsActivated(QSet<int>)));
+ 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)));
connect(controller, SIGNAL(itemHovered(int)), this, SLOT(slotItemHovered(int)));
connect(controller, SIGNAL(itemUnhovered(int)), this, SLOT(slotItemUnhovered(int)));
connect(controller, SIGNAL(itemDropEvent(int,QGraphicsSceneDragDropEvent*)), this, SLOT(slotItemDropEvent(int,QGraphicsSceneDragDropEvent*)));
+ connect(controller, SIGNAL(escapePressed()), this, SLOT(stopLoading()));
connect(controller, SIGNAL(modelChanged(KItemModelBase*,KItemModelBase*)), this, SLOT(slotModelChanged(KItemModelBase*,KItemModelBase*)));
connect(m_model, SIGNAL(directoryLoadingStarted()), this, SLOT(slotDirectoryLoadingStarted()));
this, SLOT(slotHeaderColumnWidthChanged(QByteArray,qreal,qreal)));
KItemListSelectionManager* selectionManager = controller->selectionManager();
- connect(selectionManager, SIGNAL(selectionChanged(QSet<int>,QSet<int>)),
- this, SLOT(slotSelectionChanged(QSet<int>,QSet<int>)));
+ connect(selectionManager, SIGNAL(selectionChanged(KItemSet,KItemSet)),
+ this, SLOT(slotSelectionChanged(KItemSet,KItemSet)));
m_toolTipManager = new ToolTipManager(this);
KFileItemList DolphinView::selectedItems() const
{
const KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
- QList<int> selectedIndexes = selectionManager->selectedItems().toList();
-
- qSort(selectedIndexes);
KFileItemList selectedItems;
- QListIterator<int> it(selectedIndexes);
- while (it.hasNext()) {
- const int index = it.next();
+ foreach (int index, selectionManager->selectedItems()) {
selectedItems.append(m_model->fileItem(index));
}
return selectedItems;
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<int> 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<int>, SelectionMode mode)
+ // KItemListSelectionManager::setSelected(KItemSet, SelectionMode mode)
// for that.
selectionManager->setSelected(index, 1, mode);
}
restoreState(restoreStream);
}
-void DolphinView::stopLoading()
-{
- m_model->cancelDirectoryLoading();
-}
-
void DolphinView::readSettings()
{
const int oldZoomLevel = m_view->zoomLevel();
}
if (folderCount + fileCount == 1) {
- // If only one item is selected, show the filename
- filesText = i18nc("@info:status", "<filename>%1</filename> selected", list.first().text());
+ // If only one item is selected, show info about it
+ return list.first().getStatusBarInfo();
} else {
// At least 2 items are selected
foldersText = i18ncp("@info:status", "1 Folder selected", "%1 Folders selected", folderCount);
}
}
+void DolphinView::stopLoading()
+{
+ m_model->cancelDirectoryLoading();
+}
+
bool DolphinView::eventFilter(QObject* watched, QEvent* event)
{
switch (event->type()) {
}
}
-void DolphinView::slotItemsActivated(const QSet<int>& indexes)
+void DolphinView::slotItemsActivated(const KItemSet& indexes)
{
Q_ASSERT(indexes.count() >= 2);
KFileItemList items;
items.reserve(indexes.count());
- QSetIterator<int> 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);
}
}
-void DolphinView::slotSelectionChanged(const QSet<int>& current, const QSet<int>& previous)
+void DolphinView::slotSelectionChanged(const KItemSet& current, const KItemSet& previous)
{
const int currentCount = current.count();
const int previousCount = previous.count();
m_clearSelectionBeforeSelectingNewItems = false;
}
- QSet<int> selectedItems = selectionManager->selectedItems();
+ KItemSet selectedItems = selectionManager->selectedItems();
QList<KUrl>::iterator it = m_selectedUrls.begin();
while (it != m_selectedUrls.end()) {
QMimeData* DolphinView::selectionMimeData() const
{
const KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
- const QSet<int> selectedIndexes = selectionManager->selectedItems();
+ const KItemSet selectedIndexes = selectionManager->selectedItems();
return m_model->createMimeData(selectedIndexes);
}
void DolphinView::updateWritableState()
{
const bool wasFolderWritable = m_isFolderWritable;
- m_isFolderWritable = true;
+ m_isFolderWritable = false;
const KFileItem item = m_model->rootItem();
if (!item.isNull()) {
#include <QBoxLayout>
#include <QKeyEvent>
#include <QLinkedList>
-#include <QSet>
#include <QWidget>
typedef KIO::FileUndoManager::CommandType CommandType;
class KFileItemModel;
class KItemListContainer;
class KItemModelBase;
+class KItemSet;
class KUrl;
class ToolTipManager;
class VersionControlObserver;
QList<QByteArray> visibleRoles() const;
void reload();
- void stopLoading();
/**
* Refreshes the view to get synchronized with the settings (e.g. icons size,
*/
void pasteIntoFolder();
+ void stopLoading();
+
/** Activates the view if the item list container gets focus. */
virtual bool eventFilter(QObject* watched, QEvent* event);
void activate();
void slotItemActivated(int index);
- void slotItemsActivated(const QSet<int>& indexes);
+ void slotItemsActivated(const KItemSet& indexes);
void slotItemMiddleClicked(int index);
void slotItemContextMenuRequested(int index, const QPointF& pos);
void slotViewContextMenuRequested(const QPointF& pos);
* the signal is emitted only after no selection change has been done
* within a small delay.
*/
- void slotSelectionChanged(const QSet<int>& current, const QSet<int>& previous);
+ void slotSelectionChanged(const KItemSet& current, const KItemSet& previous);
/**
* Is called by emitDelayedSelectionChangedSignal() and emits the