/****************************************************************************
                             Hyper's CD Catalog 
		A multiplatform qt and xml based catalog program
  
 Author    : Peter Deak (hyperr@freemail.hu)
 License   : GPL
 Copyright : (C) 2003 Peter Deak
****************************************************************************/

#include <qdir.h>
#include <qfile.h>
#include <qfileinfo.h>
#include <qpixmap.h>
#include <qevent.h>
#include <qpoint.h>
#include <qmessagebox.h>
#include <qdragobject.h>
#include <qmime.h>
#include <qstrlist.h>
#include <qstringlist.h>
#include <qapplication.h>
#include <qheader.h>
#include <qobject.h>

#include "dirview.h"
#include "icons.h"

/*****************************************************************************
 *
 * Class Directory
 *
 *****************************************************************************/

Directory::Directory( Directory * parent, const QString& filename )
    : QListViewItem( parent ), f(filename),
      pix( 0 )
{
    p = parent;
    readable = QDir( fullName() ).isReadable();

    if ( !readable )
	setPixmap( get_v_folderlocked_icon() );
    else
	setPixmap( get_v_folderclosed_icon() );
}


Directory::Directory( QListView * parent, const QString& filename )
    : QListViewItem( parent ), f(filename),
      pix( 0 )
{
    p = 0;
    readable = QDir( fullName() ).isReadable();
}


void Directory::setPixmap( QPixmap *px )
{
    pix = px;
    setup();
    widthChanged( 0 );
    invalidateHeight();
    repaint();
}


const QPixmap *Directory::pixmap( int i ) const
{
    if ( i )
	return 0;
    return pix;
}

void Directory::setOpen( bool o )
{
    if ( o )
	setPixmap( get_v_folderopen_icon() );
    else
	setPixmap( get_v_folderclosed_icon() );

    if ( o && !childCount() ) {
	QString s( fullName() );
	QDir thisDir( s );
	if ( !thisDir.isReadable() ) {
	    readable = FALSE;
	    setExpandable( FALSE );
	    return;
	}

	listView()->setUpdatesEnabled( FALSE );
	const QFileInfoList * files = thisDir.entryInfoList();
	if ( files ) {
	    QFileInfoListIterator it( *files );
	    QFileInfo * fi;
	    while( (fi=it.current()) != 0 ) {
		++it;
		if ( fi->fileName() == "." || fi->fileName() == ".." )
		    ; // nothing
		else if ( fi->isDir() )
		    (void)new Directory( this, fi->fileName() );
		else ;
	    }
	}
	listView()->setUpdatesEnabled( TRUE );
    }
    QListViewItem::setOpen( o );
}


void Directory::setup()
{
    setExpandable( TRUE );
    QListViewItem::setup();
}


QString Directory::fullName()
{
    QString s;
    if ( p ) {
	s = p->fullName();
	s.append( f.name() );
	s.append( "/" );
    } else {
	s = f.name();
    }
    return s;
}


QString Directory::text( int column ) const
{
    if ( column == 0 )
	return f.name();
    else if ( readable )
	return QObject::tr("Directory");
    else
	return QObject::tr("Unreadable Directory");
    return "";	
}

/*****************************************************************************
 *
 * Class DirectoryView
 *
 *****************************************************************************/

DirectoryView::DirectoryView( QWidget *parent, const char *name)
    : QListView( parent, name ),  oldCurrent( 0 ),
      dropItem( 0 ), mousePressed( FALSE )
{
    autoopen_timer = new QTimer( this );
    
    setShowSortIndicator(true);
    connect( this, SIGNAL( doubleClicked( QListViewItem * ) ),
	     this, SLOT( slotFolderSelected( QListViewItem * ) ) );

    connect( this, SIGNAL(pressed( QListViewItem * ) ),
	     this, SLOT( slotFolderSelectedR( QListViewItem * ) ) );

    connect( this, SIGNAL( returnPressed( QListViewItem * ) ),
	     this, SLOT( slotFolderSelectedR( QListViewItem * ) ) );

    setAcceptDrops( TRUE );
    viewport()->setAcceptDrops( TRUE );

    connect( autoopen_timer, SIGNAL( timeout() ),
	     this, SLOT( openFolder() ) );
	     
    addColumn(tr("Name"));
    setTreeStepSize(10);
    
    const QFileInfoList *roots=QDir::drives();
    QListIterator<QFileInfo> i(*roots);
    QFileInfo* fi;
#ifdef _WIN32
    ++i; //Skip reading floppy drive on startup.
#endif
    while ( (fi = *i) ) {
       ++i;
       Directory * root = new Directory( this, fi->filePath() );
       if(roots->count() <= 1)
          root->setOpen( TRUE ); // be interesting
     }
    setAllColumnsShowFocus( TRUE );
    repaint();
    sDir = "";
}

void DirectoryView::slotFolderSelected( QListViewItem *i )
{
    if(i==NULL) return;
    Directory *dir = (Directory*)i;
    emit folderSelected( dir->fullName() );
}

void DirectoryView::slotFolderSelectedR( QListViewItem *i )
{
    if(i==NULL) return;
    Directory *dir = (Directory*)i;
    sDir = dir->fullName();
    emit folderSelected( dir->fullName() );
}


void DirectoryView::openFolder()
{
    autoopen_timer->stop();
    if ( dropItem && !dropItem->isOpen() ) {
	dropItem->setOpen( TRUE );
	dropItem->repaint();
    }
}

static const int autoopenTime = 750;

QString DirectoryView::fullPath(QListViewItem* item)
{
    QString fullpath = item->text(0);
    while ( (item=item->parent()) ) {
	if ( item->parent() )
	    fullpath = item->text(0) + "/" + fullpath;
	else
	    fullpath = item->text(0) + fullpath;
    }
    return fullpath;
}

void DirectoryView::contentsMousePressEvent( QMouseEvent* e )
{
    QListView::contentsMousePressEvent(e);
    QPoint p( contentsToViewport( e->pos() ) );
    QListViewItem *i = itemAt( p );
    if ( i ) {
	// if the user clicked into the root decoration of the item, don't try to start a drag!
	if ( p.x() > header()->cellPos( header()->mapToActual( 0 ) ) +
	     treeStepSize() * ( i->depth() + ( rootIsDecorated() ? 1 : 0) ) + itemMargin() ||
	     p.x() < header()->cellPos( header()->mapToActual( 0 ) ) ) {
	    presspos = e->pos();
	    mousePressed = TRUE;
	}
    }
    
}


void DirectoryView::contentsMouseReleaseEvent( QMouseEvent * )
{
    mousePressed = FALSE;
}

void DirectoryView::setDir( const QString &s )
{
    QListViewItemIterator it( this );
    ++it;
    for ( ; it.current(); ++it ) {
	it.current()->setOpen( FALSE );
    }

    QStringList lst( QStringList::split(
#ifdef _WIN32    
     "\\"
#else
     "/"
#endif     
     , s ) );
     
    QListViewItem *item = firstChild();
    QStringList::Iterator it2 = lst.begin();
    for ( ; it2 != lst.end(); ++it2 ) {
	while ( item ) {
	    if ( item->text( 0 ) == *it2 ) {
		item->setOpen( TRUE );
		break;
	    }
	    item = item->itemBelow();
	}
    }

    if ( item )
	setCurrentItem( item );
}

void FileItem::setPixmap( QPixmap *p )
{
    pix = p;
    setup();
    widthChanged( 0 );
    invalidateHeight();
    repaint();
}


const QPixmap *FileItem::pixmap( int i ) const
{
    if ( i )
	return 0;
    return pix;
}
