/***************************************************************************
                          kbeardirview.cpp  -  description
                             -------------------
    begin                : Sun Jun 4 2000
    copyright            : (C) 2000 by Björn Sahlström
    email                : kbjorn@users.sourceforge.net
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

//////////////////////////////////////////////////////////////////////
// Qt specific include files
#include <qstringlist.h>
#include <qpoint.h>
#include <qpixmap.h>
#include <qmap.h>
#include <qapplication.h>
#include <qcursor.h>
//////////////////////////////////////////////////////////////////////
// KDE specific include files
#include <kstandarddirs.h>
#include <kurl.h>
#include <kiconloader.h>
#include <kfileitem.h>
#include <kglobal.h>
#include <kurldrag.h>
#include <kdebug.h>
//////////////////////////////////////////////////////////////////////
// Application specific include files
#include "kbeardirview.h"
#include "misc.h"

using namespace KBear;

#include "kbeardirview.moc"
//-----------------------------------------------
class KBearDirViewPrivate {
	public:
};
//-----------------------------------------------
KBearDirView::KBearDirView( QWidget *parent, const char *name, const SiteInfo& s )
	 : KBearTreeView(parent,name), m_animationTimer(this),
		m_animationCounter( 0 ), m_animatedItem( 0L ), m_siteInfo( s )
{
	setFullWidth( false );
	loadAnimationPixmaps();
	setCurrentItem( 0 );
	connect( &m_animationTimer, SIGNAL( timeout() ), this, SLOT( slotAnimation() ) );
	connect( this , SIGNAL( expanded( QListViewItem* ) ), this, SLOT( slotExpanded( QListViewItem* ) ) );
//	connect( this, SIGNAL( executed( QListViewItem* ) ), this, SLOT( slotExecuted( QListViewItem*) ) );
}
//-----------------------------------------------
KBearDirView::~KBearDirView(){
}
//-----------------------------------------------
void KBearDirView::slotExpanded( QListViewItem* item ) {
	if( ! item )
		return;
	KBearDirViewItem* dirItem = static_cast<KBearDirViewItem*>(item);
	if( dirItem->url().path(+1) != m_url.path(+1) ) {
		ensureItemVisible( item );
		setCurrentItem( item );
		setSelected( item, true );
//		kdDebug()<<"KBearDirView::slotExpanded emitting folderSelected()"<<endl;
		emit folderSelected( dirItem );
	}
}
//-----------------------------------------------
void KBearDirView::slotExecuted( QListViewItem* item ) {
//	kdDebug()<<"KBearDirView::slotExecuted()"<<endl;
	if( ! item|| ! item->isExpandable()  )
		return;
	
	ensureItemVisible( item );
	setCurrentItem( item );
	setSelected( item, true );
	item->setOpen( ! item->isOpen() );
//	kdDebug()<<"KBearDirView::slotExecuted()"<<endl;
	KBearDirViewItem* dirItem = static_cast<KBearDirViewItem*>(item);
	if( dirItem->url().path(+1) != m_url.path(+1) ) {
	// we only emit if folderSelected it's closed, when opening slotExpanded takes care of emitting
//	if( ! item->isOpen() ) {
//		kdDebug()<<"KBearDirView::slotExecuted emitting folderSelected()"<<endl;
		emit folderSelected( dirItem );
	}
}
//-----------------------------------------------
void KBearDirView::slotInsertItems( const KFileItemList & list)  {
	if( childCount() == 0 )
		rebuildNewTree();
	KFileItemListIterator it( list );
	for( ; it.current(); ++it ) {
		if( it.current()->isDir() )
			newDirEntry( it.current() );
	}
}
//-----------------------------------------------
void KBearDirView::newDirEntry( KFileItem* item ) {
	if( item->name() == ".."  )//|| ! currentItem()->isOpen())
		return;

	QListViewItem* i;
	i = currentItem()->firstChild();
	while( i ) {
		KBearDirViewItem* it = static_cast<KBearDirViewItem*>( i );
		if( it->url().path(1) == item->url().path(1) ){
			return;
		}
		else
			i = i->itemBelow();
	}
	QString text = item->text();
	if( item->url().path(1) == m_homeURL.path(1) )
		(void)new KBearDirViewItem( currentItem(), text, item, true );
	else
		(void)new KBearDirViewItem( currentItem(), text, item );
}
//-----------------------------------------------
void KBearDirView::slotSetURL( const KURL& url ){
//	kdDebug()<<"KBearDirView::slotSetURL()="<<url.prettyURL()<<endl;
	KURL oldURL = m_url;
	m_url = url;
	if( childCount() == 0 ) {
		rebuildNewTree();
		return;
	}
	QString currentPath = static_cast<KBearDirViewItem*>(firstChild())->url().path( +1 ) ;
	QStringList splittedRootPath( QStringList::split( "/", currentPath ) ); // split current root objects path
	if( m_url.path().left( currentPath.length() ) == currentPath ) {   // if selected path is below root path
		QListViewItemIterator it( this );
		QListViewItem *item = 0L;
		for ( ; it.current(); ++it ) {
			if ( static_cast<KBearDirViewItem*>(it.current())->url().path(1) == m_url.path(1) ) { // look if the path exists in the tree
				item = it.current();                                              // if it exists set item to path
				break;
			}
		}
		if( item && item->isExpandable() ) { // if item is set we have already been here
			blockSignals( true );
			ensureItemVisible( item );
			setCurrentItem( item );              // and set it as current item
			setSelected( item, true );
			item->setOpen( true );
			blockSignals( false );
		}
		else { 							// if the path haven't been visited already
			clear();                          // then we have to rebuild the tree
			rebuildNewTree();
		}
	}
	else if( oldURL.upURL().path(+1) == m_url.path(+1) ) { // if one step up from root path
		QListViewItem *item = firstChild();
		KFileItem* fileItem = new KFileItem( KFileItem::Unknown, KFileItem::Unknown, m_url, false );
		KBearDirViewItem* root = new KBearDirViewItem( this, m_url.path(), fileItem, (m_url.path(1) == m_homeURL.path(1)));
		item->setText( 0, splittedRootPath.last() );
		moveItem( item, root, root );
		ensureItemVisible( root );
		setCurrentItem( root );
		setSelected( root, true );
		root->setOpen( true );
	}
	else { // if more than two step backwards from root
		clear();                                                             // then we have to rebuild the tree
		rebuildNewTree();
	}
//	triggerUpdate();
}
//-----------------------------------------------
void KBearDirView::rebuildNewTree(){
//	kdDebug()<<"KBearDirView::rebuildNewTree()"<<endl;
	KFileItem* fileItem = new KFileItem( KFileItem::Unknown, KFileItem::Unknown, m_url, false );
	QString path = m_url.path(+1);
	KBearDirViewItem* root = new KBearDirViewItem( this, path, fileItem, (m_url.path(1)== m_homeURL.path(1)) );
	setCurrentItem( root );
	setSelected ( root, true );
	root->setOpen( true );
}
//-----------------------------------------------
void KBearDirView::slotPrepareForReread( const KURL& url ){
//	kdDebug()<<"KBearDirView::slotPrepareForReread()="<<url.prettyURL()<<endl;
	if( ! childCount() )
		return;
	QListViewItemIterator it( this );
	QListViewItem *item = 0L;
	for ( ; it.current(); ++it ) {
		if ( static_cast<KBearDirViewItem*>(it.current())->url().path(1) == url.path(1) ) { // look if the path exists in the tree
			item = it.current()->firstChild();  // if it exists set item first child
			while( item ) {
				QListViewItem* i = item;
				item = item->nextSibling();
				delete i;
			}
			return;
		}
	}
}
//-----------------------------------------------
void KBearDirView::slotToggleShowHidden( bool showHidden ){
	if( ! showHidden )    // if we should hide all hidden items
		deleteHiddenItems();
}
//-----------------------------------------------
bool KBearDirView::acceptDrag(QDropEvent* e ) const {
	return QUriDrag::canDecode( e )
			&& acceptDrops()
			&& dragEnabled();
}
//-----------------------------------------------
void KBearDirView::deleteHiddenItems(){
	QListViewItemIterator it ( this );
	for( ; it.current(); ++it ) {
		if( static_cast<KBearDirViewItem*>(it.current())->name()[ 0 ] == '.' )
			delete it.current();
	}
}
//-----------------------------------------------
/** Called whenever an item has been deleted */
void KBearDirView::slotDeleteItem( KFileItem* item ){
	deleteItem( item->url().path(1) );
}
//-----------------------------------------------
void KBearDirView::deleteItem( const QString& delPath ){
	QListViewItemIterator it ( this );
	for( ; it.current(); ++it ) {
		if( static_cast<KBearDirViewItem*>( it.current() )->url().path(1) == delPath ) {
			delete it.current();
			return;
		}
	}
}
//-----------------------------------------------
void KBearDirView::contentsDropEvent( QDropEvent* e ) {
	m_autoOpenTimer.stop();
	m_dropItem = 0L;

	if( ! acceptDrag( e ) ) {
		e->acceptAction( false );
		return;
	}
	e->acceptAction();				
	// the drop was accepted so lets emit this to the outside world
	emit dropped( e, QCursor::pos() );
}
//-----------------------------------------------
void KBearDirView::startDrag() {
	KURL::List urls;
	QMap<QString, QString> metaData;
	KBearDirViewItem* item = static_cast<KBearDirViewItem*>( selectedItem() );
	QPixmap pixmap = *item->KBearTreeViewItem::pixmap();
	urls.append( item->url() );
	metaData.insert( item->url().url(), item->mimetype() );
	if( urls.count() > 1 )
		pixmap = DesktopIcon( "kmultiple", 16 );

	QPoint hotspot;
	hotspot.setX( pixmap.width() / 2 );
	hotspot.setY( pixmap.height() / 2 );

	metaData.insert( "SourceID", QString::number( m_siteInfo.ID() ) );
	KURLDrag* dragObject = KURLDrag::newDrag( urls, metaData, parentWidget() );

	dragObject->setPixmap( pixmap, hotspot );
	dragObject->drag();   // start the drag
}
//-----------------------------------------------
void KBearDirView::setHomeURL( const KURL& url ){
	m_homeURL = url;
}
//-----------------------------------------------
void KBearDirView::slotAnimation() {
	QPixmap p( m_animationList[ m_animationCounter ] );
	// We don't call KBearDirViewItem:s setPixmap function here
	// since we want to keep original pixmap for restoration in slotStopAnimation
//	QListViewItem* item = currentItem();
	if( m_animatedItem ) {
		m_animatedItem->QListViewItem::setPixmap( 0, p );
		m_animationCounter = (++m_animationCounter % 6 );
	}
	QApplication::flushX();
}
//-----------------------------------------------
void KBearDirView::slotStartAnimation() {
	if( m_animatedItem )
		slotStopAnimation();
	if ( ! m_animationTimer.isActive() ) {
		m_animatedItem = currentItem();
		m_animationCounter = 0;
		m_animationTimer.start( 75 );
	}
}
//-----------------------------------------------
void KBearDirView::slotStopAnimation() {
	m_animationTimer.stop();
	if( ! m_animatedItem )
		return;

	KBearDirViewItem* item = static_cast<KBearDirViewItem*>(m_animatedItem);
	// Here we can call the KBearDirViewItems:s own function to get original pixmap
	if( item )
		item->QListViewItem::setPixmap( 0, *item->KBearTreeViewItem::pixmap() );
	m_animatedItem = 0L;
}
//-----------------------------------------------
void KBearDirView::loadAnimationPixmaps() {
	QString tmp;
	for( int i = 1; i <= 6; i++ )	{
		tmp = locate( "appdata", QString("icons/hicolor/16x16/actions/kde%1.png").arg( i ) );
		m_animationList << tmp;
	}
}
//-----------------------------------------------
