You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
filelight/src/part/fileTree.h

239 lines
6.2 KiB

//Author: Max Howell <max.howell@methylblue.com>, (C) 2004
//Copyright: See COPYING file that comes with this distribution
#ifndef FILETREE_H
#define FILETREE_H
#include <tqcstring.h> //qstrdup
#include <tqfile.h> //decodeName()
#include <stdlib.h>
//TODO these are pointlessly general purpose now, make them incredibly specific
typedef unsigned long int FileSize;
typedef unsigned long int Dirsize; //**** currently unused
template <class T> class Iterator;
template <class T> class ConstIterator;
template <class T> class Chain;
template <class T>
class Link
{
public:
Link( T* const t ) : prev( this ), next( this ), data( t ) {}
Link() : prev( this ), next( this ), data( 0 ) {}
//TODO unlinking is slow and you don't use it very much in this context.
// ** Perhaps you can make a faster deletion system that doesn't bother tidying up first
// ** and then you MUST call some kind of detach() function when you remove elements otherwise
~Link() { delete data; unlink(); }
friend class Iterator<T>;
friend class ConstIterator<T>;
friend class Chain<T>;
private:
void unlink() { prev->next = next; next->prev = prev; prev = next = this; }
Link<T>* prev;
Link<T>* next;
T* data; //ensure only iterators have access to this
};
template <class T>
class Iterator
{
public:
Iterator() : link( 0 ) { } //**** remove this, remove this REMOVE THIS!!! dangerous as your implementation doesn't test for null links, always assumes they can be derefenced
Iterator( Link<T> *p ) : link( p ) { }
bool operator==( const Iterator<T>& it ) const { return link == it.link; }
bool operator!=( const Iterator<T>& it ) const { return link != it.link; }
bool operator!=( const Link<T> *p ) const { return p != link; }
//here we have a choice, really I should make two classes one const the other not
const T* operator*() const { return link->data; }
T* operator*() { return link->data; }
Iterator<T>& operator++() { link = link->next; return *this; } //**** does it waste time returning in places where we don't use the retval?
bool isNull() const { return (link == 0); } //REMOVE WITH ABOVE REMOVAL you don't want null iterators to be possible
void transferTo( Chain<T> &chain )
{
chain.append( remove() );
}
T* const remove() //remove from list, delete Link, data is returned NOT deleted
{
T* const d = link->data;
Link<T>* const p = link->prev;
link->data = 0;
delete link;
link = p; //make iterator point to previous element, YOU must check this points to an element
return d;
}
private:
Link<T> *link;
};
template <class T>
class ConstIterator
{
public:
ConstIterator( Link<T> *p ) : link( p ) { }
bool operator==( const Iterator<T>& it ) const { return link == it.link; }
bool operator!=( const Iterator<T>& it ) const { return link != it.link; }
bool operator!=( const Link<T> *p ) const { return p != link; }
const T* operator*() const { return link->data; }
ConstIterator<T>& operator++() { link = link->next; return *this; }
private:
const Link<T> *link;
};
template <class T>
class Chain
{
public:
virtual ~Chain() { empty(); }
void append( T* const data )
{
Link<T>* const link = new Link<T>( data );
link->prev = head.prev;
link->next = &head;
head.prev->next = link;
head.prev = link;
}
void transferTo( Chain &c )
{
if( isEmpty() ) return;
Link<T>* const first = head.next;
Link<T>* const last = head.prev;
head.unlink();
first->prev = c.head.prev;
c.head.prev->next = first;
last->next = &c.head;
c.head.prev = last;
}
void empty() { while( head.next != &head ) { delete head.next; } }
Iterator<T> iterator() const { return Iterator<T>( head.next ); }
ConstIterator<T> constIterator() const { return ConstIterator<T>( head.next ); }
const Link<T> *end() const { return &head; }
bool isEmpty() const { return head.next == &head; }
private:
Link<T> head;
void operator=( const Chain& );
};
class Directory;
class TQString;
class File
{
public:
friend class Directory;
enum UnitPrefix { kilo, mega, giga, tera };
static const uint DENOMINATOR[4];
public:
File( const char *name, FileSize size ) : m_parent( 0 ), m_name( qstrdup( name ) ), m_size( size ) {}
virtual ~File() { delete [] m_name; }
const Directory *parent() const { return m_parent; }
const char *name8Bit() const { return m_name; }
const FileSize size() const { return m_size; }
TQString name() const { return TQFile::decodeName( m_name ); }
virtual bool isDirectory() const { return false; }
TQString fullPath( const Directory* = 0 ) const;
TQString humanReadableSize( UnitPrefix key = mega ) const;
public:
static TQString humanReadableSize( uint size, UnitPrefix Key = mega );
protected:
File( const char *name, FileSize size, Directory *parent ) : m_parent( parent ), m_name( qstrdup( name ) ), m_size( size ) {}
Directory *m_parent; //0 if this is treeRoot
char *m_name;
FileSize m_size; //in units of KiB
private:
File( const File& );
void operator=( const File& );
};
class Directory : public Chain<File>, public File
{
public:
Directory( const char *name ) : File( name, 0 ), m_tqchildren( 0 ) {} //DON'T pass the full path!
uint tqchildren() const { return m_tqchildren; }
virtual bool isDirectory() const { return true; }
///appends a Directory
void append( Directory *d, const char *name=0 )
{
if( name ) {
delete [] d->m_name;
d->m_name = qstrdup( name ); } //directories that had a fullpath copy just their names this way
m_tqchildren += d->tqchildren(); //doesn't include the dir itself
d->m_parent = this;
append( (File*)d ); //will add 1 to filecount for the dir itself
}
///appends a File
void append( const char *name, FileSize size )
{
append( new File( name, size, this ) );
}
private:
void append( File *p )
{
m_tqchildren++;
m_size += p->size();
Chain<File>::append( p );
}
uint m_tqchildren;
private:
Directory( const Directory& ); //undefined
void operator=( const Directory& ); //undefined
};
#endif