diff --git a/krusader/FileSystem/CMakeLists.txt b/krusader/FileSystem/CMakeLists.txt index 5ac61612..1fc66d5a 100644 --- a/krusader/FileSystem/CMakeLists.txt +++ b/krusader/FileSystem/CMakeLists.txt @@ -1,26 +1,27 @@ include_directories(${KF5_INCLUDES_DIRS} ${QT_INCLUDES}) set(FileSystem_SRCS defaultfilesystem.cpp dirlisterinterface.cpp fileitem.cpp filesystem.cpp filesystemprovider.cpp krpermhandler.cpp krquery.cpp krtrashhandler.cpp + sizecalculator.cpp virtualfilesystem.cpp ../../krArc/krlinecountingprocess.cpp ) add_library(FileSystem STATIC ${FileSystem_SRCS}) target_link_libraries(FileSystem KF5::I18n KF5::KIOCore KF5::KIOWidgets ) if(ACL_FOUND) target_link_libraries(FileSystem ${ACL_LIBS}) endif(ACL_FOUND) diff --git a/krusader/FileSystem/sizecalculator.cpp b/krusader/FileSystem/sizecalculator.cpp new file mode 100644 index 00000000..45e5f641 --- /dev/null +++ b/krusader/FileSystem/sizecalculator.cpp @@ -0,0 +1,158 @@ +/***************************************************************************** + * Copyright (C) 2017 Krusader Krew * + * * + * 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 package 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 package; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *****************************************************************************/ + +#include "sizecalculator.h" + +// QtCore +#include + +#include "virtualfilesystem.h" +#include "../krglobal.h" + +SizeCalculator::SizeCalculator(const QList &urls) + : QObject(nullptr), m_urls(urls), m_nextUrls(urls), m_totalSize(0), m_totalFiles(0), + m_totalDirs(0), m_canceled(false), m_directorySizeJob(nullptr) +{ + QTimer::singleShot(0, this, SLOT(nextUrl())); +} + +SizeCalculator::~SizeCalculator() +{ + if (m_directorySizeJob) + m_directorySizeJob->kill(); +} + +KIO::filesize_t SizeCalculator::totalSize() const +{ + return m_totalSize + (m_directorySizeJob ? m_directorySizeJob->totalSize() : 0); +} + +unsigned long SizeCalculator::totalFiles() const +{ + return m_totalFiles + (m_directorySizeJob ? m_directorySizeJob->totalFiles() : 0); +} + +unsigned long SizeCalculator::totalDirs() const +{ + return m_totalDirs + (m_directorySizeJob ? m_directorySizeJob->totalSubdirs() : 0); +} + +void SizeCalculator::cancel() +{ + m_canceled = true; + if (m_directorySizeJob) + m_directorySizeJob->kill(); + + done(); +} + +void SizeCalculator::nextUrl() +{ + if (m_canceled) + return; + + if (!m_currentUrl.isEmpty()) + emit calculated(m_currentUrl, m_currentUrlSize); + m_currentUrlSize = 0; + + if (m_nextUrls.isEmpty()) { + done(); + return; + } + m_currentUrl = m_nextUrls.takeFirst(); + + if (m_currentUrl.scheme() == "virt") { + // calculate size of all files/directories in this virtual directory + VirtualFileSystem *fs = new VirtualFileSystem(); + if (!fs->refresh(m_currentUrl)) { + krOut << "cannot refresh virtual fs, url=" << m_currentUrl; + nextUrl(); + return; + } + for (FileItem *file : fs->fileItems()) + m_nextSubUrls << file->getUrl(); + delete fs; + } else { + m_nextSubUrls << m_currentUrl; + } + + nextSubUrl(); +} + +void SizeCalculator::nextSubUrl() +{ + if (m_canceled) + return; + + if (m_nextSubUrls.isEmpty()) { + nextUrl(); + return; + } + + const QUrl url = m_nextSubUrls.takeFirst(); + KIO::StatJob *statJob = KIO::stat(url, KIO::HideProgressInfo); + connect(statJob, &KIO::Job::result, this, &SizeCalculator::slotStatResult); +} + +void SizeCalculator::slotStatResult(KJob *job) +{ + if (m_canceled) + return; + + if (job->error()) { + krOut << "stat job failed"; + nextSubUrl(); + return; + } + + const KIO::StatJob *statJob = static_cast(job); + const QUrl url = statJob->url(); + + const KFileItem kfi(statJob->statResult(), url, true); + if (kfi.isFile() || kfi.isLink()) { + m_totalFiles++; + m_totalSize += kfi.size(); + m_currentUrlSize += kfi.size(); + nextSubUrl(); + return; + } + + // URL should be a directory, we are always counting the directory itself + m_totalDirs++; + + m_directorySizeJob = KIO::directorySize(url); + connect(m_directorySizeJob, &KIO::Job::result, this, &SizeCalculator::slotDirectorySizeResult); +} + +void SizeCalculator::slotDirectorySizeResult(KJob *) +{ + if (!m_directorySizeJob->error()) { + m_totalSize += m_directorySizeJob->totalSize(); + m_currentUrlSize += m_directorySizeJob->totalSize(); + m_totalFiles += m_directorySizeJob->totalFiles(); + m_totalDirs += m_directorySizeJob->totalSubdirs(); + } + m_directorySizeJob = 0; + nextSubUrl(); +} + +void SizeCalculator::done() +{ + emit finished(m_canceled); + deleteLater(); +} diff --git a/krusader/FileSystem/sizecalculator.h b/krusader/FileSystem/sizecalculator.h new file mode 100644 index 00000000..b5e9bf37 --- /dev/null +++ b/krusader/FileSystem/sizecalculator.h @@ -0,0 +1,92 @@ +/***************************************************************************** + * Copyright (C) 2017 Krusader Krew * + * * + * 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 package 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 package; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *****************************************************************************/ + +#ifndef SIZECALCULATOR_H +#define SIZECALCULATOR_H + +// QtCore +#include +#include + +#include + +/** + * Calculate the size of files and directories (recursive). + * + * Krusader's virtual filesystem and all KIO protocols are supported. + * + * This calculator will delete itself when its finished (like KJob). + */ +class SizeCalculator : public QObject +{ + Q_OBJECT +public: + /** + * Calculate the size of files and directories defined by URLs. + * + * The calculation is automatically started (like KJob). + */ + explicit SizeCalculator(const QList &urls); + ~SizeCalculator(); + + /** Return the URLs this calculator was created with. */ + QList urls() const { return m_urls; } + /** Return the current total size calculation result. */ + KIO::filesize_t totalSize() const; + /** Return the current total number of files counted. */ + unsigned long totalFiles() const; + /** Return the current number of directories counted. */ + unsigned long totalDirs() const; + +public slots: + /** Cancel the calculation and mark for deletion. finished() will be emitted.*/ + void cancel(); + +signals: + /** Emitted when an intermediate size for one of the URLs was calculated. */ + void calculated(const QUrl &url, KIO::filesize_t size); + /** Emitted when calculation is finished or was canceled. Calculator will be deleted afterwards. */ + void finished(bool canceled); + +private: + void nextSubUrl(); + void done(); + +private slots: + void nextUrl(); + void slotStatResult(KJob *job); + void slotDirectorySizeResult(KJob *job); + +private: + const QList m_urls; + + QList m_nextUrls; + QUrl m_currentUrl; + QList m_nextSubUrls; + + KIO::filesize_t m_currentUrlSize; + KIO::filesize_t m_totalSize; + unsigned long m_totalFiles; + unsigned long m_totalDirs; + + bool m_canceled; + + QPointer m_directorySizeJob; +}; + +#endif // SIZECALCULATOR_H