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

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 #pragma once
0010 
0011 #include <cstdlib>
0012 
0013 #include <KFormat>
0014 
0015 #include <QByteArray>
0016 
0017 using FileSize = quint64;
0018 
0019 class Folder;
0020 namespace RadialMap
0021 {
0022 class Segment;
0023 } // namespace RadialMap
0024 
0025 class File
0026 {
0027     friend class Folder;
0028 
0029 public:
0030     File(const char *name, FileSize size)
0031         : m_parent(nullptr)
0032         , m_name(name)
0033         , m_size(size)
0034     {
0035     }
0036     virtual ~File() = default;
0037     File(const File &) = default;
0038     File &operator=(const File &) = default;
0039     File(File &&) = default;
0040     File &operator=(File &&) = default;
0041 
0042     QString segment() const
0043     {
0044         return m_segment;
0045     }
0046 
0047     void setSegment(const QString &segment)
0048     {
0049         Q_ASSERT(m_segment.isEmpty() || segment.isEmpty());
0050         m_segment = segment;
0051     }
0052 
0053     Folder *parent() const
0054     {
0055         return m_parent;
0056     }
0057 
0058     /** Do not use for user visible strings. Use name instead. */
0059     const char *name8Bit() const
0060     {
0061         return m_name.constData();
0062     }
0063     void setName(const QByteArray &newName)
0064     {
0065         m_name = newName;
0066     }
0067     /** Decoded name. Use when you need a QString. */
0068     QString decodedName() const
0069     {
0070         return QString::fromUtf8(m_name);
0071     }
0072     /**
0073      * Human readable name (including native separators where applicable).
0074      * Only use for display.
0075      */
0076     QString displayName() const;
0077 
0078     FileSize size() const
0079     {
0080         return m_size;
0081     }
0082 
0083     virtual bool isFolder() const
0084     {
0085         return false;
0086     }
0087 
0088     /**
0089      * Human readable path for display (including native separators where applicable.
0090      * Only use for display.
0091      */
0092     QString displayPath(const std::shared_ptr<Folder> &root = {}) const;
0093     QString humanReadableSize() const
0094     {
0095         return KFormat().formatByteSize(m_size);
0096     }
0097 
0098     /** Builds a complete QUrl by walking up to root. */
0099     QUrl url(const std::shared_ptr<Folder> &root = {}) const;
0100 
0101 protected:
0102     File(const char *name, FileSize size, Folder *parent)
0103         : m_parent(parent)
0104         , m_name(name)
0105         , m_size(size)
0106     {
0107     }
0108 
0109     Folder *m_parent; // 0 if this is treeRoot; this is a non-owning pointer, the parent owns "us"
0110     QByteArray m_name; // partial path name (e.g. 'boot/' or 'foo.svg')
0111     FileSize m_size; // in units of bytes; sum of all children's sizes
0112 
0113     QString m_segment;
0114 };
0115 
0116 class Folder : public File
0117 {
0118 public:
0119     explicit Folder(const char *name)
0120         : File(name, 0)
0121     {
0122     } // DON'T pass the full path!
0123 
0124     ~Folder() override;
0125     Folder(const Folder &) = default;
0126     Folder &operator=(const Folder &) = default;
0127     Folder(Folder &&) = default;
0128     Folder &operator=(Folder &&) = default;
0129 
0130     uint children() const
0131     {
0132         return m_children;
0133     }
0134     bool isFolder() const override
0135     {
0136         return true;
0137     }
0138 
0139     // Separate **static** function so we don't risk using this when we should be using clone.source!
0140     static void clone(const Folder *that, std::shared_ptr<Folder> other);
0141 
0142     std::shared_ptr<Folder> duplicate() const;
0143 
0144     /// appends a Folder
0145     void append(const std::shared_ptr<Folder> &d, const char *name = nullptr)
0146     {
0147         if (name) {
0148             d->m_name = name;
0149         } // directories that had a fullpath copy just their names this way
0150 
0151         m_children += d->children(); // doesn't include the dir itself
0152         Q_ASSERT(d->m_parent == this || d->m_parent == nullptr);
0153         d->m_parent = this;
0154 
0155         appendFile(d); // will add 1 to filecount for the dir itself
0156     }
0157 
0158     /// appends a File
0159     void append(const char *name, FileSize size)
0160     {
0161         appendFile(std::shared_ptr<File>(new File(name, size, this)));
0162     }
0163 
0164     /// removes a file
0165     void remove(const std::shared_ptr<File> &f)
0166     {
0167         files.removeAll(f);
0168         const FileSize childSize = f->size();
0169         for (Folder *d = this; d; d = d->parent()) {
0170             d->m_size -= childSize;
0171             d->m_children--;
0172         }
0173     }
0174 
0175     // Removes a file, but does not delete
0176     std::shared_ptr<Folder> take(const std::shared_ptr<Folder> &f)
0177     {
0178         files.removeAll(f);
0179         const FileSize childSize = f->size();
0180         for (Folder *d = this; d; d = d->parent()) {
0181             d->m_size -= childSize;
0182             d->m_children--;
0183         }
0184         return f;
0185     }
0186 
0187     QList<std::shared_ptr<File>> files;
0188 
0189 private:
0190     void appendFile(const std::shared_ptr<File> &p)
0191     {
0192         // This is also called by append(Folder), but only once all its children
0193         // were scanned. We do not need to forward the size change to our parent
0194         // since in turn we too only are added to our parent when we are have
0195         // been scanned already.
0196         m_children++;
0197         m_size += p->size();
0198         files.append(p);
0199     }
0200 
0201     uint m_children = 0;
0202 };