//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_children ( 0 ) { } //DON'T pass the full path!
uint children ( ) const { return m_children ; }
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_children + = d - > children ( ) ; //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_children + + ;
m_size + = p - > size ( ) ;
Chain < File > : : append ( p ) ;
}
uint m_children ;
private :
Directory ( const Directory & ) ; //undefined
void operator = ( const Directory & ) ; //undefined
} ;
# endif