]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/kitemviews/kfileitemmodelrolesupdater.cpp
[Details mode] Allow to fill the column size of directories with actual size
[dolphin.git] / src / kitemviews / kfileitemmodelrolesupdater.cpp
index b62ff785927378f7f44a2727ef2a90161261f1d2..c28e240a5f97ba6b54dc1bd6e5c5453a769da363 100644 (file)
 #include "kfileitemmodelrolesupdater.h"
 
 #include "kfileitemmodel.h"
+#include "private/kdirectorycontentscounter.h"
+#include "private/kpixmapmodifier.h"
 
 #include <KConfig>
 #include <KConfigGroup>
-#include <KDebug>
-#include <KFileItem>
-#include <KGlobal>
-#include <KIconLoader>
-#include <KJobWidgets>
 #include <KIO/JobUiDelegate>
 #include <KIO/PreviewJob>
+#include <KIconLoader>
+#include <KJobWidgets>
+#include <KOverlayIconPlugin>
+#include <KPluginLoader>
+#include <KSharedConfig>
 
-#include "private/kpixmapmodifier.h"
-#include "private/kdirectorycontentscounter.h"
+#ifdef HAVE_BALOO
+#include "private/kbaloorolesprovider.h"
+#include <Baloo/File>
+#include <Baloo/FileMonitor>
+#endif
 
 #include <QApplication>
 #include <QPainter>
-#include <QPixmap>
 #include <QElapsedTimer>
 #include <QTimer>
 
-#include <algorithm>
-
-#ifdef HAVE_BALOO
-    #include "private/kbaloorolesprovider.h"
-    #include <KF5/Baloo/file.h>
-    #include <KF5/Baloo/filefetchjob.h>
-    #include <KF5/Baloo/filemonitor.h>
-#endif
-
 // #define KFILEITEMMODELROLESUPDATER_DEBUG
 
 namespace {
@@ -87,21 +82,18 @@ KFileItemModelRolesUpdater::KFileItemModelRolesUpdater(KFileItemModel* model, QO
     m_pendingIndexes(),
     m_pendingPreviewItems(),
     m_previewJob(),
-    m_recentlyChangedItemsTimer(0),
+    m_recentlyChangedItemsTimer(nullptr),
     m_recentlyChangedItems(),
     m_changedItems(),
-    m_directoryContentsCounter(0)
+    m_directoryContentsCounter(nullptr)
   #ifdef HAVE_BALOO
-  , m_balooFileMonitor(0)
+  , m_balooFileMonitor(nullptr)
   #endif
 {
     Q_ASSERT(model);
 
-    const KConfigGroup globalConfig(KGlobal::config(), "PreviewSettings");
-    m_enabledPlugins = globalConfig.readEntry("Plugins", QStringList()
-                                                         << "directorythumbnail"
-                                                         << "imagethumbnail"
-                                                         << "jpegthumbnail");
+    const KConfigGroup globalConfig(KSharedConfig::openConfig(), "PreviewSettings");
+    m_enabledPlugins = globalConfig.readEntry("Plugins", KIO::PreviewJob::defaultPlugins());
 
     connect(m_model, &KFileItemModel::itemsInserted,
             this,    &KFileItemModelRolesUpdater::slotItemsInserted);
@@ -115,9 +107,9 @@ KFileItemModelRolesUpdater::KFileItemModelRolesUpdater(KFileItemModel* model, QO
             this,    &KFileItemModelRolesUpdater::slotSortRoleChanged);
 
     // Use a timer to prevent that each call of slotItemsChanged() results in a synchronous
-    // resolving of the roles. Postpone the resolving until no update has been done for 1 second.
+    // resolving of the roles. Postpone the resolving until no update has been done for 100 ms.
     m_recentlyChangedItemsTimer = new QTimer(this);
-    m_recentlyChangedItemsTimer->setInterval(1000);
+    m_recentlyChangedItemsTimer->setInterval(100);
     m_recentlyChangedItemsTimer->setSingleShot(true);
     connect(m_recentlyChangedItemsTimer, &QTimer::timeout, this, &KFileItemModelRolesUpdater::resolveRecentlyChangedItems);
 
@@ -131,6 +123,18 @@ KFileItemModelRolesUpdater::KFileItemModelRolesUpdater(KFileItemModel* model, QO
     m_directoryContentsCounter = new KDirectoryContentsCounter(m_model, this);
     connect(m_directoryContentsCounter, &KDirectoryContentsCounter::result,
             this,                       &KFileItemModelRolesUpdater::slotDirectoryContentsCountReceived);
+
+    auto plugins = KPluginLoader::instantiatePlugins(QStringLiteral("kf5/overlayicon"), nullptr, qApp);
+    foreach (QObject *it, plugins) {
+        auto plugin = qobject_cast<KOverlayIconPlugin*>(it);
+        if (plugin) {
+            m_overlayIconsPlugin.append(plugin);
+            connect(plugin, &KOverlayIconPlugin::overlaysChanged, this, &KFileItemModelRolesUpdater::slotOverlaysChanged);
+        } else {
+            // not our/valid plugin, so delete the created object
+            it->deleteLater();
+        }
+    }
 }
 
 KFileItemModelRolesUpdater::~KFileItemModelRolesUpdater()
@@ -280,13 +284,13 @@ void KFileItemModelRolesUpdater::setRoles(const QSet<QByteArray>& roles)
             }
         }
 
-        if (hasBalooRole && !m_balooFileMonitor) {
+        if (hasBalooRole && m_balooConfig.fileIndexingEnabled() && !m_balooFileMonitor) {
             m_balooFileMonitor = new Baloo::FileMonitor(this);
             connect(m_balooFileMonitor, &Baloo::FileMonitor::fileMetaDataChanged,
                     this, &KFileItemModelRolesUpdater::applyChangedBalooRoles);
         } else if (!hasBalooRole && m_balooFileMonitor) {
             delete m_balooFileMonitor;
-            m_balooFileMonitor = 0;
+            m_balooFileMonitor = nullptr;
         }
 #endif
 
@@ -350,7 +354,7 @@ void KFileItemModelRolesUpdater::slotItemsInserted(const KItemRangeList& itemRan
 
 void KFileItemModelRolesUpdater::slotItemsRemoved(const KItemRangeList& itemRanges)
 {
-    Q_UNUSED(itemRanges);
+    Q_UNUSED(itemRanges)
 
     const bool allItemsRemoved = (m_model->count() == 0);
 
@@ -361,9 +365,9 @@ void KFileItemModelRolesUpdater::slotItemsRemoved(const KItemRangeList& itemRang
             m_balooFileMonitor->clear();
         } else {
             QStringList newFileList;
-            foreach (const QString& itemUrl, m_balooFileMonitor->files()) {
-                if (m_model->index(itemUrl) >= 0) {
-                    newFileList.append(itemUrl);
+            foreach (const QString& file, m_balooFileMonitor->files()) {
+                if (m_model->index(QUrl::fromLocalFile(file)) >= 0) {
+                    newFileList.append(file);
                 }
             }
             m_balooFileMonitor->setFiles(newFileList);
@@ -400,10 +404,10 @@ void KFileItemModelRolesUpdater::slotItemsRemoved(const KItemRangeList& itemRang
     }
 }
 
-void KFileItemModelRolesUpdater::slotItemsMoved(const KItemRange& itemRange, QList<int> movedToIndexes)
+void KFileItemModelRolesUpdater::slotItemsMoved(const KItemRange& itemRange, const QList<int> &movedToIndexes)
 {
-    Q_UNUSED(itemRange);
-    Q_UNUSED(movedToIndexes);
+    Q_UNUSED(itemRange)
+    Q_UNUSED(movedToIndexes)
 
     // The visible items might have changed.
     startUpdating();
@@ -412,7 +416,7 @@ void KFileItemModelRolesUpdater::slotItemsMoved(const KItemRange& itemRange, QLi
 void KFileItemModelRolesUpdater::slotItemsChanged(const KItemRangeList& itemRanges,
                                                   const QSet<QByteArray>& roles)
 {
-    Q_UNUSED(roles);
+    Q_UNUSED(roles)
 
     // Find out if slotItemsChanged() has been done recently. If that is the
     // case, resolving the roles is postponed until a timer has exceeded
@@ -440,8 +444,8 @@ void KFileItemModelRolesUpdater::slotItemsChanged(const KItemRangeList& itemRang
 void KFileItemModelRolesUpdater::slotSortRoleChanged(const QByteArray& current,
                                                      const QByteArray& previous)
 {
-    Q_UNUSED(current);
-    Q_UNUSED(previous);
+    Q_UNUSED(current)
+    Q_UNUSED(previous)
 
     if (m_resolvableRoles.contains(current)) {
         m_pendingSortRoleItems.clear();
@@ -490,10 +494,9 @@ void KFileItemModelRolesUpdater::slotGotPreview(const KFileItem& item, const QPi
 
     QPixmap scaledPixmap = pixmap;
 
-    const QString mimeType = item.mimetype();
-    const int slashIndex = mimeType.indexOf(QLatin1Char('/'));
-    const QString mimeTypeGroup = mimeType.left(slashIndex);
-    if (mimeTypeGroup == QLatin1String("image")) {
+    if (!pixmap.hasAlpha()
+        && m_iconSize.width()  > KIconLoader::SizeSmallMedium
+        && m_iconSize.height() > KIconLoader::SizeSmallMedium) {
         if (m_enlargeSmallPreviews) {
             KPixmapModifier::applyFrame(scaledPixmap, m_iconSize);
         } else {
@@ -503,7 +506,7 @@ void KFileItemModelRolesUpdater::slotGotPreview(const KFileItem& item, const QPi
             const bool enlargingRequired = scaledPixmap.width()  < contentSize.width() &&
                                            scaledPixmap.height() < contentSize.height();
             if (enlargingRequired) {
-                QSize frameSize = scaledPixmap.size();
+                QSize frameSize = scaledPixmap.size() / scaledPixmap.devicePixelRatio();
                 frameSize.scale(m_iconSize, Qt::KeepAspectRatio);
 
                 QPixmap largeFrame(frameSize);
@@ -512,18 +515,19 @@ void KFileItemModelRolesUpdater::slotGotPreview(const KFileItem& item, const QPi
                 KPixmapModifier::applyFrame(largeFrame, frameSize);
 
                 QPainter painter(&largeFrame);
-                painter.drawPixmap((largeFrame.width()  - scaledPixmap.width()) / 2,
-                                   (largeFrame.height() - scaledPixmap.height()) / 2,
+                painter.drawPixmap((largeFrame.width()  - scaledPixmap.width() / scaledPixmap.devicePixelRatio()) / 2,
+                                   (largeFrame.height() - scaledPixmap.height() / scaledPixmap.devicePixelRatio()) / 2,
                                    scaledPixmap);
                 scaledPixmap = largeFrame;
             } else {
-                // The image must be shrinked as it is too large to fit into
+                // The image must be shrunk as it is too large to fit into
                 // the available icon size
                 KPixmapModifier::applyFrame(scaledPixmap, m_iconSize);
             }
         }
     } else {
-        KPixmapModifier::scale(scaledPixmap, m_iconSize);
+        KPixmapModifier::scale(scaledPixmap, m_iconSize * qApp->devicePixelRatio());
+        scaledPixmap.setDevicePixelRatio(qApp->devicePixelRatio());
     }
 
     QHash<QByteArray, QVariant> data = rolesData(item);
@@ -580,7 +584,7 @@ void KFileItemModelRolesUpdater::slotPreviewFailed(const KFileItem& item)
 
 void KFileItemModelRolesUpdater::slotPreviewJobFinished()
 {
-    m_previewJob = 0;
+    m_previewJob = nullptr;
 
     if (m_state != PreviewJobRunning) {
         return;
@@ -622,7 +626,7 @@ void KFileItemModelRolesUpdater::resolveNextSortRole()
 
     if (!m_pendingSortRoleItems.isEmpty()) {
         applySortProgressToModel();
-        QTimer::singleShot(0, this, SLOT(resolveNextSortRole()));
+        QTimer::singleShot(0, this, &KFileItemModelRolesUpdater::resolveNextSortRole);
     } else {
         m_state = Idle;
 
@@ -657,7 +661,7 @@ void KFileItemModelRolesUpdater::resolveNextPendingRoles()
     }
 
     if (!m_pendingIndexes.isEmpty()) {
-        QTimer::singleShot(0, this, SLOT(resolveNextPendingRoles()));
+        QTimer::singleShot(0, this, &KFileItemModelRolesUpdater::resolveNextPendingRoles);
     } else {
         m_state = Idle;
 
@@ -694,32 +698,27 @@ void KFileItemModelRolesUpdater::resolveRecentlyChangedItems()
     updateChangedItems();
 }
 
-void KFileItemModelRolesUpdater::applyChangedBalooRoles(const QString& itemUrl)
+void KFileItemModelRolesUpdater::applyChangedBalooRoles(const QString& file)
 {
 #ifdef HAVE_BALOO
-    const KFileItem item = m_model->fileItem(itemUrl);
+    const KFileItem item = m_model->fileItem(QUrl::fromLocalFile(file));
 
     if (item.isNull()) {
         // itemUrl is not in the model anymore, probably because
         // the corresponding file has been deleted in the meantime.
         return;
     }
-
-    Baloo::FileFetchJob* job = new Baloo::FileFetchJob(item.localPath());
-    connect(job, &Baloo::FileFetchJob::finished, this, &KFileItemModelRolesUpdater::applyChangedBalooRolesJobFinished);
-    job->setProperty("item", QVariant::fromValue(item));
-    job->start();
+    applyChangedBalooRolesForItem(item);
 #else
-#ifndef Q_CC_MSVC
-    Q_UNUSED(itemUrl);
-#endif
+    Q_UNUSED(file)
 #endif
 }
 
-void KFileItemModelRolesUpdater::applyChangedBalooRolesJobFinished(KJob* kjob)
+void KFileItemModelRolesUpdater::applyChangedBalooRolesForItem(const KFileItem &item)
 {
 #ifdef HAVE_BALOO
-    const KFileItem item = kjob->property("item").value<KFileItem>();
+    Baloo::File file(item.localPath());
+    file.load();
 
     const KBalooRolesProvider& rolesProvider = KBalooRolesProvider::instance();
     QHash<QByteArray, QVariant> data;
@@ -731,8 +730,7 @@ void KFileItemModelRolesUpdater::applyChangedBalooRolesJobFinished(KJob* kjob)
         data.insert(role, QVariant());
     }
 
-    Baloo::FileFetchJob* job = static_cast<Baloo::FileFetchJob*>(kjob);
-    QHashIterator<QByteArray, QVariant> it(rolesProvider.roleValues(job->file(), m_roles));
+    QHashIterator<QByteArray, QVariant> it(rolesProvider.roleValues(file, m_roles));
     while (it.hasNext()) {
         it.next();
         data.insert(it.key(), it.value());
@@ -744,31 +742,34 @@ void KFileItemModelRolesUpdater::applyChangedBalooRolesJobFinished(KJob* kjob)
     m_model->setData(index, data);
     connect(m_model, &KFileItemModel::itemsChanged,
             this,    &KFileItemModelRolesUpdater::slotItemsChanged);
+#else
+#ifndef Q_CC_MSVC
+    Q_UNUSED(item)
+#endif
 #endif
 }
 
-void KFileItemModelRolesUpdater::slotDirectoryContentsCountReceived(const QString& path, int count)
+void KFileItemModelRolesUpdater::slotDirectoryContentsCountReceived(const QString& path, int count, long size)
 {
     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));
+        const int index = m_model->index(QUrl::fromLocalFile(path));
         if (index >= 0) {
             QHash<QByteArray, QVariant> data;
 
             if (getSizeRole) {
-                data.insert("size", count);
+                data.insert("count", count);
+                if (size != -1) {
+                    data.insert("size", QVariant::fromValue(size));
+                }
             }
             if (getIsExpandableRole) {
                 data.insert("isExpandable", count > 0);
             }
 
-            disconnect(m_model, &KFileItemModel::itemsChanged,
-                       this,    &KFileItemModelRolesUpdater::slotItemsChanged);
             m_model->setData(index, data);
-            connect(m_model, &KFileItemModel::itemsChanged,
-                    this,    &KFileItemModelRolesUpdater::slotItemsChanged);
         }
     }
 }
@@ -820,7 +821,7 @@ void KFileItemModelRolesUpdater::startUpdating()
         m_pendingIndexes = indexes;
         // Trigger the asynchronous resolving of all roles.
         m_state = ResolvingAllRoles;
-        QTimer::singleShot(0, this, SLOT(resolveNextPendingRoles()));
+        QTimer::singleShot(0, this, &KFileItemModelRolesUpdater::resolveNextPendingRoles);
     }
 }
 
@@ -855,7 +856,7 @@ void KFileItemModelRolesUpdater::startPreviewJob()
     m_state = PreviewJobRunning;
 
     if (m_pendingPreviewItems.isEmpty()) {
-        QTimer::singleShot(0, this, SLOT(slotPreviewJobFinished()));
+        QTimer::singleShot(0, this, &KFileItemModelRolesUpdater::slotPreviewJobFinished);
         return;
     }
 
@@ -898,7 +899,7 @@ void KFileItemModelRolesUpdater::startPreviewJob()
     KIO::PreviewJob* job = new KIO::PreviewJob(itemSubSet, cacheSize, &m_enabledPlugins);
 
     job->setIgnoreMaximumSize(itemSubSet.first().isLocalFile());
-    if (job->ui()) {
+    if (job->uiDelegate()) {
         KJobWidgets::setWindow(job, qApp->activeWindow());
     }
 
@@ -932,7 +933,7 @@ void KFileItemModelRolesUpdater::updateChangedItems()
             // asynchronous determination of the sort role.
             killPreviewJob();
             m_state = ResolvingSortRole;
-            QTimer::singleShot(0, this, SLOT(resolveNextSortRole()));
+            QTimer::singleShot(0, this, &KFileItemModelRolesUpdater::resolveNextSortRole);
         }
 
         return;
@@ -976,7 +977,7 @@ void KFileItemModelRolesUpdater::updateChangedItems()
         if (!resolvingInProgress) {
             // Trigger the asynchronous resolving of the changed roles.
             m_state = ResolvingAllRoles;
-            QTimer::singleShot(0, this, SLOT(resolveNextPendingRoles()));
+            QTimer::singleShot(0, this, &KFileItemModelRolesUpdater::resolveNextPendingRoles);
         }
     }
 }
@@ -994,7 +995,7 @@ void KFileItemModelRolesUpdater::applySortRole(int index)
         data.insert("type", item.mimeComment());
     } else if (m_model->sortRole() == "size" && item.isLocalFile() && item.isDir()) {
         const QString path = item.localPath();
-        data.insert("size", m_directoryContentsCounter->countDirectoryContentsSynchronously(path));
+        m_directoryContentsCounter->scanDirectory(path);
     } else {
         // Probably the sort role is a baloo role - just determine all roles.
         data = rolesData(item);
@@ -1067,7 +1068,7 @@ QHash<QByteArray, QVariant> KFileItemModelRolesUpdater::rolesData(const KFileIte
             // 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();
-            m_directoryContentsCounter->addDirectory(path);
+            m_directoryContentsCounter->scanDirectory(path);
         } else if (getSizeRole) {
             data.insert("size", -1); // -1 indicates an unknown number of items
         }
@@ -1077,17 +1078,37 @@ QHash<QByteArray, QVariant> KFileItemModelRolesUpdater::rolesData(const KFileIte
         data.insert("type", item.mimeComment());
     }
 
-    data.insert("iconOverlays", item.overlays());
+    QStringList overlays = item.overlays();
+    foreach(KOverlayIconPlugin *it, m_overlayIconsPlugin) {
+        overlays.append(it->getOverlays(item.url()));
+    }
+    data.insert("iconOverlays", overlays);
 
 #ifdef HAVE_BALOO
     if (m_balooFileMonitor) {
         m_balooFileMonitor->addFile(item.localPath());
-        applyChangedBalooRoles(item.localPath());
+        applyChangedBalooRolesForItem(item);
     }
 #endif
     return data;
 }
 
+void KFileItemModelRolesUpdater::slotOverlaysChanged(const QUrl& url, const QStringList &)
+{
+    const KFileItem item = m_model->fileItem(url);
+    if (item.isNull()) {
+        return;
+    }
+    const int index = m_model->index(item);
+    QHash<QByteArray, QVariant> data =  m_model->data(index);
+    QStringList overlays = item.overlays();
+    foreach (KOverlayIconPlugin *it, m_overlayIconsPlugin) {
+        overlays.append(it->getOverlays(url));
+    }
+    data.insert("iconOverlays", overlays);
+    m_model->setData(index, data);
+}
+
 void KFileItemModelRolesUpdater::updateAllPreviews()
 {
     if (m_state == Paused) {
@@ -1108,7 +1129,7 @@ void KFileItemModelRolesUpdater::killPreviewJob()
         disconnect(m_previewJob,  &KIO::PreviewJob::finished,
                    this, &KFileItemModelRolesUpdater::slotPreviewJobFinished);
         m_previewJob->kill();
-        m_previewJob = 0;
+        m_previewJob = nullptr;
         m_pendingPreviewItems.clear();
     }
 }
@@ -1127,7 +1148,7 @@ QList<int> KFileItemModelRolesUpdater::indexesToResolve() const
 
     // We need a reasonable upper limit for number of items to resolve after
     // and before the visible range. m_maximumVisibleItems can be quite large
-    // when using Compace View.
+    // when using Compact View.
     const int readAheadItems = qMin(ReadAheadPages * m_maximumVisibleItems, ResolveAllItemsLimit / 2);
 
     // Add items after the visible range.
@@ -1170,4 +1191,3 @@ QList<int> KFileItemModelRolesUpdater::indexesToResolve() const
     return result;
 }
 
-#include "kfileitemmodelrolesupdater.moc"