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.
239 lines
6.2 KiB
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> //tqstrdup
|
|
#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( tqstrdup( 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( tqstrdup( 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 = tqstrdup( 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
|