/***************************************************************************
                          dctransferview.cpp  -  description
                             -------------------
    begin                : Sat Feb 23 2002
    copyright            : (C) 2002-2005 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 "dctransferview.h"

#include <q3listview.h>
#include <qcursor.h>
#include <qtabwidget.h>
#include <qmessagebox.h>
#include <QTextEdit>
#include <qdatetime.h>
#include <qinputdialog.h>
#include <qtimer.h>
#include <QMdiArea>
#include <QMdiSubWindow>
#include <qcombobox.h>
#include <qregexp.h>
#include <qlayout.h>
//Added by qt3to4:
#include <QKeyEvent>
#include <QGridLayout>
#include <QResizeEvent>
#include <QShowEvent>
#include <QEvent>
#include <QHeaderView>

#include "dcconfig.h"
#include "dcfilebrowser.h"
#include "dcconnectionmanager.h"
#include "dcmenuhandler.h"
#include "dcfiletransferinfo.h"
#include "dcevent.h"
#include "dchubsearch.h"
#include "dcedittransfer.h"
#include "dciconloader.h"

// for user commands
#include "dcclient.h"

#include "dctransferviewitems.h"
#include "dcwidget.h"
#include "dcguiutils.h"

/* for posting event to it */
#include "dcgui.h"

#include <dclib/dcos.h>
#include <dclib/cutils.h>

#include <list>

#define TIMER_BASE 500

DCTransferView * g_pTransferView = 0;

/** */
DCTransferView::DCTransferView( QWidget * parent ) : QWidget( parent )
{
	int idx;

	lastTransfersWidth = -1;
	lastWaitWidth = -1;
	lastFilesWidth = -1;
	lastSlotsWidth = -1;

	setupUi(this);

	// set default icon
	setWindowIcon( g_pIconLoader->GetPixmap(eiTRANSFER) );

	// set the ColumnWidthMode to manual, we have to do this
	// because using the Q3ListView resizeMode AllColumns means that it is
	// impossible to change the size of the last column
	// and QTreeView only resizes the last column
	for( idx = 0; idx < ListView_TRANSFER->columns(); idx++ )
	{
		ListView_TRANSFER->setColumnWidthMode( idx, Q3ListView::Manual );
	}
	for( idx = 0; idx < ListView_TRANSFERWAIT->columns(); idx++ )
	{
		ListView_TRANSFERWAIT->setColumnWidthMode( idx, Q3ListView::Manual );
	}
	for( idx = 0; idx < ListView_LOCALFILES->columns(); idx++ )
	{
		ListView_LOCALFILES->setColumnWidthMode( idx, Q3ListView::Manual );
	}
	
	/* disable this, we are adjusting the column widths */
	TreeWidget_SLOTS->header()->setStretchLastSection(false);

	TreeWidget_SLOTS->sortByColumn( 0, Qt::AscendingOrder );

	pMessageList = new QList<CDCMessage*>();

	Timer = new QTimer;
	m_pMessageQueueMutex = new QMutex();

	InitDocument();

	g_pTransferView = this;
}

/** */
DCTransferView::~DCTransferView()
{
	g_pTransferView = NULL;

	if ( Timer )
	{
		Timer->stop();
		delete Timer;
	}

	m_pMessageQueueMutex->lock();

	if ( pMessageList )
	{
		QList<CDCMessage*> * tmp = pMessageList;
		pMessageList = 0;
		
		for ( QList<CDCMessage*>::const_iterator it = tmp->constBegin(); it != tmp->constEnd(); ++it )
		{
			delete *it;
		}
		
		delete tmp;
	}

	ListView_TRANSFER->setUpdatesEnabled(false);
	ListView_TRANSFERWAIT->setUpdatesEnabled(false);
	ListView_LOCALFILES->setUpdatesEnabled(false);
	ListView_TRANSFER->setSortColumn(-1);
	ListView_TRANSFERWAIT->setSortColumn(-1);
	ListView_LOCALFILES->setSortColumn(-1);

	if ( !m_QueueMap.isEmpty() )
	{
		for ( TransferQueueMap::const_iterator it = m_QueueMap.constBegin(); it != m_QueueMap.constEnd(); ++it )
		{
			QueueParentMap * submap = it.value();
			for ( QueueParentMap::const_iterator it2 = submap->constBegin(); it2 != submap->constEnd(); ++it2 )
			{
				delete it2.value();
			}
			submap->clear();
			delete submap;
		}
		m_QueueMap.clear();
	}

	if ( !m_QueueLocalMap.isEmpty() )
	{
		for ( QueueParentMap::const_iterator it = m_QueueLocalMap.constBegin(); it != m_QueueLocalMap.constEnd(); ++it )
		{
			delete it.value();
		}
		m_QueueLocalMap.clear();
	}

	if ( !m_ActiveTransferMap.isEmpty() )
	{
		for ( ActiveTransferMap::const_iterator it = m_ActiveTransferMap.constBegin(); it != m_ActiveTransferMap.constEnd(); ++it )
		{
			delete it.value();
		}
		m_ActiveTransferMap.clear();
	}

	DLM_SaveQueue();

	m_pMessageQueueMutex->unlock();

	delete m_pMessageQueueMutex;
	m_pMessageQueueMutex = 0;
}

/** */
void DCTransferView::InitDocument()
{
	StringMap * map;

	// setup log text edit - almost everything is now in the .ui file
	TextEdit_LOG->document()->setMaximumBlockCount( 300 );

	// default setting
	if ( g_pConfig->GetMap("TRANSFERVIEW",map) == false )
	{
		// view is docked
		(*map)["DOCKED"] = QString("1");
	}

	connect( TabWidget_TRANSFER,SIGNAL(currentChanged(QWidget*)), this, SLOT(slotTabWidgetCurrentChange(QWidget*)) );
	connect( ListView_TRANSFER, SIGNAL(contextMenuRequested( Q3ListViewItem *, const QPoint &, int )), this, SLOT(slotRightButtonClickedTransferList(Q3ListViewItem*, const QPoint &, int )) );
	connect( ListView_TRANSFERWAIT, SIGNAL(contextMenuRequested( Q3ListViewItem *, const QPoint &, int )), this, SLOT(slotRightButtonClickedTransferWaitList(Q3ListViewItem*, const QPoint &, int )) );
	connect( ListView_LOCALFILES, SIGNAL(contextMenuRequested( Q3ListViewItem *, const QPoint &, int )), this, SLOT(slotRightButtonClickedLocalFilesList(Q3ListViewItem*, const QPoint &, int )) );
	connect( ListView_TRANSFERWAIT,SIGNAL(doubleClicked(Q3ListViewItem*)), this, SLOT(slotDoubleClickedTransferWaitList(Q3ListViewItem*)) );
	connect( TreeWidget_SLOTS, SIGNAL(customContextMenuRequested( const QPoint & )), this, SLOT(slotContextMenuUserSlotList( const QPoint & )) );
	connect( TextEdit_LOG, SIGNAL(customContextMenuRequested( const QPoint & )), this, SLOT(slotRightButtonClickedLog( const QPoint & )) );

	connect( Timer, SIGNAL(timeout()), this, SLOT(timerDone()) );

	Timer->setSingleShot( true );
	Timer->start( TIMER_BASE );
}

/** */
void DCTransferView::DeInitDocument()
{
	// deinit transferview
	// StringMap * map;

	// save hub view settings
	// g_pConfig->GetMap("HUBVIEW",map);
}

/** current tab widget change slot */
void DCTransferView::slotTabWidgetCurrentChange(QWidget*)
{
	SizeColumnsPreservingRatios();
}

/** overridden so that the column widths are initialized on first show() */
void DCTransferView::showEvent( QShowEvent * event )
{
	QWidget::showEvent( event );

	if ( isVisible() )
	{
		SizeColumnsPreservingRatios();
	}
}

/** resize event handler */
void DCTransferView::resizeEvent( QResizeEvent * )
{
	SizeColumnsPreservingRatios();
}

/** Initialize or adjusts widths of the ListView/TreeView columns */
void DCTransferView::SizeColumnsPreservingRatios()
{
	int width;
	
	if ( ListView_TRANSFER->isVisible() )
	{
		width = ListView_TRANSFER->width();
		if ( width > 0 )
		{
			if ( lastTransfersWidth == -1 )
			{
				// approximately double width of list view
				// less important columns are not shown
				ListView_TRANSFER->setColumnWidth( 0, ((width*1)/7) );
				ListView_TRANSFER->setColumnWidth( 1, ((width*1)/7) );
				ListView_TRANSFER->setColumnWidth( 2, ((width*3)/7) );
				ListView_TRANSFER->setColumnWidth( 3, ((width*2)/7) );
				ListView_TRANSFER->setColumnWidth( 4, ((width*2)/7) );
				ListView_TRANSFER->setColumnWidth( 5, ((width*2)/7) );
				ListView_TRANSFER->setColumnWidth( 6, ((width*2)/7) );
				
				// this changes the width of ListView_TRANSFER
				lastTransfersWidth = ListView_TRANSFER->width();
			}
			else if ( lastTransfersWidth != width )
			{
				DCGuiUtils::AdjustColumnWidths( ListView_TRANSFER, lastTransfersWidth );
				lastTransfersWidth = ListView_TRANSFER->width();
			}
		}
	}
	else if ( ListView_TRANSFERWAIT->isVisible() )
	{
		width = ListView_TRANSFERWAIT->width();
		if ( width > 0 )
		{
			if ( lastWaitWidth == -1 )
			{
				ListView_TRANSFERWAIT->setColumnWidth( 0, ((width*4 )/29) );
				ListView_TRANSFERWAIT->setColumnWidth( 1, ((width*11)/29) );
				ListView_TRANSFERWAIT->setColumnWidth( 2, ((width*5 )/29) );
				ListView_TRANSFERWAIT->setColumnWidth( 3, ((width*4 )/29) );
				ListView_TRANSFERWAIT->setColumnWidth( 4, ((width*5 )/29) );
				
				
				lastWaitWidth = ListView_TRANSFERWAIT->width();
			}
			else if ( lastWaitWidth != width )
			{
				DCGuiUtils::AdjustColumnWidths( ListView_TRANSFERWAIT, lastWaitWidth );
				lastWaitWidth = ListView_TRANSFERWAIT->width();
			}
		}
	}
	else if ( ListView_LOCALFILES->isVisible() )
	{
		width = ListView_LOCALFILES->width();
		if ( width > 0 )
		{
			if ( lastFilesWidth == -1 )
			{
				ListView_LOCALFILES->setColumnWidth( 0, ((width*5)/16) );
				ListView_LOCALFILES->setColumnWidth( 1, ((width*2)/16) );
				ListView_LOCALFILES->setColumnWidth( 2, ((width*3)/16) );
				ListView_LOCALFILES->setColumnWidth( 3, ((width*2)/16) );
				ListView_LOCALFILES->setColumnWidth( 4, ((width*4)/16) );
				
				lastFilesWidth = ListView_LOCALFILES->width();
			}
			else if ( lastFilesWidth != width )
			{
				DCGuiUtils::AdjustColumnWidths( ListView_LOCALFILES, lastFilesWidth );
				lastFilesWidth = ListView_LOCALFILES->width();
			}
		}
	}
	else if ( TreeWidget_SLOTS->isVisible() )
	{
		width = TreeWidget_SLOTS->width();
		if ( width > 0 )
		{
			if ( lastSlotsWidth == -1 )
			{
				TreeWidget_SLOTS->setColumnWidth( 0, width/3 );
				TreeWidget_SLOTS->setColumnWidth( 1, width/3 );
				TreeWidget_SLOTS->setColumnWidth( 2, width/3 );
				lastSlotsWidth = TreeWidget_SLOTS->width();
			}
			else if ( lastSlotsWidth != width )
			{
				DCGuiUtils::AdjustColumnWidths( TreeWidget_SLOTS, lastSlotsWidth );
				lastSlotsWidth = TreeWidget_SLOTS->width();
			}
		}
	}
}

/** download manager callback function */
int DCTransferView::DC_DownloadManagerCallBack( CDCMessage * DCMessage )
{
	int err = -1;

	if ( m_pMessageQueueMutex == 0 )
	{
		return err;
	}
	
	m_pMessageQueueMutex->lock();

	if ( DCMessage && pMessageList )
	{
		pMessageList->append(DCMessage);
		err = 0;
	}

	m_pMessageQueueMutex->unlock();

	return err;
}

/** */
void DCTransferView::timerDone()
{
	CDCMessage *DCMsg;
	bool bLVWaitUpdate = false;
	int i;

	for(i=0;i<50;i++)
	{
		if ( m_pMessageQueueMutex->tryLock() == false )
		{
			break;
		}

		if ( pMessageList && !pMessageList->isEmpty() )
		{
			DCMsg = pMessageList->takeFirst();
		}
		else
		{
			DCMsg = 0;
		}

		m_pMessageQueueMutex->unlock();

		if ( DCMsg == 0 )
		{
			break;
		}

		switch ( DCMsg->m_eType )
		{
			case DC_MESSAGE_DM_INFO:
			{
				QApplication::postEvent( g_pMainWin, new DC_DownloadManagerEvent( (CDownloadManagerInfo*)DCMsg ) );

				DCMsg = 0;

				break;
			}

			case DC_MESSAGE_FM_INFO:
			{
				QApplication::postEvent( g_pMainWin, new DC_FileManagerEvent( (CFileManagerInfo*)DCMsg ) );

				DCMsg = 0;

				break;
			}

			case DC_MESSAGE_TRAFFIC:
			{
				QApplication::postEvent( g_pMainWin, new DC_TrafficInfoEvent( (DCMessageTraffic*)DCMsg ) );

				DCMsg = 0;

				break;
			}

			case DC_MESSAGE_SLOT_OBJECT:
			{
				MessageSlot( (CMessageDMSlotObject *)DCMsg );
				break;
			}

			case DC_MESSAGE_LOG:
			{
				MessageLog( (CMessageLog*)DCMsg );

				break;
			}

			case DC_MESSAGE_FILE_OBJECT:
			{
				CMessageDMFileObject * msg = (CMessageDMFileObject*)DCMsg;

				// must be called BEFORE UpdateTransferWaitList
				UpdateLocalFileList( msg );

				if ( UpdateTransferWaitList( msg ) )
				{
					bLVWaitUpdate = true;
				}

				break;
			}

			case DC_MESSAGE_TRANSFER_OBJECT:
			{
				MessageTransfer( (CMessageDMTransferObject*)DCMsg );

				break;
			}

			case DC_MESSAGE_FILELIST_OBJECT:
			{
				CMessageDMFileListObject * msg = (CMessageDMFileListObject*)DCMsg;

				QStringList dirs;
				
				if ( msg->m_pDirList )
				{
					for ( std::list<CString>::const_iterator it = msg->m_pDirList->begin(); it != msg->m_pDirList->end(); ++it )
					{
						dirs << QString::fromAscii(it->Data());
					}
				}

				NewFileBrowser(msg->sNick.Data(),msg->sHubName.Data(),msg->sHubHost.Data(),msg->sLocalFile.Data(),msg->sJumpTo.Data(),dirs);

				break;
			}

			default:
			{
				break;
			}
		}

		if ( DCMsg )
		{
			delete DCMsg;
		}
	}

	if ( bLVWaitUpdate )
	{
		ListView_TRANSFERWAIT->setUpdatesEnabled(true);
		ListView_TRANSFERWAIT->triggerUpdate();
	}

	Timer->setSingleShot( true );
	Timer->start( TIMER_BASE );
}

/** */
void DCTransferView::MessageSlot( CMessageDMSlotObject * msg )
{
	int index = 0;
	QTreeWidgetItem * item = TreeWidget_SLOTS->topLevelItem( index );

	while(item)
	{
		if ( (item->text(0) == QString::fromAscii(msg->sNick.Data())) &&
		     (item->text(1) == QString::fromAscii(msg->sHubName.Data())) )
		{
			if ( (msg->iSlots == 0) && (!msg->bPermanent) )
			{
				delete item;
				item=0;
			}

			break;
		}

		index++;
		item = TreeWidget_SLOTS->topLevelItem( index );
	}

	if ( (!item) && ((msg->iSlots > 0) || (msg->bPermanent)) )
	{
		item = new QTreeWidgetItem( TreeWidget_SLOTS );
		item->setText( 0, msg->sNick.Data() );
		item->setText( 1, msg->sHubName.Data() );
	}

	if (item)
	{
		if ( msg->bPermanent )
		{
			item->setText(2,"X");
		}
		else
		{
			item->setText(2,QString().setNum(msg->iSlots));
		}
	}
}

/** */
void DCTransferView::MessageLog( CMessageLog * msg )
{
	bool bscroll;

	if ( TextEdit_LOG->verticalScrollBar()->maximum() == TextEdit_LOG->verticalScrollBar()->value() )
	{
		bscroll = true;
	}
	else
	{
		bscroll = false;
	}

	TextEdit_LOG->append( QTime::currentTime().toString("[hh:mm:ss] ") + QString(msg->sMessage.Data()) );

	if ( bscroll )
	{
		// QT3 TextEdit_LOG->scrollToBottom();
		// QT3 TextEdit_LOG->moveCursor( Q3TextEdit::MoveEnd, false );
		TextEdit_LOG->moveCursor( QTextCursor::End, QTextCursor::MoveAnchor );
	}
}

/** */
void DCTransferView::MessageTransfer( CMessageDMTransferObject * msg )
{
	CMessageDMTransferObject * msg1 = 0;
				
	CString s;
	QString n;

	m_ActiveTransferMapMutex.lock();

	DCTransferListItem * TransferListItem = m_ActiveTransferMap.value(msg->m_nTransferID);

	if ( TransferListItem == 0 )
	{
		if ( msg->bRemoveTransfer == false )
		{
			// create new entry
			TransferListItem = new DCTransferListItem();
			TransferListItem->pItem = new DC_QProgressListItem( ListView_TRANSFER, 2 );

			if ( msg->m_bEncrypted )
//				TransferListItem->pItem->setPixmap(0,QPixmap(ssl_no_xpm));
//			else
				TransferListItem->pItem->setPixmap(0,g_pIconLoader->GetPixmap(eiSSL_YES));

			if ( !g_pConfig->GetTransferViewOptions(etvoFILEPERCENT) )
			{
				TransferListItem->pItem->SetProgressEnable(false);
			}
			
			TransferListItem->pObject = new CMessageDMTransferObject();
						
			msg1 = TransferListItem->pObject;
			// set transfer id
			msg1->m_nTransferID = msg->m_nTransferID;

			m_ActiveTransferMap.insert( msg->m_nTransferID, TransferListItem );
		}
		else
		{
			m_ActiveTransferMapMutex.unlock();
			return;
		}
	}
	else if ( msg->bRemoveTransfer )
	{
		m_ActiveTransferMap.remove(msg->m_nTransferID);
		delete TransferListItem;
		m_ActiveTransferMapMutex.unlock();
		return;
	}

	msg1 = TransferListItem->pObject;

	//
	if ( msg1->m_bEncrypted != msg->m_bEncrypted )
	{
		msg1->m_bEncrypted = msg->m_bEncrypted;

		if ( msg->m_bEncrypted )
//			TransferListItem->pItem->setPixmap(0,QPixmap(ssl_no_xpm));
//		else
			TransferListItem->pItem->setPixmap(0,g_pIconLoader->GetPixmap(eiSSL_YES));
	}

	// update transfer state
	if ( msg1->eState != msg->eState )
	{
		msg1->eState = msg->eState;
		
		switch(msg1->eState)
		{
			case estTRANSFERDOWNLOAD:
				TransferListItem->pItem->setPixmap(2,g_pIconLoader->GetPixmap(eiDOWN));
				TransferListItem->pItem->setTransferState("d");
				//TransferListItem->pItem->setText(3,tr("Download"));
				break;
			case estTRANSFERUPLOAD:
				TransferListItem->pItem->setPixmap(2,g_pIconLoader->GetPixmap(eiUP));
				TransferListItem->pItem->setTransferState("u");
				//TransferListItem->pItem->setText(3,tr("Upload"));
				break;
			case estTRANSFERHANDSHAKE:
				TransferListItem->pItem->setPixmap(2,g_pIconLoader->GetPixmap(eiBACK));
				TransferListItem->pItem->setTransferState("h");
				//TransferListItem->pItem->setText(3,tr("Handshake"));
				break;
			case estNONE:
				//TransferListItem->pItem->setText(3,tr("Nothing"));
				TransferListItem->pItem->setTransferState("n");
				break;
			default:
				TransferListItem->pItem->setPixmap(2,g_pIconLoader->GetPixmap(eiHELP));
				TransferListItem->pItem->setTransferState("q");
				//TransferListItem->pItem->setText(3,tr("Unknown"));
				break;
		}
	}

	// update nick
	if ( msg1->m_sDstNick != msg->m_sDstNick )
	{
		msg1->m_sDstNick = msg->m_sDstNick;
		//TransferListItem->pItem->setText( 0, msg->m_sDstNick.Data() );
		if ( msg1->sHost != msg->sHost )
			msg1->sHost    = msg->sHost;

		n  = msg1->m_sDstNick.Data();
		n += " (";
		n += msg1->sHost.Data();
		n += ")";

		TransferListItem->pItem->setText(0, n );
	}
	// update user host
	else if ( msg1->sHost != msg->sHost )
	{
		msg1->sHost    = msg->sHost;
		
		n  = msg1->m_sDstNick.Data();
		n += " (";
		n += msg1->sHost.Data();
		n += ")";

		TransferListItem->pItem->setText(0, n );
	}

	// update hub
	if ( msg1->sHubName != msg->sHubName )
	{
		msg1->sHubName = msg->sHubName;

		TransferListItem->pItem->setText(1, msg1->sHubName.Data() );
	}

	// update hubhost
	if ( msg1->m_sHubHost != msg->m_sHubHost )
	{
		msg1->m_sHubHost = msg->m_sHubHost;
	}
				
	// update filename
	if ( msg1->m_sSrcFile != msg->m_sSrcFile )
	{
		TransferListItem->pItem->resetProgress();
		QString meh = msg->m_sSrcFile.Data();
		if ( meh.contains( '\\', Qt::CaseInsensitive ) )
			meh = meh.mid( meh.lastIndexOf( '\\' )+1, meh.length() );
		else if ( meh.contains( '/', Qt::CaseInsensitive ) )
			meh = meh.mid( meh.lastIndexOf( '/' )+1, meh.length() );
		
		if ( meh.isEmpty() ) // partial list transfer
		{
			TransferListItem->pItem->setText( 3, QString::fromAscii(msg->m_sSrcFile.Data()) );
		}
		else
		{
			TransferListItem->pItem->setText( 3, meh );
		}
		
		// update local filename
		msg1->m_sSrcFile = msg->m_sSrcFile;
		TransferListItem->pItem->resetProgress();
		TransferListItem->pItem->setText( 5, msg->m_sSrcFile.Data() );
	}

	// update remote filename + path
	if ( msg1->m_sDstFile != msg->m_sDstFile )
	{
		msg1->m_sDstFile = msg->m_sDstFile;
		TransferListItem->pItem->resetProgress();
		TransferListItem->pItem->setText( 4, msg->m_sDstFile.Data() );
	}

	// update TTH
	if ( msg1->m_sTTH != msg->m_sTTH )
	{
		msg1->m_sTTH = msg->m_sTTH;
		TransferListItem->pItem->setText( 6, msg->m_sTTH.Data() );
	}

	// update transfer rate
	if ( (msg1->lRate != msg->lRate) ||
	     (msg1->m_nMultiRate != msg->m_nMultiRate) ||
	     (msg1->lSize != msg->lSize) ||
	     (msg1->lSizeDone != msg->lSizeDone) ||
	     (msg1->lStartPosition != msg->lStartPosition) ||
	     (msg1->lTransfered != msg->lTransfered) ||
	     (msg1->lEndPosition != msg->lEndPosition) )
	{
		msg1->lRate = msg->lRate;
		msg1->m_nMultiRate = msg->m_nMultiRate;
		msg1->lSize = msg->lSize;
		msg1->lSizeDone = msg->lSizeDone;
		msg1->lStartPosition = msg->lStartPosition;
		msg1->lTransfered = msg->lTransfered;
		msg1->lEndPosition = msg->lEndPosition;
		
		s = "";

		if ( g_pConfig->GetTransferViewOptions(etvoCHUNKPERCENT) )
		{
			if ( (msg1->lEndPosition-msg1->lStartPosition) != 0 )
			{
				s += CString::number(((msg1->lTransfered)*100)/(msg1->lEndPosition-msg1->lStartPosition));
				s += "% ";
			}
			else
			{
				s += "0% ";
			}
		}

		if ( g_pConfig->GetTransferViewOptions(etvoFILEPERCENT) )
		{
			TransferListItem->pItem->SetProgressEnable(true);
			if ( msg1->lSize != 0 )
			{
				TransferListItem->pItem->setProgress( (msg1->lSizeDone*100)/msg1->lSize );
			}
			else
			{
				TransferListItem->pItem->setProgress( 0 );
			}

/*			if ( msg1->lSize != 0 )
			{
				s += CString::number(((msg1->lSizeDone)*100)/msg1->lSize);
				s += "% ";
			}
			else
			{
					s += "0% ";
			}
*/
		}
		else
		{
			TransferListItem->pItem->SetProgressEnable(false);
		}
		
		if ( g_pConfig->GetTransferViewOptions(etvoCHUNKSIZE) )
		{
			s += " ";
			// s += CString::number(msg->lStartPosition);
			s += CUtils::GetSizeString(msg->lStartPosition,g_pConfig->GetUnit());
			s += "/";
			// s += CString::number(msg->lStartPosition+msg->lTransfered);
			s += CUtils::GetSizeString(msg->lStartPosition+msg->lTransfered,g_pConfig->GetUnit());
			s += "/";
			// s += CString::number(msg->lEndPosition);
			s += CUtils::GetSizeString(msg->lEndPosition,g_pConfig->GetUnit());
		}

		if ( g_pConfig->GetTransferViewOptions(etvoFILESIZE) )
		{
			s += " ";
			// s += CString::number(msg->lSizeDone);
			s += CUtils::GetSizeString(msg->lSizeDone,g_pConfig->GetUnit());
			s += "/";
			// s += CString::number(msg->lSize);
			s += CUtils::GetSizeString(msg->lSize,g_pConfig->GetUnit());
		}

		if ( g_pConfig->GetTransferViewOptions(etvoDOWNLOADRATESINGLE) )
		{
			ulonglong rate;

			rate = msg->lRate;

			s += " [";
			s += CUtils::GetTransferString(rate);
			s += "]";
		}

		if ( g_pConfig->GetTransferViewOptions(etvoELAPSEDTIMESINGLE) )
		{
			ulonglong rate = 0;

			rate = msg1->lSize-msg1->lSizeDone;

			if ( msg->lRate>0 )
				rate/=msg->lRate;

			s += " [";
			s += CUtils::GetTimeString(rate);
			s += "]";
		}

		if ( g_pConfig->GetTransferViewOptions(etvoDOWNLOADRATEMULTI) )
		{
			ulonglong rate;

			if ( (msg1->m_nMultiRate == 0) && (msg1->lRate != 0) )
				rate = msg1->lRate;
			else
				rate = msg1->m_nMultiRate;
						
			s += " [";
			s += CUtils::GetTransferString(rate);
			s += "]";
		}

		if ( g_pConfig->GetTransferViewOptions(etvoELAPSEDTIMEMULTI) )
		{
			ulonglong rate,r;

			rate = msg1->lSize-msg1->lSizeDone;

			if ( (msg1->m_nMultiRate == 0) && (msg1->lRate != 0) )
				r=msg1->lRate;
			else
				r=msg1->m_nMultiRate;
			
			if ( r>0 )
				rate/=r;

			s += " [";
			s += CUtils::GetTimeString(rate);
			s += "]";
		}

		TransferListItem->pItem->setText(2,s.Data());
	}

	m_ActiveTransferMapMutex.unlock();
}

/** */
bool DCTransferView::UpdateTransferWaitList( CMessageDMFileObject * msg )
{
	QString s;
	bool bLVWaitUpdate = false;

	m_QueueMapMutex.lock();

	// get the list for the nick
	QString qnick = QString::fromAscii( msg->m_sNick.Data() );
	QueueParentMap * parents = m_QueueMap.value( qnick );

	if ( parents == 0 )
	{
		// not found
		if ( msg->m_bRemoveFile )
		{
			// abort
			m_QueueMapMutex.unlock();
			return bLVWaitUpdate;
		}
		else
		{
			// create new list for this nick
			parents = new QueueParentMap();
			m_QueueMap.insert( qnick, parents );
		}
	}

	// get the list for the hub
	QString qhubname = QString::fromAscii( msg->m_sHubName.Data() );
	QString qhubhost = QString::fromAscii( msg->m_sHubHost.Data() );
	DCTransferQueueParent * TransferQueueParent = parents->value( qhubname );
	
	if ( TransferQueueParent == 0 )
	{
		// create new list
		ListView_TRANSFERWAIT->setUpdatesEnabled(false);
		bLVWaitUpdate = true;

		TransferQueueParent = new DCTransferQueueParent();
		TransferQueueParent->pItem = new Q3ListViewItem( ListView_TRANSFERWAIT, qnick );
		TransferQueueParent->pItem->setText(1,qhubname);
		TransferQueueParent->pItem->setText(2,qhubhost);

		TransferQueueParent->sHubName = qhubname;
		TransferQueueParent->sHubHost = qhubhost;

		parents->insert( qhubname, TransferQueueParent );
	}
	else
	{
		// update the view
		if ( TransferQueueParent->sHubHost != qhubhost )
		{
			ListView_TRANSFERWAIT->setUpdatesEnabled(false);
			bLVWaitUpdate = true;
			TransferQueueParent->sHubHost = qhubhost;
			TransferQueueParent->pItem->setText(2,qhubhost);
		}
	}

	// get the fileobject from the file list
	QString qremotefile;
	DCTransferQueueChild * TransferQueueChild = 0;
	if ( !(msg->m_sRemoteFile.IsEmpty()) )
	{
		qremotefile = QString::fromAscii( msg->m_sRemoteFile.Data() );
		TransferQueueChild = TransferQueueParent->m_QueueChildMap.value( qremotefile );
	}

	// check for remove this entry
	if ( msg->m_bRemoveFile )
	{
		ListView_TRANSFERWAIT->setUpdatesEnabled(false);
		bLVWaitUpdate = true;

		// remove all files with the root
		if ( msg->m_sRemoteFile.IsEmpty() )
		{
			// remove all items from the list and view
			// this is now handled by the TransferQueueParent/TransferQueueChild destructors
			delete TransferQueueParent;
			parents->remove( qhubname );
			
			if ( parents->isEmpty() )
			{
				m_QueueMap.remove( qnick );
				delete parents;
			}
		}
		// remove only the given file
		else
		{
			// remove the file
			if ( TransferQueueChild != 0 )
			{
				TransferQueueParent->m_QueueChildMap.remove( qremotefile );
				delete TransferQueueChild;
			}

			// remove empty list ...
			if ( TransferQueueParent->m_QueueChildMap.isEmpty() )
			{
				parents->remove( qhubname );
				delete TransferQueueParent;
				
				if ( parents->isEmpty() )
				{
					m_QueueMap.remove( qnick );
					delete parents;
				}
			}
		}
	}
	// update the entry
	else
	{
		// set the user state
		switch(msg->m_eTransferWaitState)
		{
			case etwsWAIT:
				s = tr("Wait");
				break;
			case etwsIDLE:
				s = tr("Idle");
				break;
			case etwsRUN:
				s = tr("Run");
				s += " [";
				s += QString().setNum(msg->m_nConnections);
				s += "]";
				break;
			case etwsHUBOFFLINE:
				s = tr("Hub offline");
				break;
			case etwsUSEROFFLINE:
				s = tr("User offline");
				break;
			case etwsUSERBUSY:
				s = tr("User busy");
				break;
			case etwsSENDERROR:
				s = tr("Send error");
				break;
			default:
				s = tr("Unknown");
				break;
		}

		TransferQueueParent->pItem->setText(3,s);

		if ( !(msg->m_sRemoteFile.IsEmpty()) )
		{
			// create a entry for this file
			if ( TransferQueueChild == 0 )
			{
				ListView_TRANSFERWAIT->setUpdatesEnabled(false);
				bLVWaitUpdate = true;

				TransferQueueChild = new DCTransferQueueChild();
			
				// create and set object pointer
				TransferQueueChild->pObject = new CMessageDMFileObject();
				*(TransferQueueChild->pObject) = *msg;
				TransferQueueChild->pItem   = new Q3ListViewItem ( TransferQueueParent->pItem, "" );
				TransferQueueChild->pItem->setText(1, qremotefile );
				TransferQueueChild->pItem->setText(2, QString().setNum(msg->m_nSize) );

				TransferQueueParent->m_QueueChildMap.insert( qremotefile, TransferQueueChild );
			}

			// update the file state
			switch(msg->m_eTransferFileState)
			{
				case etfsNONE:
					s = tr("Idle");
					break;
				case etfsTRANSFER:
					s = tr("Transfer");
					break;
				case etfsERROR:
					s = tr("Error");
					break;
				case etfsPAUSE:
					s = tr("Pause");
					break;
				default:
					s = tr("Unknown");
					break;
			}

			if ( msg->m_bMulti )
			{
				s = "*"+s;
			}

			s += "/";
			s += QString().setNum(msg->m_nPriority);

			TransferQueueChild->pItem->setText(3,s);
			
			// the TTH may have been filled in from another source
			TransferQueueChild->pItem->setText(4, msg->m_sTTH.Data());
			
			if ( msg->m_pDirList )
			{
				/* make QT list of dirs actually in the queue */
				QStringList queuedirs;
				for ( std::list<CString>::const_iterator cit = msg->m_pDirList->begin(); cit != msg->m_pDirList->end(); ++cit )
				{
					queuedirs << QString::fromAscii( cit->Data() );
				}
				
				TransferQueueChild->pItem->setText(0,tr("%1 folders").arg(queuedirs.size()));
				
				/* make list of dirs currently shown as being in the queue */
				QList<Q3ListViewItem*> visdirs;
				for ( Q3ListViewItem * diritem = TransferQueueChild->pItem->firstChild(); diritem; diritem = diritem->nextSibling() )
				{
					visdirs << diritem;
				}
				
				/* remove from both lists entries that match */
				QList<Q3ListViewItem*>::iterator it = visdirs.begin();
				while ( it != visdirs.end() )
				{
					if ( queuedirs.removeAll( (*it)->text(1) ) > 0 )
					{
						it = visdirs.erase( it );
					}
					else
					{
						++it;
					}
				}
				
				/* Any items still in the list are no longer in the queue so delete them */
				for ( QList<Q3ListViewItem*>::const_iterator vit = visdirs.constBegin(); vit != visdirs.constEnd(); ++vit )
				{
					delete *vit;
					bLVWaitUpdate = true;
				}
				
				/* Remaining strings are new directories, create items for them */
				for ( QStringList::const_iterator sit = queuedirs.constBegin(); sit != queuedirs.constEnd(); ++sit )
				{
					Q3ListViewItem * newchild = new Q3ListViewItem( TransferQueueChild->pItem );
					newchild->setText( 1, *sit );
					bLVWaitUpdate = true;
				}
			}
			else
			{
				TransferQueueChild->pItem->setText(0,"");
				while ( TransferQueueChild->pItem->firstChild() )
				{
					delete TransferQueueChild->pItem->firstChild();
					bLVWaitUpdate = true;
				}
			}
		}
	}

	m_QueueMapMutex.unlock();

	return bLVWaitUpdate;
}

/** */
bool DCTransferView::UpdateLocalFileList( CMessageDMFileObject * msg )
{
	QString s;
	bool bLVWaitUpdate = false;
	QString hnindex;
	DCTransferQueueParent * TransferQueueParent = 0;
	DCTransferQueueChild * TransferQueueChild = 0;

	QString qnick = QString::fromAscii( msg->m_sNick.Data() );
	QString qhubname = QString::fromAscii( msg->m_sHubName.Data() );

	m_QueueLocalMapMutex.lock();

	if ( msg->m_sLocalFile.IsEmpty() )
	{
		if  ( msg->m_bRemoveFile == false )
		{
			// abort
			m_QueueLocalMapMutex.unlock();
			return bLVWaitUpdate;
		}
		else
		{
			// This is a bad case : when removing all downloads corresponding to a nick

			// get the list for the nick
			QueueParentMap * parents = m_QueueMap.value( qnick );
			if ( parents == 0 )
			{
				printf("Nick not found while updating LocalFileList\n");
				m_QueueLocalMapMutex.unlock();
				return bLVWaitUpdate;
			}

			// get the list for the hub
			TransferQueueParent = parents->value( qhubname );
			if ( TransferQueueParent == 0 )
			{
				printf("Hub not found while updating LocalFileList\n");
				m_QueueLocalMapMutex.unlock();
				return bLVWaitUpdate;
			}

			// get the list with the files
			// remove all items from the list
			for ( QueueChildMap::const_iterator it = TransferQueueParent->m_QueueChildMap.constBegin(); it != TransferQueueParent->m_QueueChildMap.constEnd(); ++it )
			{
				CMessageDMFileObject * msg2 = it.value()->pObject;
				hnindex  = QString::fromAscii( msg2->m_sHubName.Data() );
				hnindex += QString::fromAscii( "|" );
				hnindex += QString::fromAscii( msg2->m_sNick.Data() );

				QString lf = QString::fromAscii( msg2->m_sLocalFile.Data() );
				DCTransferQueueParent * localparent = m_QueueLocalMap.value( lf );
				if ( localparent != 0 )
				{
					DCTransferQueueChild * localchild = localparent->m_QueueChildMap.value( hnindex );
					if ( localchild != 0 )
					{
						bLVWaitUpdate = true;
						localparent->m_QueueChildMap.remove( hnindex );
						delete localchild;
						
						if ( localparent->m_QueueChildMap.isEmpty() )
						{
							m_QueueLocalMap.remove( lf );
							delete localparent;
						}
					}
				}
			}
			m_QueueLocalMapMutex.unlock();
			return bLVWaitUpdate;
		}
	}

	QString qlocalfile = QString::fromAscii( msg->m_sLocalFile.Data() );

	TransferQueueParent = m_QueueLocalMap.value( qlocalfile );
	if ( TransferQueueParent == 0 )
	{
		// not found
		if ( msg->m_bRemoveFile )
		{
			// abort
			m_QueueLocalMapMutex.unlock();
			return bLVWaitUpdate;
		}
		else
		{
			QString size_h;

			// create new list for this nick
			TransferQueueParent = new DCTransferQueueParent();

			size_h = QString().setNum(msg->m_nSize);
			size_h += " (";
			size_h += DCGuiUtils::GetSizeString(msg->m_nSize);
			size_h += ")";

			TransferQueueParent->pItem = new DC_QListViewItem( ListView_LOCALFILES );
			((DC_QListViewItem*)(TransferQueueParent->pItem))->mycol   = 1;
			((DC_QListViewItem*)(TransferQueueParent->pItem))->myvalue = msg->m_nSize;
			TransferQueueParent->pItem->setText(0,qlocalfile);
			TransferQueueParent->pItem->setText(1,size_h);
			TransferQueueParent->pItem->setText(4,msg->m_sTTH.Data());

			m_QueueLocalMap.insert( qlocalfile, TransferQueueParent );
		}
	}
	else
	{
		// update TTH
		if ( TransferQueueParent->pItem->text(4).isEmpty() )
		{
			if ( !(msg->m_sTTH.IsEmpty()) )
			{
				TransferQueueParent->pItem->setText(4,msg->m_sTTH.Data());
			}
		}
		else
		{
			if ( TransferQueueParent->pItem->text(4).toAscii().constData() != msg->m_sTTH )
			{
				printf("Warning TTH changed for '%s' was %s now %s\n",msg->m_sLocalFile.Data(),TransferQueueParent->pItem->text(4).toAscii().constData(),msg->m_sTTH.Data());
				TransferQueueParent->pItem->setText(4,msg->m_sTTH.Data());
			}
		}
	}

	hnindex  = qhubname;
	hnindex += "|";
	hnindex += qnick;
	
	TransferQueueChild = TransferQueueParent->m_QueueChildMap.value( hnindex );
	
	// check for remove this entry
	if ( msg->m_bRemoveFile )
	{
		if ( TransferQueueChild != 0 )
		{
			TransferQueueParent->m_QueueChildMap.remove( hnindex );
			delete TransferQueueChild;

			if ( TransferQueueParent->m_QueueChildMap.isEmpty() )
			{
				m_QueueLocalMap.remove( qlocalfile );
				delete TransferQueueParent;
			}
		}
	}
	else
	{
		if ( TransferQueueChild == 0 )
		{
			TransferQueueChild = new DCTransferQueueChild();

			TransferQueueChild->pItem = new DC_QListViewItem( TransferQueueParent->pItem );
			TransferQueueChild->pItem->setText(0,qnick);
			TransferQueueChild->pItem->setText(1,qhubname);
			TransferQueueChild->pItem->setText(2,QString::fromAscii(msg->m_sRemoteFile.Data()));

			TransferQueueParent->m_QueueChildMap.insert( hnindex, TransferQueueChild );
		}
		
		// set or update the user state
		switch(msg->m_eTransferWaitState)
		{
			case etwsWAIT:
				s = tr("Wait");
				break;
			case etwsIDLE:
				s = tr("Idle");
				break;
			case etwsRUN:
				s  = tr("Run");
				s += " [";
				s += QString().setNum(msg->m_nConnections);
				s += "]";
				break;
			case etwsHUBOFFLINE:
				s = tr("Hub offline");
				break;
			case etwsUSEROFFLINE:
				s = tr("User offline");
				break;
			case etwsUSERBUSY:
				s = tr("User busy");
				break;
			case etwsSENDERROR:
				s = tr("Send error");
				break;
			default:
				s = tr("Unknown");
				break;
		}
		
		TransferQueueChild->pItem->setText(3,s);
	}

	m_QueueLocalMapMutex.unlock();

	return true;
}

/** */
void DCTransferView::NewLocalFileBrowser( const bool lock )
{
	/* the InitTree line is duplicated
	 * otherwise gcc thinks d might be used uninitialised
	 */
	
	if ( lock )
	{
		QDialog * d = new QDialog(this);
		d->setWindowTitle( tr("My") + " - Filebrowser" );
		d->setWindowIcon( g_pIconLoader->GetPixmap(eiVIEW_SIDETREE) );
		QGridLayout * Layout = new QGridLayout();
		Layout->setMargin(4);
		d->setLayout(Layout);
		DCFileBrowser * bft = new DCFileBrowser( d, false );
		Layout->addWidget( bft, 0, 0 );
		bft->InitTree(g_pConfig->GetNick().Data(),QString::null,QString::null,"/dev/null/ownfilelist");
		d->exec();
		delete d;
	}
	else
	{
		DCFileBrowser * bft = new DCFileBrowser( g_pConnectionManager->GetMdiArea() );
		QMdiSubWindow * subwin = g_pConnectionManager->GetMdiArea()->addSubWindow(bft);
		bft->setAttribute(Qt::WA_DeleteOnClose);
		bft->InitTree(g_pConfig->GetNick().Data(),QString::null,QString::null,"/dev/null/ownfilelist");
		subwin->setWindowIcon( g_pIconLoader->GetPixmap(eiVIEW_SIDETREE) );
		bft->show();
	}
}

/** */
void DCTransferView::NewFileBrowser( QString nick, QString hubname, QString hubhost, QString filename, QString jumpto, QStringList dirs )
{
	DCFileBrowser *bft;
	bft = new DCFileBrowser( g_pConnectionManager->GetMdiArea() );
	bft->setAttribute(Qt::WA_DeleteOnClose);
	QMdiSubWindow * subwin = g_pConnectionManager->GetMdiArea()->addSubWindow(bft);

	// set transfer
	bft->InitTree(nick,hubname,hubhost,filename,jumpto,dirs);
	subwin->setWindowIcon( g_pIconLoader->GetPixmap(eiVIEW_SIDETREE) );
	bft->show();
}

bool DCTransferView::IsUserInQueue( QString Nick, QString Hubname )
{
	m_QueueMapMutex.lock();

	// get the list corresponding to the nick
	QueueParentMap * parents = m_QueueMap.value( Nick );
	if ( parents == 0 )
	{
		m_QueueMapMutex.unlock();
		return false;
	}

	// search for the corresponding hub
	if ( parents->contains( Hubname ) )
	{
		m_QueueMapMutex.unlock();
		return true;
	}

	m_QueueMapMutex.unlock();
	return false;
}

/** */
void DCTransferView::GetLocalFilesList( QStringList & LocalFiles, QString tth, ulonglong size )
{
	Q3ListViewItem * LocalFileItem = ListView_LOCALFILES->firstChild();
	
	LocalFiles.clear();
	
	while ( LocalFileItem )
	{
		if ( LocalFileItem->text(4).isEmpty() )
		{
			if ( size == ((DC_QListViewItem*)LocalFileItem)->myvalue )
			{
				LocalFiles.push_back( LocalFileItem->text(0) );
			}
		}
		else
		{
			if ( tth == LocalFileItem->text(4) )
			{
				LocalFiles.push_back( LocalFileItem->text(0) );
			}
		}
		
		LocalFileItem = LocalFileItem->nextSibling();
	}
}

/** */
void DCTransferView::GetLocalFilesList( QStringList & LocalFiles, ulonglong size )
{
	Q3ListViewItem * LocalFileItem = ListView_LOCALFILES->firstChild();

	LocalFiles.clear();

	while( LocalFileItem )
	{
		if ( LocalFileItem->text(1) != "0" ) // size
		{
			if (( size == 0 ) || ( ((DC_QListViewItem*)LocalFileItem)->myvalue == size ))
			{
				LocalFiles.push_back( LocalFileItem->text(0) );
			}
		}
		LocalFileItem = LocalFileItem->nextSibling();
	}
}

/** */
ulonglong DCTransferView::FindTransferID( Q3ListViewItem * item )
{
	CMessageDMTransferObject * msg;
	DCTransferListItem * TransferListItem = 0;
	ulonglong id = 0;

	m_ActiveTransferMapMutex.lock();

	for ( ActiveTransferMap::const_iterator it = m_ActiveTransferMap.constBegin(); it != m_ActiveTransferMap.constEnd(); ++it )
	{
		TransferListItem = it.value();
		msg = TransferListItem->pObject;

		if ( TransferListItem->pItem == item )
		{
			id = msg->m_nTransferID;
			break;
		}
	}

	m_ActiveTransferMapMutex.unlock();

	return id;
}

/** */
bool DCTransferView::GetTransferMessageObject( Q3ListViewItem * item, CMessageDMTransferObject * obj )
{
	bool res = false;
	
	CMessageDMTransferObject * msg;
	DCTransferListItem * TransferListItem = 0;

	m_ActiveTransferMapMutex.lock();

	for ( ActiveTransferMap::const_iterator it = m_ActiveTransferMap.constBegin(); it != m_ActiveTransferMap.constEnd(); ++it )
	{
		TransferListItem = it.value();
		msg = TransferListItem->pObject;

		if ( TransferListItem->pItem == item )
		{
			*obj = *msg;
			res = true;
			break;
		}
	}

	m_ActiveTransferMapMutex.unlock();

	return res;
}

/** */
eConnectionState DCTransferView::GetTransferDirection( ulonglong sid )
{
	CMessageDMTransferObject * msg;
	eConnectionState state = estNONE;

	m_ActiveTransferMapMutex.lock();

	DCTransferListItem * TransferListItem = m_ActiveTransferMap.value(sid);
	if ( TransferListItem != 0 )
	{
		msg = TransferListItem->pObject;
		if ( msg )
			state = msg->eState;
	}

	m_ActiveTransferMapMutex.unlock();

	return state;
}

/** */
void DCTransferView::ConnectToAllHubs()
{
	m_QueueMapMutex.lock();

	for ( TransferQueueMap::const_iterator it1 = m_QueueMap.constBegin(); it1 != m_QueueMap.constEnd(); ++it1 )
	{
		QueueParentMap * parents = it1.value();
		
		for ( QueueParentMap::const_iterator it2 = parents->constBegin(); it2 != parents->constEnd(); ++it2 )
		{
			DCTransferQueueParent * TransferQueueParent = it2.value();
			g_pConnectionManager->Connect( TransferQueueParent->sHubName.toAscii().constData(), TransferQueueParent->sHubHost.toAscii().constData() );
		}
	}

	m_QueueMapMutex.unlock();
}

/** */
void DCTransferView::SearchFileClone(QString filename, ulonglong size)
{
	QString searchtxt;
	QRegExp re_ext;

	// convert local file name into a suitable search expression
	if ( filename.contains('\\') )
		searchtxt = filename.section('\\',-1);
	else
		searchtxt = filename.section('/',-1);
	searchtxt.replace("_"," ");
	searchtxt.replace("-"," ");
	re_ext = QRegExp("\\.(\\w{3,4})$");
	searchtxt.replace( re_ext, " "+re_ext.cap(1) );
	re_ext = QRegExp(",");
	while (searchtxt.contains(re_ext))
	    searchtxt.replace(re_ext," ");
	re_ext = QRegExp("\\s(a|the|and|or|in|to|of)\\s");
	re_ext.setCaseSensitivity(Qt::CaseInsensitive);
	while (searchtxt.contains(re_ext))
	    searchtxt.replace(re_ext," ");
	re_ext = QRegExp("^(the|a)\\s");
	re_ext.setCaseSensitivity(Qt::CaseInsensitive);
	while (searchtxt.contains(re_ext))
	    searchtxt.remove(re_ext);
	re_ext = QRegExp("\\s{2,}");
	while (searchtxt.contains(re_ext))
	    searchtxt.replace(re_ext," ");

	/* there is no exact size search type so do at least half size */
	DCHubSearch * hubsearch = new DCHubSearch( g_pConnectionManager->GetMdiArea() );
	hubsearch->SetSearchForFile( searchtxt, eftALL, 1, size/2 );
	hubsearch->show();
	hubsearch->StartSearchWithPrompt();
}

/** */
void DCTransferView::EditExistingTransfer(QString & nick, QString & hubname, QString & hubhost, CList<DCHubObject> * list )
{
	DCEditTransfer * dialg = new DCEditTransfer(this);

	dialg->Init(nick,hubname,hubhost,list);

	if ( dialg->exec() == QDialog::Accepted )
	{
		CString OldNick;
		CString OldHubname;

		OldNick = nick.toAscii().constData();
		OldHubname = hubname.toAscii().constData();

		nick	= dialg->LineEdit_NICK->text();
		hubname	= dialg->LineEdit_HUBNAME->text();
		hubhost	= dialg->LineEdit_HUBHOST->text();

		DLM_QueueEdit( OldNick, OldHubname, nick.toAscii().constData(), hubname.toAscii().constData(), hubhost.toAscii().constData());
	}

	delete dialg;
}

/** */
void DCTransferView::slotRightButtonClickedTransferList( Q3ListViewItem * item , const QPoint &, int )
{
	QAction * chosen = 0;
	QMenu * m;
	CMessageDMTransferObject transfermsg;
	DCClient * client = 0;
	QMap<QAction*, DC_UserMenuCommand*> addedcommands;
	
	if( item == 0 )
	{
		return;
	}

	if ( GetTransferMessageObject(item,&transfermsg) == false )
	{
		return;
	}

	m = new QMenu(this);

	QAction * privchat = DCMenuHandler::addAction( m, emiPRIVATE_CHAT, (transfermsg.m_sDstNick.NotEmpty()) );
	QAction * browse = DCMenuHandler::addAction( m, emiBROWSE_USER_FILES, (transfermsg.m_sDstNick.NotEmpty()) ); // ,(UserFileInfo.sUserFileList.NotEmpty()) );
	DCMenuHandler::addAction( m, emiSEPARATOR );
	QAction * close = DCMenuHandler::addAction( m, emiCLOSE_TRANSFER );
	QAction * rate = DCMenuHandler::addAction( m, emiCHANGE_TRANSFER_RATE, (GetTransferDirection(transfermsg.m_nTransferID) == estTRANSFERUPLOAD) && (g_pConfig->GetDynamicUploadRate() == false));

	client = g_pConnectionManager->GetClientForHub( transfermsg.sHubName, transfermsg.m_sHubHost );
	
	if ( client != 0 )
	{
		addedcommands = client->AddMenuCommands( m, euccChat );
	}

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

	delete m;

	if ( chosen == privchat )
        {
                // open chat with user
                g_pConnectionManager->OpenPrivateChat( transfermsg.sHubName.Data(), transfermsg.m_sHubHost.Data(), transfermsg.m_sDstNick.Data() );
        }
        else if ( chosen == browse )
        {
		// TODO: check if hub online ...

                // add transfer to the waitlist
		CString empty;
                DLM_QueueAdd( transfermsg.m_sDstNick, transfermsg.sHubName,
                              transfermsg.m_sHubHost,
                              DC_USER_FILELIST, DC_USER_FILELIST, empty, empty, eltBUFFER,
                              0, 0, 0, empty );
        }
	else if ( chosen == close )
	{
		if ( DLM_TransferClose( transfermsg.m_nTransferID ) == false )
		{
			// TODO: error message
		}
	}
	else if ( chosen == rate )
	{
		bool ok = false;
		ulonglong rate;

		if ( DLM_TransferGetRate( transfermsg.m_nTransferID, rate ) == false )
		{
			// TODO: error message
		}
		else
		{
			rate = QInputDialog::getInteger(
				this,
				tr("Change Transfer-Rate"),
				tr("Please enter a Transfer-Rate [B/s] (0=off)"),
				rate, 0, 9999999, 512,
				&ok
			);
		}

		if ( ok )
		{
			if ( (rate < 512) && (rate != 0) )
			{
				rate = 512;
			}

			if ( DLM_TransferSetRate( transfermsg.m_nTransferID, rate ) == false )
			{
				// TODO: error message
			}
		}
	}
	else if ( addedcommands.contains( chosen ) )
	{
		DC_UserMenuCommand * umc = addedcommands[ chosen ];
		
		QString origcommand = umc->m_sCommand;
		QString usercommand = client->replaceCommandTags( origcommand, transfermsg.m_sDstNick.Data() );
		
		if ( usercommand.isEmpty() )
		{
			// had a %[line:reason] but dialog was cancelled
			return;
		}
		
		QString fullfilename, filesize, filesizeshort, filetth;
		
		fullfilename = transfermsg.m_sDstFile.Data();
		filesize.setNum(transfermsg.lSize);
		filesizeshort = DCGuiUtils::GetSizeString( transfermsg.lSize );
		
		filetth = item->text(6);
		if ( filetth.isEmpty() )
		{
			filetth = tr("None");
		}
		
		usercommand.replace( "%[file]", fullfilename );
		usercommand.replace( "%[fileFN]", fullfilename );
		
		usercommand.replace( "%[filesize]", filesize );
		usercommand.replace( "%[fileSI]", filesize );
		
		usercommand.replace( "%[filesizeshort]", filesizeshort );
		usercommand.replace( "%[fileSIshort]", filesizeshort );
		
		usercommand.replace( "%[tth]", filetth );
		usercommand.replace( "%[fileTR]", filetth );
		
		usercommand.replace( "%[type]", tr("File") );
		usercommand.replace( "%[speed]", CUtils::GetTransferString( transfermsg.lRate ).Data() );
		
		client->SendString( usercommand.toAscii().constData() );
	}
}

/** */
void DCTransferView::slotRightButtonClickedTransferWaitList( Q3ListViewItem * /*item*/ , const QPoint &, int )
{
        QAction * chosen = 0;
        QMenu * m;
        Q3ListViewItem * item1;
        QString nick,hubname,hubhost,file;
        CUserFileInfo UserFileInfo;
        QList<Q3ListViewItem*> selitems;
        Q3ListViewItem * curitem;
        bool inactiveTransfer = true, b;
	int numSelected;
	DCClient * client = 0;
	QMap<QAction*, DC_UserMenuCommand*> addedcommands;
	bool addUserCommands = true;

	numSelected = DCGuiUtils::SelectedItems( ListView_TRANSFERWAIT, selitems );

	if ( numSelected == 0 )
	{
		return;
	}

	for ( int i = 0; i < selitems.size(); i++ )
        {
		curitem = selitems.at(i);
		
		if ( curitem->depth() == 2 )
		{
			item1 = curitem->parent()->parent();
		}
                else if ( curitem->depth() == 1 )
                {
                        item1 = curitem->parent();
                }
                else
                {
                        item1 = curitem;
                }

                if ( item1 == 0 )
                {
                        return;
                }

                nick    = item1->text(0);
                hubname = item1->text(1);
		
		if ( (!hubhost.isEmpty()) && (hubhost != item1->text(2)) )
		{
			addUserCommands = false;
		}
		
                hubhost = item1->text(2);

		if ( item1 != curitem )
		{
			if ( curitem->depth() == 2 )
			{
				file = curitem->parent()->text(1);
			}
			else
			{
				file = curitem->text(1);
			}
		}
		else
		{
			file = "";
		}

		if ( DLM_QueueGetFileInfo(nick.toAscii().constData(),hubname.toAscii().constData(),hubhost.toAscii().constData(),file.toAscii().constData(),&UserFileInfo) == false )
		{
			return;
		}

		inactiveTransfer = inactiveTransfer && ( ((UserFileInfo.eWaitState != etwsRUN) && (UserFileInfo.eWaitState != etwsWAIT)) ||
					( (!file.isEmpty()) && (UserFileInfo.eFileState!=etfsTRANSFER)));
        }

        if ( numSelected != 1 )
        {
		nick = hubname = hubhost = "";
        }

	m = new QMenu(this);

	QAction * pause = DCMenuHandler::addAction( m, emiPAUSE_TRANSFER_QUEUE );
	QAction * resume = DCMenuHandler::addAction( m, emiRESUME_TRANSFER_QUEUE );
	QAction * remove = DCMenuHandler::addAction( m, emiREMOVE_TRANSFER_QUEUE, inactiveTransfer );
	//DCMenuHandler::InsertMenu( m, emiREMOVE_TRANSFER_QUEUE_DISK, (inactiveTransfer && false) ); //(TransferItem.eState == etwsIDLE) );
	DCMenuHandler::addAction( m, emiSEPARATOR );
	QAction * tryconn = DCMenuHandler::addAction( m, emiTRY_CONNECT, (inactiveTransfer) );
	QAction * connhub = DCMenuHandler::addAction( m, emiCONNECT_TO_HUB );
	QAction * connallhub = DCMenuHandler::addAction( m, emiCONNECT_TO_ALL_HUBS );
	QAction * browse = DCMenuHandler::addAction( m, emiBROWSE_USER_FILES, (numSelected==1) );
	DCMenuHandler::addAction( m, emiSEPARATOR );
	QAction * fileinfo = DCMenuHandler::addAction( m, emiFILE_INFO, ((UserFileInfo.sLocalFile.NotEmpty()) && (numSelected==1)) );
	DCMenuHandler::addAction( m, emiSEPARATOR );
	QAction * edit = DCMenuHandler::addAction( m, emiEDIT_TRANSFER, ((selitems.first()->depth() == 0) && (inactiveTransfer) && (numSelected==1)) );
	QAction * editprio = DCMenuHandler::addAction( m, emiEDIT_FILE_PRIORITY );
	QAction * updserver = DCMenuHandler::addAction( m, emiUPDATE_SERVER);
	QAction * save = DCMenuHandler::addAction( m, emiSAVE_QUEUE );

	if ( addUserCommands )
	{
		curitem = selitems.first();
		if ( curitem->depth() == 2 )
		{
			curitem = curitem->parent()->parent();
		}
		else if ( curitem->depth() == 1 )
		{
			curitem = curitem->parent();
		}
		
		client = g_pConnectionManager->GetClientForHub( curitem->text(1).toAscii().constData(),curitem->text(2).toAscii().constData() );
		
		if ( client != 0 )
		{
			addedcommands = client->AddMenuCommands( m, euccChat );
		}
	}

        chosen = m->exec(QCursor::pos());
        delete m;

        if ( chosen == connhub )
        {
                for ( int i = 0; i < selitems.size(); i++ )
                {
			curitem = selitems.at(i);
			
			if ( curitem->depth() == 2 )
			{
				item1 = curitem->parent()->parent();
			}
                        else if ( curitem->depth() == 1 )
                        {
                                item1 = curitem->parent();
                        }
                        else
                        {
                                item1 = curitem;
                        }
                        hubname = item1->text(1);
                        hubhost	= item1->text(2);

			if ( g_pConnectionManager->IsHubOnline(hubname.toAscii().constData(),hubhost.toAscii().constData()) == ehsNONE )
			{
				g_pConnectionManager->Connect( hubname.toAscii().constData(), hubhost.toAscii().constData() );
			}
		}
        }
        else if ( chosen == connallhub )
        {
                ConnectToAllHubs();
        }
        else if ( chosen == browse )
        {
		DLM_QueueAdd(
			nick.toAscii().constData(),
			hubname.toAscii().constData(),
			hubhost.toAscii().constData(),
			DC_USER_FILELIST,
			DC_USER_FILELIST,
			file.toAscii().constData(), // jump to file
			CString(),
			eltBUFFER,
			0,
			0,
			0,
			CString()
		);
        }
        else if ( chosen == tryconn )
        {
			for ( int i = 0; i < selitems.size(); i++ ) {
				curitem = selitems.at(i);
				if ( curitem->depth() == 2 ) {
					item1 = curitem->parent()->parent();
				} else if ( curitem->depth() == 1 ) {
					item1 = curitem->parent();
				} else {
					item1 = curitem;
				}
				nick    = item1->text(0);
				hubname = item1->text(1);
                if ( DLM_TransferConnect( nick.toAscii().constData(), hubname.toAscii().constData() ) == false ) {
					// error message
					QMessageBox::critical( this, tr("Try Connect"),
						tr("User and Hub not found in the queue !") + "\n\n" +
						tr("Nick:") + " '" +
						nick + "'\n" +
						tr("Hub:") + " '" + hubname + "'\n" );
				}
			}
        }
	else if ( (chosen == pause) || (chosen == resume) )
	{
		if ( chosen == pause )
		{
			b = true;
		}
		else
		{
			b = false;
		}

                for ( int i = 0; i < selitems.size(); i++ )
                {	
			curitem = selitems.at(i);
			
			if ( curitem->depth() == 2 )
			{
				item1 = curitem->parent()->parent();
				file = curitem->parent()->text(1);
			}
                        else if ( curitem->depth() == 1 )
                        {
                                item1 = curitem->parent();
				file = curitem->text(1);
                        }
                        else
                        {
                                item1 = curitem;
				file = "";
                        }

                        nick    = item1->text(0);
                        hubname = item1->text(1);

                        if ( DLM_QueuePause( nick.toAscii().constData(), hubname.toAscii().constData(), file.toAscii().constData(), b ) == false )
                        {
                                // TODO: error handling
                        }
                }
	}
        else if ( chosen == remove )
        {
		if (g_pConfig->GetQueryOnFileDelete()) {
			// first we ask the user
			switch( QMessageBox::warning( this, tr("Remove Transfer"),
				tr("You are sure ?"),
				tr("Remove"),
				tr("Cancel"), 0, 0, 1 ) )
			{
				case 1: // The user clicked the Quit or pressed Escape
					return;
				default:
					break;
			}
		}

                for ( int i = 0; i < selitems.size(); i++ )
                {
			curitem = selitems.at(i);
			
			if ( curitem->depth() == 2 )
			{
				/* removing the filelist removes all folders */
				if ( curitem->parent()->isSelected() )
				{
					continue;
				}
				item1 = curitem->parent()->parent();
				file = curitem->text(1);
			}
                        else if ( curitem->depth() == 1 )
                        {
                                item1 = curitem->parent();
				file = curitem->text(1);
                        }
                        else
                        {
                                item1 = curitem;
				file = "";
                        }

                        nick    = item1->text(0);
                        hubname = item1->text(1);

			if ( curitem->depth() == 2 )
			{
				const int res = DLM_QueueRemoveDirectory( nick.toAscii().constData(),hubname.toAscii().constData(),file.toAscii().constData());
				switch ( res )
				{
					case 0:
						// no error
						break;
					case 1:
						QMessageBox::warning( this, tr("Remove folder from queue"), tr("User/hub not found") );
						break;
					case 2:
						QMessageBox::warning( this, tr("Remove folder from queue"), tr("No directories queued for that user") );
						break;
					case 3:
						QMessageBox::warning( this, tr("Remove folder from queue"), tr("Directory not found") );
						break;
					default:
						break;
				}
			}
			else
			{
				if ( DLM_QueueRemove(nick.toAscii().constData(),hubname.toAscii().constData(),file.toAscii().constData()) == false )
				{
					// TODO: error handling
				}
			}
                }
        }
        else if ( chosen == fileinfo )
        {
		DCFileTransferInfo * ft = new DCFileTransferInfo( UserFileInfo.sLocalFile, g_pConnectionManager->GetMdiArea() );
		g_pConnectionManager->GetMdiArea()->addSubWindow( ft );
		ft->show();
        }
        else if ( chosen == updserver )
        {
                for ( int i = 0; i < selitems.size(); i++ )
                {
			curitem = selitems.at(i);
			
			if ( curitem->depth() == 2 )
			{
				item1 = curitem->parent()->parent();
			}
                        else if ( curitem->depth() == 1 )
                        {
                                item1 = curitem->parent();
                        }
                        else
                        {
                                item1 = curitem;
                        }

                        nick    = item1->text(0);
                        hubname = item1->text(1);

			if ( DLM_QueueUpdateHub( nick.toAscii().constData(), hubname.toAscii().constData() ) == false )
			{
				// TODO: error message ...
			}
		}
        }
        else if ( chosen == edit )
        {
		CList<DCHubObject> list;

		curitem = selitems.first();

                nick    = curitem->text(0);
                hubname = curitem->text(1);
                hubhost = curitem->text(2);

		DLM_QueueGetHub( nick.toAscii().constData(), hubname.toAscii().constData(), &list );

                EditExistingTransfer( nick, hubname, hubhost, &list );
        }
	else if ( chosen == editprio )
	{
		bool ok = false;
		int priority=0;

		priority = QInputDialog::getInteger(
			this,
			tr("Change File-Priority"),
			tr("Please enter a priority"),
			priority, 0, MAX_FILE_PRIORITY, 1,
			&ok
		);

		if ( ok )
		{
	                for ( int i = 0; i < selitems.size(); i++ )
        	        {
				curitem = selitems.at(i);
				
	                        if ( curitem->depth() == 0 )
        	                {
			                for ( item1 = curitem->firstChild(); item1; item1 = item1->nextSibling() )
        			        {
			                        nick    = curitem->text(0);
        			                hubname = curitem->text(1);
						file    = item1->text(1);

						if ( DLM_QueueSetFilePriority( nick.toAscii().constData(), hubname.toAscii().constData(), file.toAscii().constData(), priority ) == false )
						{
							// TODO: error message ...
						}
					}
				}
	                        else if ( curitem->depth() == 1 )
        	                {
                	                item1 = curitem->parent();

		                        nick    = item1->text(0);
        		                hubname = item1->text(1);
					file    = curitem->text(1);

					if ( DLM_QueueSetFilePriority( nick.toAscii().constData(), hubname.toAscii().constData(), file.toAscii().constData(), priority ) == false )
					{
						// TODO: error message ...
					}
				}
				else if ( curitem->depth() == 2 )
				{
					item1   = curitem->parent()->parent();
					nick    = item1->text(0);
					hubname = item1->text(1);
					file    = curitem->parent()->text(1);
					
					DLM_QueueSetFilePriority( nick.toAscii().constData(), hubname.toAscii().constData(), file.toAscii().constData(), priority );
				}
			}
		}
	}
        else if ( chosen == save )
        {
                DLM_SaveQueue();
        }
	else if ( addedcommands.contains( chosen ) )
	{
		DC_UserMenuCommand * umc = addedcommands[ chosen ];
		
		QString usercommand = umc->m_sCommand;
		QString origUserCommand = usercommand;
		
		QString fullfilename, filesize, filesizeshort, filetth;
		QStringList nicksDone;
		
		Q3ListViewItem * parent;
		
		for ( int i = 0; i < selitems.size() ; i++ )
		{
			curitem = selitems.at(i);
			parent = curitem;
			
			if ( curitem->depth() == 2 )
			{
				parent = curitem->parent()->parent();
			}
			else if ( curitem->depth() == 1 )
			{
				parent = curitem->parent();
			}
			
			if ( (umc->m_nType == euctRawOnce) && (nicksDone.contains(parent->text(0))) )
			{
				continue;
			}
			
			usercommand = client->replaceCommandTags( origUserCommand, parent->text(0) );
			
			if ( usercommand.isEmpty() )
			{
				// had a %[line:reason] but dialog was cancelled
				continue;
			}
			
			if ( curitem != parent )
			{
				QString filetype;
				if ( curitem->depth() == 2 )
				{
					fullfilename = curitem->text(1);
					filesize = "0";
					filesizeshort = DCGuiUtils::GetSizeString( 0 );
					filetth = tr("None");
					filetype = tr("Directory");
				}
				else
				{
					fullfilename = curitem->text(1);
					filesize = curitem->text(2);
					filesizeshort = DCGuiUtils::GetSizeString( filesize.toULongLong() );
					
					filetth = curitem->text(4);
					if ( filetth.isEmpty() )
					{
						filetth = tr("None");
					}
					
					filetype = tr("File");
				}
				
				usercommand.replace( "%[file]", fullfilename );
				usercommand.replace( "%[fileFN]", fullfilename );
				
				usercommand.replace( "%[filesize]", filesize );
				usercommand.replace( "%[fileSI]", filesize );
				
				usercommand.replace( "%[filesizeshort]", filesizeshort );
				usercommand.replace( "%[fileSIshort]", filesizeshort );
				
				usercommand.replace( "%[tth]", filetth );
				usercommand.replace( "%[fileTR]", filetth );
				
				usercommand.replace( "%[type]", filetype );
			}
			
			client->SendString( usercommand.toAscii().constData() );
			
			nicksDone << parent->text(0);
		}
	}

	selitems.clear();
}


/** */
void DCTransferView::slotRightButtonClickedLocalFilesList( Q3ListViewItem * item , const QPoint &, int )
{
	QAction * chosen = 0;
	QMenu * m;
	Q3ListViewItem * item1;
	QString localfile,nick,hubname,remotefile;
	ulonglong size;
	CUserFileInfo UserFileInfo;
	bool removetransfer = true;

	if( item == 0 )
	{
		return;
	}

	if ( item->depth() == 1 )
	{
		item1 = item->parent();
	}
	else
	{
		item1 = item;
	}

	if ( item1 == 0 )
	{
		return;
	}

	localfile = item1->text(0);
	size      = item1->text(1).left(item1->text(1).indexOf(' ')).toULongLong();

	if ( item->depth() == 1 )
	{
		nick       = item->text(0);
		hubname    = item->text(1);
		remotefile = item->text(2);

		if (DLM_QueueGetFileInfo(nick.toAscii().constData(),hubname.toAscii().constData(),"hubhost",remotefile.toAscii().constData(),&UserFileInfo) == false)
	        {
			return;
		}
		removetransfer = ((UserFileInfo.eWaitState != etwsRUN) && (UserFileInfo.eWaitState != etwsWAIT)) ||
                                   ( (!remotefile.isEmpty()) && (UserFileInfo.eFileState!=etfsTRANSFER));
	}
	else
	{
		Q3ListViewItem * tmpitem;
		for(tmpitem=item->firstChild(); tmpitem; tmpitem=tmpitem->nextSibling())
                {
			nick       = tmpitem->text(0);
			hubname    = tmpitem->text(1);
			remotefile = tmpitem->text(2);
			if (DLM_QueueGetFileInfo(nick.toAscii().constData(),hubname.toAscii().constData(),"hubhost",remotefile.toAscii().constData(),&UserFileInfo) == false)
			{
				return;
			}
			removetransfer = removetransfer && ( ((UserFileInfo.eWaitState != etwsRUN) && (UserFileInfo.eWaitState != etwsWAIT)) ||
							     ( (!remotefile.isEmpty()) && (UserFileInfo.eFileState!=etfsTRANSFER)));
		}

		nick       = "";
		hubname    = "";
		remotefile = "";
	}

	m = new QMenu(this);

	QAction * clone = DCMenuHandler::addAction( m, emiSEARCH_FILE_CLONE, (size > 0) );
	QAction * clonetth = DCMenuHandler::addAction( m, emiSEARCH_FILE_CLONE_TTH, !(item1->text(4).isEmpty()) );
	DCMenuHandler::addAction( m, emiSEPARATOR );
	QAction * remove = DCMenuHandler::addAction( m, emiREMOVE_TRANSFER_QUEUE, removetransfer );
	//DCMenuHandler::InsertMenu( m, emiREMOVE_TRANSFER_QUEUE_DISK, (removetransfer && false) ); //(TransferItem.eState == etwsIDLE) );
	DCMenuHandler::addAction( m, emiSEPARATOR );

	QAction * info = DCMenuHandler::addAction( m, emiFILE_INFO, (!localfile.isEmpty()) && (size > 0) );

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

	delete m;

        if ( chosen == remove )
        {
		if (g_pConfig->GetQueryOnFileDelete()) {
			// first we ask the user
			switch( QMessageBox::warning( this, tr("Remove Transfer"),
				tr("You are sure ?"),
				tr("Remove"),
				tr("Cancel"), 0, 0, 1 ) )
			{
				case 1: // The user clicked the Quit or pressed Escape
					return;
				default:
					break;
			}
		}

                if (item->depth() == 0)
                {
                        Q3ListViewItem * tmpitem;
                        for(tmpitem=item->firstChild(); tmpitem; tmpitem=tmpitem->nextSibling())
                        {
                                nick       = tmpitem->text(0);
                                hubname    = tmpitem->text(1);
                                remotefile = tmpitem->text(2);
                                if ( DLM_QueueRemove(nick.toAscii().constData(),hubname.toAscii().constData(),remotefile.toAscii().constData()) == false )
                                {
                                        // TODO: error handling
                                }
                        }
                }
                if ( DLM_QueueRemove(nick.toAscii().constData(),hubname.toAscii().constData(),remotefile.toAscii().constData()) == false )
                {
                        // TODO: error handling
                }
        }
	else if ( chosen == info )
	{
		DCFileTransferInfo * ft = new DCFileTransferInfo( localfile.toAscii().constData(), g_pConnectionManager->GetMdiArea() );
		g_pConnectionManager->GetMdiArea()->addSubWindow( ft );
		ft->show();
	}
	else if ( chosen == clone )
	{
		if ( remotefile.isEmpty() )
			SearchFileClone(localfile, size);
		else
			SearchFileClone(remotefile, size);
	}
	else if ( chosen == clonetth )
	{
		DCHubSearch * hubsearch = new DCHubSearch( g_pConnectionManager->GetMdiArea() );
		hubsearch->SetSearchForFile( item1->text(4), eftHASH );
		hubsearch->show();
		hubsearch->StartSearchWithPrompt();
	}
}

/** */
void DCTransferView::slotDoubleClickedTransferWaitList( Q3ListViewItem * /*item*/ )
{
	Q3ListViewItem * item;
	Q3ListViewItem * item0;
	QString nick;
	QString hubname;
	QString hubhost;
        CUserFileInfo UserFileInfo;

	item = ListView_TRANSFERWAIT->currentItem();

	if (item->depth() == 0)
	{
		item0 = item;
	}
	else
	{
		item0 = item->parent();
	}

	nick    = item0->text(0);
	hubname = item0->text(1);
	hubhost = item0->text(2);

	if (item->depth() == 0)
	{
		if ( g_pConnectionManager->IsHubOnline(hubname.toAscii().constData(),hubhost.toAscii().constData()) == ehsNONE )
		{
			if ( DLM_QueueUpdateHub( nick.toAscii().constData(), hubname.toAscii().constData() ) == false )
			{
				// TODO: error message ...
			}
			g_pConnectionManager->Connect( hubname.toAscii().constData(), hubhost.toAscii().constData() );
			return;
		}
	}

	if ( DLM_QueueGetFileInfo(nick.toAscii().constData(),hubname.toAscii().constData(),hubhost.toAscii().constData(),CString(),&UserFileInfo) == false )
	{
		return;
	}

	if ( (UserFileInfo.eWaitState != etwsRUN) && (UserFileInfo.eWaitState != etwsWAIT) )
	{
		if ( DLM_TransferConnect( nick.toAscii().constData(), hubname.toAscii().constData() ) == false )
		{
			// error message
			QMessageBox::critical( this, tr("Try Connect"),
				tr("User and Hub not found in the queue !") + "\n\n" +
				tr("Nick:") + " '" +
				nick + "'\n" +
				tr("Hub:") + " '" + hubname + "'\n" );
		}
	}
}

/** */
void DCTransferView::slotContextMenuUserSlotList( const QPoint & )
{
	QList<QTreeWidgetItem*> selected = TreeWidget_SLOTS->selectedItems();
	
	if ( selected.size() == 0 )
	{
		return;
	}
	
	QTreeWidgetItem * item = selected.at(0);
	QAction * chosen = 0;
	QMenu * m;

	if( item == 0 )
	{
		return;
	}

	m = new QMenu(this);

	QAction * remove = DCMenuHandler::addAction( m, emiREMOVE );

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

	delete m;

        if ( chosen == remove )
        {
		DLM_AddUserSlot( item->text(0).toAscii().constData(), item->text(1).toAscii().constData(), 0 );
        }
}

/** */
void DCTransferView::slotRightButtonClickedLog( const QPoint& )
{
	QAction * chosen = 0;
	QMenu *m;

	m = new QMenu(this);

	QAction * copy = DCMenuHandler::addAction( m, emiCOPY, TextEdit_LOG->textCursor().hasSelection() );
	QAction * clear = DCMenuHandler::addAction( m, emiCLEAR, true );
	QAction * selectall = DCMenuHandler::addAction( m, emiSELECT_ALL, true );

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

	delete m;

	if ( chosen == copy )
	{
		TextEdit_LOG->copy();
	}
	else if ( chosen == clear )
	{
		TextEdit_LOG->clear();
	}
	else if ( chosen == selectall )
	{
		QTextCursor cursor = TextEdit_LOG->textCursor();
		cursor.select( QTextCursor::Document );
		TextEdit_LOG->setTextCursor( cursor );
	}
}
