/***************************************************************************
* Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * Copyright (C) 2011 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 *
#include <KDirLister>
#include "kitemviews/kfileitemmodel.h"
+#include "kitemviews/private/kfileitemmodeldirlister.h"
#include "testdir.h"
+void myMessageOutput(QtMsgType type, const char* msg)
+{
+ switch (type) {
+ case QtDebugMsg:
+ break;
+ case QtWarningMsg:
+ break;
+ case QtCriticalMsg:
+ fprintf(stderr, "Critical: %s\n", msg);
+ break;
+ case QtFatalMsg:
+ fprintf(stderr, "Fatal: %s\n", msg);
+ abort();
+ default:
+ break;
+ }
+}
+
namespace {
const int DefaultTimeout = 5000;
};
Q_DECLARE_METATYPE(KItemRangeList)
+Q_DECLARE_METATYPE(QList<int>)
class KFileItemModelTest : public QObject
{
void testDefaultRoles();
void testDefaultSortRole();
- void testDefaultGroupRole();
+ void testDefaultGroupedSorting();
void testNewItems();
void testRemoveItems();
+ void testDirLoadingCompleted();
+ void testSetData();
+ void testSetDataWithModifiedSortRole_data();
+ void testSetDataWithModifiedSortRole();
void testModelConsistencyWhenInsertingItems();
void testItemRangeConsistencyWhenInsertingItems();
void testExpandItems();
+ void testExpandParentItems();
+ void testSorting();
- void testExpansionLevelsCompare_data();
- void testExpansionLevelsCompare();
+ void testIndexForKeyboardSearch();
+
+ void testNameFilter();
private:
bool isModelConsistent() const;
+ QStringList itemsInModel() const;
private:
KFileItemModel* m_model;
- KDirLister* m_dirLister;
TestDir* m_testDir;
};
void KFileItemModelTest::init()
{
+ // The item-model tests result in a huge number of debugging
+ // output from kdelibs. Only show critical and fatal messages.
+ qInstallMsgHandler(myMessageOutput);
+
+ qRegisterMetaType<KItemRange>("KItemRange");
qRegisterMetaType<KItemRangeList>("KItemRangeList");
qRegisterMetaType<KFileItemList>("KFileItemList");
m_testDir = new TestDir();
- m_dirLister = new KDirLister();
- m_model = new KFileItemModel(m_dirLister);
+ m_model = new KFileItemModel();
+ m_model->m_dirLister->setAutoUpdate(false);
}
void KFileItemModelTest::cleanup()
delete m_model;
m_model = 0;
- delete m_dirLister;
- m_dirLister = 0;
-
delete m_testDir;
m_testDir = 0;
}
void KFileItemModelTest::testDefaultRoles()
{
const QSet<QByteArray> roles = m_model->roles();
- QCOMPARE(roles.count(), 2);
- QVERIFY(roles.contains("name"));
+ QCOMPARE(roles.count(), 3);
+ QVERIFY(roles.contains("text"));
QVERIFY(roles.contains("isDir"));
+ QVERIFY(roles.contains("isLink"));
}
void KFileItemModelTest::testDefaultSortRole()
{
- QCOMPARE(m_model->sortRole(), QByteArray("name"));
+ QCOMPARE(m_model->sortRole(), QByteArray("text"));
QStringList files;
files << "c.txt" << "a.txt" << "b.txt";
m_testDir->createFiles(files);
- m_dirLister->openUrl(m_testDir->url());
+ m_model->loadDirectory(m_testDir->url());
QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
QCOMPARE(m_model->count(), 3);
- QCOMPARE(m_model->data(0)["name"].toString(), QString("a.txt"));
- QCOMPARE(m_model->data(1)["name"].toString(), QString("b.txt"));
- QCOMPARE(m_model->data(2)["name"].toString(), QString("c.txt"));
+ QCOMPARE(m_model->data(0)["text"].toString(), QString("a.txt"));
+ QCOMPARE(m_model->data(1)["text"].toString(), QString("b.txt"));
+ QCOMPARE(m_model->data(2)["text"].toString(), QString("c.txt"));
}
-void KFileItemModelTest::testDefaultGroupRole()
+void KFileItemModelTest::testDefaultGroupedSorting()
{
- QVERIFY(m_model->groupRole().isEmpty());
+ QCOMPARE(m_model->groupedSorting(), false);
}
void KFileItemModelTest::testNewItems()
files << "a.txt" << "b.txt" << "c.txt";
m_testDir->createFiles(files);
- m_dirLister->openUrl(m_testDir->url());
+ m_model->loadDirectory(m_testDir->url());
QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
QCOMPARE(m_model->count(), 3);
void KFileItemModelTest::testRemoveItems()
{
m_testDir->createFile("a.txt");
- m_dirLister->openUrl(m_testDir->url());
+ m_testDir->createFile("b.txt");
+ m_model->loadDirectory(m_testDir->url());
QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+ QCOMPARE(m_model->count(), 2);
+ QVERIFY(isModelConsistent());
+
+ m_testDir->removeFile("a.txt");
+ m_model->m_dirLister->updateDirectory(m_testDir->url());
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsRemoved(KItemRangeList)), DefaultTimeout));
QCOMPARE(m_model->count(), 1);
+ QVERIFY(isModelConsistent());
+}
+
+void KFileItemModelTest::testDirLoadingCompleted()
+{
+ QSignalSpy loadingCompletedSpy(m_model, SIGNAL(directoryLoadingCompleted()));
+ QSignalSpy itemsInsertedSpy(m_model, SIGNAL(itemsInserted(KItemRangeList)));
+ QSignalSpy itemsRemovedSpy(m_model, SIGNAL(itemsRemoved(KItemRangeList)));
+
+ m_testDir->createFiles(QStringList() << "a.txt" << "b.txt" << "c.txt");
+
+ m_model->loadDirectory(m_testDir->url());
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(directoryLoadingCompleted()), DefaultTimeout));
+ QCOMPARE(loadingCompletedSpy.count(), 1);
+ QCOMPARE(itemsInsertedSpy.count(), 1);
+ QCOMPARE(itemsRemovedSpy.count(), 0);
+ QCOMPARE(m_model->count(), 3);
+
+ m_testDir->createFiles(QStringList() << "d.txt" << "e.txt");
+ m_model->m_dirLister->updateDirectory(m_testDir->url());
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(directoryLoadingCompleted()), DefaultTimeout));
+ QCOMPARE(loadingCompletedSpy.count(), 2);
+ QCOMPARE(itemsInsertedSpy.count(), 2);
+ QCOMPARE(itemsRemovedSpy.count(), 0);
+ QCOMPARE(m_model->count(), 5);
m_testDir->removeFile("a.txt");
- m_dirLister->updateDirectory(m_testDir->url());
+ m_testDir->createFile("f.txt");
+ m_model->m_dirLister->updateDirectory(m_testDir->url());
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(directoryLoadingCompleted()), DefaultTimeout));
+ QCOMPARE(loadingCompletedSpy.count(), 3);
+ QCOMPARE(itemsInsertedSpy.count(), 3);
+ QCOMPARE(itemsRemovedSpy.count(), 1);
+ QCOMPARE(m_model->count(), 5);
+
+ m_testDir->removeFile("b.txt");
+ m_model->m_dirLister->updateDirectory(m_testDir->url());
QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsRemoved(KItemRangeList)), DefaultTimeout));
- QCOMPARE(m_model->count(), 0);
+ QCOMPARE(loadingCompletedSpy.count(), 4);
+ QCOMPARE(itemsInsertedSpy.count(), 3);
+ QCOMPARE(itemsRemovedSpy.count(), 2);
+ QCOMPARE(m_model->count(), 4);
+
+ QVERIFY(isModelConsistent());
+}
+
+void KFileItemModelTest::testSetData()
+{
+ m_testDir->createFile("a.txt");
+
+ m_model->loadDirectory(m_testDir->url());
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+
+ QHash<QByteArray, QVariant> values;
+ values.insert("customRole1", "Test1");
+ values.insert("customRole2", "Test2");
+
+ QSignalSpy itemsChangedSpy(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet<QByteArray>)));
+ m_model->setData(0, values);
+ QCOMPARE(itemsChangedSpy.count(), 1);
+
+ values = m_model->data(0);
+ QCOMPARE(values.value("customRole1").toString(), QString("Test1"));
+ QCOMPARE(values.value("customRole2").toString(), QString("Test2"));
+ QVERIFY(isModelConsistent());
+}
+
+void KFileItemModelTest::testSetDataWithModifiedSortRole_data()
+{
+ QTest::addColumn<int>("changedIndex");
+ QTest::addColumn<int>("changedRating");
+ QTest::addColumn<bool>("expectMoveSignal");
+ QTest::addColumn<int>("ratingIndex0");
+ QTest::addColumn<int>("ratingIndex1");
+ QTest::addColumn<int>("ratingIndex2");
+
+ // Default setup:
+ // Index 0 = rating 2
+ // Index 1 = rating 4
+ // Index 2 = rating 6
+
+ QTest::newRow("Index 0: Rating 3") << 0 << 3 << false << 3 << 4 << 6;
+ QTest::newRow("Index 0: Rating 5") << 0 << 5 << true << 4 << 5 << 6;
+ QTest::newRow("Index 0: Rating 8") << 0 << 8 << true << 4 << 6 << 8;
+
+ QTest::newRow("Index 2: Rating 1") << 2 << 1 << true << 1 << 2 << 4;
+ QTest::newRow("Index 2: Rating 3") << 2 << 3 << true << 2 << 3 << 4;
+ QTest::newRow("Index 2: Rating 5") << 2 << 5 << false << 2 << 4 << 5;
+}
+
+void KFileItemModelTest::testSetDataWithModifiedSortRole()
+{
+ QFETCH(int, changedIndex);
+ QFETCH(int, changedRating);
+ QFETCH(bool, expectMoveSignal);
+ QFETCH(int, ratingIndex0);
+ QFETCH(int, ratingIndex1);
+ QFETCH(int, ratingIndex2);
+
+ // Changing the value of a sort-role must result in
+ // a reordering of the items.
+ QCOMPARE(m_model->sortRole(), QByteArray("text"));
+
+ QStringList files;
+ files << "a.txt" << "b.txt" << "c.txt";
+ m_testDir->createFiles(files);
+
+ m_model->loadDirectory(m_testDir->url());
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+
+ // Fill the "rating" role of each file:
+ // a.txt -> 2
+ // b.txt -> 4
+ // c.txt -> 6
+
+ QHash<QByteArray, QVariant> ratingA;
+ ratingA.insert("rating", 2);
+ m_model->setData(0, ratingA);
+
+ QHash<QByteArray, QVariant> ratingB;
+ ratingB.insert("rating", 4);
+ m_model->setData(1, ratingB);
+
+ QHash<QByteArray, QVariant> ratingC;
+ ratingC.insert("rating", 6);
+ m_model->setData(2, ratingC);
+
+ m_model->setSortRole("rating");
+ QCOMPARE(m_model->data(0).value("rating").toInt(), 2);
+ QCOMPARE(m_model->data(1).value("rating").toInt(), 4);
+ QCOMPARE(m_model->data(2).value("rating").toInt(), 6);
+
+ // Now change the rating from a.txt. This usually results
+ // in reordering of the items.
+ QHash<QByteArray, QVariant> rating;
+ rating.insert("rating", changedRating);
+ m_model->setData(changedIndex, rating);
+
+ if (expectMoveSignal) {
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsMoved(KItemRange,QList<int>)), DefaultTimeout));
+ }
+
+ QCOMPARE(m_model->data(0).value("rating").toInt(), ratingIndex0);
+ QCOMPARE(m_model->data(1).value("rating").toInt(), ratingIndex1);
+ QCOMPARE(m_model->data(2).value("rating").toInt(), ratingIndex2);
+ QVERIFY(isModelConsistent());
}
void KFileItemModelTest::testModelConsistencyWhenInsertingItems()
{
- QSKIP("Temporary disabled", SkipSingle);
+ //QSKIP("Temporary disabled", SkipSingle);
// KFileItemModel prevents that inserting a punch of items sequentially
// results in an itemsInserted()-signal for each item. Instead internally
// one itemsInserted()-signal. However in this test we want to stress
// KFileItemModel to do a lot of insert operation and hence decrease
// the timeout to 1 millisecond.
- m_model->m_minimumUpdateIntervalTimer->setInterval(1);
-
m_testDir->createFile("1");
- m_dirLister->openUrl(m_testDir->url());
+ m_model->loadDirectory(m_testDir->url());
QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
QCOMPARE(m_model->count(), 1);
m_testDir->createFile(QString::number(itemName));
}
- m_dirLister->updateDirectory(m_testDir->url());
+ m_model->m_dirLister->updateDirectory(m_testDir->url());
if (spy.count() == 0) {
QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
}
// Due to inserting the 3 items one item-range with index == 0 and
// count == 3 must be given
QSignalSpy spy1(m_model, SIGNAL(itemsInserted(KItemRangeList)));
- m_dirLister->openUrl(m_testDir->url());
+ m_model->loadDirectory(m_testDir->url());
QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
QCOMPARE(spy1.count(), 1);
m_testDir->createFiles(files);
QSignalSpy spy2(m_model, SIGNAL(itemsInserted(KItemRangeList)));
- m_dirLister->updateDirectory(m_testDir->url());
+ m_model->m_dirLister->updateDirectory(m_testDir->url());
QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
QCOMPARE(spy2.count(), 1);
// 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();
- modelRoles << "isExpanded" << "expansionLevel";
+ modelRoles << "isExpanded" << "isExpandable" << "expandedParentsCount";
m_model->setRoles(modelRoles);
QStringList files;
files << "a/a/1" << "a/a-1/1"; // missing folders are created automatically
m_testDir->createFiles(files);
- m_dirLister->openUrl(m_testDir->url());
+ // Store the URLs of all folders in a set.
+ QSet<KUrl> allFolders;
+ allFolders << KUrl(m_testDir->name() + 'a') << KUrl(m_testDir->name() + "a/a") << KUrl(m_testDir->name() + "a/a-1");
+
+ m_model->loadDirectory(m_testDir->url());
QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
// So far, the model contains only "a/"
QCOMPARE(m_model->count(), 1);
QVERIFY(m_model->isExpandable(0));
QVERIFY(!m_model->isExpanded(0));
+ QVERIFY(m_model->expandedDirectories().empty());
QSignalSpy spyInserted(m_model, SIGNAL(itemsInserted(KItemRangeList)));
QVERIFY(m_model->isExpanded(0));
QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
QCOMPARE(m_model->count(), 3); // 3 items: "a/", "a/a/", "a/a-1/"
+ QCOMPARE(m_model->expandedDirectories(), QSet<KUrl>() << KUrl(m_testDir->name() + 'a'));
QCOMPARE(spyInserted.count(), 1);
KItemRangeList itemRangeList = spyInserted.takeFirst().at(0).value<KItemRangeList>();
QVERIFY(m_model->isExpanded(1));
QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
QCOMPARE(m_model->count(), 4); // 4 items: "a/", "a/a/", "a/a/1", "a/a-1/"
+ QCOMPARE(m_model->expandedDirectories(), QSet<KUrl>() << KUrl(m_testDir->name() + 'a') << KUrl(m_testDir->name() + "a/a"));
QCOMPARE(spyInserted.count(), 1);
itemRangeList = spyInserted.takeFirst().at(0).value<KItemRangeList>();
m_model->setExpanded(3, true);
QVERIFY(m_model->isExpanded(3));
QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
- QCOMPARE(m_model->count(), 5); // 4 items: "a/", "a/a/", "a/a/1", "a/a-1/", "a/a-1/1"
+ 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);
QCOMPARE(spyInserted.count(), 1);
itemRangeList = spyInserted.takeFirst().at(0).value<KItemRangeList>();
// Collapse the top-level folder -> all other items should disappear
m_model->setExpanded(0, false);
QVERIFY(!m_model->isExpanded(0));
+ QCOMPARE(m_model->count(), 1);
+ QVERIFY(!m_model->expandedDirectories().contains(KUrl(m_testDir->name() + 'a'))); // TODO: Make sure that child URLs are also removed
+
QCOMPARE(spyRemoved.count(), 1);
itemRangeList = spyRemoved.takeFirst().at(0).value<KItemRangeList>();
QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(1, 4)); // 4 items removed
+
+ // Clear the model, reload the folder and try to restore the expanded folders.
+ m_model->clear();
+ QCOMPARE(m_model->count(), 0);
+ QVERIFY(m_model->expandedDirectories().empty());
+
+ m_model->loadDirectory(m_testDir->url());
+ m_model->restoreExpandedDirectories(allFolders);
+ 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"
+ 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));
+ QCOMPARE(m_model->expandedDirectories(), allFolders);
+
+ // Move to a sub folder, then call restoreExpandedFolders() *before* going back.
+ // This is how DolphinView restores the expanded folders when navigating in history.
+ m_model->loadDirectory(KUrl(m_testDir->name() + "a/a/"));
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(directoryLoadingCompleted()), DefaultTimeout));
+ QCOMPARE(m_model->count(), 1); // 1 item: "1"
+ m_model->restoreExpandedDirectories(allFolders);
+ m_model->loadDirectory(m_testDir->url());
+ 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);
+}
+
+void KFileItemModelTest::testExpandParentItems()
+{
+ // Create a tree structure of folders:
+ // a 1/
+ // a 1/b1/
+ // a 1/b1/c1/
+ // a2/
+ // a2/b2/
+ // a2/b2/c2/
+ // a2/b2/c2/d2/
+ QSet<QByteArray> modelRoles = m_model->roles();
+ modelRoles << "isExpanded" << "isExpandable" << "expandedParentsCount";
+ m_model->setRoles(modelRoles);
+
+ QStringList files;
+ files << "a 1/b1/c1/file.txt" << "a2/b2/c2/d2/file.txt"; // missing folders are created automatically
+ m_testDir->createFiles(files);
+
+ m_model->loadDirectory(m_testDir->url());
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+
+ // So far, the model contains only "a 1/" and "a2/".
+ QCOMPARE(m_model->count(), 2);
+ QVERIFY(m_model->expandedDirectories().empty());
+
+ // Expand the parents of "a2/b2/c2".
+ m_model->expandParentDirectories(KUrl(m_testDir->name() + "a2/b2/c2"));
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(directoryLoadingCompleted()), DefaultTimeout));
+
+ // The model should now contain "a 1/", "a2/", "a2/b2/", and "a2/b2/c2/".
+ // It's important that only the parents of "a1/b1/c1" are expanded.
+ QCOMPARE(m_model->count(), 4);
+ QVERIFY(!m_model->isExpanded(0));
+ QVERIFY(m_model->isExpanded(1));
+ QVERIFY(m_model->isExpanded(2));
+ QVERIFY(!m_model->isExpanded(3));
+
+ // Expand the parents of "a 1/b1".
+ m_model->expandParentDirectories(KUrl(m_testDir->name() + "a 1/b1"));
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(directoryLoadingCompleted()), DefaultTimeout));
+
+ // The model should now contain "a 1/", "a 1/b1/", "a2/", "a2/b2", and "a2/b2/c2/".
+ // It's important that only the parents of "a 1/b1/" and "a2/b2/c2/" are expanded.
+ 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));
+}
+
+void KFileItemModelTest::testSorting()
+{
+ // Create some files with different sizes and modification times to check the different sorting options
+ QDateTime now = QDateTime::currentDateTime();
+
+ QSet<QByteArray> roles;
+ roles.insert("text");
+ roles.insert("isExpanded");
+ roles.insert("isExpandable");
+ roles.insert("expandedParentsCount");
+ m_model->setRoles(roles);
+
+ m_testDir->createDir("c/c-2");
+ m_testDir->createFile("c/c-2/c-3");
+ m_testDir->createFile("c/c-1");
+
+ m_testDir->createFile("a", "A file", now.addDays(-3));
+ m_testDir->createFile("b", "A larger file", now.addDays(0));
+ m_testDir->createDir("c", now.addDays(-2));
+ m_testDir->createFile("d", "The largest file in this directory", now.addDays(-1));
+ m_testDir->createFile("e", "An even larger file", now.addDays(-4));
+ m_testDir->createFile(".f");
+
+ m_model->loadDirectory(m_testDir->url());
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+
+ int index = m_model->index(KUrl(m_testDir->url().url() + 'c'));
+ m_model->setExpanded(index, true);
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+
+ index = m_model->index(KUrl(m_testDir->url().url() + "c/c-2"));
+ m_model->setExpanded(index, true);
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+
+ // Default: Sort by Name, ascending
+ QCOMPARE(m_model->sortRole(), QByteArray("text"));
+ QCOMPARE(m_model->sortOrder(), Qt::AscendingOrder);
+ QVERIFY(m_model->sortDirectoriesFirst());
+ QVERIFY(!m_model->showHiddenFiles());
+ QCOMPARE(itemsInModel(), QStringList() << "c" << "c-2" << "c-3" << "c-1" << "a" << "b" << "d" << "e");
+
+ QSignalSpy spyItemsMoved(m_model, SIGNAL(itemsMoved(KItemRange,QList<int>)));
+
+ // Sort by Name, ascending, 'Sort Folders First' disabled
+ m_model->setSortDirectoriesFirst(false);
+ QCOMPARE(m_model->sortRole(), QByteArray("text"));
+ 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);
+
+ // Sort by Name, descending
+ m_model->setSortDirectoriesFirst(true);
+ m_model->setSortOrder(Qt::DescendingOrder);
+ QCOMPARE(m_model->sortRole(), QByteArray("text"));
+ 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);
+
+ // Sort by Date, descending
+ m_model->setSortDirectoriesFirst(true);
+ m_model->setSortRole("date");
+ QCOMPARE(m_model->sortRole(), QByteArray("date"));
+ 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);
+
+ // Sort by Date, ascending
+ m_model->setSortOrder(Qt::AscendingOrder);
+ QCOMPARE(m_model->sortRole(), QByteArray("date"));
+ QCOMPARE(m_model->sortOrder(), Qt::AscendingOrder);
+ QCOMPARE(itemsInModel(), QStringList() << "c" << "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);
+
+ // Sort by Date, ascending, 'Sort Folders First' disabled
+ m_model->setSortDirectoriesFirst(false);
+ QCOMPARE(m_model->sortRole(), QByteArray("date"));
+ QCOMPARE(m_model->sortOrder(), Qt::AscendingOrder);
+ 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);
+
+ // Sort by Name, ascending, 'Sort Folders First' disabled
+ m_model->setSortRole("text");
+ QCOMPARE(m_model->sortOrder(), Qt::AscendingOrder);
+ QVERIFY(!m_model->sortDirectoriesFirst());
+ 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>() << 7 << 0 << 2 << 3 << 4 << 5 << 6 << 1);
+
+ // Sort by Size, ascending, 'Sort Folders First' disabled
+ m_model->setSortRole("size");
+ QCOMPARE(m_model->sortRole(), QByteArray("size"));
+ QCOMPARE(m_model->sortOrder(), Qt::AscendingOrder);
+ QVERIFY(!m_model->sortDirectoriesFirst());
+ QCOMPARE(itemsInModel(), QStringList() << "c" << "c-2" << "c-3" << "c-1" << "a" << "b" << "e" << "d");
+ QCOMPARE(spyItemsMoved.count(), 1);
+ 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(spyItemsMoved.count(), 0);
+
+ // Sort by Size, descending, 'Sort Folders First' enabled
+ m_model->setSortOrder(Qt::DescendingOrder);
+ 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(spyItemsMoved.count(), 1);
+ QCOMPARE(spyItemsMoved.takeFirst().at(1).value<QList<int> >(), QList<int>() << 0 << 4 << 3 << 2 << 1);
+
+ // TODO: Sort by other roles; show/hide hidden files
}
-void KFileItemModelTest::testExpansionLevelsCompare_data()
+void KFileItemModelTest::testIndexForKeyboardSearch()
{
- QTest::addColumn<QString>("urlA");
- QTest::addColumn<QString>("urlB");
- QTest::addColumn<int>("result");
-
- QTest::newRow("Equal") << "/a/b" << "/a/b" << 0;
- QTest::newRow("Sub path: A < B") << "/a/b" << "/a/b/c" << -1;
- QTest::newRow("Sub path: A > B") << "/a/b/c" << "/a/b" << +1;
- QTest::newRow("Same level: /a/1 < /a-1/1") << "/a/1" << "/a-1/1" << -1;
- QTest::newRow("Same level: /a-/1 > /a/1") << "/a-1/1" << "/a/1" << +1;
- QTest::newRow("Different levels: /a/a/1 < /a/a-1") << "/a/a/1" << "/a/a-1" << -1;
- QTest::newRow("Different levels: /a/a-1 > /a/a/1") << "/a/a-1" << "/a/a/1" << +1;
+ QStringList files;
+ files << "a" << "aa" << "Image.jpg" << "Image.png" << "Text" << "Text1" << "Text2" << "Text11";
+ m_testDir->createFiles(files);
+
+ m_model->loadDirectory(m_testDir->url());
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+
+ // Search from index 0
+ QCOMPARE(m_model->indexForKeyboardSearch("a", 0), 0);
+ QCOMPARE(m_model->indexForKeyboardSearch("aa", 0), 1);
+ QCOMPARE(m_model->indexForKeyboardSearch("i", 0), 2);
+ QCOMPARE(m_model->indexForKeyboardSearch("image", 0), 2);
+ QCOMPARE(m_model->indexForKeyboardSearch("image.jpg", 0), 2);
+ QCOMPARE(m_model->indexForKeyboardSearch("image.png", 0), 3);
+ QCOMPARE(m_model->indexForKeyboardSearch("t", 0), 4);
+ QCOMPARE(m_model->indexForKeyboardSearch("text", 0), 4);
+ QCOMPARE(m_model->indexForKeyboardSearch("text1", 0), 5);
+ QCOMPARE(m_model->indexForKeyboardSearch("text2", 0), 6);
+ QCOMPARE(m_model->indexForKeyboardSearch("text11", 0), 7);
+
+ // Start a search somewhere in the middle
+ QCOMPARE(m_model->indexForKeyboardSearch("a", 1), 1);
+ QCOMPARE(m_model->indexForKeyboardSearch("i", 3), 3);
+ QCOMPARE(m_model->indexForKeyboardSearch("t", 5), 5);
+ QCOMPARE(m_model->indexForKeyboardSearch("text1", 6), 7);
+
+ // Test searches that go past the last item back to index 0
+ QCOMPARE(m_model->indexForKeyboardSearch("a", 2), 0);
+ QCOMPARE(m_model->indexForKeyboardSearch("i", 7), 2);
+ QCOMPARE(m_model->indexForKeyboardSearch("image.jpg", 3), 2);
+ QCOMPARE(m_model->indexForKeyboardSearch("text2", 7), 6);
+
+ // Test searches that yield no result
+ QCOMPARE(m_model->indexForKeyboardSearch("aaa", 0), -1);
+ QCOMPARE(m_model->indexForKeyboardSearch("b", 0), -1);
+ QCOMPARE(m_model->indexForKeyboardSearch("image.svg", 0), -1);
+ QCOMPARE(m_model->indexForKeyboardSearch("text3", 0), -1);
+ QCOMPARE(m_model->indexForKeyboardSearch("text3", 5), -1);
+
+ // Test upper case searches (note that search is case insensitive)
+ QCOMPARE(m_model->indexForKeyboardSearch("A", 0), 0);
+ QCOMPARE(m_model->indexForKeyboardSearch("aA", 0), 1);
+ QCOMPARE(m_model->indexForKeyboardSearch("TexT", 5), 5);
+ QCOMPARE(m_model->indexForKeyboardSearch("IMAGE", 4), 2);
+
+ // TODO: Maybe we should also test keyboard searches in directories which are not sorted by Name?
}
-void KFileItemModelTest::testExpansionLevelsCompare()
+void KFileItemModelTest::testNameFilter()
{
- QFETCH(QString, urlA);
- QFETCH(QString, urlB);
- QFETCH(int, result);
+ QStringList files;
+ files << "A1" << "A2" << "Abc" << "Bcd" << "Cde";
+ m_testDir->createFiles(files);
+
+ m_model->loadDirectory(m_testDir->url());
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+
+ m_model->setNameFilter("A"); // Shows A1, A2 and Abc
+ QCOMPARE(m_model->count(), 3);
+
+ m_model->setNameFilter("A2"); // Shows only A2
+ QCOMPARE(m_model->count(), 1);
+
+ m_model->setNameFilter("A2"); // Shows only A1
+ QCOMPARE(m_model->count(), 1);
+
+ m_model->setNameFilter("Bc"); // Shows "Abc" and "Bcd"
+ QCOMPARE(m_model->count(), 2);
- const KFileItem a(KUrl(urlA), QString(), mode_t(-1));
- const KFileItem b(KUrl(urlB), QString(), mode_t(-1));
- QCOMPARE(m_model->expansionLevelsCompare(a, b), result);
+ m_model->setNameFilter("bC"); // Shows "Abc" and "Bcd"
+ QCOMPARE(m_model->count(), 2);
+
+ m_model->setNameFilter(QString()); // Shows again all items
+ QCOMPARE(m_model->count(), 5);
}
bool KFileItemModelTest::isModelConsistent() const
{
+ if (m_model->m_items.count() != m_model->m_itemData.count()) {
+ return false;
+ }
+
for (int i = 0; i < m_model->count(); ++i) {
const KFileItem item = m_model->fileItem(i);
if (item.isNull()) {
return true;
}
+QStringList KFileItemModelTest::itemsInModel() const
+{
+ QStringList items;
+ for (int i = 0; i < m_model->count(); i++) {
+ items << m_model->data(i).value("text").toString();
+ }
+ return items;
+}
+
QTEST_KDEMAIN(KFileItemModelTest, NoGUI)
#include "kfileitemmodeltest.moc"