#include "dolphin_generalsettings.h"
#include "dolphin_detailsmodesettings.h"
#include "dolphindebug.h"
-#include "private/kfileitemmodeldirlister.h"
#include "private/kfileitemmodelsortalgorithm.h"
-#include <kio_version.h>
+#include <KDirLister>
+#include <KIO/Job>
#include <KLocalizedString>
#include <KUrlMimeData>
KItemModelBase("text", parent),
m_dirLister(nullptr),
m_sortDirsFirst(true),
- m_sortHiddenLast(false),
m_sortRole(NameRole),
m_sortingProgressPercent(-1),
m_roles(),
loadSortingSettings();
- m_dirLister = new KFileItemModelDirLister(this);
+ m_dirLister = new KDirLister(this);
+ m_dirLister->setAutoErrorHandlingEnabled(false);
m_dirLister->setDelayedMimeTypes(true);
const QWidget* parentWidget = qobject_cast<QWidget*>(parent);
m_dirLister->setMainWindow(parentWidget->window());
}
- connect(m_dirLister, &KFileItemModelDirLister::started, this, &KFileItemModel::directoryLoadingStarted);
+ connect(m_dirLister, &KCoreDirLister::started, this, &KFileItemModel::directoryLoadingStarted);
connect(m_dirLister, QOverload<>::of(&KCoreDirLister::canceled), this, &KFileItemModel::slotCanceled);
- connect(m_dirLister, &KFileItemModelDirLister::itemsAdded, this, &KFileItemModel::slotItemsAdded);
- connect(m_dirLister, &KFileItemModelDirLister::itemsDeleted, this, &KFileItemModel::slotItemsDeleted);
- connect(m_dirLister, &KFileItemModelDirLister::refreshItems, this, &KFileItemModel::slotRefreshItems);
+ connect(m_dirLister, &KCoreDirLister::itemsAdded, this, &KFileItemModel::slotItemsAdded);
+ connect(m_dirLister, &KCoreDirLister::itemsDeleted, this, &KFileItemModel::slotItemsDeleted);
+ connect(m_dirLister, &KCoreDirLister::refreshItems, this, &KFileItemModel::slotRefreshItems);
connect(m_dirLister, QOverload<>::of(&KCoreDirLister::clear), this, &KFileItemModel::slotClear);
- connect(m_dirLister, &KFileItemModelDirLister::infoMessage, this, &KFileItemModel::infoMessage);
- connect(m_dirLister, &KFileItemModelDirLister::errorMessage, this, &KFileItemModel::errorMessage);
- connect(m_dirLister, &KFileItemModelDirLister::percent, this, &KFileItemModel::directoryLoadingProgress);
+ connect(m_dirLister, &KCoreDirLister::infoMessage, this, &KFileItemModel::infoMessage);
+ connect(m_dirLister, &KCoreDirLister::jobError, this, &KFileItemModel::slotListerError);
+ connect(m_dirLister, &KCoreDirLister::percent, this, &KFileItemModel::directoryLoadingProgress);
connect(m_dirLister, QOverload<const QUrl&, const QUrl&>::of(&KCoreDirLister::redirection), this, &KFileItemModel::directoryRedirection);
- connect(m_dirLister, &KFileItemModelDirLister::urlIsFileError, this, &KFileItemModel::urlIsFileError);
-
-#if KIO_VERSION < QT_VERSION_CHECK(5, 79, 0)
- connect(m_dirLister, QOverload<const QUrl&>::of(&KCoreDirLister::completed), this, &KFileItemModel::slotCompleted);
-#else
connect(m_dirLister, &KCoreDirLister::listingDirCompleted, this, &KFileItemModel::slotCompleted);
-#endif
// Apply default roles that should be determined
resetRoles();
return m_sortDirsFirst;
}
- void KFileItemModel::setSortHiddenLast(bool hiddenLast)
- {
- if (hiddenLast != m_sortHiddenLast) {
- m_sortHiddenLast = hiddenLast;
- resortAllItems();
- }
- }
-
- bool KFileItemModel::sortHiddenLast() const
- {
- return m_sortHiddenLast;
- }
-
void KFileItemModel::setShowHiddenFiles(bool show)
{
m_dirLister->setShowingDotFiles(show);
QSet<QByteArray> changedRoles;
KFileItemList changedFiles;
+ // Contains the indexes of the currently visible items
+ // that should get hidden and hence moved to m_filteredItems.
+ QVector<int> newFilteredIndexes;
+
+ // Contains currently hidden items that should
+ // get visible and hence removed from m_filteredItems
+ QList<ItemData*> newVisibleItems;
+
QListIterator<QPair<KFileItem, KFileItem> > it(items);
while (it.hasNext()) {
const QPair<KFileItem, KFileItem>& itemPair = it.next();
const KFileItem& oldItem = itemPair.first;
const KFileItem& newItem = itemPair.second;
const int indexForItem = index(oldItem);
+ const bool newItemMatchesFilter = m_filter.matches(newItem);
if (indexForItem >= 0) {
m_itemData[indexForItem]->item = newItem;
// Keep old values as long as possible if they could not retrieved synchronously yet.
// The update of the values will be done asynchronously by KFileItemModelRolesUpdater.
- QHashIterator<QByteArray, QVariant> it(retrieveData(newItem, m_itemData.at(indexForItem)->parent));
- QHash<QByteArray, QVariant>& values = m_itemData[indexForItem]->values;
+ ItemData * const itemData = m_itemData.at(indexForItem);
+ QHashIterator<QByteArray, QVariant> it(retrieveData(newItem, itemData->parent));
while (it.hasNext()) {
it.next();
const QByteArray& role = it.key();
- if (values.value(role) != it.value()) {
- values.insert(role, it.value());
+ if (itemData->values.value(role) != it.value()) {
+ itemData->values.insert(role, it.value());
changedRoles.insert(role);
}
}
m_items.remove(oldItem.url());
- m_items.insert(newItem.url(), indexForItem);
- changedFiles.append(newItem);
- indexes.append(indexForItem);
+ if (newItemMatchesFilter) {
+ m_items.insert(newItem.url(), indexForItem);
+ changedFiles.append(newItem);
+ indexes.append(indexForItem);
+ } else {
+ newFilteredIndexes.append(indexForItem);
+ m_filteredItems.insert(newItem, itemData);
+ }
} else {
// Check if 'oldItem' is one of the filtered items.
QHash<KFileItem, ItemData*>::iterator it = m_filteredItems.find(oldItem);
itemData->values.clear();
m_filteredItems.erase(it);
- m_filteredItems.insert(newItem, itemData);
+ if (newItemMatchesFilter) {
+ newVisibleItems.append(itemData);
+ } else {
+ m_filteredItems.insert(newItem, itemData);
+ }
}
}
}
+ // Hide items, previously visible that should get hidden
+ const KItemRangeList removedRanges = KItemRangeList::fromSortedContainer(newFilteredIndexes);
+ removeItems(removedRanges, KeepItemData);
+
+ // Show previously hidden items that should get visible
+ insertItems(newVisibleItems);
+
// If the changed items have been created recently, they might not be in m_items yet.
// In that case, the list 'indexes' might be empty.
if (indexes.isEmpty()) {
}
}
- // Show hidden files and folders last
- if (m_sortHiddenLast) {
- const bool isHiddenA = a->item.isHidden();
- const bool isHiddenB = b->item.isHidden();
- if (isHiddenA && !isHiddenB) {
- return false;
- } else if (!isHiddenA && isHiddenB) {
- return true;
- }
- }
-
if (m_sortDirsFirst || (DetailsModeSettings::directorySizeCount() && m_sortRole == SizeRole)) {
const bool isDirA = a->item.isDir();
const bool isDirB = b->item.isDir();
int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b, const QCollator& collator) const
{
+ // This function must never return 0, because that would break stable
+ // sorting, which leads to all kinds of bugs.
+ // See: https://bugs.kde.org/show_bug.cgi?id=433247
+ // If two items have equal sort values, let the fallbacks at the bottom of
+ // the function handle it.
const KFileItem& itemA = a->item;
const KFileItem& itemB = b->item;
auto valueA = a->values.value("count");
auto valueB = b->values.value("count");
if (valueA.isNull()) {
- if (valueB.isNull()) {
- result = 0;
- break;
- } else {
- result = -1;
- break;
+ if (!valueB.isNull()) {
+ return -1;
}
} else if (valueB.isNull()) {
- result = +1;
- break;
+ return +1;
} else {
if (valueA.toLongLong() < valueB.toLongLong()) {
- result = -1;
- break;
+ return -1;
} else if (valueA.toLongLong() > valueB.toLongLong()) {
- result = +1;
- break;
- } else {
- result = 0;
- break;
+ return +1;
}
}
+ break;
}
+
KIO::filesize_t sizeA = 0;
if (itemA.isDir()) {
sizeA = a->values.value("size").toULongLong();
} else {
sizeB = itemB.size();
}
- if (sizeA > sizeB) {
- result = +1;
- } else if (sizeA < sizeB) {
- result = -1;
- } else {
- result = 0;
+ if (sizeA < sizeB) {
+ return -1;
+ } else if (sizeA > sizeB) {
+ return +1;
}
break;
}
const long long dateTimeA = itemA.entry().numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME, -1);
const long long dateTimeB = itemB.entry().numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME, -1);
if (dateTimeA < dateTimeB) {
- result = -1;
+ return -1;
} else if (dateTimeA > dateTimeB) {
- result = +1;
+ return +1;
}
break;
}
const long long dateTimeA = itemA.entry().numberValue(KIO::UDSEntry::UDS_CREATION_TIME, -1);
const long long dateTimeB = itemB.entry().numberValue(KIO::UDSEntry::UDS_CREATION_TIME, -1);
if (dateTimeA < dateTimeB) {
- result = -1;
+ return -1;
} else if (dateTimeA > dateTimeB) {
- result = +1;
+ return +1;
}
break;
}
const QDateTime dateTimeA = a->values.value("deletiontime").toDateTime();
const QDateTime dateTimeB = b->values.value("deletiontime").toDateTime();
if (dateTimeA < dateTimeB) {
- result = -1;
+ return -1;
} else if (dateTimeA > dateTimeB) {
- result = +1;
+ return +1;
}
break;
}
const QString roleValueA = a->values.value(role).toString();
const QString roleValueB = b->values.value(role).toString();
if (!roleValueA.isEmpty() && roleValueB.isEmpty()) {
- result = -1;
+ return -1;
} else if (roleValueA.isEmpty() && !roleValueB.isEmpty()) {
- result = +1;
+ return +1;
} else if (isRoleValueNatural(m_sortRole)) {
result = stringCompare(roleValueA, roleValueB, collator);
} else {
return true;
}
+
+void KFileItemModel::slotListerError(KIO::Job *job)
+{
+ if (job->error() == KIO::ERR_IS_FILE) {
+ if (auto *listJob = qobject_cast<KIO::ListJob *>(job)) {
+ Q_EMIT urlIsFileError(listJob->url());
+ }
+ } else {
+ const QString errorString = job->errorString();
+ Q_EMIT errorMessage(!errorString.isEmpty() ? errorString : i18nc("@info:status", "Unknown error."));
+ }
+}
#include <QTimer>
#include <QMimeData>
+#include <KDirLister>
#include <kio/job.h>
#include "kitemviews/kfileitemmodel.h"
-#include "kitemviews/private/kfileitemmodeldirlister.h"
#include "testdir.h"
void myMessageOutput(QtMsgType type, const QMessageLogContext& context, const QString& msg)
void KFileItemModelTest::testSorting()
{
- // testDir structure is as follows
- // ./
- // ├─ .g/
- // ├─ a
- // ├─ b
- // ├─ c/
- // │ ├─ c-2/
- // │ │ ├─ c-3
- // │ ├─ c-1
- // ├─ .f
- // ├─ d
- // ├─ e
-
QSignalSpy itemsInsertedSpy(m_model, &KFileItemModel::itemsInserted);
QSignalSpy itemsMovedSpy(m_model, &KFileItemModel::itemsMoved);
QVERIFY(itemsMovedSpy.isValid());
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_testDir->createDir(".g");
m_model->loadDirectory(m_testDir->url());
QVERIFY(itemsInsertedSpy.wait());
- QCOMPARE(itemsInsertedSpy.count(), 1);
- KItemRangeList itemRangeList = itemsInsertedSpy.takeFirst().at(0).value<KItemRangeList>();
- QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(0, 5));
int index = m_model->index(QUrl(m_testDir->url().url() + "/c"));
m_model->setExpanded(index, true);
QVERIFY(itemsInsertedSpy.wait());
- QCOMPARE(itemsInsertedSpy.count(), 1);
- itemRangeList = itemsInsertedSpy.takeFirst().at(0).value<KItemRangeList>();
- QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(1, 2));
index = m_model->index(QUrl(m_testDir->url().url() + "/c/c-2"));
m_model->setExpanded(index, true);
QVERIFY(itemsInsertedSpy.wait());
- QCOMPARE(itemsInsertedSpy.count(), 1);
- itemRangeList = itemsInsertedSpy.takeFirst().at(0).value<KItemRangeList>();
- QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(2, 1));
// Default: Sort by Name, ascending
QCOMPARE(m_model->sortRole(), QByteArray("text"));
QCOMPARE(itemsMovedSpy.first().at(0).value<KItemRange>(), KItemRange(4, 4));
QCOMPARE(itemsMovedSpy.takeFirst().at(1).value<QList<int> >(), QList<int>() << 7 << 6 << 5 << 4);
- // 'Show Hidden Files' enabled
- m_model->setShowHiddenFiles(true);
- QVERIFY(m_model->showHiddenFiles());
- QVERIFY(!m_model->sortHiddenLast());
- QCOMPARE(itemsInModel(), QStringList() << "c" << "c-2" << "c-3" << "c-1" << ".g" << "d" << "e" << "b" << "a" << ".f");
- QCOMPARE(itemsMovedSpy.count(), 0);
- QCOMPARE(itemsInsertedSpy.count(), 1);
- QCOMPARE(itemsInsertedSpy.takeFirst().at(0).value<KItemRangeList>(), KItemRangeList() << KItemRange(4, 1) << KItemRange(8, 1));
-
- // 'Sort Hidden Files Last' enabled
- m_model->setSortHiddenLast(true);
- QVERIFY(m_model->sortHiddenLast());
- QCOMPARE(itemsInModel(), QStringList() << "c" << "c-2" << "c-3" << "c-1" << "d" << "e" << "b" << "a" << ".g" << ".f");
- QCOMPARE(itemsMovedSpy.count(), 1);
- QCOMPARE(itemsInsertedSpy.count(), 0);
- QCOMPARE(itemsMovedSpy.first().at(0).value<KItemRange>(), KItemRange(4, 5));
- QCOMPARE(itemsMovedSpy.takeFirst().at(1).value<QList<int> >(), QList<int>() << 8 << 4 << 5 << 6 << 7);
-
- // Sort by Name
- m_model->setSortRole("text");
- QCOMPARE(itemsInModel(), QStringList() << "c" << "c-2" << "c-3" << "c-1" << "e" << "d" << "b" << "a" << ".g" << ".f");
- QCOMPARE(itemsMovedSpy.count(), 1);
- QCOMPARE(itemsMovedSpy.first().at(0).value<KItemRange>(), KItemRange(4, 2));
- QCOMPARE(itemsMovedSpy.takeFirst().at(1).value<QList<int> >(), QList<int>() << 5 << 4);
-
- // Sort ascending
- m_model->setSortOrder(Qt::AscendingOrder);
- QCOMPARE(itemsInModel(), QStringList() << "c" << "c-2" << "c-3" << "c-1" << "a" << "b" << "d" << "e" << ".g" << ".f");
- QCOMPARE(itemsMovedSpy.count(), 1);
- QCOMPARE(itemsMovedSpy.first().at(0).value<KItemRange>(), KItemRange(4, 4));
- QCOMPARE(itemsMovedSpy.takeFirst().at(1).value<QList<int> >(), QList<int>() << 7 << 6 << 5 << 4);
-
- // 'Sort Folders First' disabled
- m_model->setSortDirectoriesFirst(false);
- QVERIFY(!m_model->sortDirectoriesFirst());
- QCOMPARE(itemsInModel(), QStringList() << "a" << "b" << "c" << "c-1" << "c-2" << "c-3" << "d" << "e" << ".f" << ".g");
- QCOMPARE(itemsMovedSpy.count(), 1);
- QCOMPARE(itemsMovedSpy.first().at(0).value<KItemRange>(), KItemRange(0, 10));
- QCOMPARE(itemsMovedSpy.takeFirst().at(1).value<QList<int> >(), QList<int>() << 2 << 4 << 5 << 3 << 0 << 1 << 6 << 7 << 9 << 8);
-
+ // TODO: Sort by other roles; show/hide hidden files
}
void KFileItemModelTest::testIndexForKeyboardSearch()
#include "dolphinview.h"
+#include "dolphin_compactmodesettings.h"
#include "dolphin_detailsmodesettings.h"
+#include "dolphin_iconsmodesettings.h"
#include "dolphin_generalsettings.h"
#include "dolphinitemlistview.h"
#include "dolphinnewfilemenuobserver.h"
return m_model->sortDirectoriesFirst();
}
- void DolphinView::setSortHiddenLast(bool hiddenLast)
- {
- if (sortHiddenLast() != hiddenLast) {
- updateSortHiddenLast(hiddenLast);
- }
- }
-
- bool DolphinView::sortHiddenLast() const
- {
- return m_model->sortHiddenLast();
- }
-
void DolphinView::setVisibleRoles(const QList<QByteArray>& roles)
{
const QList<QByteArray> previousRoles = roles;
Q_EMIT sortFoldersFirstChanged(foldersFirst);
}
- void DolphinView::updateSortHiddenLast(bool hiddenLast)
- {
- ViewProperties props(viewPropertiesUrl());
- props.setSortHiddenLast(hiddenLast);
-
- m_model->setSortHiddenLast(hiddenLast);
-
- Q_EMIT sortHiddenLastChanged(hiddenLast);
- }
-
-
QPair<bool, QString> DolphinView::pasteInfo() const
{
const QMimeData *mimeData = QApplication::clipboard()->mimeData();
void DolphinView::resetZoomLevel()
{
- ViewModeSettings::ViewMode mode;
-
+ // TODO : Switch to using ViewModeSettings after MR #256 is merged
+ int defaultIconSize = KIconLoader::SizeSmall;
switch (m_mode) {
- case IconsView: mode = ViewModeSettings::IconsMode; break;
- case CompactView: mode = ViewModeSettings::CompactMode; break;
- case DetailsView: mode = ViewModeSettings::DetailsMode; break;
+ case IconsView:
+ IconsModeSettings::self()->useDefaults(true);
+ defaultIconSize = IconsModeSettings::iconSize();
+ IconsModeSettings::self()->useDefaults(false);
+ break;
+ case DetailsView:
+ DetailsModeSettings::self()->useDefaults(true);
+ defaultIconSize = DetailsModeSettings::iconSize();
+ DetailsModeSettings::self()->useDefaults(false);
+ break;
+ case CompactView:
+ CompactModeSettings::self()->useDefaults(true);
+ defaultIconSize = CompactModeSettings::iconSize();
+ CompactModeSettings::self()->useDefaults(false);
+ break;
+ default:
+ Q_ASSERT(false);
+ break;
}
- const ViewModeSettings settings(mode);
- const QSize iconSize = QSize(settings.iconSize(), settings.iconSize());
- setZoomLevel(ZoomLevelInfo::zoomLevelForIconSize(iconSize));
+
+ setZoomLevel(ZoomLevelInfo::zoomLevelForIconSize(QSize(defaultIconSize, defaultIconSize)));
}
void DolphinView::observeCreatedItem(const QUrl& url)
Q_EMIT sortFoldersFirstChanged(sortFoldersFirst);
}
- const bool sortHiddenLast = props.sortHiddenLast();
- if (sortHiddenLast != m_model->sortHiddenLast()) {
- m_model->setSortHiddenLast(sortHiddenLast);
- Q_EMIT sortHiddenLastChanged(sortHiddenLast);
- }
-
const QList<QByteArray> visibleRoles = props.visibleRoles();
if (visibleRoles != m_visibleRoles) {
const QList<QByteArray> previousVisibleRoles = m_visibleRoles;