File indexing completed on 2024-05-05 17:56:56
0001 /* 0002 SPDX-FileCopyrightText: 2017-2022 Krusader Krew <https://krusader.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "sizecalculator.h" 0008 0009 // QtCore 0010 #include <QDebug> 0011 #include <QTimer> 0012 0013 #include <KIO/StatJob> 0014 0015 #include "fileitem.h" 0016 #include "virtualfilesystem.h" 0017 0018 SizeCalculator::SizeCalculator(const QList<QUrl> &urls) 0019 : QObject(nullptr) 0020 , m_urls(urls) 0021 , m_nextUrls(urls) 0022 , m_totalSize(0) 0023 , m_totalFiles(0) 0024 , m_totalDirs(0) 0025 , m_canceled(false) 0026 , m_directorySizeJob(nullptr) 0027 { 0028 QTimer::singleShot(0, this, &SizeCalculator::start); 0029 } 0030 0031 SizeCalculator::~SizeCalculator() 0032 { 0033 if (m_directorySizeJob) 0034 m_directorySizeJob->kill(); 0035 } 0036 0037 void SizeCalculator::start() 0038 { 0039 emit started(); 0040 nextUrl(); 0041 } 0042 0043 void SizeCalculator::add(const QUrl &url) 0044 { 0045 m_urls.append(url); 0046 m_nextUrls.append(url); 0047 emitProgress(); 0048 } 0049 0050 KIO::filesize_t SizeCalculator::totalSize() const 0051 { 0052 return m_totalSize + (m_directorySizeJob ? m_directorySizeJob->totalSize() : 0); 0053 } 0054 0055 unsigned long SizeCalculator::totalFiles() const 0056 { 0057 return m_totalFiles + (m_directorySizeJob ? m_directorySizeJob->totalFiles() : 0); 0058 } 0059 0060 unsigned long SizeCalculator::totalDirs() const 0061 { 0062 return m_totalDirs + (m_directorySizeJob ? m_directorySizeJob->totalSubdirs() : 0); 0063 } 0064 0065 void SizeCalculator::cancel() 0066 { 0067 m_canceled = true; 0068 if (m_directorySizeJob) 0069 m_directorySizeJob->kill(); 0070 0071 done(); 0072 } 0073 0074 void SizeCalculator::nextUrl() 0075 { 0076 if (m_canceled) 0077 return; 0078 0079 emitProgress(); 0080 0081 if (!m_currentUrl.isEmpty()) 0082 emit calculated(m_currentUrl, m_currentUrlSize); 0083 m_currentUrlSize = 0; 0084 0085 if (m_nextUrls.isEmpty()) { 0086 done(); 0087 return; 0088 } 0089 m_currentUrl = m_nextUrls.takeFirst(); 0090 0091 if (m_currentUrl.scheme() == "virt") { 0092 // calculate size of all files/directories in this virtual directory 0093 auto *fs = new VirtualFileSystem(); 0094 if (!fs->scanDir(m_currentUrl)) { 0095 qWarning() << "cannot scan virtual FS, URL=" << m_currentUrl.toDisplayString(); 0096 nextUrl(); 0097 return; 0098 } 0099 const QList<FileItem *> fileItems = fs->fileItems(); 0100 for (FileItem *file : fileItems) 0101 m_nextSubUrls << file->getUrl(); 0102 delete fs; 0103 } else { 0104 m_nextSubUrls << m_currentUrl; 0105 } 0106 0107 nextSubUrl(); 0108 } 0109 0110 void SizeCalculator::nextSubUrl() 0111 { 0112 if (m_canceled) 0113 return; 0114 0115 if (m_nextSubUrls.isEmpty()) { 0116 nextUrl(); 0117 return; 0118 } 0119 0120 const QUrl url = m_nextSubUrls.takeFirst(); 0121 KIO::StatJob *statJob = KIO::stat(url, KIO::HideProgressInfo); 0122 connect(statJob, &KIO::Job::result, this, &SizeCalculator::slotStatResult); 0123 } 0124 0125 void SizeCalculator::slotStatResult(KJob *job) 0126 { 0127 if (m_canceled) 0128 return; 0129 0130 if (job->error()) { 0131 qWarning() << "stat job failed, error=" << job->error() << "; error string=" << job->errorString(); 0132 nextSubUrl(); 0133 return; 0134 } 0135 0136 const KIO::StatJob *statJob = dynamic_cast<KIO::StatJob *>(job); 0137 const QUrl &url = statJob->url(); 0138 0139 const KFileItem kfi(statJob->statResult(), url, true); 0140 if (kfi.isFile() || kfi.isLink()) { 0141 m_totalFiles++; 0142 m_totalSize += kfi.size(); 0143 m_currentUrlSize += kfi.size(); 0144 nextSubUrl(); 0145 return; 0146 } 0147 0148 // URL should be a directory, we are always counting the directory itself 0149 m_totalDirs++; 0150 0151 m_directorySizeJob = KIO::directorySize(url); 0152 connect(m_directorySizeJob.data(), &KIO::Job::result, this, &SizeCalculator::slotDirectorySizeResult); 0153 } 0154 0155 void SizeCalculator::slotDirectorySizeResult(KJob *) 0156 { 0157 if (!m_directorySizeJob->error()) { 0158 m_totalSize += m_directorySizeJob->totalSize(); 0159 // do not count filesystem size of empty directories for this current directory 0160 m_currentUrlSize += m_directorySizeJob->totalFiles() == 0 ? 0 : m_directorySizeJob->totalSize(); 0161 m_totalFiles += m_directorySizeJob->totalFiles(); 0162 m_totalDirs += m_directorySizeJob->totalSubdirs(); 0163 } 0164 m_directorySizeJob = nullptr; 0165 nextSubUrl(); 0166 } 0167 0168 void SizeCalculator::done() 0169 { 0170 emit finished(m_canceled); 0171 deleteLater(); 0172 } 0173 0174 void SizeCalculator::emitProgress() 0175 { 0176 emit progressChanged(((m_urls.length() - m_nextUrls.length()) * 100) / m_urls.length()); 0177 }