/***************************************************************************
                          dcfilebrowser.cpp  -  description
                             -------------------
    begin                : Fre Nov 29 2002
    copyright            : (C) 2002 by Mathias Küster
    email                : mathen@users.berlios.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include <qapplication.h>
#include <qregexp.h>
#include <qheader.h>
#include <qlabel.h>
#include <qpopupmenu.h>
#include <qcursor.h>
#include <qfiledialog.h>
#include <qtoolbutton.h>
#include <qcombobox.h>
#include <qtextcodec.h>
#include <qtooltip.h>
#include <qclipboard.h>
#include <qmessagebox.h>

#include <dcwidget.h>
#include <dcmenuhandler.h>
#include <dcconfig.h>
#include <dciconloader.h>

#include "dcfilebrowser.h"

#include <dclib/dcos.h>
#include <dclib/core/cstring.h>
#include <dclib/core/cdir.h>
#include <dclib/core/cxml.h>
#include <dclib/cutils.h>

// for file type icons
#include <dclib/cfilemanager.h>

/** */
DCFileBrowser::DCFileBrowser( QWidget* parent, const char *name, int wflags, bool viewonly )
	: DCDialogFileBrowser( parent, name, wflags )
{
	// set caption
	setCaption(tr("Filebrowser"));
	
	// set width mode
	ListView_DIRECTORY->setColumnWidthMode( 0, QListView::Maximum );
	ListView_FILES->setColumnWidthMode( 0, QListView::Maximum );
	ListView_FILES->setColumnWidthMode( 1, QListView::Maximum );
	ListView_FILES->setColumnWidthMode( 2, QListView::Maximum );
	ListView_FILES->setColumnWidthMode( 3, QListView::Maximum );
	ListView_FILES->setColumnWidthMode( 4, QListView::Maximum );
	
	// hide the column header - only if not using size column
	if ( g_pConfig->GetFolderSizesInLeftPane() == FALSE )
	{
		ListView_DIRECTORY->header()->hide();
	}

	m_pCodec     = 0;
	m_pCodecRemote = 0;
	m_nShareSize = 0;
	m_nFileCount = 0;

	if ( !viewonly )
	{
		InitDocument();
	}
}

/** */
DCFileBrowser::~DCFileBrowser()
{
	QListViewItemIterator it( ListView_DIRECTORY );

	for ( ; it.current(); it++ )
	{
		((DCFileBrowserListItem*)it.current())->m_pFileList.clear();
	}
}
                                                                                   
void DCFileBrowser::InitDocument()
{
	QTextCodec *codec;
	int i;
	QStringList lst;
	
	connect( ListView_DIRECTORY, SIGNAL(selectionChanged()), this, SLOT(slotCurrentChangedDirectory()) );
	connect( ListView_DIRECTORY, SIGNAL(expanded(QListViewItem*)), this, SLOT(slotExpandedDirectory(QListViewItem*)) );
	connect( ListView_DIRECTORY, SIGNAL(collapsed(QListViewItem*)), this, SLOT(slotCollapsedDirectory(QListViewItem*)) );
	connect( ListView_DIRECTORY, SIGNAL(contextMenuRequested( QListViewItem *, const QPoint &, int )), this, SLOT(slotRightButtonClickedDirectory(QListViewItem*, const QPoint &, int )) );
	connect( ListView_FILES, SIGNAL(contextMenuRequested( QListViewItem *, const QPoint &, int )), this, SLOT(slotRightButtonClickedFiles(QListViewItem*, const QPoint &, int )) );
	connect( ListView_FILES, SIGNAL(doubleClicked( QListViewItem *, const QPoint &, int)), this, SLOT(slotItemDoubleClicked( QListViewItem *, const QPoint &, int )) );

 	connect( ToolButton_OPEN, SIGNAL(clicked()), this, SLOT(slotFileOpen()) );
 	connect( ToolButton_SAVE, SIGNAL(clicked()), this, SLOT(slotFileSave()) );

 	connect( ComboBox_ENCODING, SIGNAL(activated(const QString &)), this, SLOT(slotCodecChange(const QString &)) );
 	
	connect( ComboBox_RENCODING, SIGNAL(activated(const QString &)), this, SLOT(slotCodecRemoteChange(const QString &)) );
	
	// init encoding combo box
	for (i=0;(codec = QTextCodec::codecForIndex(i));i++)
	{
		lst << codec->name();
	}

	lst.sort();
	ComboBox_ENCODING->insertItem("DEFAULT");
	ComboBox_ENCODING->insertStringList(lst);
	ComboBox_ENCODING->setCurrentItem(0);
	
	ComboBox_RENCODING->insertItem("DEFAULT");
	ComboBox_RENCODING->insertStringList(lst);
	
	for(i=0;i<ComboBox_RENCODING->count();i++)
	{
		if ( ComboBox_RENCODING->text(i) == g_pConfig->GetDefaultFBRemoteEncoding() )
		{
			ComboBox_RENCODING->setCurrentItem(i);
			break;
		}
	}
	slotCodecRemoteChange(ComboBox_RENCODING->currentText());	
}

/** */
void DCFileBrowser::ClearView()
{
	ListView_FILES->clear();

	QListViewItemIterator it( ListView_DIRECTORY );

	for ( ; it.current(); it++ )
	{
		((DCFileBrowserListItem*)it.current())->m_pFileList.clear();
	}

	ListView_DIRECTORY->clear();
}

/** */
void DCFileBrowser::slotCodecRemoteChange( const QString & s )
{
	if ( (m_pCodecRemote == 0) && ( s == "DEFAULT" ) )
	{
		return;
	}
	
	if ( s == "DEFAULT" )
	{
		m_pCodecRemote = 0;
	}
	else
	{
		m_pCodecRemote = QTextCodec::codecForName(s);
	}
	
}

/** */
void DCFileBrowser::slotCodecChange( const QString & s )
{
	QTextCodec * codec;

	if ( (m_pCodec == 0) && ( s == "DEFAULT" ) )
	{
		return;
	}
	
	if ( s == "DEFAULT" )
	{
		codec = 0;
	}
	else
	{
		codec = QTextCodec::codecForName(s);
	}
	
	if ( codec != m_pCodec )
	{
		m_pCodec = codec;
			
		if ( m_sFileName != "" )
		{
			LoadFileList(m_sFileName);
		}
		else
		{
			InitTree( m_sNick, m_sHubName, m_sHubHost, m_sType, m_sFileName, m_sList );
		}
	}
}

/** */
void DCFileBrowser::slotFileOpen()
{
	QString s = QFileDialog::getOpenFileName(
		"",
		"",
		this,
		tr("open filelist dialog"),
		tr("Choose a file") );

	if ( s == "" )
	{
		return;
	}
	
	LoadFileList(s);
}

/** */
void DCFileBrowser::slotFileSave()
{
	CXml xml;

	QString s = QFileDialog::getSaveFileName(
                    "",
                    "",
                    this,
                    tr("save file dialog"),
                    tr("Choose a filename to save under") );

	if ( s == "" )
	{
		return;
	}

	QFile file( s );

	if ( file.open( IO_WriteOnly ) )
	{
		QTextStream stream(&file);
		
		s  = "---HEADER START---\n";
		s += "TYPE=" + m_sType + "\n";
            	s += "NICK=";
		s += xml.ToUTF8(m_sNick).Data();
		s += "\n";
            	s += "HUBNAME=" ;
		s += xml.ToUTF8(m_sHubName).Data();
		s += "\n";
            	s += "HUBHOST=";
		s += xml.ToUTF8(m_sHubHost).Data();
		s += "\n";
            	s += "---HEADER END---\n";
		
		if ( m_sType != "XMLFILELIST" )
		{
			s += xml.ToUTF8(m_sList.ascii()).Data();
		}
		else
		{
			s += m_sList;
		}
		
		stream.writeRawBytes(s.ascii(),strlen(s.ascii()));

        	file.close();
	}
}

/** */
void DCFileBrowser::slotCurrentChangedDirectory()
{
	DCFileItem * FileItem;
	CDir dir;
	QString s;
	QPtrList<QListViewItem> selitems;
	ulonglong size=0;
	int items = 0;
	int citems = 0;
	QListViewItem * item = 0;

	// clear filelist
	ListView_FILES->clear();

	// check if only one dir selected
	if ( selectedItems( ListView_DIRECTORY, selitems ) == 1 )
	{
		item = selitems.first();

		for ( FileItem = ((DCFileBrowserListItem*)item)->m_pFileList.first(); FileItem; FileItem = ((DCFileBrowserListItem*)item)->m_pFileList.next() )
		{
			if ( (g_pConfig->GetFoldersInRightPane() == FALSE) && (FileItem->m_bIsDir == TRUE) )
			{
				// do not show it
				continue;
			}
			
			size += FileItem->m_sSize.toULongLong();
			s = dir.Extension(FileItem->m_sName.ascii()).Data();

			if ( s != "" )
				s += " " + tr("file");

			DC_FBListViewItem *item1 = new DC_FBListViewItem(ListView_FILES);
			item1->myvalue = FileItem->m_sSize.toULongLong();
			item1->mycol   = 1;
			item1->m_bSortTop = FALSE;
			
			if ( FileItem->m_bIsDir )
			{
				s = tr("Folder");
				item1->setPixmap(0,m_FolderPixmap);
				
				if ( g_pConfig->GetFoldersInRightPaneOnTop() == TRUE )
				{
					item1->m_bSortTop = TRUE;
				}
			}
			else
			{
				eFileTypes type = CFileManager::Instance()->GetFileType(FileItem->m_sName.ascii());
				QPixmap icon;
				
				switch (type)
				{
					case eftMP3:
						icon = g_pIconLoader->GetPixmap(eiFILETYPE_MP3);
						break;
					case eftARCHIVE:
						icon = g_pIconLoader->GetPixmap(eiFILETYPE_ARCHIVE);
						break;
					case eftDOCUMENT:
						icon = g_pIconLoader->GetPixmap(eiFILETYPE_DOCUMENT);
						break;
					case eftAPPLICATION:
						icon = g_pIconLoader->GetPixmap(eiFILETYPE_APPLICATION);
						break;
					case eftPICTURE:
						icon = g_pIconLoader->GetPixmap(eiFILETYPE_PICTURE);
						break;
					case eftVIDEO:
						icon = g_pIconLoader->GetPixmap(eiFILETYPE_VIDEO);
						break;
					default:
						icon = g_pIconLoader->GetPixmap(eiFILETYPE_UNKNOWN);
						break;
				}
				
				item1->setPixmap( 0, icon );
				
				items++;
			}

			item1->setText(0,FileItem->m_sName);
			item1->setText(1,CUtils::GetSizeString(FileItem->m_sSize.toULongLong(), g_pConfig->GetUnit()).Data() );
			item1->setText(2,FileItem->m_sSize);
			item1->setText(3,s);
			item1->setText(4,FileItem->m_sHash);
		}
	}

	if ( item )
	{
		citems = item->childCount();
	}

	TextLabel_STATUS->setText( QString().setNum(items+citems) + " " + tr("Items") + " - " + 
					QString().setNum(items) + " " + tr("Files") +
					" (" + CUtils::GetSizeString(size,g_pConfig->GetUnit()).Data() + " " + tr("Total") + ") - " +
					QString().setNum(citems) + " " + tr("Directories") );
}

/** */
void DCFileBrowser::slotExpandedDirectory( QListViewItem * item )
{
	if ( item->parent() != NULL )
		item->setPixmap(0,g_pIconLoader->GetPixmap(eiFOLDER_BLUE_OPEN));
}

/** */
void DCFileBrowser::slotCollapsedDirectory( QListViewItem * item )
{
	if ( item->parent() != NULL )
		item->setPixmap(0,g_pIconLoader->GetPixmap(eiFOLDER_BLUE));
}

/** */
void DCFileBrowser::slotRightButtonClickedDirectory( QListViewItem * item, const QPoint &, int column )
{
	CreateMenu(item,TRUE,column);
}

/** */
void DCFileBrowser::slotRightButtonClickedFiles( QListViewItem * item, const QPoint &, int column )
{
	CreateMenu(item,FALSE,column);
}

/** */
void DCFileBrowser::LoadFileList( QString s )
{
	QByteArray ba;
	m_sFileName = s;

	QFile file( s );

	m_sNick    = "";
	m_sHubName = "";
	m_sHubHost = "";
	m_sType    = "";
	m_sList    = "";

	ClearView();

	if ( file.open( IO_ReadOnly ) )
	{
		QTextStream stream( &file );
		
		// readLine() will convert from file UTF-8 to QString 16bit unicode
		stream.setEncoding( QTextStream::UnicodeUTF8 );
		
		QString line;

		line = stream.readLine();
		
		if ( line == "---HEADER START---" )
		{
			// read header
			while ( !stream.atEnd() && line!="---HEADER END---" )
			{
				line = stream.readLine();

				if ( line.find("TYPE=") == 0 )
				{
					m_sType = line.mid(5);
				}
				else if ( line.find("NICK=") == 0 )
				{
					m_sNick = line.mid(5);
				}
				else if ( line.find("HUBNAME=") == 0 )
				{
					m_sHubName = line.mid(8);
				}
				else if ( line.find("HUBHOST=") == 0 )
				{
					m_sHubHost = line.mid(8);
				}
			}

			// the loop reading one byte at a time was replaced
			// with this
			ba = stream.device()->readAll();
			
			// WARNING! ba.data() includes trailing garbage!
			// it must only be used in conjunction with ba.size()
			
			// convert the byte array to QString 16bit unicode
			if ( m_sType == "XMLFILELIST" )
			{
				// XML lists should be in UTF-8
				m_sList = QString::fromUtf8( ba.data(), ba.size() );
			}
			else
			{
				// text lists get converted to UTF-8 by CXml in cdownloadmanager.cpp
				// we want it in UTF-8
				// but without the &NN xml substitutions
				CXml xml;
				CString list;
				list.Set( ba.data(), ba.size() );
				m_sList = QString::fromUtf8( xml.FromUtf8( list, "UTF-8" ).Data() );
			}
		}

        	file.close();

		InitTree( m_sNick, m_sHubName, m_sHubHost, m_sType, m_sFileName, m_sList );
	}
}

/** */
void DCFileBrowser::AddDirectory( QListViewItem * item, QString name )
{
	((DCFileBrowserListItem*)item)->m_pFileList.setAutoDelete(TRUE);
	((DCFileBrowserListItem*)item)->m_sName = name;

	if ( m_pCodec )
		name = m_pCodec->toUnicode(name);

	item->setText(0,name);
	item->setPixmap(0,m_FolderPixmap);
	
	((DCFileBrowserListItem*)item)->m_nBytes = 0;
}

/** */
void DCFileBrowser::AddFile( QListViewItem * item, DCFileItem * fileitem )
{
	// increment filecounter
	if ( fileitem->m_bIsDir == FALSE )
		m_nFileCount++;

	// recode filename
	if ( m_pCodec )
		fileitem->m_sName = m_pCodec->toUnicode(fileitem->m_sName);

	// check size
	if ( fileitem->m_sSize == "" )
		fileitem->m_sSize = tr("<wrong length>");
	else
		if ( fileitem->m_bIsDir == FALSE )
			m_nShareSize += fileitem->m_sSize.toULongLong();

	// add fileitem to filelist
	((DCFileBrowserListItem*)item)->m_pFileList.append(fileitem);
	
	// add to folder contents size
	((DCFileBrowserListItem*)item)->m_nBytes += fileitem->m_sSize.toULongLong();
	
	DCFileItem * pFileItem = ((DCFileBrowserListItem*)item)->m_pFileItem;
	
	if ( pFileItem != 0 )
	{
		pFileItem->m_sSize = QString().setNum( ((DCFileBrowserListItem*)item)->m_nBytes );
	}
}

/** */
void DCFileBrowser::InitTree( QString nick, QString hubname, QString hubhost, QString type, QString filename, QString list )
{
	QListViewItem * item;
	
	// store values
	m_sNick     = nick;
	m_sHubName  = hubname;
	m_sHubHost  = hubhost;
	m_sType     = type;
	m_sFileName = filename;
	m_sList     = list;

	// reset count values
	m_nShareSize = 0;
	m_nFileCount = 0;

	ClearView();

	// set dialog caption
	setCaption( nick + " - " + tr("Filebrowser") + " [" + hubname + "]" );

	// get folder pixmap
	m_FolderPixmap = g_pIconLoader->GetPixmap(eiFOLDER_BLUE);

	// disable updates
	ListView_DIRECTORY->setUpdatesEnabled(FALSE);

	// create root item
	item = new DCFileBrowserListItem( ListView_DIRECTORY );
	item->setText(0,tr("Root Directory"));
	item->setPixmap(0,g_pIconLoader->GetPixmap(eiFOLDER_RED));
	((DCFileBrowserListItem*)item)->m_pFileItem = 0;

	if ( m_sType != "XMLFILELIST" )
		InitTXTTree(item);			
	else
		InitXMLTree(item);

	// update summary
	TextLabel_SUMMARY->setText( QString(CString().setNum(m_nFileCount).Data()) + " " + tr("Files") + " (" + 
					QString(CUtils::GetSizeString(m_nShareSize,g_pConfig->GetUnit()).Data()) + " " + tr("Total") + ")" );

	// update tooltip
	QToolTip::add( TextLabel_SUMMARY, (CString().setNum(m_nShareSize) + " B").Data() );	

	// update view
	ListView_DIRECTORY->setUpdatesEnabled(TRUE);
	ListView_DIRECTORY->triggerUpdate();

	// open first tree
	ListView_DIRECTORY->setOpen(ListView_DIRECTORY->firstChild(),TRUE);
}

/** */
void DCFileBrowser::InitTXTTree( QListViewItem * item )
{
	QString s1,sname,slength;
	long i,j,d;
	int depth;

	i = j = 0;

	while((i=m_sList.find("\xD\xA",j))>=0)
	{
		s1 = m_sList.mid(j,i-j);

		depth=0;
		while( (s1.find("\x9",depth)) != -1 )
			depth++;
		s1 = s1.replace( QRegExp("\x9"), "" );

		if (item)
			while ( depth < item->depth() )
				if ( (item=item->parent()) == 0 )
					break;

		if ( s1 == "" )
			s1 = "\\";

		if ( s1 != "" )
		{
			d = s1.findRev("|");

			if ( d != -1 ) // parse file entry
			{
				DCFileItem * FileItem = new DCFileItem();

				FileItem->m_sName = s1.mid(0,d);
				FileItem->m_sSize = s1.right(s1.length()-d-1);
				FileItem->m_bIsDir = FALSE;
				
				AddFile( item, FileItem );
			}
			else // parse dir entry
			{
				DCFileItem * FileItem = new DCFileItem();
				
				FileItem->m_sName = s1;
				FileItem->m_sSize = "0";
				FileItem->m_bIsDir = TRUE;
				
				AddFile( item, FileItem );
				
				if ( item == 0 )
					item = new DCFileBrowserListItem( ListView_DIRECTORY );
				else
					item = new DCFileBrowserListItem( item );
				
				((DCFileBrowserListItem*)item)->m_pFileItem = FileItem;

				AddDirectory( item, s1 );
			}
		}

		j = i+2;
	}
	
	// fixup the folder sizes
	QListViewItem * cur = ListView_DIRECTORY->firstChild();
	while ( cur )
	{
		CalcDirSize( cur );
		
		cur = cur->nextSibling();
	}
}

/** */
void DCFileBrowser::InitXMLTree( QListViewItem * item )
{
	CXml * xml;
	xmlNodePtr node;

	xml = new CXml();
	
	// strlen(m_sList.ascii()) replaces m_sList.length() to fix bug
	// with codec for C strings set to UTF-8
	if ( xml->ParseMemory(m_sList.ascii(),strlen(m_sList.ascii())) == TRUE )
	{
		for(node=xml->doc()->children;node!=0;node=node->next)
		{
			if ( !xmlStrcmp( node->name, (const xmlChar*)"FileListing" ) )
			{
				ParseXMLTree(xml,node->xmlChildrenNode,item);
			}
		}
	}

	delete xml;
}

/** */
void DCFileBrowser::ParseXMLTree( CXml * xml, xmlNodePtr node, QListViewItem * item )
{
	CString s;

	for(;node!=0;node=node->next)
	{
		if ( !xmlStrcmp( node->name, (const xmlChar*)"Directory" ) )
		{
			QListViewItem * item1;
			
			item1 = new DCFileBrowserListItem( item );
			((DCFileBrowserListItem*)item1)->m_pFileItem = 0;
			
			s = xml->prop(node,"Name");
			AddDirectory(item1,QString::fromUtf8(s.Data()));
			
			ParseXMLTree(xml,node->xmlChildrenNode,item1);
			
			DCFileItem * FileItem = new DCFileItem();
			FileItem->m_sName = QString::fromUtf8(s.Data());
			FileItem->m_sSize = QString().setNum(((DCFileBrowserListItem*)item1)->m_nBytes);
			FileItem->m_bIsDir = TRUE;
			AddFile(item,FileItem);
			((DCFileBrowserListItem*)item1)->m_pFileItem = FileItem;
						
			if ( g_pConfig->GetFolderSizesInLeftPane() == TRUE )
			{
				CString size = CUtils::GetSizeString( ((DCFileBrowserListItem*)item1)->m_nBytes, g_pConfig->GetUnit() );
				item1->setText( 1, size.Data() );
			}
		}
		else if ( !xmlStrcmp( node->name, (const xmlChar*)"File" ) )
		{
			DCFileItem * FileItem = new DCFileItem();
			s = xml->prop(node,"Name");
			FileItem->m_sName = QString::fromUtf8(s.Data());
			FileItem->m_sSize = xml->prop(node,"Size").Data();
			FileItem->m_sHash = xml->prop(node,"TTH").Data();
			FileItem->m_bIsDir = FALSE;
			
			AddFile(item,FileItem);
		}
	}
}

/** */
int DCFileBrowser::selectedItems( QListView * list, QPtrList<QListViewItem> & lst )
{
	QListViewItemIterator it( (QListView *)list );

	for ( ; it.current(); it++ )
	{
		if ( it.current()->isSelected() )
		{
			lst.append(it.current());
		}
	}

	return lst.count();
}

/** */
QString DCFileBrowser::CreateRemotePath( QListViewItem * item )
{
	QString s;
	QListViewItem * pitem;
	
	if( !item )
	{
		return "";
	}

	pitem = item;
	s = ((DCFileBrowserListItem*)pitem)->m_sName;
	
	while ( (pitem=pitem->parent()) != 0 )
	{
		// check for root entry
		if ( pitem->parent() != 0 )
		{
			s = ((DCFileBrowserListItem*)pitem)->m_sName + "\\" + s;
		}
	}

	s = s.replace( QRegExp("\\\\\\\\"), "\\" );

	return s;
}

/** */
void DCFileBrowser::CreateMenu( QListViewItem *, bool direntry, int column )
{
	int id,i;
	QString s;
	ulonglong size;
	QString rootPath  = QString::null;
	QString localName = QString::null;
	QPtrList<QListViewItem> selitems;
	QListViewItem * curitem;
	bool hasFolderItems = FALSE;
	
	if ( direntry )
	{
		i = selectedItems( ListView_DIRECTORY, selitems );
	}
	else
	{
		i = selectedItems( ListView_FILES, selitems );
		
		QPtrListIterator<QListViewItem> plit ( selitems );
		
		QListViewItem * cur = 0;
		
		while ( (cur = plit.current()) != 0 )
		{
			++plit;
			
			if ( cur->text(3) == tr("Folder") )
			{
				hasFolderItems = TRUE;
				break;
			} 
		}
	}

	// nothing on no selection
	if ( i == 0 )
	{
		return;
	}

/* TODO readadd test
	if ( direntry && (item->parent() == 0) )
	{
		return;
	}
*/
	QPopupMenu * m = new QPopupMenu(this);

	DCMenuHandler::InsertMenu(m, emiDOWNLOAD);
	DCMenuHandler::InsertMenu(m, emiDOWNLOAD_TO);
	// disable 'download as' on directories
	DCMenuHandler::InsertMenu(m, emiDOWNLOAD_AS, ((direntry ? FALSE : TRUE) && !hasFolderItems));
	DCMenuHandler::InsertMenu(m, emiDOWNLOAD_IN, ((direntry ? FALSE : TRUE) && !hasFolderItems));
	DCMenuHandler::InsertMenu(m, emiSEPARATOR);
	DCMenuHandler::InsertMenu(m, emiCOPY_COLUMN_TO_CLIPBOARD, (direntry ? FALSE : TRUE));
	DCMenuHandler::InsertMenu(m, emiCOPY_ROW_TO_CLIPBOARD, (direntry ? FALSE : TRUE));
	DCMenuHandler::InsertMenu(m, emiCOPYMAGNETLINK, ((direntry ? FALSE : TRUE) && !hasFolderItems ));
	DCMenuHandler::InsertMenu(m, emiSEPARATOR);

	id = m->exec(QCursor::pos());

	delete m;
	
	if ( id == emiCOPY_COLUMN_TO_CLIPBOARD )
	{
		QString s="";
		QClipboard *cb = QApplication::clipboard();
		cb->setText("");

                for ( curitem = selitems.first(); curitem; curitem = selitems.next() )
                {
			s += curitem->text(column) + "\n";
		}

		cb->setText(s);
	}
	else if ( id == emiCOPY_ROW_TO_CLIPBOARD )
	{
		int idx;
		QString s="";
		QClipboard *cb = QApplication::clipboard();
		cb->setText("");

                for ( curitem = selitems.first(); curitem; curitem = selitems.next() )
                {
			for( idx = 0; idx < ListView_FILES->columns(); idx++ )
			{
				s += curitem->text(idx) + " ";
			}

			s += "\n";
		}

		cb->setText(s);
	}
	else if ( id == emiCOPYMAGNETLINK )
	{
		//magnet:?xt=urn:tree:tiger:EOSA5AGTL5SD3VWCF3R2OH2WMGXV3S3R7SYN4YA&xl=708780032&dn=FC-6-i386-disc1.iso
		QString all = "";
		QClipboard *cb = QApplication::clipboard();
		
		for ( curitem = selitems.first(); curitem; curitem = selitems.next() )
		{
			// add tth
			all += "magnet:?xt=urn:tree:tiger:";
			all += curitem->text(4);
			
			// add filesize
			all += "&xl=";
			all += curitem->text(2);
			
			// add filename
			all += "&dn=";
			QString filename = curitem->text(0);
			
			QUrl::encode(filename);
			
			//fixme DC++ replaces spaces with + character
			//filename = filename.replace(' ','+');
			
			all += filename;
			
			all += "\n";
		}
		
		// remove trailing "\n"
		all = all.stripWhiteSpace();
		
		cb->setText(all);
	}
	// Check if the user wants a non-default destination
	else if ( id == emiDOWNLOAD_TO )
	{
		rootPath = QFileDialog::getExistingDirectory("", this, "dldia",
                                                     tr("Select destination"));
		if ( rootPath.isEmpty() )
		{
			// If the user cancel, then we don't download
			return;
		}
	}
	// Should the file be renamed
	else if(id == emiDOWNLOAD_AS)
	{
		rootPath = QFileDialog::getSaveFileName("", "", this, "dldia",
                                                tr("Select a filename"));
		if ( rootPath.isEmpty() )
		{
			return;
		}

		QFileInfo fi(rootPath);
		rootPath = fi.dirPath();
		localName = fi.fileName();

		if ( rootPath.isEmpty() || localName.isEmpty() )
		{
			return;
		}
	}
	else if ( id == emiDOWNLOAD_IN )
	{
		QString localrootpath;
		QString localname;
		QString localpath;
		QString remotePath;

		if ( !(curitem = selitems.first()) )
			return;

		size = ((DC_QListViewItem *)curitem)->myvalue;

		// all files need equal size
                for ( curitem = selitems.first(); curitem; curitem = selitems.next() )
                {
			if ( size != ((DC_QListViewItem *)curitem)->myvalue )
				return;
		}

		if ( m_FileTool.SelectFileSource( size, localname, localrootpath, localpath ) == FALSE )
		{
			return;
		}

		// get the full remote path
		remotePath = CreateRemotePath(ListView_DIRECTORY->currentItem());
		QString remotePathAndFile;
                for ( curitem = selitems.first(); curitem; curitem = selitems.next() )
                {
			if ( m_pCodec )
				s = m_pCodec->fromUnicode(curitem->text(0));
			else
				s = curitem->text(0);
			
			remotePathAndFile = remotePath + "\\" + s;
			if ( m_pCodecRemote ) {
			    remotePathAndFile = m_pCodecRemote->fromUnicode(remotePathAndFile);
			}
					    
			// add transfer to the waitlist
			m_FileTool.CheckFile( m_sNick.ascii(), m_sHubName.ascii(), m_sHubHost.ascii(),
				  remotePathAndFile.ascii(), localname.ascii(), localpath.ascii(), localrootpath.ascii(), eltFILE,
		  		  size, curitem->text(4).ascii(), TRUE);
		}
	}

	// Is this a download?
	if ( (id == emiDOWNLOAD) || (id == emiDOWNLOAD_TO) || (id == emiDOWNLOAD_AS) )
	{
                for ( curitem = selitems.first(); curitem; curitem = selitems.next() )
                {
			// directory download from left pane
			if ( direntry )
			{
				s = curitem->text(0);
					
				DownloadPath( rootPath, s, QString::null, curitem );
			}
			else if ( curitem->text(3) == tr("Folder") ) // directory download from right pane
			{
				QListViewItem * diritem = GetDirItem( curitem );
				
				DownloadPath( rootPath, diritem->text(0), QString::null, diritem );
			}
			// Single file download
			else
			{
				QString remotePath;
				QString remoteName;
				
				// set localname
				if ( id != emiDOWNLOAD_AS )
				{
					localName = curitem->text(0);
				}

				// get the full remote path
				remotePath = CreateRemotePath(ListView_DIRECTORY->currentItem());
				
				if ( m_pCodec )
				    remoteName = m_pCodec->fromUnicode(curitem->text(0));
				else
				    remoteName = curitem->text(0);
				
				DownloadFile( rootPath, "", localName, remotePath, remoteName, ((DC_QListViewItem *)curitem)->myvalue, curitem->text(4) );
			}
		}
	}
}

/** */
void DCFileBrowser::DownloadPath( QString rootPath, QString localPath, QString localName, QListViewItem * item )
{
	QString remotePath;
	DCFileItem * FileItem = 0;
	QString s;
	QString remoteFile;

	if ( !item )
	{
		return;
	}
	
	// get the full remote path
	remotePath = CreateRemotePath(item);
	
	for ( FileItem = ((DCFileBrowserListItem*)item)->m_pFileList.first(); FileItem; FileItem = ((DCFileBrowserListItem*)item)->m_pFileList.next() )
	{
		if ( FileItem->m_bIsDir == FALSE )
		{
			if ( m_pCodec ) {
		    	remoteFile = m_pCodec->fromUnicode(FileItem->m_sName);
			} else {
		    	remoteFile = FileItem->m_sName;
			}
			DownloadFile( rootPath, localPath, localName, remotePath, 
				remoteFile, FileItem->m_sSize.toULongLong(), FileItem->m_sHash );
		}
	}

	item = item->firstChild();

	while( item )
	{
		s = item->text(0);
			
		DownloadPath(rootPath,localPath + "\\" + s,localName,item);
		item = item->nextSibling();
	}
}

/** */
void DCFileBrowser::DownloadFile( QString rootPath, QString localPath, QString localName, 
				  QString remotePath, QString remoteName, ulonglong size,
				  QString hash )
{
	// append filename to the remote path
	remotePath += "\\" + remoteName;
	if ( m_pCodecRemote ) {
	    remotePath = m_pCodecRemote->fromUnicode(remotePath);
	}
			    
			    
	if ( localName == QString::null )
	{
		if ( m_pCodec ) 
		    localName = m_pCodec->toUnicode(remoteName);
		else
		    localName = remoteName;
		
	}

	
	m_FileTool.CheckFile(m_sNick.ascii(),
		m_sHubName.ascii(),
		m_sHubHost.ascii(),
		remotePath.ascii(),
		(const char*)localName.local8Bit(),
		(const char*)localPath.local8Bit(),
		(const char*)rootPath.local8Bit(), eltFILE,
		size, hash.ascii() );
	
	
}

/** Double click to download the item, copied from DCFileBrowser::CreateMenu */
void DCFileBrowser::slotItemDoubleClicked( QListViewItem * item, const QPoint &, int )
{
	QString rootPath = QString::null;
	QString localName = QString::null;
	
	if ( item == 0 ) // null pointer check, just in case
	{
		return;
	}
	
	if ( item->text(3) == tr("Folder") )
	{
		// we cannot open the folder since that would delete the existing
		// QListViewItems, which is not allowed in this slot and causes
		// random crashes
		
		/* QListViewItem * diritem = ListView_DIRECTORY->currentItem();
		
		if ( diritem == 0 )
		{
			printf("Double click a folder needs a ListView_DIRECTORY->currentItem()\n");
			return;
		}
		
		for ( diritem = diritem->firstChild(); diritem != 0; diritem = diritem->nextSibling() )
		{
			if ( diritem->text(0) == item->text(0) )
			{
				ListView_DIRECTORY->clearSelection();
				ListView_DIRECTORY->ensureItemVisible( diritem );
				ListView_DIRECTORY->setSelected( diritem, TRUE );
				ListView_DIRECTORY->setCurrentItem( diritem );
				break;
			}
		} */
		
		QListViewItem * diritem = GetDirItem( item );
		
		// ask for confirmation since this is unusual behaviour
		int confirm = QMessageBox::question(
			this,
			tr("Download contents?"),
			tr("Download the contents of \"") + diritem->text(0) + "\" ?",
			QMessageBox::Yes,
			QMessageBox::No
		);
		
		if ( confirm == QMessageBox::Yes )
		{
			DownloadPath( rootPath, diritem->text(0), localName, diritem );
		}
	}
	else
	{
		QString remotePath;
		QString remoteName;
		
		// get the full remote path
		remotePath = CreateRemotePath(ListView_DIRECTORY->currentItem());
		
		if ( m_pCodec )
			remoteName = m_pCodec->fromUnicode(item->text(0));
		else
			remoteName = item->text(0);
		
		DownloadFile( rootPath, "", localName, remotePath, remoteName, ((DC_QListViewItem *)item)->myvalue, item->text(4) );
	}
}

/** Only needed for non-xml filelists */
ulonglong DCFileBrowser::CalcDirSize( QListViewItem * item )
{
	ulonglong total = 0;

	DCFileBrowserListItem * cur = (DCFileBrowserListItem*) item;
	
	QPtrListIterator<DCFileItem> it( cur->m_pFileList );
	for ( ; it.current(); ++it)
	{
		if ( it.current()->m_bIsDir == TRUE )
		{
			QListViewItem * child = item->firstChild();
			
			while ( child )
			{
				if ( child->text(0) == it.current()->m_sName )
				{
					total += CalcDirSize( child );
					break;
				}
				
				child = child->nextSibling();
			}
		}
		else
		{
			total += it.current()->m_sSize.toULongLong();
		}
	}
	
	DCFileItem * pFileItem = cur->m_pFileItem;
	if ( pFileItem != 0 )
	{
		pFileItem->m_sSize = QString().setNum(total);
	}
	
	cur->m_nBytes = total;
	
	if ( g_pConfig->GetFolderSizesInLeftPane() == TRUE )
	{
		CString size = CUtils::GetSizeString( total, g_pConfig->GetUnit() );
		cur->setText( 1, size.Data() );
	}
	
	//printf( "CalcDirSize for %s = %lld\n", item->text(0).ascii(), total );
	
	return total;
}

/** */
QListViewItem * DCFileBrowser::GetDirItem( QListViewItem * item )
{
	QListViewItem * diritem = ListView_DIRECTORY->currentItem();
	
	if ( item == 0 )
	{
		return 0;
	}
	
	if ( diritem == 0 )
	{
		return 0;
	}
	
	for ( diritem = diritem->firstChild(); diritem != 0; diritem = diritem->nextSibling() )
	{
		if ( diritem->text(0) == item->text(0) )
		{
			return diritem;
		}
	}
	
	return 0;
}
