]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/kitemviews/kfileitemmodel.cpp
Add role for file creation time.
[dolphin.git] / src / kitemviews / kfileitemmodel.cpp
index 1f94972c2dc40d1bd5160b592b274e8a960459f3..b725d950797b4620f61955b373f0b8e2399e6360 100644 (file)
@@ -24,6 +24,8 @@
 #include "dolphin_generalsettings.h"
 
 #include <KLocalizedString>
+#include <KUrlMimeData>
+
 #include "dolphindebug.h"
 
 #include "private/kfileitemmodelsortalgorithm.h"
@@ -78,6 +80,7 @@ KFileItemModel::KFileItemModel(QObject* parent) :
     connect(m_dirLister, static_cast<void(KFileItemModelDirLister::*)()>(&KFileItemModelDirLister::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, static_cast<void(KFileItemModelDirLister::*)(const QUrl&, const QUrl&)>(&KFileItemModelDirLister::redirection), this, &KFileItemModel::directoryRedirection);
     connect(m_dirLister, &KFileItemModelDirLister::urlIsFileError, this, &KFileItemModel::urlIsFileError);
 
@@ -89,6 +92,7 @@ KFileItemModel::KFileItemModel(QObject* parent) :
     m_roles.insert("text");
     m_roles.insert("isDir");
     m_roles.insert("isLink");
+    m_roles.insert("isHidden");
 
     // For slow KIO-slaves like used for searching it makes sense to show results periodically even
     // before the completed() or canceled() signal has been emitted.
@@ -265,7 +269,7 @@ QMimeData* KFileItemModel::createMimeData(const KItemSet& indexes) const
         lastAddedItem = itemData;
         const KFileItem& item = itemData->item;
         if (!item.isNull()) {
-            urls << item.targetUrl();
+            urls << item.url();
 
             bool isLocal;
             mostLocalUrls << item.mostLocalUrl(isLocal);
@@ -275,13 +279,7 @@ QMimeData* KFileItemModel::createMimeData(const KItemSet& indexes) const
         }
     }
 
-    const bool different = canUseMostLocalUrls && mostLocalUrls != urls;
-    if (different) {
-        data->setUrls(mostLocalUrls);
-    } else {
-        data->setUrls(urls);
-    }
-
+    KUrlMimeData::setUrls(urls, mostLocalUrls, data);
     return data;
 }
 
@@ -331,7 +329,26 @@ QList<QPair<int, QVariant> > KFileItemModel::groups() const
         switch (typeForRole(sortRole())) {
         case NameRole:        m_groups = nameRoleGroups(); break;
         case SizeRole:        m_groups = sizeRoleGroups(); break;
-        case DateRole:        m_groups = dateRoleGroups(); break;
+        case ModificationTimeRole:
+            m_groups = timeRoleGroups([](const ItemData *item) {
+                return item->item.time(KFileItem::ModificationTime);
+            });
+            break;
+        case CreationTimeRole:
+            m_groups = timeRoleGroups([](const ItemData *item) {
+                return item->item.time(KFileItem::CreationTime);
+            });
+            break;
+        case AccessTimeRole:
+            m_groups = timeRoleGroups([](const ItemData *item) {
+                return item->item.time(KFileItem::AccessTime);
+            });
+            break;
+        case DeletionTimeRole:
+            m_groups = timeRoleGroups([](const ItemData *item) {
+                return item->values.value("deletiontime").toDateTime();
+            });
+            break;
         case PermissionsRole: m_groups = permissionRoleGroups(); break;
         case RatingRole:      m_groups = ratingRoleGroups(); break;
         default:              m_groups = genericStringRoleGroups(sortRole()); break;
@@ -420,12 +437,15 @@ int KFileItemModel::index(const QUrl& url) const
             foreach (const QUrl& url, indexesForUrl.uniqueKeys()) {
                 if (indexesForUrl.count(url) > 1) {
                     qCWarning(DolphinDebug) << "Multiple items found with the URL" << url;
-                    foreach (int index, indexesForUrl.values(url)) {
-                        const ItemData* data = m_itemData.at(index);
-                        qCWarning(DolphinDebug) << "index" << index << ":" << data->item;
+
+                    auto it = indexesForUrl.find(url);
+                    while (it != indexesForUrl.end() && it.key() == url) {
+                        const ItemData* data = m_itemData.at(it.value());
+                        qCWarning(DolphinDebug) << "index" << it.value() << ":" << data->item;
                         if (data->parent) {
                             qCWarning(DolphinDebug) << "parent" << data->parent->item;
                         }
+                        ++it;
                     }
                 }
             }
@@ -594,7 +614,12 @@ int KFileItemModel::expandedParentsCount(int index) const
 
 QSet<QUrl> KFileItemModel::expandedDirectories() const
 {
-    return m_expandedDirs.values().toSet();
+    QSet<QUrl> result;
+    const auto dirs = m_expandedDirs;
+    for (const auto &dir : dirs) {
+        result.insert(dir);
+    }
+    return result;
 }
 
 void KFileItemModel::restoreExpandedDirectories(const QSet<QUrl> &urls)
@@ -1314,6 +1339,7 @@ void KFileItemModel::prepareItemsForSorting(QList<ItemData*>& itemDataList)
     case GroupRole:
     case DestinationRole:
     case PathRole:
+    case DeletionTimeRole:
         // These roles can be determined with retrieveData, and they have to be stored
         // in the QHash "values" for the sorting.
         foreach (ItemData* itemData, itemDataList) {
@@ -1466,6 +1492,7 @@ KFileItemModel::RoleType KFileItemModel::typeForRole(const QByteArray& role) con
         // with KFileItemModel::roleForType() in case if a change is done).
         roles.insert("isDir", IsDirRole);
         roles.insert("isLink", IsLinkRole);
+        roles.insert("isHidden", IsHiddenRole);
         roles.insert("isExpanded", IsExpandedRole);
         roles.insert("isExpandable", IsExpandableRole);
         roles.insert("expandedParentsCount", ExpandedParentsCountRole);
@@ -1492,6 +1519,7 @@ QByteArray KFileItemModel::roleForType(RoleType roleType) const
         // with KFileItemModel::typeForRole() in case if a change is done).
         roles.insert(IsDirRole, "isDir");
         roles.insert(IsLinkRole, "isLink");
+        roles.insert(IsHiddenRole, "isHidden");
         roles.insert(IsExpandedRole, "isExpanded");
         roles.insert(IsExpandableRole, "isExpandable");
         roles.insert(ExpandedParentsCountRole, "expandedParentsCount");
@@ -1519,6 +1547,10 @@ QHash<QByteArray, QVariant> KFileItemModel::retrieveData(const KFileItem& item,
         data.insert(sharedValue("isLink"), true);
     }
 
+    if (m_requestRole[IsHiddenRole] && item.isHidden()) {
+        data.insert(sharedValue("isHidden"), true);
+    }
+
     if (m_requestRole[NameRole]) {
         data.insert(sharedValue("text"), item.text());
     }
@@ -1527,12 +1559,28 @@ QHash<QByteArray, QVariant> KFileItemModel::retrieveData(const KFileItem& item,
         data.insert(sharedValue("size"), item.size());
     }
 
-    if (m_requestRole[DateRole]) {
+    if (m_requestRole[ModificationTimeRole]) {
         // Don't use KFileItem::timeString() as this is too expensive when
         // having several thousands of items. Instead the formatting of the
         // date-time will be done on-demand by the view when the date will be shown.
         const QDateTime dateTime = item.time(KFileItem::ModificationTime);
-        data.insert(sharedValue("date"), dateTime);
+        data.insert(sharedValue("modificationtime"), dateTime);
+    }
+
+    if (m_requestRole[CreationTimeRole]) {
+        // Don't use KFileItem::timeString() as this is too expensive when
+        // having several thousands of items. Instead the formatting of the
+        // date-time will be done on-demand by the view when the date will be shown.
+        const QDateTime dateTime = item.time(KFileItem::CreationTime);
+        data.insert(sharedValue("creationtime"), dateTime);
+    }
+
+    if (m_requestRole[AccessTimeRole]) {
+        // Don't use KFileItem::timeString() as this is too expensive when
+        // having several thousands of items. Instead the formatting of the
+        // date-time will be done on-demand by the view when the date will be shown.
+        const QDateTime dateTime = item.time(KFileItem::AccessTime);
+        data.insert(sharedValue("accesstime"), dateTime);
     }
 
     if (m_requestRole[PermissionsRole]) {
@@ -1578,6 +1626,14 @@ QHash<QByteArray, QVariant> KFileItemModel::retrieveData(const KFileItem& item,
         data.insert(sharedValue("path"), path);
     }
 
+    if (m_requestRole[DeletionTimeRole]) {
+        QDateTime deletionTime;
+        if (item.url().scheme() == QLatin1String("trash")) {
+            deletionTime = QDateTime::fromString(item.entry().stringValue(KIO::UDSEntry::UDS_EXTRA + 1), Qt::ISODate);
+        }
+        data.insert(sharedValue("deletiontime"), deletionTime);
+    }
+
     if (m_requestRole[IsExpandableRole] && isDir) {
         data.insert(sharedValue("isExpandable"), true);
     }
@@ -1757,7 +1813,7 @@ int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b, const
         break;
     }
 
-    case DateRole: {
+    case ModificationTimeRole: {
         const QDateTime dateTimeA = itemA.time(KFileItem::ModificationTime);
         const QDateTime dateTimeB = itemB.time(KFileItem::ModificationTime);
         if (dateTimeA < dateTimeB) {
@@ -1768,6 +1824,28 @@ int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b, const
         break;
     }
 
+    case CreationTimeRole: {
+        const QDateTime dateTimeA = itemA.time(KFileItem::CreationTime);
+        const QDateTime dateTimeB = itemB.time(KFileItem::CreationTime);
+        if (dateTimeA < dateTimeB) {
+            result = -1;
+        } else if (dateTimeA > dateTimeB) {
+            result = +1;
+        }
+        break;
+    }
+
+    case DeletionTimeRole: {
+        const QDateTime dateTimeA = a->values.value("deletiontime").toDateTime();
+        const QDateTime dateTimeB = b->values.value("deletiontime").toDateTime();
+        if (dateTimeA < dateTimeB) {
+            result = -1;
+        } else if (dateTimeA > dateTimeB) {
+            result = +1;
+        }
+        break;
+    }
+
     case RatingRole: {
         result = a->values.value("rating").toInt() - b->values.value("rating").toInt();
         break;
@@ -1937,7 +2015,7 @@ QList<QPair<int, QVariant> > KFileItemModel::sizeRoleGroups() const
     return groups;
 }
 
-QList<QPair<int, QVariant> > KFileItemModel::dateRoleGroups() const
+QList<QPair<int, QVariant> > KFileItemModel::timeRoleGroups(std::function<QDateTime(const ItemData *)> fileTimeCb) const
 {
     Q_ASSERT(!m_itemData.isEmpty());
 
@@ -1946,26 +2024,26 @@ QList<QPair<int, QVariant> > KFileItemModel::dateRoleGroups() const
 
     const QDate currentDate = QDate::currentDate();
 
-    QDate previousModifiedDate;
+    QDate previousFileDate;
     QString groupValue;
     for (int i = 0; i <= maxIndex; ++i) {
         if (isChildItem(i)) {
             continue;
         }
 
-        const QDateTime modifiedTime = m_itemData.at(i)->item.time(KFileItem::ModificationTime);
-        const QDate modifiedDate = modifiedTime.date();
-        if (modifiedDate == previousModifiedDate) {
+        const QDateTime fileTime = fileTimeCb(m_itemData.at(i));
+        const QDate fileDate = fileTime.date();
+        if (fileDate == previousFileDate) {
             // The current item is in the same group as the previous item
             continue;
         }
-        previousModifiedDate = modifiedDate;
+        previousFileDate = fileDate;
 
-        const int daysDistance = modifiedDate.daysTo(currentDate);
+        const int daysDistance = fileDate.daysTo(currentDate);
 
         QString newGroupValue;
-        if (currentDate.year() == modifiedDate.year() &&
-            currentDate.month() == modifiedDate.month()) {
+        if (currentDate.year() == fileDate.year() &&
+            currentDate.month() == fileDate.month()) {
 
             switch (daysDistance / 7) {
             case 0:
@@ -1973,7 +2051,7 @@ QList<QPair<int, QVariant> > KFileItemModel::dateRoleGroups() const
                 case 0:  newGroupValue = i18nc("@title:group Date", "Today"); break;
                 case 1:  newGroupValue = i18nc("@title:group Date", "Yesterday"); break;
                 default:
-                    newGroupValue = modifiedTime.toString(
+                    newGroupValue = fileTime.toString(
                         i18nc("@title:group Date: The week day name: dddd", "dddd"));
                     newGroupValue = i18nc("Can be used to script translation of \"dddd\""
                         "with context @title:group Date", "%1", newGroupValue);
@@ -1997,18 +2075,18 @@ QList<QPair<int, QVariant> > KFileItemModel::dateRoleGroups() const
             }
         } else {
             const QDate lastMonthDate = currentDate.addMonths(-1);
-            if  (lastMonthDate.year() == modifiedDate.year() &&
-                 lastMonthDate.month() == modifiedDate.month()) {
+            if  (lastMonthDate.year() == fileDate.year() &&
+                 lastMonthDate.month() == fileDate.month()) {
 
                 if (daysDistance == 1) {
-                    newGroupValue = modifiedTime.toString(i18nc("@title:group Date: "
+                    newGroupValue = fileTime.toString(i18nc("@title:group Date: "
                         "MMMM is full month name in current locale, and yyyy is "
                         "full year number", "'Yesterday' (MMMM, yyyy)"));
                     newGroupValue = i18nc("Can be used to script translation of "
                         "\"'Yesterday' (MMMM, yyyy)\" with context @title:group Date",
                         "%1", newGroupValue);
                 } else if (daysDistance <= 7) {
-                    newGroupValue = modifiedTime.toString(i18nc("@title:group Date: "
+                    newGroupValue = fileTime.toString(i18nc("@title:group Date: "
                         "The week day name: dddd, MMMM is full month name "
                         "in current locale, and yyyy is full year number",
                         "dddd (MMMM, yyyy)"));
@@ -2016,28 +2094,28 @@ QList<QPair<int, QVariant> > KFileItemModel::dateRoleGroups() const
                         "\"dddd (MMMM, yyyy)\" with context @title:group Date",
                         "%1", newGroupValue);
                 } else if (daysDistance <= 7 * 2) {
-                    newGroupValue = modifiedTime.toString(i18nc("@title:group Date: "
+                    newGroupValue = fileTime.toString(i18nc("@title:group Date: "
                         "MMMM is full month name in current locale, and yyyy is "
                         "full year number", "'One Week Ago' (MMMM, yyyy)"));
                     newGroupValue = i18nc("Can be used to script translation of "
                         "\"'One Week Ago' (MMMM, yyyy)\" with context @title:group Date",
                         "%1", newGroupValue);
                 } else if (daysDistance <= 7 * 3) {
-                    newGroupValue = modifiedTime.toString(i18nc("@title:group Date: "
+                    newGroupValue = fileTime.toString(i18nc("@title:group Date: "
                         "MMMM is full month name in current locale, and yyyy is "
                         "full year number", "'Two Weeks Ago' (MMMM, yyyy)"));
                     newGroupValue = i18nc("Can be used to script translation of "
                         "\"'Two Weeks Ago' (MMMM, yyyy)\" with context @title:group Date",
                         "%1", newGroupValue);
                 } else if (daysDistance <= 7 * 4) {
-                    newGroupValue = modifiedTime.toString(i18nc("@title:group Date: "
+                    newGroupValue = fileTime.toString(i18nc("@title:group Date: "
                         "MMMM is full month name in current locale, and yyyy is "
                         "full year number", "'Three Weeks Ago' (MMMM, yyyy)"));
                     newGroupValue = i18nc("Can be used to script translation of "
                         "\"'Three Weeks Ago' (MMMM, yyyy)\" with context @title:group Date",
                         "%1", newGroupValue);
                 } else {
-                    newGroupValue = modifiedTime.toString(i18nc("@title:group Date: "
+                    newGroupValue = fileTime.toString(i18nc("@title:group Date: "
                         "MMMM is full month name in current locale, and yyyy is "
                         "full year number", "'Earlier on' MMMM, yyyy"));
                     newGroupValue = i18nc("Can be used to script translation of "
@@ -2045,7 +2123,7 @@ QList<QPair<int, QVariant> > KFileItemModel::dateRoleGroups() const
                         "%1", newGroupValue);
                 }
             } else {
-                newGroupValue = modifiedTime.toString(i18nc("@title:group "
+                newGroupValue = fileTime.toString(i18nc("@title:group "
                     "The month and year: MMMM is full month name in current locale, "
                     "and yyyy is full year number", "MMMM, yyyy"));
                 newGroupValue = i18nc("Can be used to script translation of "
@@ -2216,11 +2294,14 @@ const KFileItemModel::RoleInfoMap* KFileItemModel::rolesInfoMap(int& count)
         { 0,             NoRole,          0, 0,                                             0, 0,                                     false, false },
         { "text",        NameRole,        I18N_NOOP2_NOSTRIP("@label", "Name"),             0, 0,                                     false, false },
         { "size",        SizeRole,        I18N_NOOP2_NOSTRIP("@label", "Size"),             0, 0,                                     false, false },
-        { "date",        DateRole,        I18N_NOOP2_NOSTRIP("@label", "Date"),             0, 0,                                     false, false },
+        { "modificationtime",        ModificationTimeRole,        I18N_NOOP2_NOSTRIP("@label", "Modified"),             0, 0,                                     false, false },
+        { "creationtime",        CreationTimeRole,        I18N_NOOP2_NOSTRIP("@label", "Created"),             0, 0,                                     false, false },
+        { "accesstime",        AccessTimeRole,        I18N_NOOP2_NOSTRIP("@label", "Accessed"),             0, 0,                                     false, false },
         { "type",        TypeRole,        I18N_NOOP2_NOSTRIP("@label", "Type"),             0, 0,                                     false, false },
         { "rating",      RatingRole,      I18N_NOOP2_NOSTRIP("@label", "Rating"),           0, 0,                                     true,  false },
         { "tags",        TagsRole,        I18N_NOOP2_NOSTRIP("@label", "Tags"),             0, 0,                                     true,  false },
         { "comment",     CommentRole,     I18N_NOOP2_NOSTRIP("@label", "Comment"),          0, 0,                                     true,  false },
+        { "title",       TitleRole,       I18N_NOOP2_NOSTRIP("@label", "Title"),            I18N_NOOP2_NOSTRIP("@label", "Document"), true,  true  },
         { "wordCount",   WordCountRole,   I18N_NOOP2_NOSTRIP("@label", "Word Count"),       I18N_NOOP2_NOSTRIP("@label", "Document"), true,  true  },
         { "lineCount",   LineCountRole,   I18N_NOOP2_NOSTRIP("@label", "Line Count"),       I18N_NOOP2_NOSTRIP("@label", "Document"), true,  true  },
         { "imageSize",   ImageSizeRole,   I18N_NOOP2_NOSTRIP("@label", "Image Size"),       I18N_NOOP2_NOSTRIP("@label", "Image"),    true,  true  },
@@ -2230,6 +2311,7 @@ const KFileItemModel::RoleInfoMap* KFileItemModel::rolesInfoMap(int& count)
         { "duration",    DurationRole,    I18N_NOOP2_NOSTRIP("@label", "Duration"),         I18N_NOOP2_NOSTRIP("@label", "Audio"),    true,  true  },
         { "track",       TrackRole,       I18N_NOOP2_NOSTRIP("@label", "Track"),            I18N_NOOP2_NOSTRIP("@label", "Audio"),    true,  true  },
         { "path",        PathRole,        I18N_NOOP2_NOSTRIP("@label", "Path"),             I18N_NOOP2_NOSTRIP("@label", "Other"),    false, false },
+        { "deletiontime",DeletionTimeRole,I18N_NOOP2_NOSTRIP("@label", "Deletion Time"),    I18N_NOOP2_NOSTRIP("@label", "Other"),    false, false },
         { "destination", DestinationRole, I18N_NOOP2_NOSTRIP("@label", "Link Destination"), I18N_NOOP2_NOSTRIP("@label", "Other"),    false, false },
         { "originUrl",   OriginUrlRole,   I18N_NOOP2_NOSTRIP("@label", "Downloaded From"),  I18N_NOOP2_NOSTRIP("@label", "Other"),    true,  false },
         { "permissions", PermissionsRole, I18N_NOOP2_NOSTRIP("@label", "Permissions"),      I18N_NOOP2_NOSTRIP("@label", "Other"),    false, false },
@@ -2324,4 +2406,3 @@ bool KFileItemModel::isConsistent() const
 
     return true;
 }
-