File indexing completed on 2024-05-26 17:06:05

0001 /*
0002     SPDX-FileCopyrightText: 2003-2004 Max Howell <max.howell@methylblue.com>
0003     SPDX-FileCopyrightText: 2004-2022 Krusader Krew <https://krusader.org>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "builder.h"
0009 #include "Config.h"
0010 #include "widget.h"
0011 
0012 // QtCore
0013 #include <QLocale>
0014 
0015 #include <KI18n/KLocalizedString>
0016 
0017 //**** REMOVE NEED FOR the +1 with MAX_RING_DEPTH uses
0018 //**** add some angle bounds checking (possibly in Segment ctor? can I delete in a ctor?)
0019 //**** this class is a mess
0020 
0021 RadialMap::Builder::Builder(RadialMap::Map *m, const Directory *const d, bool fast)
0022     : m_map(m)
0023     , m_root(d)
0024     , m_minSize(static_cast<FileSize>(static_cast<long double>(d->size() * 3) / (PI * m->height() - m->MAP_2MARGIN)))
0025     , m_depth(&m->m_visibleDepth)
0026 {
0027     m_signature = new Chain<Segment>[*m_depth + 1];
0028 
0029     if (!fast) { //|| *m_depth == 0 ) //depth 0 is special case usability-wise //**** WHY?!
0030         // determine depth rather than use old one
0031         findVisibleDepth(d); // sets m_depth
0032     }
0033 
0034     m_map->setRingBreadth();
0035     setLimits(m_map->m_ringBreadth);
0036     build(d);
0037 
0038     m_map->m_signature = m_signature;
0039 
0040     delete[] m_limits;
0041 }
0042 
0043 void RadialMap::Builder::findVisibleDepth(const Directory *const dir, const unsigned int depth)
0044 {
0045     //**** because I don't use the same minimumSize criteria as in the visual function
0046     //     this can lead to incorrect visual representation
0047     //**** BUT, you can't set those limits until you know m_depth!
0048 
0049     //**** also this function doesn't check to see if anything is actually visible
0050     //     it just assumes that when it reaches a new level everything in it is visible
0051     //     automatically. This isn't right especially as there might be no files in the
0052     //     dir provided to this function!
0053 
0054     static uint stopDepth = 0;
0055 
0056     if (dir == m_root) {
0057         stopDepth = *m_depth;
0058         *m_depth = 0;
0059     }
0060 
0061     if (*m_depth < depth)
0062         *m_depth = depth;
0063     if (*m_depth >= stopDepth)
0064         return;
0065 
0066     for (ConstIterator<File> it = dir->constIterator(); it != dir->end(); ++it)
0067         if ((*it)->isDir() && (*it)->size() > m_minSize)
0068             findVisibleDepth(dynamic_cast<const Directory *>(*it), depth + 1); // if no files greater than min size the depth is still recorded
0069 }
0070 
0071 void RadialMap::Builder::setLimits(const uint &b) // b = breadth?
0072 {
0073     long double size3 = m_root->size() * 3;
0074     long double pi2B = PI * 2 * b;
0075 
0076     m_limits = new FileSize[*m_depth + 1]; // FIXME delete!
0077 
0078     for (unsigned int d = 0; d <= *m_depth; ++d)
0079         m_limits[d] = static_cast<FileSize>(size3 / (pi2B * (d + 1))); // min is angle that gives 3px outer diameter for that depth
0080 }
0081 
0082 //**** segments currently overlap at edges (i.e. end of first is start of next)
0083 bool RadialMap::Builder::build(const Directory *const dir, const unsigned int depth, unsigned int a_start, const unsigned int a_end)
0084 {
0085     // first iteration: dir == m_root
0086 
0087     if (dir->fileCount() == 0) // we do fileCount rather than size to avoid chance of divide by zero later
0088         return false;
0089 
0090     FileSize hiddenSize = 0;
0091     uint hiddenFileCount = 0;
0092 
0093     for (ConstIterator<File> it = dir->constIterator(); it != dir->end(); ++it) {
0094         if ((*it)->size() > m_limits[depth]) {
0095             auto a_len = (unsigned int)(5760 * ((double)(*it)->size() / (double)m_root->size()));
0096 
0097             auto *s = new Segment(*it, a_start, a_len);
0098 
0099             (m_signature + depth)->append(s);
0100 
0101             if ((*it)->isDir()) {
0102                 if (depth != *m_depth) {
0103                     // recurse
0104                     s->m_hasHiddenChildren = build(dynamic_cast<const Directory *>(*it), depth + 1, a_start, a_start + a_len);
0105                 } else
0106                     s->m_hasHiddenChildren = true;
0107             }
0108 
0109             a_start += a_len; //**** should we add 1?
0110 
0111         } else {
0112             hiddenSize += (*it)->size();
0113 
0114             if ((*it)->isDir()) //**** considered virtual, but dir wouldn't count itself!
0115                 hiddenFileCount += dynamic_cast<const Directory *>(*it)->fileCount(); // need to add one to count the dir as well
0116 
0117             ++hiddenFileCount;
0118         }
0119     }
0120 
0121     if (hiddenFileCount == dir->fileCount() && !Config::showSmallFiles)
0122 
0123         return true;
0124 
0125     else if ((Config::showSmallFiles && hiddenSize > m_limits[depth]) || (depth == 0 && (hiddenSize > dir->size() / 8)) /*|| > size() * 0.75*/) {
0126         // append a segment for unrepresented space - a "fake" segment
0127 
0128         const QString s = i18np("%1 file: ~ %2", "%1 files: ~ %2", QLocale().toString(hiddenFileCount), File::humanReadableSize(hiddenSize / hiddenFileCount));
0129         (m_signature + depth)->append(new Segment(new File(s, hiddenSize), a_start, a_end - a_start, true));
0130     }
0131 
0132     return false;
0133 }