/***************************************************************************
                          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>
#include <QCursor>
#include <QTabWidget>
#include <QMessageBox>
#include <QTextEdit>
#include <QDateTime>
#include <QInputDialog>
#include <QTimer>
#include <QMdiArea>
#include <QMdiSubWindow>
#include <QComboBox>
#include <QRegExp>
#include <QLayout>
#include <QKeyEvent>
#include <QGridLayout>
#include <QResizeEvent>
#include <QShowEvent>
#include <QEvent>
#include <QHeaderView>
#include <QMdiSubWindow>

#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"
#include "dcipfilter.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 <dclib/cfilemanager.h>

#include <list>

#define TIMER_BASE 500

DCTransferView *DCTransferView::pTransferView = NULL;

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

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

    setupUi(this);

    // set default icon
    setWindowIcon(DCIconLoader::Instance()->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();

    container = NULL;
}

/** */
DCTransferView::~DCTransferView() {

    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 (DCConfig::Instance()->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
    // DCConfig::Instance()->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(DCGuiApp::Instance(), new DC_DownloadManagerEvent((CDownloadManagerInfo*) DCMsg));

                DCMsg = 0;

                break;
            }

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

                DCMsg = 0;

                break;
            }

            case DC_MESSAGE_TRAFFIC:
            {
                QApplication::postEvent(DCGuiApp::Instance(), 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) {

    if (msg && (msg->eState == estTRANSFERHANDSHAKE) && DCConfig::Instance()->GetIgnoreHandshake())
        return;

    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, DCIconLoader::Instance()->GetPixmap(eiSSL_YES));

            if (!DCConfig::Instance()->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, DCIconLoader::Instance()->GetPixmap(eiSSL_YES));
    }

    eDIRECTION msg_direction;
    bool ok = true;

    switch (msg->eState) {
        case estTRANSFERDOWNLOAD:
            msg_direction = eDIRECTION_IN;

            break;
        case estTRANSFERUPLOAD:
            msg_direction = eDIRECTION_OUT;

            break;
        case estTRANSFERHANDSHAKE:
        default:
            msg_direction = eDIRECTION_OUT;
    }

    if (DCIPFilter::Instance())
        ok = DCIPFilter::Instance()->OK(QString(msg->sHost.Data()), msg_direction);

    // update transfer state
    if ((msg1->eState != msg->eState) && ok) {
        msg1->eState = msg->eState;

        switch (msg1->eState) {
            case estTRANSFERDOWNLOAD:
                TransferListItem->pItem->setPixmap(2, DCIconLoader::Instance()->GetPixmap(eiDOWN));
                TransferListItem->pItem->setTransferState("d");
                //TransferListItem->pItem->setText(3,tr("Download"));
                break;
            case estTRANSFERUPLOAD:
                TransferListItem->pItem->setPixmap(2, DCIconLoader::Instance()->GetPixmap(eiUP));
                TransferListItem->pItem->setTransferState("u");
                //TransferListItem->pItem->setText(3,tr("Upload"));
                break;
            case estTRANSFERHANDSHAKE:
                TransferListItem->pItem->setPixmap(2, DCIconLoader::Instance()->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, DCIconLoader::Instance()->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());
    }

    if (!ok) { //remove all posible file paths from queue
        DLM_QueueRemove(msg->m_sDstNick.Data(),
                msg->sHubName.Data(),
                "");
        DLM_QueueRemove(msg->m_sDstNick.Data(),
                msg->sHubName.Data(),
                msg->m_sDstFile.Data());

        DLM_TransferClose(msg->m_nTransferID);
    }

    // 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 (DCConfig::Instance()->GetTransferViewOptions(etvoCHUNKPERCENT)) {
            if ((msg1->lEndPosition - msg1->lStartPosition) != 0) {
                s += CString::number(((msg1->lTransfered)*100) / (msg1->lEndPosition - msg1->lStartPosition));
                s += "% ";
            } else {
                s += "0% ";
            }
        }

        if (DCConfig::Instance()->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 (DCConfig::Instance()->GetTransferViewOptions(etvoCHUNKSIZE)) {
            s += " ";
            // s += CString::number(msg->lStartPosition);
            s += CUtils::GetSizeString(msg->lStartPosition, DCConfig::Instance()->GetUnit());
            s += "/";
            // s += CString::number(msg->lStartPosition+msg->lTransfered);
            s += CUtils::GetSizeString(msg->lStartPosition + msg->lTransfered, DCConfig::Instance()->GetUnit());
            s += "/";
            // s += CString::number(msg->lEndPosition);
            s += CUtils::GetSizeString(msg->lEndPosition, DCConfig::Instance()->GetUnit());
        }

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

        if (DCConfig::Instance()->GetTransferViewOptions(etvoDOWNLOADRATESINGLE)) {
            ulonglong rate;

            rate = msg->lRate;

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

        if (DCConfig::Instance()->GetTransferViewOptions(etvoELAPSEDTIMESINGLE)) {
            ulonglong rate = 0;

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

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

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

        if (DCConfig::Instance()->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 (DCConfig::Instance()->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") + QString(" - ") + tr("File browser"));
        d->setWindowIcon(DCIconLoader::Instance()->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(DCConfig::Instance()->GetNick().Data(), QString::null, QString::null, "/dev/null/ownfilelist");
        d->exec();
        delete d;
    } else {
        DCFileBrowser * bft = new DCFileBrowser(DCConnectionManager::Instance()->GetMdiArea());
        QMdiSubWindow * subwin = DCConnectionManager::Instance()->GetMdiArea()->addSubWindow(bft);
        subwin->setAttribute(Qt::WA_DeleteOnClose);
        bft->setAttribute(Qt::WA_DeleteOnClose);
        bft->InitTree(DCConfig::Instance()->GetNick().Data(), QString::null, QString::null, "/dev/null/ownfilelist");
        subwin->setWindowIcon(DCIconLoader::Instance()->GetPixmap(eiVIEW_SIDETREE));
        bft->SetContainer(subwin);
        bft->show();

        connect(bft, SIGNAL(onDie(QWidget*)), DCGuiApp::Instance(), SLOT(slotChildOnDie(QWidget*)));
        DCConnectionManager::Instance()->addTab(bft, QString(DCConfig::Instance()->GetNick().Data()) + " - " + tr("File browser"));
    }
}

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

    // set transfer
    bft->InitTree(nick, hubname, hubhost, filename, jumpto, dirs);
    subwin->setWindowIcon(DCIconLoader::Instance()->GetPixmap(eiVIEW_SIDETREE));
    bft->SetContainer(subwin);
    bft->show();

    connect(bft, SIGNAL(onDie(QWidget*)), DCGuiApp::Instance(), SLOT(slotChildOnDie(QWidget*)));
    DCConnectionManager::Instance()->addTab(bft, nick + " - " + tr("File browser"));
}

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();
            DCConnectionManager::Instance()->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(DCConnectionManager::Instance()->GetMdiArea());
    connect(hubsearch, SIGNAL(onDie(QWidget*)), DCGuiApp::Instance(), SLOT(slotChildOnDie(QWidget*)));
    hubsearch->SetSearchForFile(searchtxt, eftALL, 1, size / 2);
    hubsearch->setWindowIcon(QIcon(DCIconLoader::Instance()->GetPixmap(eiFIND)));
    hubsearch->show();

    DCConnectionManager::Instance()->addTab((QWidget*) hubsearch,
            QApplication::translate("DCDialogHubSearch", "Hub Search", 0, QApplication::UnicodeUTF8));

    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) && (DCConfig::Instance()->GetDynamicUploadRate() == false));

    client = DCConnectionManager::Instance()->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
        DCConnectionManager::Instance()->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 = DCConnectionManager::Instance()->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 (DCConnectionManager::Instance()->IsHubOnline(hubname.toAscii().constData(), hubhost.toAscii().constData()) == ehsNONE) {
                DCConnectionManager::Instance()->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 (DCConfig::Instance()->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, DCConnectionManager::Instance()->GetMdiArea());
	ft->SetContainer(DCConnectionManager::Instance()->GetMdiArea()->addSubWindow(ft));
        connect(ft, SIGNAL(onDie(QWidget*)), DCGuiApp::Instance(), SLOT(slotChildOnDie(QWidget*)));
	ft->GetContainer()->show();
        DCConnectionManager::Instance()->addTab(
                (QWidget*) ft,
                QApplication::translate("DCDialogFileTransferInfo",
                "File Transfer Info", 0,
                QApplication::UnicodeUTF8));
    } 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 (DCConfig::Instance()->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(),
							 DCConnectionManager::Instance()->GetMdiArea());

	ft->SetContainer(DCConnectionManager::Instance()->GetMdiArea()->addSubWindow(ft));

        connect(ft, SIGNAL(onDie(QWidget*)), DCGuiApp::Instance(), SLOT(slotChildOnDie(QWidget*)));

	ft->GetContainer()->show();

	DCConnectionManager::Instance()->addTab(ft,
                QApplication::translate("DCDialogFileTransferInfo",
                "File Transfer Info",
                0,
                QApplication::UnicodeUTF8));
    } else if (chosen == clone) {
        if (remotefile.isEmpty())
            SearchFileClone(localfile, size);
        else
            SearchFileClone(remotefile, size);
    } else if (chosen == clonetth) {
        DCHubSearch * hubsearch = new DCHubSearch(DCConnectionManager::Instance()->GetMdiArea());
        connect(hubsearch, SIGNAL(onDie(QWidget*)), DCGuiApp::Instance(), SLOT(slotChildOnDie(QWidget*)));
        hubsearch->SetSearchForFile(item1->text(4), eftHASH);

        hubsearch->show();

        DCConnectionManager::Instance()->addTab((QWidget*) hubsearch,
                QApplication::translate("DCDialogHubSearch", "Hub Search", 0, QApplication::UnicodeUTF8));

        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 (DCConnectionManager::Instance()->IsHubOnline(hubname.toAscii().constData(), hubhost.toAscii().constData()) == ehsNONE) {
            if (DLM_QueueUpdateHub(nick.toAscii().constData(), hubname.toAscii().constData()) == false) {
                // TODO: error message ...
            }
            DCConnectionManager::Instance()->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);
    }
}

void DCTransferView::initContainer() {
    if (!container)
        container = new QMdiSubWindow();
    container->setWidget(this);
}

void DCTransferView::deinitContainer() {
    if (container) {
        container->setWidget(0);
        container->setParent(0);
    }
}

QMdiSubWindow *DCTransferView::GetContainer() const {
    return container;
}

void DCTransferView::closeEvent(QCloseEvent *e) {
    emit onDie(this);

    deinitContainer();

    hide();

    e->ignore();
}

void DCTransferView::GetDownloadFileList(QStringList &files) {
    files.clear();

    m_ActiveTransferMapMutex.lock();

    for (ActiveTransferMap::const_iterator it = m_ActiveTransferMap.constBegin(); it != m_ActiveTransferMap.constEnd(); ++it) {
        files << it.value()->pObject->m_sSrcFile.Data();
    }

    m_ActiveTransferMapMutex.unlock();
}
