File indexing completed on 2024-04-21 05:48:32

0001 /***********************************************************************
0002  * SPDX-FileCopyrightText: 2003-2004 Max Howell <max.howell@methylblue.com>
0003  * SPDX-FileCopyrightText: 2008-2009 Martin Sandsmark <martin.sandsmark@kde.org>
0004  * SPDX-FileCopyrightText: 2022 Harald Sitter <sitter@kde.org>
0005  *
0006  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0007  ***********************************************************************/
0008 
0009 #include "remoteLister.h"
0010 #include "filelight_debug.h"
0011 #include "scan.h"
0012 
0013 #include <QList>
0014 
0015 #include <kio_version.h>
0016 
0017 namespace Filelight
0018 {
0019 
0020 // You need to use a single DirLister.
0021 // One per folder breaks KIO (seemingly) and also uses un-godly amounts of memory!
0022 
0023 struct Store {
0024     /// location of the folder
0025     const QUrl url;
0026     /// the folder on which we are operating
0027     std::shared_ptr<Folder> folder;
0028     /// so we can reference the parent store
0029     const std::shared_ptr<Store> parent = nullptr;
0030     /// directories in this folder that need to be scanned before we can propagate()
0031     QList<std::shared_ptr<Store>> stores;
0032 
0033     Store(const QUrl &url_, const QString &name, const std::shared_ptr<Store> &parentStore)
0034         : url(url_)
0035         , folder(std::make_shared<Folder>((name + QLatin1Char('/')).toUtf8().constData()))
0036         , parent(parentStore)
0037     {
0038     }
0039     ~Store() = default;
0040 
0041 private:
0042     Q_DISABLE_COPY_MOVE(Store)
0043 };
0044 
0045 std::shared_ptr<Store> propagate(Store *store, const std::shared_ptr<Store> &root)
0046 {
0047     /// returns the next store available for scanning (or the root itself)
0048 
0049     while (store->parent) {
0050         qCDebug(FILELIGHT_LOG) << "propagate: " << store->url;
0051         store->parent->folder->append(store->folder);
0052         if (!store->parent->stores.isEmpty()) {
0053             return store->parent;
0054         }
0055         store = store->parent.get();
0056     }
0057 
0058     return root;
0059 }
0060 
0061 RemoteLister::RemoteLister(const QUrl &url, ScanManager *parent)
0062     : KDirLister(parent)
0063     , m_root(std::make_shared<Store>(url, url.url(), nullptr))
0064     , m_store(m_root)
0065     , m_manager(parent)
0066 {
0067     setShowHiddenFiles(true);
0068 
0069     // Use SIGNAL(result(KIO::Job*)) instead and then use Job::error()
0070     connect(this, static_cast<void (KCoreDirLister::*)()>(&KCoreDirLister::completed), this, &RemoteLister::onCompleted);
0071     connect(this, static_cast<void (KCoreDirLister::*)()>(&KCoreDirLister::canceled), this, &RemoteLister::onCanceled);
0072 }
0073 
0074 void RemoteLister::onCanceled()
0075 {
0076     qCDebug(FILELIGHT_LOG) << "Canceled";
0077     Q_EMIT branchCompleted(nullptr);
0078 }
0079 
0080 void RemoteLister::onCompleted()
0081 {
0082     // m_folder is set to the folder we should operate on
0083 
0084     const KFileItemList items = KDirLister::items();
0085     for (const auto &item : items) {
0086         if (item.isDir()) {
0087             m_store->stores << std::make_shared<Store>(item.url(), item.name(), m_store);
0088         } else {
0089             m_store->folder->append(item.name().toUtf8().constData(), item.size());
0090             m_manager->m_totalSize += item.size();
0091         }
0092 
0093         m_manager->m_files++;
0094     }
0095 
0096     if (m_store->stores.isEmpty()) {
0097         // no directories to scan, so we need to append ourselves to the parent folder
0098         // propagate() will return the next ancestor that has stores left to be
0099         // scanned, or root if we are done
0100         if (auto newStore = propagate(m_store.get(), m_root); newStore != m_store) {
0101             // We need to clean up old stores
0102             m_store = newStore;
0103         }
0104     }
0105 
0106     if (!m_store->stores.isEmpty()) {
0107         // we should operate with this store next time this function is called
0108         m_store = m_store->stores.takeFirst();
0109 
0110         const auto url = m_store->url;
0111         qCDebug(FILELIGHT_LOG) << "scanning: " << url;
0112         openUrl(url);
0113         return;
0114     }
0115 
0116     qCDebug(FILELIGHT_LOG) << "I think we're done";
0117     Q_ASSERT(m_root == m_store);
0118     Q_EMIT branchCompleted(m_store->folder);
0119 }
0120 
0121 RemoteLister::~RemoteLister()
0122 {
0123     stop();
0124 }
0125 
0126 } // namespace Filelight