mirror of
https://invent.kde.org/system/dolphin
synced 2024-09-17 15:31:20 +00:00
Count the items inside directories in another thread
This prevents that the GUI freezes if there are many files inside the directory, or if the access to the directory is slow for some other reason. BUG: 318518 REVIEW: 111920 FIXED-IN: 4.12.0
This commit is contained in:
parent
8f7c3619ec
commit
4bfc28cb4b
|
@ -58,6 +58,8 @@ set(dolphinprivate_LIB_SRCS
|
||||||
kitemviews/kstandarditemlistwidget.cpp
|
kitemviews/kstandarditemlistwidget.cpp
|
||||||
kitemviews/kstandarditemlistview.cpp
|
kitemviews/kstandarditemlistview.cpp
|
||||||
kitemviews/kstandarditemmodel.cpp
|
kitemviews/kstandarditemmodel.cpp
|
||||||
|
kitemviews/private/kdirectorycontentscounter.cpp
|
||||||
|
kitemviews/private/kdirectorycontentscounterworker.cpp
|
||||||
kitemviews/private/kfileitemclipboard.cpp
|
kitemviews/private/kfileitemclipboard.cpp
|
||||||
kitemviews/private/kfileitemmodeldirlister.cpp
|
kitemviews/private/kfileitemmodeldirlister.cpp
|
||||||
kitemviews/private/kfileitemmodelfilter.cpp
|
kitemviews/private/kfileitemmodelfilter.cpp
|
||||||
|
|
|
@ -24,13 +24,13 @@
|
||||||
#include <KConfig>
|
#include <KConfig>
|
||||||
#include <KConfigGroup>
|
#include <KConfigGroup>
|
||||||
#include <KDebug>
|
#include <KDebug>
|
||||||
#include <KDirWatch>
|
|
||||||
#include <KFileItem>
|
#include <KFileItem>
|
||||||
#include <KGlobal>
|
#include <KGlobal>
|
||||||
#include <KIO/JobUiDelegate>
|
#include <KIO/JobUiDelegate>
|
||||||
#include <KIO/PreviewJob>
|
#include <KIO/PreviewJob>
|
||||||
|
|
||||||
#include "private/kpixmapmodifier.h"
|
#include "private/kpixmapmodifier.h"
|
||||||
|
#include "private/kdirectorycontentscounter.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
@ -46,14 +46,6 @@
|
||||||
#include <Nepomuk2/ResourceManager>
|
#include <Nepomuk2/ResourceManager>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Required includes for subItemsCount():
|
|
||||||
#ifdef Q_WS_WIN
|
|
||||||
#include <QDir>
|
|
||||||
#else
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <QFile>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// #define KFILEITEMMODELROLESUPDATER_DEBUG
|
// #define KFILEITEMMODELROLESUPDATER_DEBUG
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -95,8 +87,7 @@ KFileItemModelRolesUpdater::KFileItemModelRolesUpdater(KFileItemModel* model, QO
|
||||||
m_recentlyChangedItemsTimer(0),
|
m_recentlyChangedItemsTimer(0),
|
||||||
m_recentlyChangedItems(),
|
m_recentlyChangedItems(),
|
||||||
m_changedItems(),
|
m_changedItems(),
|
||||||
m_dirWatcher(0),
|
m_directoryContentsCounter(0)
|
||||||
m_watchedDirs()
|
|
||||||
#ifdef HAVE_NEPOMUK
|
#ifdef HAVE_NEPOMUK
|
||||||
, m_nepomukResourceWatcher(0),
|
, m_nepomukResourceWatcher(0),
|
||||||
m_nepomukUriItems()
|
m_nepomukUriItems()
|
||||||
|
@ -135,10 +126,9 @@ KFileItemModelRolesUpdater::KFileItemModelRolesUpdater(KFileItemModel* model, QO
|
||||||
m_resolvableRoles += KNepomukRolesProvider::instance().roles();
|
m_resolvableRoles += KNepomukRolesProvider::instance().roles();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// When folders are expandable or the item-count is shown for folders, it is necessary
|
m_directoryContentsCounter = new KDirectoryContentsCounter(m_model, this);
|
||||||
// to watch the number of items of the sub-folder to be able to react on changes.
|
connect(m_directoryContentsCounter, SIGNAL(result(QString,int)),
|
||||||
m_dirWatcher = new KDirWatch(this);
|
this, SLOT(slotDirectoryContentsCountReceived(QString,int)));
|
||||||
connect(m_dirWatcher, SIGNAL(dirty(QString)), this, SLOT(slotDirWatchDirty(QString)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KFileItemModelRolesUpdater::~KFileItemModelRolesUpdater()
|
KFileItemModelRolesUpdater::~KFileItemModelRolesUpdater()
|
||||||
|
@ -367,25 +357,6 @@ void KFileItemModelRolesUpdater::slotItemsRemoved(const KItemRangeList& itemRang
|
||||||
|
|
||||||
const bool allItemsRemoved = (m_model->count() == 0);
|
const bool allItemsRemoved = (m_model->count() == 0);
|
||||||
|
|
||||||
if (!m_watchedDirs.isEmpty()) {
|
|
||||||
// Don't let KDirWatch watch for removed items
|
|
||||||
if (allItemsRemoved) {
|
|
||||||
foreach (const QString& path, m_watchedDirs) {
|
|
||||||
m_dirWatcher->removeDir(path);
|
|
||||||
}
|
|
||||||
m_watchedDirs.clear();
|
|
||||||
} else {
|
|
||||||
QMutableSetIterator<QString> it(m_watchedDirs);
|
|
||||||
while (it.hasNext()) {
|
|
||||||
const QString& path = it.next();
|
|
||||||
if (m_model->index(KUrl(path)) < 0) {
|
|
||||||
m_dirWatcher->removeDir(path);
|
|
||||||
it.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_NEPOMUK
|
#ifdef HAVE_NEPOMUK
|
||||||
if (m_nepomukResourceWatcher) {
|
if (m_nepomukResourceWatcher) {
|
||||||
// Don't let the ResourceWatcher watch for removed items
|
// Don't let the ResourceWatcher watch for removed items
|
||||||
|
@ -783,7 +754,7 @@ void KFileItemModelRolesUpdater::applyChangedNepomukRoles(const Nepomuk2::Resour
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void KFileItemModelRolesUpdater::slotDirWatchDirty(const QString& path)
|
void KFileItemModelRolesUpdater::slotDirectoryContentsCountReceived(const QString& path, int count)
|
||||||
{
|
{
|
||||||
const bool getSizeRole = m_roles.contains("size");
|
const bool getSizeRole = m_roles.contains("size");
|
||||||
const bool getIsExpandableRole = m_roles.contains("isExpandable");
|
const bool getIsExpandableRole = m_roles.contains("isExpandable");
|
||||||
|
@ -791,16 +762,9 @@ void KFileItemModelRolesUpdater::slotDirWatchDirty(const QString& path)
|
||||||
if (getSizeRole || getIsExpandableRole) {
|
if (getSizeRole || getIsExpandableRole) {
|
||||||
const int index = m_model->index(KUrl(path));
|
const int index = m_model->index(KUrl(path));
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
if (!m_model->fileItem(index).isDir()) {
|
|
||||||
// If INotify is used, KDirWatch issues the dirty() signal
|
|
||||||
// also for changed files inside the directory, even if we
|
|
||||||
// don't enable this behavior explicitly (see bug 309740).
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QHash<QByteArray, QVariant> data;
|
QHash<QByteArray, QVariant> data;
|
||||||
|
|
||||||
const int count = subItemsCount(path);
|
|
||||||
if (getSizeRole) {
|
if (getSizeRole) {
|
||||||
data.insert("size", count);
|
data.insert("size", count);
|
||||||
}
|
}
|
||||||
|
@ -808,9 +772,11 @@ void KFileItemModelRolesUpdater::slotDirWatchDirty(const QString& path)
|
||||||
data.insert("isExpandable", count > 0);
|
data.insert("isExpandable", count > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that we do not block the itemsChanged signal here.
|
disconnect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet<QByteArray>)),
|
||||||
// This ensures that a new preview will be generated.
|
this, SLOT(slotItemsChanged(KItemRangeList,QSet<QByteArray>)));
|
||||||
m_model->setData(index, data);
|
m_model->setData(index, data);
|
||||||
|
connect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet<QByteArray>)),
|
||||||
|
this, SLOT(slotItemsChanged(KItemRangeList,QSet<QByteArray>)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1037,7 +1003,7 @@ void KFileItemModelRolesUpdater::applySortRole(int index)
|
||||||
data.insert("type", item.mimeComment());
|
data.insert("type", item.mimeComment());
|
||||||
} else if (m_model->sortRole() == "size" && item.isLocalFile() && item.isDir()) {
|
} else if (m_model->sortRole() == "size" && item.isLocalFile() && item.isDir()) {
|
||||||
const QString path = item.localPath();
|
const QString path = item.localPath();
|
||||||
data.insert("size", subItemsCount(path));
|
data.insert("size", m_directoryContentsCounter->countDirectoryContentsSynchronously(path));
|
||||||
} else {
|
} else {
|
||||||
// Probably the sort role is a Nepomuk role - just determine all roles.
|
// Probably the sort role is a Nepomuk role - just determine all roles.
|
||||||
data = rolesData(item);
|
data = rolesData(item);
|
||||||
|
@ -1105,7 +1071,7 @@ bool KFileItemModelRolesUpdater::applyResolvedRoles(const KFileItem& item, Resol
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<QByteArray, QVariant> KFileItemModelRolesUpdater::rolesData(const KFileItem& item) const
|
QHash<QByteArray, QVariant> KFileItemModelRolesUpdater::rolesData(const KFileItem& item)
|
||||||
{
|
{
|
||||||
QHash<QByteArray, QVariant> data;
|
QHash<QByteArray, QVariant> data;
|
||||||
|
|
||||||
|
@ -1114,19 +1080,10 @@ QHash<QByteArray, QVariant> KFileItemModelRolesUpdater::rolesData(const KFileIte
|
||||||
|
|
||||||
if ((getSizeRole || getIsExpandableRole) && item.isDir()) {
|
if ((getSizeRole || getIsExpandableRole) && item.isDir()) {
|
||||||
if (item.isLocalFile()) {
|
if (item.isLocalFile()) {
|
||||||
|
// 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();
|
const QString path = item.localPath();
|
||||||
const int count = subItemsCount(path);
|
m_directoryContentsCounter->addDirectory(path);
|
||||||
if (getSizeRole) {
|
|
||||||
data.insert("size", count);
|
|
||||||
}
|
|
||||||
if (getIsExpandableRole) {
|
|
||||||
data.insert("isExpandable", count > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_dirWatcher->contains(path)) {
|
|
||||||
m_dirWatcher->addDir(path);
|
|
||||||
m_watchedDirs.insert(path);
|
|
||||||
}
|
|
||||||
} else if (getSizeRole) {
|
} else if (getSizeRole) {
|
||||||
data.insert("size", -1); // -1 indicates an unknown number of items
|
data.insert("size", -1); // -1 indicates an unknown number of items
|
||||||
}
|
}
|
||||||
|
@ -1170,61 +1127,6 @@ QHash<QByteArray, QVariant> KFileItemModelRolesUpdater::rolesData(const KFileIte
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
int KFileItemModelRolesUpdater::subItemsCount(const QString& path) const
|
|
||||||
{
|
|
||||||
const bool countHiddenFiles = m_model->showHiddenFiles();
|
|
||||||
const bool showFoldersOnly = m_model->showDirectoriesOnly();
|
|
||||||
|
|
||||||
#ifdef Q_WS_WIN
|
|
||||||
QDir dir(path);
|
|
||||||
QDir::Filters filters = QDir::NoDotAndDotDot | QDir::System;
|
|
||||||
if (countHiddenFiles) {
|
|
||||||
filters |= QDir::Hidden;
|
|
||||||
}
|
|
||||||
if (showFoldersOnly) {
|
|
||||||
filters |= QDir::Dirs;
|
|
||||||
} else {
|
|
||||||
filters |= QDir::AllEntries;
|
|
||||||
}
|
|
||||||
return dir.entryList(filters).count();
|
|
||||||
#else
|
|
||||||
// Taken from kdelibs/kio/kio/kdirmodel.cpp
|
|
||||||
// Copyright (C) 2006 David Faure <faure@kde.org>
|
|
||||||
|
|
||||||
int count = -1;
|
|
||||||
DIR* dir = ::opendir(QFile::encodeName(path));
|
|
||||||
if (dir) { // krazy:exclude=syscalls
|
|
||||||
count = 0;
|
|
||||||
struct dirent *dirEntry = 0;
|
|
||||||
while ((dirEntry = ::readdir(dir))) {
|
|
||||||
if (dirEntry->d_name[0] == '.') {
|
|
||||||
if (dirEntry->d_name[1] == '\0' || !countHiddenFiles) {
|
|
||||||
// Skip "." or hidden files
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (dirEntry->d_name[1] == '.' && dirEntry->d_name[2] == '\0') {
|
|
||||||
// Skip ".."
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If only directories are counted, consider an unknown file type and links also
|
|
||||||
// as directory instead of trying to do an expensive stat()
|
|
||||||
// (see bugs 292642 and 299997).
|
|
||||||
const bool countEntry = !showFoldersOnly ||
|
|
||||||
dirEntry->d_type == DT_DIR ||
|
|
||||||
dirEntry->d_type == DT_LNK ||
|
|
||||||
dirEntry->d_type == DT_UNKNOWN;
|
|
||||||
if (countEntry) {
|
|
||||||
++count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
::closedir(dir);
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void KFileItemModelRolesUpdater::updateAllPreviews()
|
void KFileItemModelRolesUpdater::updateAllPreviews()
|
||||||
{
|
{
|
||||||
if (m_state == Paused) {
|
if (m_state == Paused) {
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
#include <QSize>
|
#include <QSize>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
class KDirWatch;
|
class KDirectoryContentsCounter;
|
||||||
class KFileItemModel;
|
class KFileItemModel;
|
||||||
class KJob;
|
class KJob;
|
||||||
class QPixmap;
|
class QPixmap;
|
||||||
|
@ -218,12 +218,7 @@ private slots:
|
||||||
|
|
||||||
void applyChangedNepomukRoles(const Nepomuk2::Resource& resource, const Nepomuk2::Types::Property& property);
|
void applyChangedNepomukRoles(const Nepomuk2::Resource& resource, const Nepomuk2::Types::Property& property);
|
||||||
|
|
||||||
/**
|
void slotDirectoryContentsCountReceived(const QString& path, int count);
|
||||||
* Is invoked if a directory watched by KDirWatch got dirty. Updates
|
|
||||||
* the "isExpandable"- and "size"-roles of the item that matches to
|
|
||||||
* the given path.
|
|
||||||
*/
|
|
||||||
void slotDirWatchDirty(const QString& path);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
|
@ -267,7 +262,7 @@ private:
|
||||||
ResolveAll
|
ResolveAll
|
||||||
};
|
};
|
||||||
bool applyResolvedRoles(const KFileItem& item, ResolveHint hint);
|
bool applyResolvedRoles(const KFileItem& item, ResolveHint hint);
|
||||||
QHash<QByteArray, QVariant> rolesData(const KFileItem& item) const;
|
QHash<QByteArray, QVariant> rolesData(const KFileItem& item);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The number of items of the path \a path.
|
* @return The number of items of the path \a path.
|
||||||
|
@ -349,9 +344,8 @@ private:
|
||||||
// Items which have not been changed repeatedly recently.
|
// Items which have not been changed repeatedly recently.
|
||||||
QSet<KFileItem> m_changedItems;
|
QSet<KFileItem> m_changedItems;
|
||||||
|
|
||||||
KDirWatch* m_dirWatcher;
|
KDirectoryContentsCounter* m_directoryContentsCounter;
|
||||||
mutable QSet<QString> m_watchedDirs; // Required as sadly KDirWatch does not offer a getter method
|
|
||||||
// to get all watched directories.
|
|
||||||
#ifdef HAVE_NEPOMUK
|
#ifdef HAVE_NEPOMUK
|
||||||
Nepomuk2::ResourceWatcher* m_nepomukResourceWatcher;
|
Nepomuk2::ResourceWatcher* m_nepomukResourceWatcher;
|
||||||
mutable QHash<QUrl, KUrl> m_nepomukUriItems;
|
mutable QHash<QUrl, KUrl> m_nepomukUriItems;
|
||||||
|
|
164
src/kitemviews/private/kdirectorycontentscounter.cpp
Normal file
164
src/kitemviews/private/kdirectorycontentscounter.cpp
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
|
||||||
|
* Copyright (C) 2013 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 *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "kdirectorycontentscounter.h"
|
||||||
|
|
||||||
|
#include "kdirectorycontentscounterworker.h"
|
||||||
|
#include <kitemviews/kfileitemmodel.h>
|
||||||
|
|
||||||
|
#include <KDirWatch>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
|
KDirectoryContentsCounter::KDirectoryContentsCounter(KFileItemModel* model, QObject* parent) :
|
||||||
|
QObject(parent),
|
||||||
|
m_model(model),
|
||||||
|
m_queue(),
|
||||||
|
m_workerThread(0),
|
||||||
|
m_worker(0),
|
||||||
|
m_workerIsBusy(false),
|
||||||
|
m_dirWatcher(0),
|
||||||
|
m_watchedDirs()
|
||||||
|
{
|
||||||
|
connect(m_model, SIGNAL(itemsRemoved(KItemRangeList)),
|
||||||
|
this, SLOT(slotItemsRemoved()));
|
||||||
|
|
||||||
|
m_workerThread = new QThread(this);
|
||||||
|
m_worker = new KDirectoryContentsCounterWorker();
|
||||||
|
m_worker->moveToThread(m_workerThread);
|
||||||
|
|
||||||
|
connect(this, SIGNAL(requestDirectoryContentsCount(QString,KDirectoryContentsCounterWorker::Options)),
|
||||||
|
m_worker, SLOT(countDirectoryContents(QString,KDirectoryContentsCounterWorker::Options)));
|
||||||
|
connect(m_worker, SIGNAL(result(QString,int)),
|
||||||
|
this, SLOT(slotResult(QString,int)));
|
||||||
|
|
||||||
|
m_workerThread->start();
|
||||||
|
|
||||||
|
m_dirWatcher = new KDirWatch(this);
|
||||||
|
connect(m_dirWatcher, SIGNAL(dirty(QString)), this, SLOT(slotDirWatchDirty(QString)));
|
||||||
|
}
|
||||||
|
|
||||||
|
KDirectoryContentsCounter::~KDirectoryContentsCounter()
|
||||||
|
{
|
||||||
|
m_workerThread->quit();
|
||||||
|
m_workerThread->wait();
|
||||||
|
|
||||||
|
delete m_worker;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KDirectoryContentsCounter::addDirectory(const QString& path)
|
||||||
|
{
|
||||||
|
startWorker(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
int KDirectoryContentsCounter::countDirectoryContentsSynchronously(const QString& path)
|
||||||
|
{
|
||||||
|
if (!m_dirWatcher->contains(path)) {
|
||||||
|
m_dirWatcher->addDir(path);
|
||||||
|
m_watchedDirs.insert(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
KDirectoryContentsCounterWorker::Options options;
|
||||||
|
|
||||||
|
if (m_model->showHiddenFiles()) {
|
||||||
|
options |= KDirectoryContentsCounterWorker::CountHiddenFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_model->showDirectoriesOnly()) {
|
||||||
|
options |= KDirectoryContentsCounterWorker::CountDirectoriesOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
return KDirectoryContentsCounterWorker::subItemsCount(path, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KDirectoryContentsCounter::slotResult(const QString& path, int count)
|
||||||
|
{
|
||||||
|
m_workerIsBusy = false;
|
||||||
|
|
||||||
|
if (!m_dirWatcher->contains(path)) {
|
||||||
|
m_dirWatcher->addDir(path);
|
||||||
|
m_watchedDirs.insert(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_queue.isEmpty()) {
|
||||||
|
startWorker(m_queue.dequeue());
|
||||||
|
}
|
||||||
|
|
||||||
|
emit result(path, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KDirectoryContentsCounter::slotDirWatchDirty(const QString& path)
|
||||||
|
{
|
||||||
|
const int index = m_model->index(KUrl(path));
|
||||||
|
if (index >= 0) {
|
||||||
|
if (!m_model->fileItem(index).isDir()) {
|
||||||
|
// If INotify is used, KDirWatch issues the dirty() signal
|
||||||
|
// also for changed files inside the directory, even if we
|
||||||
|
// don't enable this behavior explicitly (see bug 309740).
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
startWorker(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KDirectoryContentsCounter::slotItemsRemoved()
|
||||||
|
{
|
||||||
|
const bool allItemsRemoved = (m_model->count() == 0);
|
||||||
|
|
||||||
|
if (!m_watchedDirs.isEmpty()) {
|
||||||
|
// Don't let KDirWatch watch for removed items
|
||||||
|
if (allItemsRemoved) {
|
||||||
|
foreach (const QString& path, m_watchedDirs) {
|
||||||
|
m_dirWatcher->removeDir(path);
|
||||||
|
}
|
||||||
|
m_watchedDirs.clear();
|
||||||
|
m_queue.clear();
|
||||||
|
} else {
|
||||||
|
QMutableSetIterator<QString> it(m_watchedDirs);
|
||||||
|
while (it.hasNext()) {
|
||||||
|
const QString& path = it.next();
|
||||||
|
if (m_model->index(KUrl(path)) < 0) {
|
||||||
|
m_dirWatcher->removeDir(path);
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KDirectoryContentsCounter::startWorker(const QString& path)
|
||||||
|
{
|
||||||
|
if (m_workerIsBusy) {
|
||||||
|
m_queue.enqueue(path);
|
||||||
|
} else {
|
||||||
|
KDirectoryContentsCounterWorker::Options options;
|
||||||
|
|
||||||
|
if (m_model->showHiddenFiles()) {
|
||||||
|
options |= KDirectoryContentsCounterWorker::CountHiddenFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_model->showDirectoriesOnly()) {
|
||||||
|
options |= KDirectoryContentsCounterWorker::CountDirectoriesOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit requestDirectoryContentsCount(path, options);
|
||||||
|
m_workerIsBusy = true;
|
||||||
|
}
|
||||||
|
}
|
90
src/kitemviews/private/kdirectorycontentscounter.h
Normal file
90
src/kitemviews/private/kdirectorycontentscounter.h
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
|
||||||
|
* Copyright (C) 2013 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 *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef KDIRECTORYCONTENTSCOUNTER_H
|
||||||
|
#define KDIRECTORYCONTENTSCOUNTER_H
|
||||||
|
|
||||||
|
#include "kdirectorycontentscounterworker.h"
|
||||||
|
|
||||||
|
#include <QSet>
|
||||||
|
#include <QQueue>
|
||||||
|
|
||||||
|
class KDirWatch;
|
||||||
|
class KFileItemModel;
|
||||||
|
class QString;
|
||||||
|
|
||||||
|
class KDirectoryContentsCounter : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit KDirectoryContentsCounter(KFileItemModel* model, QObject* parent = 0);
|
||||||
|
~KDirectoryContentsCounter();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests the number of items inside the directory \a path. The actual
|
||||||
|
* counting is done asynchronously, and the result is announced via the
|
||||||
|
* signal \a result.
|
||||||
|
*
|
||||||
|
* The directory \a path is watched for changes, and the signal is emitted
|
||||||
|
* again if a change occurs.
|
||||||
|
*/
|
||||||
|
void addDirectory(const QString& path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In contrast to \a addDirectory, this function counts the items inside
|
||||||
|
* the directory \a path synchronously and returns the result.
|
||||||
|
*
|
||||||
|
* The directory is watched for changes, and the signal \a result is
|
||||||
|
* emitted if a change occurs.
|
||||||
|
*/
|
||||||
|
int countDirectoryContentsSynchronously(const QString& path);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/**
|
||||||
|
* Signals that the directory \a path contains \a count items.
|
||||||
|
*/
|
||||||
|
void result(const QString& path, int count);
|
||||||
|
|
||||||
|
void requestDirectoryContentsCount(const QString& path, KDirectoryContentsCounterWorker::Options options);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void slotResult(const QString& path, int count);
|
||||||
|
void slotDirWatchDirty(const QString& path);
|
||||||
|
void slotItemsRemoved();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void startWorker(const QString& path);
|
||||||
|
|
||||||
|
private:
|
||||||
|
KFileItemModel* m_model;
|
||||||
|
|
||||||
|
QQueue<QString> m_queue;
|
||||||
|
|
||||||
|
QThread* m_workerThread;
|
||||||
|
KDirectoryContentsCounterWorker* m_worker;
|
||||||
|
bool m_workerIsBusy;
|
||||||
|
|
||||||
|
KDirWatch* m_dirWatcher;
|
||||||
|
QSet<QString> m_watchedDirs; // Required as sadly KDirWatch does not offer a getter method
|
||||||
|
// to get all watched directories.
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
95
src/kitemviews/private/kdirectorycontentscounterworker.cpp
Normal file
95
src/kitemviews/private/kdirectorycontentscounterworker.cpp
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
|
||||||
|
* Copyright (C) 2013 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 *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "kdirectorycontentscounterworker.h"
|
||||||
|
|
||||||
|
// Required includes for subItemsCount():
|
||||||
|
#ifdef Q_WS_WIN
|
||||||
|
#include <QDir>
|
||||||
|
#else
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <QFile>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
KDirectoryContentsCounterWorker::KDirectoryContentsCounterWorker(QObject* parent) :
|
||||||
|
QObject(parent)
|
||||||
|
{
|
||||||
|
qRegisterMetaType<KDirectoryContentsCounterWorker::Options>();
|
||||||
|
}
|
||||||
|
|
||||||
|
int KDirectoryContentsCounterWorker::subItemsCount(const QString& path, Options options)
|
||||||
|
{
|
||||||
|
const bool countHiddenFiles = options & CountHiddenFiles;
|
||||||
|
const bool countDirectoriesOnly = options & CountDirectoriesOnly;
|
||||||
|
|
||||||
|
#ifdef Q_WS_WIN
|
||||||
|
QDir dir(path);
|
||||||
|
QDir::Filters filters = QDir::NoDotAndDotDot | QDir::System;
|
||||||
|
if (countHiddenFiles) {
|
||||||
|
filters |= QDir::Hidden;
|
||||||
|
}
|
||||||
|
if (countDirectoriesOnly) {
|
||||||
|
filters |= QDir::Dirs;
|
||||||
|
} else {
|
||||||
|
filters |= QDir::AllEntries;
|
||||||
|
}
|
||||||
|
return dir.entryList(filters).count();
|
||||||
|
#else
|
||||||
|
// Taken from kdelibs/kio/kio/kdirmodel.cpp
|
||||||
|
// Copyright (C) 2006 David Faure <faure@kde.org>
|
||||||
|
|
||||||
|
int count = -1;
|
||||||
|
DIR* dir = ::opendir(QFile::encodeName(path));
|
||||||
|
if (dir) { // krazy:exclude=syscalls
|
||||||
|
count = 0;
|
||||||
|
struct dirent *dirEntry = 0;
|
||||||
|
while ((dirEntry = ::readdir(dir))) {
|
||||||
|
if (dirEntry->d_name[0] == '.') {
|
||||||
|
if (dirEntry->d_name[1] == '\0' || !countHiddenFiles) {
|
||||||
|
// Skip "." or hidden files
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (dirEntry->d_name[1] == '.' && dirEntry->d_name[2] == '\0') {
|
||||||
|
// Skip ".."
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If only directories are counted, consider an unknown file type and links also
|
||||||
|
// as directory instead of trying to do an expensive stat()
|
||||||
|
// (see bugs 292642 and 299997).
|
||||||
|
const bool countEntry = !countDirectoriesOnly ||
|
||||||
|
dirEntry->d_type == DT_DIR ||
|
||||||
|
dirEntry->d_type == DT_LNK ||
|
||||||
|
dirEntry->d_type == DT_UNKNOWN;
|
||||||
|
if (countEntry) {
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
::closedir(dir);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void KDirectoryContentsCounterWorker::countDirectoryContents(const QString& path, Options options)
|
||||||
|
{
|
||||||
|
emit result(path, subItemsCount(path, options));
|
||||||
|
}
|
71
src/kitemviews/private/kdirectorycontentscounterworker.h
Normal file
71
src/kitemviews/private/kdirectorycontentscounterworker.h
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2013 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 *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef KDIRECTORYCONTENTENTSCOUNTERWORKER_H
|
||||||
|
#define KDIRECTORYCONTENTENTSCOUNTERWORKER_H
|
||||||
|
|
||||||
|
#include <QFlags>
|
||||||
|
#include <QMetaType>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class QString;
|
||||||
|
|
||||||
|
class KDirectoryContentsCounterWorker : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Option {
|
||||||
|
NoOptions = 0x0,
|
||||||
|
CountHiddenFiles = 0x1,
|
||||||
|
CountDirectoriesOnly = 0x2
|
||||||
|
};
|
||||||
|
Q_DECLARE_FLAGS(Options, Option)
|
||||||
|
|
||||||
|
explicit KDirectoryContentsCounterWorker(QObject* parent = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Counts the items inside the directory \a path using the options
|
||||||
|
* \a options.
|
||||||
|
*
|
||||||
|
* @return The number of items.
|
||||||
|
*/
|
||||||
|
static int subItemsCount(const QString& path, Options options);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/**
|
||||||
|
* Signals that the directory \a path contains \a count items.
|
||||||
|
*/
|
||||||
|
void result(const QString& path, int count);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
/**
|
||||||
|
* Requests the number of items inside the directory \a path using the
|
||||||
|
* options \a options. The result is announced via the signal \a result.
|
||||||
|
*/
|
||||||
|
// Note that the full type name KDirectoryContentsCounterWorker::Options
|
||||||
|
// is needed here. Just using 'Options' is OK for the compiler, but
|
||||||
|
// confuses moc.
|
||||||
|
void countDirectoryContents(const QString& path, KDirectoryContentsCounterWorker::Options options);
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(KDirectoryContentsCounterWorker::Options)
|
||||||
|
Q_DECLARE_OPERATORS_FOR_FLAGS(KDirectoryContentsCounterWorker::Options)
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue