summaryrefslogtreecommitdiffstats
path: root/src/part/radialMap/builder.cpp
blob: 68dc382e8e260eb6905036ed6bdfbf010be82d1a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
//Author:    Max Howell <max.howell@methylblue.com>, (C) 2003-4
//Copyright: See COPYING file that comes with this distribution

#include "builder.h"
#include "Config.h"
#include "fileTree.h"
#include <kglobal.h> //locale object
#include <klocale.h>
#include "widget.h"


//**** REMOVE NEED FOR the +1 with MAX_RING_DEPTH uses
//**** add some angle bounds checking (possibly in Segment ctor? can I delete in a ctor?)
//**** this class is a mess

RadialMap::Builder::Builder( RadialMap::Map *m, const Directory* const d, bool fast )
  : m_map( m )
  , m_root( d )
  , m_minSize( static_cast<unsigned int>((d->size() * 3) / (PI * m->height() - m->MAP_2MARGIN )) )
  , m_depth( &m->m_visibleDepth )
{
    m_signature = new Chain<Segment> [*m_depth + 1];

    if( !fast )//|| *m_depth == 0 ) //depth 0 is special case usability-wise //**** WHY?!
    {
        //determine depth rather than use old one
        findVisibleDepth( d ); //sets m_depth
    }

    m_map->setRingBreadth();
    setLimits( m_map->m_ringBreadth );
    build( d );

    m_map->m_signature = m_signature;

    delete [] m_limits;
}


void
RadialMap::Builder::findVisibleDepth( const Directory* const dir, const unsigned int depth )
{
    //**** because I don't use the same minimumSize criteria as in the visual function
    //     this can lead to incorrect visual representation
    //**** BUT, you can't set those limits until you know m_depth!

    //**** also this function doesn't check to see if anything is actually visible
    //     it just assumes that when it reaches a new level everything in it is visible
    //     automatically. This isn't right especially as there might be no files in the
    //     dir provided to this function!

    static uint stopDepth = 0;

    if( dir == m_root )
    {
        stopDepth = *m_depth;
        *m_depth = 0;
    }

    if( *m_depth < depth ) *m_depth = depth;
    if( *m_depth >= stopDepth ) return;

    for( ConstIterator<File> it = dir->constIterator(); it != dir->end(); ++it )
        if( (*it)->isDirectory() && (*it)->size() > m_minSize )
            findVisibleDepth( (Directory *)*it, depth + 1 ); //if no files greater than min size the depth is still recorded
}

void
RadialMap::Builder::setLimits( const uint &b ) //b = breadth?
{
    double size3 = m_root->size() * 3;
    double pi2B   = PI * 2 * b;

    m_limits = new uint [*m_depth + 1]; //FIXME delete!

    for( unsigned int d = 0; d <= *m_depth; ++d )
        m_limits[d] = (uint)(size3 / (double)(pi2B * (d + 1))); //min is angle that gives 3px outer diameter for that depth
}


//**** segments currently overlap at edges (i.e. end of first is start of next)
bool
RadialMap::Builder::build( const Directory* const dir, const unsigned int depth, unsigned int a_start, const unsigned int a_end )
{
    //first iteration: dir == m_root

    if( dir->children() == 0 ) //we do fileCount rather than size to avoid chance of divide by zero later
        return false;

    uint hiddenSize = 0, hiddenFileCount = 0;

    for( ConstIterator<File> it = dir->constIterator(); it != dir->end(); ++it )
    {
        if( (*it)->size() > m_limits[depth] )
        {
            unsigned int a_len = (unsigned int)(5760 * ((double)(*it)->size() / (double)m_root->size()));

            Segment *s = new Segment( *it, a_start, a_len );

            (m_signature + depth)->append( s );

            if( (*it)->isDirectory() )
            {
                if( depth != *m_depth )
                {
                    //recurse
                    s->m_hasHiddenChildren = build( (Directory*)*it, depth + 1, a_start, a_start + a_len );
                }
                else s->m_hasHiddenChildren = true;
            }

            a_start += a_len; //**** should we add 1?

        } else {

            hiddenSize += (*it)->size();

            if( (*it)->isDirectory() ) //**** considered virtual, but dir wouldn't count itself!
                hiddenFileCount += static_cast<const Directory*>(*it)->children(); //need to add one to count the dir as well

            ++hiddenFileCount;
        }
    }

   if( hiddenFileCount == dir->children() && !Config::showSmallFiles )
      return true;

   else if( (Config::showSmallFiles && hiddenSize > m_limits[depth]) || (depth == 0 && (hiddenSize > dir->size()/8)) /*|| > size() * 0.75*/ )
   {
      //append a segment for unrepresented space - a "fake" segment

      // I dunno how to i18n this
      const QString s = i18n( "There can't ever be only 1 file", "%1 files, each about %2" )
         .arg( hiddenFileCount )
         .arg( File::humanReadableSize( hiddenSize/hiddenFileCount ) );

      (m_signature + depth)->append( new Segment( new File( s.local8Bit(), hiddenSize ), a_start, a_end - a_start, true ) );
   }

   return false;
}