File indexing completed on 2024-04-28 09:43:49
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: 2017-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 "fileTree.h" 0010 0011 #include <QDir> 0012 #include <QUrl> 0013 0014 #include "fileCleaner.h" 0015 #include "filelight_debug.h" 0016 0017 Folder::~Folder() 0018 { 0019 // Trees can be partially destroyed, make sure we remove the reference up to us, it's not a smart pointer 0020 // because that'd risk causing a loop. 0021 if (!m_parent) { 0022 for (auto &file : files) { 0023 file->m_parent = nullptr; 0024 } 0025 } 0026 FileCleaner::instance()->clean(files); 0027 } 0028 0029 QString File::displayName() const 0030 { 0031 const QString decodedName = QString::fromUtf8(m_name); 0032 return url().isLocalFile() ? QDir::toNativeSeparators(decodedName) : decodedName; 0033 } 0034 0035 QString File::displayPath(const std::shared_ptr<Folder> &root) const 0036 { 0037 // Use QUrl to sanitize the path for display and then run it through 0038 // QDir to make sure we use native path separators. 0039 const QUrl url = this->url(root); 0040 const QString cleanPath = url.toDisplayString(QUrl::PreferLocalFile | QUrl::NormalizePathSegments); 0041 return url.isLocalFile() ? QDir::toNativeSeparators(cleanPath) : cleanPath; 0042 } 0043 0044 QUrl File::url(const std::shared_ptr<Folder> &root) const 0045 { 0046 QString path; 0047 0048 // prevent returning empty string when there is something we could return 0049 const auto rootPtr = root.get() != this ? root.get() : nullptr; 0050 for (const File *d = this; d != rootPtr && d; d = d->parent()) { 0051 path.prepend(QString::fromUtf8(d->name8Bit())); 0052 } 0053 0054 return QUrl::fromUserInput(path, QString(), QUrl::AssumeLocalFile); 0055 } 0056 0057 void Folder::clone(const Folder *that, std::shared_ptr<Folder> other) 0058 { 0059 struct Clone { 0060 const Folder *source; 0061 std::shared_ptr<Folder> target; 0062 std::shared_ptr<Folder> parent; 0063 }; 0064 QList<Clone> completedClones; 0065 QList<Clone> clones({{that, other, nullptr}}); 0066 while (!clones.isEmpty()) { 0067 const auto &clone = clones.takeLast(); 0068 qCDebug(FILELIGHT_LOG) << "cloning" << clone.source->m_name << clone.source << "into" << clone.target.get() << "parent" << clone.parent.get(); 0069 for (const auto &file : clone.source->files) { 0070 qCDebug(FILELIGHT_LOG) << " " << file->displayName() << file->isFolder(); 0071 if (file->isFolder()) { 0072 auto folder = std::dynamic_pointer_cast<Folder>(file); 0073 clones.append(Clone{folder.get(), std::make_shared<Folder>(folder->m_name.constData()), clone.target}); 0074 } else { 0075 clone.target->append(file->m_name.constData(), file->m_size); 0076 } 0077 } 0078 completedClones.append(clone); 0079 } 0080 for (auto it = completedClones.rbegin(); it != completedClones.rend(); ++it) { 0081 // Appending forwards the size data, it must only happen after all duplicating is done so the sizes are known. 0082 // And obviously in reverse order of existence in the tree. 0083 auto clone = *it; 0084 if (clone.parent) { 0085 clone.parent->append(clone.target); 0086 } 0087 } 0088 } 0089 0090 std::shared_ptr<Folder> Folder::duplicate() const 0091 { 0092 // We completely detach the subtree upon duplication, otherwise we'd have parent pointers pointing back into 0093 // the old tree causing major headaches when trying to keep clean object states. This does take longer 0094 // because we need to create additional objects, but is safer overall. 0095 auto other = std::make_shared<Folder>(m_name.constData()); 0096 clone(this, other); 0097 return other; 0098 }