#include "kfileitemmodel.h"
-#include "dolphin_detailsmodesettings.h"
+#include "dolphin_contentdisplaysettings.h"
#include "dolphin_generalsettings.h"
#include "dolphindebug.h"
#include "private/kfileitemmodelsortalgorithm.h"
+#include "views/draganddrophelper.h"
#include <KDirLister>
#include <KIO/Job>
+#include <KIO/ListJob>
#include <KLocalizedString>
#include <KUrlMimeData>
-#include <kio_version.h>
#include <QElapsedTimer>
#include <QIcon>
#include <QRecursiveMutex>
#include <QTimer>
#include <QWidget>
-#include <algorithm>
#include <klazylocalizedstring.h>
Q_GLOBAL_STATIC(QRecursiveMutex, s_collatorMutex)
// for a lot of items within a quite small timeslot. To prevent expensive resortings the
// resorting is postponed until the timer has been exceeded.
m_resortAllItemsTimer = new QTimer(this);
- m_resortAllItemsTimer->setInterval(500);
+ m_resortAllItemsTimer->setInterval(100); // 100 is a middle ground between sorting too frequently which makes the view unreadable
+ // and sorting too infrequently which leads to users seeing an outdated sort order.
m_resortAllItemsTimer->setSingleShot(true);
connect(m_resortAllItemsTimer, &QTimer::timeout, this, &KFileItemModel::resortAllItems);
connect(GeneralSettings::self(), &GeneralSettings::sortingChoiceChanged, this, &KFileItemModel::slotSortingChoiceChanged);
+
+ setShowTrashMime(m_dirLister->showHiddenFiles() || !GeneralSettings::hideXTrashFile());
}
KFileItemModel::~KFileItemModel()
}
m_dirLister->openUrl(url, KDirLister::Reload);
+
+ Q_EMIT directoryRefreshing();
}
QUrl KFileItemModel::directory() const
return m_sortHiddenLast;
}
+void KFileItemModel::setShowTrashMime(bool showTrashMime)
+{
+ const auto trashMime = QStringLiteral("application/x-trash");
+ QStringList excludeFilter = m_filter.excludeMimeTypes();
+
+ if (showTrashMime) {
+ excludeFilter.removeAll(trashMime);
+ } else if (!excludeFilter.contains(trashMime)) {
+ excludeFilter.append(trashMime);
+ }
+
+ setExcludeMimeTypeFilter(excludeFilter);
+}
+
+void KFileItemModel::scheduleResortAllItems()
+{
+ if (!m_resortAllItemsTimer->isActive()) {
+ m_resortAllItemsTimer->start();
+ }
+}
+
void KFileItemModel::setShowHiddenFiles(bool show)
{
-#if KIO_VERSION < QT_VERSION_CHECK(5, 100, 0)
- m_dirLister->setShowingDotFiles(show);
-#else
m_dirLister->setShowHiddenFiles(show);
-#endif
+ setShowTrashMime(show || !GeneralSettings::hideXTrashFile());
m_dirLister->emitChanges();
if (show) {
dispatchPendingItemsToInsert();
bool KFileItemModel::showHiddenFiles() const
{
-#if KIO_VERSION < QT_VERSION_CHECK(5, 100, 0)
- return m_dirLister->showingDotFiles();
-#else
return m_dirLister->showHiddenFiles();
-#endif
}
void KFileItemModel::setShowDirectoriesOnly(bool enabled)
bool KFileItemModel::supportsDropping(int index) const
{
- const KFileItem item = fileItem(index);
+ KFileItem item;
+ if (index == -1) {
+ item = rootItem();
+ } else {
+ item = fileItem(index);
+ }
+ return !item.isNull() && DragAndDropHelper::supportsDropping(item);
+}
+
+bool KFileItemModel::canEnterOnHover(int index) const
+{
+ KFileItem item;
+ if (index == -1) {
+ item = rootItem();
+ } else {
+ item = fileItem(index);
+ }
return !item.isNull() && (item.isDir() || item.isDesktopFile());
}
m_expandedDirs.remove(targetUrl);
m_dirLister->stop(url);
-#if KIO_VERSION >= QT_VERSION_CHECK(5, 92, 0)
m_dirLister->forgetDirs(url);
-#endif
const int parentLevel = expandedParentsCount(index);
const int itemCount = m_itemData.count();
const QUrl url = itemData->item.url();
m_expandedDirs.remove(targetUrl);
m_dirLister->stop(url); // TODO: try to unit-test this, see https://bugs.kde.org/show_bug.cgi?id=332102#c11
-#if KIO_VERSION >= QT_VERSION_CHECK(5, 92, 0)
m_dirLister->forgetDirs(url);
-#endif
expandedChildren.append(targetUrl);
}
++childIndex;
return m_filter.mimeTypes();
}
+void KFileItemModel::setExcludeMimeTypeFilter(const QStringList &filters)
+{
+ if (m_filter.excludeMimeTypes() != filters) {
+ dispatchPendingItemsToInsert();
+ m_filter.setExcludeMimeTypes(filters);
+ applyFilters();
+ }
+}
+
+QStringList KFileItemModel::excludeMimeTypeFilter() const
+{
+ return m_filter.excludeMimeTypes();
+}
+
void KFileItemModel::applyFilters()
{
// ===STEP 1===
// If this is a child of an expanded folder, we must make sure that its whole parental chain will also be shown.
// We will go up through its parental chain until we either:
- // 1 - reach the "root item" of the current view, i.e the currently opened folder on Dolphin. Their children have their ItemData::parent set to nullptr.
- // or
- // 2 - we reach an unfiltered parent or a previously discovered ancestor.
+ // 1 - reach the "root item" of the current view, i.e the currently opened folder on Dolphin. Their children have their ItemData::parent set to
+ // nullptr. or 2 - we reach an unfiltered parent or a previously discovered ancestor.
for (ItemData *parent = it.value()->parent; parent && !ancestorsOfNewVisibleItems.contains(parent->item) && m_filteredItems.contains(parent->item);
parent = parent->parent) {
// We wish we could remove this parent from m_filteredItems right now, but we are iterating over it
}
info.requiresBaloo = map[i].requiresBaloo;
info.requiresIndexer = map[i].requiresIndexer;
+ if (!map[i].tooltipTranslation.isEmpty()) {
+ info.tooltip = map[i].tooltipTranslation.toString();
+ } else {
+ info.tooltip = QString();
+ }
rolesInfo.append(info);
}
}
// been moved because of the resorting.
QList<QUrl> oldUrls;
oldUrls.reserve(itemCount);
- for (const ItemData *itemData : qAsConst(m_itemData)) {
+ for (const ItemData *itemData : std::as_const(m_itemData)) {
oldUrls.append(itemData->item.url());
}
indexesToRemoveWithChildren.reserve(m_itemData.count());
const int itemCount = m_itemData.count();
- for (int index : qAsConst(indexesToRemove)) {
+ for (int index : std::as_const(indexesToRemove)) {
indexesToRemoveWithChildren.append(index);
const int parentLevel = expandedParentsCount(index);
case DeletionTimeRole:
// These roles can be determined with retrieveData, and they have to be stored
// in the QHash "values" for the sorting.
- for (ItemData *itemData : qAsConst(itemDataList)) {
+ for (ItemData *itemData : std::as_const(itemDataList)) {
if (itemData->values.isEmpty()) {
itemData->values = retrieveData(itemData->item, itemData->parent);
}
case TypeRole:
// At least store the data including the file type for items with known MIME type.
- for (ItemData *itemData : qAsConst(itemDataList)) {
+ for (ItemData *itemData : std::as_const(itemDataList)) {
if (itemData->values.isEmpty()) {
const KFileItem item = itemData->item;
if (item.isDir() || item.isMimeTypeKnown()) {
// Trigger a resorting if necessary. Note that this can happen even if the sort
// role has not changed at all because the file name can be used as a fallback.
- if (changedRoles.contains(sortRole()) || changedRoles.contains(roleForType(NameRole))) {
+ if (changedRoles.contains(sortRole()) || changedRoles.contains(roleForType(NameRole))
+ || (changedRoles.contains("count") && sortRole() == "size")) { // "count" is used in the "size" sort role, so this might require a resorting.
for (const KItemRange &range : itemRanges) {
bool needsResorting = false;
}
if (needsResorting) {
- m_resortAllItemsTimer->start();
+ scheduleResortAllItems();
return;
}
}
}
if (m_requestRole[IsHiddenRole]) {
- data.insert(sharedValue("isHidden"), item.isHidden());
+ data.insert(sharedValue("isHidden"), item.isHidden() || item.mimetype() == QStringLiteral("application/x-trash"));
}
if (m_requestRole[NameRole]) {
}
if (m_requestRole[ExtensionRole] && !isDir) {
+ // TODO KF6 use KFileItem::suffix 464722
data.insert(sharedValue("extension"), QFileInfo(item.name()).suffix());
}
}
if (m_requestRole[PermissionsRole]) {
- data.insert(sharedValue("permissions"), item.permissionsString());
+ data.insert(sharedValue("permissions"), QVariantList() << item.permissionsString() << item.permissions());
}
if (m_requestRole[OwnerRole]) {
}
}
- if (m_sortDirsFirst || (DetailsModeSettings::directorySizeCount() && m_sortRole == SizeRole)) {
+ if (m_sortDirsFirst
+ || (ContentDisplaySettings::directorySizeMode() == ContentDisplaySettings::EnumDirectorySizeMode::ContentCount && m_sortRole == SizeRole)) {
const bool isDirA = a->item.isDir();
const bool isDirB = b->item.isDir();
if (isDirA && !isDirB) {
break;
case SizeRole: {
- if (DetailsModeSettings::directorySizeCount() && itemA.isDir()) {
+ if (ContentDisplaySettings::directorySizeMode() == ContentDisplaySettings::EnumDirectorySizeMode::ContentCount && itemA.isDir()) {
// folders first then
// items A and B are folders thanks to lessThan checks
auto valueA = a->values.value("count");
KIO::filesize_t fileSize = !item.isNull() ? item.size() : ~0U;
QString newGroupValue;
if (!item.isNull() && item.isDir()) {
- if (DetailsModeSettings::directorySizeCount() || m_sortDirsFirst) {
+ if (ContentDisplaySettings::directorySizeMode() == ContentDisplaySettings::EnumDirectorySizeMode::ContentCount || m_sortDirsFirst) {
newGroupValue = i18nc("@title:group Size", "Folders");
} else {
fileSize = m_itemData.at(i)->values.value("size").toULongLong();
if (info.permission(QFile::ExeUser)) {
user += i18nc("@item:intext Access permission, concatenated", "Execute, ");
}
- user = user.isEmpty() ? i18nc("@item:intext Access permission, concatenated", "Forbidden") : user.mid(0, user.count() - 2);
+ user = user.isEmpty() ? i18nc("@item:intext Access permission, concatenated", "Forbidden") : user.mid(0, user.length() - 2);
// Set group string
QString group;
if (info.permission(QFile::ExeGroup)) {
group += i18nc("@item:intext Access permission, concatenated", "Execute, ");
}
- group = group.isEmpty() ? i18nc("@item:intext Access permission, concatenated", "Forbidden") : group.mid(0, group.count() - 2);
+ group = group.isEmpty() ? i18nc("@item:intext Access permission, concatenated", "Forbidden") : group.mid(0, group.length() - 2);
// Set others string
QString others;
if (info.permission(QFile::ExeOther)) {
others += i18nc("@item:intext Access permission, concatenated", "Execute, ");
}
- others = others.isEmpty() ? i18nc("@item:intext Access permission, concatenated", "Forbidden") : others.mid(0, others.count() - 2);
+ others = others.isEmpty() ? i18nc("@item:intext Access permission, concatenated", "Forbidden") : others.mid(0, others.length() - 2);
const QString newGroupValue = i18nc("@title:group Files and folders by permissions", "User: %1 | Group: %2 | Others: %3", user, group, others);
if (newGroupValue != groupValue) {
const KFileItemModel::RoleInfoMap *KFileItemModel::rolesInfoMap(int &count)
{
static const RoleInfoMap rolesInfoMap[] = {
- // | role | roleType | role translation | group translation | requires Baloo | requires indexer
- { nullptr, NoRole, KLazyLocalizedString(), KLazyLocalizedString(), false, false },
- { "text", NameRole, kli18nc("@label", "Name"), KLazyLocalizedString(), false, false },
- { "size", SizeRole, kli18nc("@label", "Size"), KLazyLocalizedString(), false, false },
- { "modificationtime", ModificationTimeRole, kli18nc("@label", "Modified"), KLazyLocalizedString(), false, false },
- { "creationtime", CreationTimeRole, kli18nc("@label", "Created"), KLazyLocalizedString(), false, false },
- { "accesstime", AccessTimeRole, kli18nc("@label", "Accessed"), KLazyLocalizedString(), false, false },
- { "type", TypeRole, kli18nc("@label", "Type"), KLazyLocalizedString(), false, false },
- { "rating", RatingRole, kli18nc("@label", "Rating"), KLazyLocalizedString(), true, false },
- { "tags", TagsRole, kli18nc("@label", "Tags"), KLazyLocalizedString(), true, false },
- { "comment", CommentRole, kli18nc("@label", "Comment"), KLazyLocalizedString(), true, false },
- { "title", TitleRole, kli18nc("@label", "Title"), kli18nc("@label", "Document"), true, true },
- { "author", AuthorRole, kli18nc("@label", "Author"), kli18nc("@label", "Document"), true, true },
- { "publisher", PublisherRole, kli18nc("@label", "Publisher"), kli18nc("@label", "Document"), true, true },
- { "pageCount", PageCountRole, kli18nc("@label", "Page Count"), kli18nc("@label", "Document"), true, true },
- { "wordCount", WordCountRole, kli18nc("@label", "Word Count"), kli18nc("@label", "Document"), true, true },
- { "lineCount", LineCountRole, kli18nc("@label", "Line Count"), kli18nc("@label", "Document"), true, true },
- { "imageDateTime", ImageDateTimeRole, kli18nc("@label", "Date Photographed"), kli18nc("@label", "Image"), true, true },
- { "dimensions", DimensionsRole, kli18nc("@label width x height", "Dimensions"), kli18nc("@label", "Image"), true, true },
- { "width", WidthRole, kli18nc("@label", "Width"), kli18nc("@label", "Image"), true, true },
- { "height", HeightRole, kli18nc("@label", "Height"), kli18nc("@label", "Image"), true, true },
- { "orientation", OrientationRole, kli18nc("@label", "Orientation"), kli18nc("@label", "Image"), true, true },
- { "artist", ArtistRole, kli18nc("@label", "Artist"), kli18nc("@label", "Audio"), true, true },
- { "genre", GenreRole, kli18nc("@label", "Genre"), kli18nc("@label", "Audio"), true, true },
- { "album", AlbumRole, kli18nc("@label", "Album"), kli18nc("@label", "Audio"), true, true },
- { "duration", DurationRole, kli18nc("@label", "Duration"), kli18nc("@label", "Audio"), true, true },
- { "bitrate", BitrateRole, kli18nc("@label", "Bitrate"), kli18nc("@label", "Audio"), true, true },
- { "track", TrackRole, kli18nc("@label", "Track"), kli18nc("@label", "Audio"), true, true },
- { "releaseYear", ReleaseYearRole, kli18nc("@label", "Release Year"), kli18nc("@label", "Audio"), true, true },
- { "aspectRatio", AspectRatioRole, kli18nc("@label", "Aspect Ratio"), kli18nc("@label", "Video"), true, true },
- { "frameRate", FrameRateRole, kli18nc("@label", "Frame Rate"), kli18nc("@label", "Video"), true, true },
- { "path", PathRole, kli18nc("@label", "Path"), kli18nc("@label", "Other"), false, false },
- { "extension", ExtensionRole, kli18nc("@label", "File Extension"), kli18nc("@label", "Other"), false, false },
- { "deletiontime", DeletionTimeRole, kli18nc("@label", "Deletion Time"), kli18nc("@label", "Other"), false, false },
- { "destination", DestinationRole, kli18nc("@label", "Link Destination"), kli18nc("@label", "Other"), false, false },
- { "originUrl", OriginUrlRole, kli18nc("@label", "Downloaded From"), kli18nc("@label", "Other"), true, false },
- { "permissions", PermissionsRole, kli18nc("@label", "Permissions"), kli18nc("@label", "Other"), false, false },
- { "owner", OwnerRole, kli18nc("@label", "Owner"), kli18nc("@label", "Other"), false, false },
- { "group", GroupRole, kli18nc("@label", "User Group"), kli18nc("@label", "Other"), false, false },
+ // clang-format off
+ // | role | roleType | role translation | group translation | requires Baloo | requires indexer
+ { nullptr, NoRole, KLazyLocalizedString(), KLazyLocalizedString(), KLazyLocalizedString(), false, false },
+ { "text", NameRole, kli18nc("@label", "Name"), KLazyLocalizedString(), KLazyLocalizedString(), false, false },
+ { "size", SizeRole, kli18nc("@label", "Size"), KLazyLocalizedString(), KLazyLocalizedString(), false, false },
+ { "modificationtime", ModificationTimeRole, kli18nc("@label", "Modified"), KLazyLocalizedString(), kli18nc("@tooltip", "The date format can be selected in settings."), false, false },
+ { "creationtime", CreationTimeRole, kli18nc("@label", "Created"), KLazyLocalizedString(), kli18nc("@tooltip", "The date format can be selected in settings."), false, false },
+ { "accesstime", AccessTimeRole, kli18nc("@label", "Accessed"), KLazyLocalizedString(), kli18nc("@tooltip", "The date format can be selected in settings."), false, false },
+ { "type", TypeRole, kli18nc("@label", "Type"), KLazyLocalizedString(), KLazyLocalizedString(), false, false },
+ { "rating", RatingRole, kli18nc("@label", "Rating"), KLazyLocalizedString(), KLazyLocalizedString(), true, false },
+ { "tags", TagsRole, kli18nc("@label", "Tags"), KLazyLocalizedString(), KLazyLocalizedString(), true, false },
+ { "comment", CommentRole, kli18nc("@label", "Comment"), KLazyLocalizedString(), KLazyLocalizedString(), true, false },
+ { "title", TitleRole, kli18nc("@label", "Title"), kli18nc("@label", "Document"), KLazyLocalizedString(), true, true },
+ { "author", AuthorRole, kli18nc("@label", "Author"), kli18nc("@label", "Document"), KLazyLocalizedString(), true, true },
+ { "publisher", PublisherRole, kli18nc("@label", "Publisher"), kli18nc("@label", "Document"), KLazyLocalizedString(), true, true },
+ { "pageCount", PageCountRole, kli18nc("@label", "Page Count"), kli18nc("@label", "Document"), KLazyLocalizedString(), true, true },
+ { "wordCount", WordCountRole, kli18nc("@label", "Word Count"), kli18nc("@label", "Document"), KLazyLocalizedString(), true, true },
+ { "lineCount", LineCountRole, kli18nc("@label", "Line Count"), kli18nc("@label", "Document"), KLazyLocalizedString(), true, true },
+ { "imageDateTime", ImageDateTimeRole, kli18nc("@label", "Date Photographed"), kli18nc("@label", "Image"), KLazyLocalizedString(), true, true },
+ { "dimensions", DimensionsRole, kli18nc("@label width x height", "Dimensions"), kli18nc("@label", "Image"), KLazyLocalizedString(), true, true },
+ { "width", WidthRole, kli18nc("@label", "Width"), kli18nc("@label", "Image"), KLazyLocalizedString(), true, true },
+ { "height", HeightRole, kli18nc("@label", "Height"), kli18nc("@label", "Image"), KLazyLocalizedString(), true, true },
+ { "orientation", OrientationRole, kli18nc("@label", "Orientation"), kli18nc("@label", "Image"), KLazyLocalizedString(), true, true },
+ { "artist", ArtistRole, kli18nc("@label", "Artist"), kli18nc("@label", "Audio"), KLazyLocalizedString(), true, true },
+ { "genre", GenreRole, kli18nc("@label", "Genre"), kli18nc("@label", "Audio"), KLazyLocalizedString(), true, true },
+ { "album", AlbumRole, kli18nc("@label", "Album"), kli18nc("@label", "Audio"), KLazyLocalizedString(), true, true },
+ { "duration", DurationRole, kli18nc("@label", "Duration"), kli18nc("@label", "Audio"), KLazyLocalizedString(), true, true },
+ { "bitrate", BitrateRole, kli18nc("@label", "Bitrate"), kli18nc("@label", "Audio"), KLazyLocalizedString(), true, true },
+ { "track", TrackRole, kli18nc("@label", "Track"), kli18nc("@label", "Audio"), KLazyLocalizedString(), true, true },
+ { "releaseYear", ReleaseYearRole, kli18nc("@label", "Release Year"), kli18nc("@label", "Audio"), KLazyLocalizedString(), true, true },
+ { "aspectRatio", AspectRatioRole, kli18nc("@label", "Aspect Ratio"), kli18nc("@label", "Video"), KLazyLocalizedString(), true, true },
+ { "frameRate", FrameRateRole, kli18nc("@label", "Frame Rate"), kli18nc("@label", "Video"), KLazyLocalizedString(), true, true },
+ { "path", PathRole, kli18nc("@label", "Path"), kli18nc("@label", "Other"), KLazyLocalizedString(), false, false },
+ { "extension", ExtensionRole, kli18nc("@label", "File Extension"), kli18nc("@label", "Other"), KLazyLocalizedString(), false, false },
+ { "deletiontime", DeletionTimeRole, kli18nc("@label", "Deletion Time"), kli18nc("@label", "Other"), KLazyLocalizedString(), false, false },
+ { "destination", DestinationRole, kli18nc("@label", "Link Destination"), kli18nc("@label", "Other"), KLazyLocalizedString(), false, false },
+ { "originUrl", OriginUrlRole, kli18nc("@label", "Downloaded From"), kli18nc("@label", "Other"), KLazyLocalizedString(), true, false },
+ { "permissions", PermissionsRole, kli18nc("@label", "Permissions"), kli18nc("@label", "Other"), kli18nc("@tooltip", "The permission format can be changed in settings. Options are Symbolic, Numeric (Octal) or Combined formats"), false, false },
+ { "owner", OwnerRole, kli18nc("@label", "Owner"), kli18nc("@label", "Other"), KLazyLocalizedString(), false, false },
+ { "group", GroupRole, kli18nc("@label", "User Group"), kli18nc("@label", "Other"), KLazyLocalizedString(), false, false },
};
+ // clang-format on
count = sizeof(rolesInfoMap) / sizeof(RoleInfoMap);
return rolesInfoMap;
Q_EMIT errorMessage(!errorString.isEmpty() ? errorString : i18nc("@info:status", "Unknown error."));
}
}
+
+#include "moc_kfileitemmodel.cpp"