/* -*- c++ -*-
 *
 * downloadpage.cpp
 *
 * Copyright (C) 2003 Petter Stokke <ummo@hellokitty.com>
 * Copyright (C) 2006 Christian Muehlhaeuser <chris@chris.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.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

#include <kaction.h>
#include <kconfig.h>
#include <kdebug.h>
#include <klistview.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <knotifyclient.h>
#include <knuminput.h>
#include <ktoolbarbutton.h>

#include <qcheckbox.h>
#include <qpopupmenu.h>
#include <qregexp.h>
#include <qsplitter.h>
#include <qtimer.h>

#include "infodialog.h"
#include "infolist.h"
#include "kmldonkey.h"
#include "prefs.h"
#include "renamedialog.h"

#include "downloadpage.h"
#include "downloadpage.moc"

DownloadPage::DownloadPage( QWidget* parent )
    : QVBox( parent, "downloadPage" )
    , KMLDonkeyPage()
    , ClipboardHelper()
    , m_timer( new QTimer( this ) )
{
    downloadFileList.setAutoDelete( true );
    downloadedFileList.setAutoDelete( true );

    downloadSplitter = new QSplitter( (QWidget*)this, "downloadSplitter" );
    downloadSplitter->setOrientation( QSplitter::Vertical );

    QVBox *downloadBox = new QVBox( downloadSplitter );
    {
        QHBox *searchBox = new QHBox( downloadBox );
        searchBox->setMargin( 4 );

        KToolBarButton *button = new KToolBarButton( "locationbar_erase", 0, searchBox );
        m_filterEdit = new ClickLineEdit( i18n( "Filter here" ), searchBox );
        m_filterEdit->setFrame( QFrame::Sunken );

        QToolTip::add( button, i18n( "Clear filter" ) );
        QToolTip::add( m_filterEdit, i18n( "Enter space-separated terms to filter the download list" ) );

        connect( button, SIGNAL( clicked() ), m_filterEdit, SLOT( clear() ) );
    }

    downloadView = new InfoList( downloadBox, "downloadView", true );
    downloadView->addColumn( i18n( "File name" ) );
    downloadView->addColumn( i18n( "Priority" ) );
    downloadView->addColumn( i18n( "Status" ) );
    downloadView->addColumn( i18n( "Speed" ) );
    downloadView->addColumn( i18n( "Size" ) );
    downloadView->addColumn( i18n( "Received" ) );
    downloadView->addColumn( i18n( "%" ) );
    downloadView->addColumn( i18n( "ETA" ) );
    downloadView->addColumn( i18n( "Network" ) );
    downloadView->addColumn( i18n( "Availability" ) );
    downloadView->addColumn( i18n( "Hash" ) );
    downloadView->addColumn( i18n( "Last seen" ) );
    downloadView->addColumn( i18n( "Age" ) );
    downloadView->addColumn( i18n( "File type" ) );
    downloadView->setItemsRenameable( true );

    downloadedView = new InfoList( downloadSplitter, "downloadedView", true );
    downloadedView->addColumn( i18n( "File name" ) );
    downloadedView->addColumn( i18n( "Size" ) );
    downloadedView->addColumn( i18n( "Format" ) );
    downloadedView->addColumn( i18n( "Network" ) );
    downloadedView->addColumn( i18n( "Hash" ) );
    downloadedView->addColumn( i18n( "File type" ) );

    connect( m_timer,        SIGNAL( timeout() ), SLOT( slotSetFilter() ) );
    connect( m_filterEdit,   SIGNAL( textChanged( const QString& ) ), SLOT( slotSetFilterTimeout() ) );
    connect( m_filterEdit,   SIGNAL( returnPressed() ), SLOT( slotSetFilter() ) );

    connect( downloadView,   SIGNAL( contextMenu( KListView*, QListViewItem*, const QPoint& ) ),
             this,             SLOT( contextDownload( KListView*, QListViewItem*, const QPoint& ) ) );
    connect( downloadView,   SIGNAL( doubleClicked( QListViewItem* ) ),
             this,             SLOT( downloadDoubleClick( QListViewItem* ) ) );
    connect( downloadView,   SIGNAL( returnPressed( QListViewItem* ) ),
             this,             SLOT( downloadDoubleClick( QListViewItem* ) ) );
    connect( downloadedView, SIGNAL( contextMenu( KListView*, QListViewItem*, const QPoint& ) ),
             this,             SLOT( contextDownloaded( KListView*, QListViewItem*, const QPoint& ) ) );

    connect( downloadView,   SIGNAL( selectionChanged() ), SLOT( clearDownloadedSelection() ) );
    connect( downloadedView, SIGNAL( selectionChanged() ), SLOT( clearDownloadSelection() ) );

    connect( KMLDonkey::App->donkey, SIGNAL( fileUpdated( int ) ), this, SLOT( fileUpdated( int ) ) );
    connect( KMLDonkey::App->donkey, SIGNAL( fileAdded( int, bool ) ), this, SLOT( fileAdded( int, bool ) ) );
    connect( KMLDonkey::App->donkey, SIGNAL( fileRemoved( int ) ), this, SLOT( fileRemoved( int ) ) );
}


void
DownloadPage::updateDownloadView()
{
    QIntDictIterator<FileInfo> it (KMLDonkey::App->donkey->downloadFiles() );

    for ( ; it.current(); ++it )
        if ( it.current()->fileState() != FileInfo::Complete )
            fileUpdated( it.current()->fileNo() );
}


void
DownloadPage::slotSetFilterTimeout() //SLOT
{
    m_timer->start( 280, true ); //stops the timer for us first
}


void
DownloadPage::slotSetFilter() //SLOT
{
    m_timer->stop();

    setFilter( m_filterEdit->text() );
    updateDownloadView();
}


void
DownloadPage::handleGenericAction( const QString& action )
{
    if ( downloadView->hasFocus() )
    {
        if (action == "copy_url") copyFileToClipboard( URL );
            else if (action == "copy_html") copyFileToClipboard( HTML );
            else if (action == "copy_hash") copyFileToClipboard( Hash );
            else if (action == "file_information") actionFileInformation();
    }
    else if ( downloadedView->hasFocus() )
    {
        if (action == "copy_url") copyCompleteToClipboard( URL );
            else if (action == "copy_html") copyCompleteToClipboard( HTML );
            else if (action == "copy_hash") copyCompleteToClipboard( Hash );
            else if (action == "file_information") actionCompleteFileInformation();
    }
}


void
DownloadPage::deactivatePageActions()
{
    enableActionList( downloadActions, false );
    enableActionList( downloadedActions, false );
}


QStringList
DownloadPage::supportedGenericActions()
{
    QStringList actions;
    QPtrList<QListViewItem> dl = downloadView->selectedItems();
    QPtrList<QListViewItem> cl = downloadedView->selectedItems();

    if ( !dl.isEmpty() )
    {
        enableActionList( downloadActions, true );
        actions.append( "copy_url" );
        actions.append( "copy_html" );
        actions.append( "copy_hash" );
        actions.append( "file_information" );
    }
    else
        enableActionList( downloadActions, false );

    if ( !cl.isEmpty() )
    {
        enableActionList( downloadedActions, true );
        actions.append( "copy_url" );
        actions.append( "copy_html" );
        actions.append( "copy_hash" );
        actions.append( "file_information" );
    }
    else
        enableActionList( downloadedActions, false );

    return actions;
}


void
DownloadPage::plugGenericActions( QObject* object, const char* slot )
{
    connect( this, SIGNAL( genericActionsChanged( KMLDonkeyPage* ) ), object, slot );
}


void
DownloadPage::setupActions( KActionCollection* actionCollection )
{
    downloadActions.append( new KAction( i18n( "&Pause" ), "player_pause", 0, this, SLOT( actionPauseFile() ),
                                       actionCollection, "pause_selected" ) );
    downloadActions.append( new KAction( i18n( "&Resume" ), "player_play", 0, this, SLOT( actionResumeFile() ),
                                       actionCollection, "resume_selected" ) );
    downloadActions.append( new KAction( i18n( "&Cancel" ), "cancel", 0, this, SLOT( actionCancelFile() ),
                                       actionCollection, "cancel_selected" ) );
    downloadActions.append( new KAction( i18n( "Re&name" ), 0, "F2", this, SLOT( actionRenameFileInPlace() ),
                                       actionCollection, "rename_inplace" ) );
    downloadActions.append( new KAction( i18n( "Ren&ame To..." ), 0, 0, this, SLOT( actionRenameFile() ),
                                       actionCollection, "rename_selected" ) );
    downloadActions.append( new KAction( i18n( "Re&try Connect" ), "reload", 0, this, SLOT( actionRetryConnect() ),
                                       actionCollection, "retry_selected" ) );
    downloadActions.append( new KAction( i18n( "Pre&view" ), "thumbnail", 0, this, SLOT( actionPreviewFile() ),
                                       actionCollection, "preview_selected" ) );
    downloadActions.append( new KAction( i18n( "Verify Chunks" ), 0, 0, this, SLOT( actionVerifyFile() ),
                                       actionCollection, "verify_selected" ) );
    downloadActions.append( new KAction( i18n( "Get &Format Info" ), 0, 0, this, SLOT( actionGetFileFormat() ),
                                       actionCollection, "get_format_selected" ) );

    hidePausedAction = new KToggleAction( i18n( "&Hide Paused Downloads" ), "filter", 0, actionCollection, "hide_paused_downloads" );
    connect( hidePausedAction, SIGNAL( toggled( bool ) ), SLOT( actionHidePaused( bool ) ) );
    hideUnpausedAction = new KToggleAction( i18n( "Show Only Paused Downloads" ), "filter", 0, actionCollection, "hide_unpaused_downloads" );
    connect( hideUnpausedAction, SIGNAL( toggled( bool ) ), SLOT( actionHideUnpaused( bool ) ) );
    sortDownloadingFirstAction = new KToggleAction( i18n( "Sort Downloading Files First" ), "filter", 0, actionCollection, "sort_downloading_first" );
    connect( sortDownloadingFirstAction, SIGNAL( toggled( bool ) ), SLOT( actionSortDownloadingFirst( bool ) ) );
    sortPausedLastAction = new KToggleAction( i18n( "Sort Paused Files Last" ), "filter", 0, actionCollection, "sort_paused_last" );
    connect( sortPausedLastAction, SIGNAL( toggled( bool ) ), SLOT( actionSortPausedLast( bool ) ) );

    KActionMenu* priMenu = new KActionMenu( i18n( "Priorit&y" ), "flag", actionCollection, "priority_menu" );
    priMenu->setDelayed( false );
    downloadActions.append( priMenu );

    KAction* action;
    action = new KAction( i18n( "Very L&ow Priority" ), "2leftarrow", 0, this, SLOT( actionFilePriorityVeryLow() ), actionCollection, "priority_very_low" );
    priMenu->insert( action );
    downloadActions.append( action );
    action = new KAction( i18n( "&Low Priority" ), "1leftarrow", 0, this, SLOT( actionFilePriorityLow() ), actionCollection, "priority_low" );
    priMenu->insert( action );
    downloadActions.append( action );
    action = new KAction( i18n( "&Normal Priority" ), "1uparrow", 0, this, SLOT( actionFilePriorityNormal() ), actionCollection, "priority_normal" );
    priMenu->insert( action );
    downloadActions.append( action );
    action = new KAction( i18n( "&High Priority" ), "1rightarrow", 0, this, SLOT( actionFilePriorityHigh() ), actionCollection, "priority_high" );
    priMenu->insert( action );
    downloadActions.append( action );
    action = new KAction( i18n( "&Very High Priority" ), "2rightarrow", 0, this, SLOT( actionFilePriorityVeryHigh() ), actionCollection, "priority_very_high" );
    priMenu->insert( action );
    downloadActions.append( action );

    downloadedActions.append( new KAction( i18n( "&Open" ), "thumbnail", 0, this, SLOT( actionOpenFile() ), actionCollection, "open_selected" ) );
    downloadedActions.append( new KAction( i18n( "&Commit" ), "filesave", 0, this, SLOT( actionCommitFile() ), actionCollection, "commit_selected" ) );
    downloadedActions.append( new KAction( i18n( "Commit &As..." ), "filesaveas", 0, this, SLOT( actionCommitFileAs() ), actionCollection, "commit_as_selected" ) );

    //FIXME: this is realy ugly ;-)
    (void)new KAction( i18n( "Activate Download Page" ), 0, 0, this, SLOT( actionActivatePage() ), actionCollection, "activate_page_download" );

    enableActionList( downloadActions, false );
    enableActionList( downloadedActions, false );
}


void
DownloadPage::clear()
{
    deactivatePageActions();
    downloadedFileList.clear();
    downloadFileList.clear();
    downloadView->clear();
    downloadedView->clear();
}


void
DownloadPage::clearDownloadSelection()
{
    downloadView->clearSelection();
    emit genericActionsChanged( static_cast<KMLDonkeyPage*>( this ) );
}


void
DownloadPage::clearDownloadedSelection()
{
    downloadedView->clearSelection();
    emit genericActionsChanged( static_cast<KMLDonkeyPage*>( this ) );
}


void
DownloadPage::configurePrefsDialog( KMLDonkeyPreferences* prefs )
{
    if ( !prefs )
        return;

    prefs->renamerPage->enableAutorenameCheckbox->setChecked( KMLDonkey::App->enableAutorename );
    emit prefs->renamerPage->enableAutorename( KMLDonkey::App->enableAutorename );

    prefs->renamerPage->renlisteditor->addRows( KMLDonkey::App->autorenameList );
    prefs->listsPage->hidePausedCheckbox->setChecked( hidePausedAction->isChecked() );
    prefs->listsPage->hideUnpausedCheckbox->setChecked( hideUnpausedAction->isChecked() );
    prefs->listsPage->SortDownloadingFirstCheckBox->setChecked( sortDownloadingFirstAction->isChecked() );
    prefs->listsPage->SortPausedLastCheckBox->setChecked( sortPausedLastAction->isChecked() );

    if ( downloadView->sortInterval() > 0 )
    {
        prefs->listsPage->autoDownloadResortCheckbox->setChecked( true );
        prefs->listsPage->downloadResortEntry->setValue( downloadView->sortInterval() );
    }
    else
        prefs->listsPage->autoDownloadResortCheckbox->setChecked( false );
}


void
DownloadPage::applyPreferences( KMLDonkeyPreferences* prefs )
{
    const QFont& font = KMLDonkey::App->listFont;

    if ( downloadView->font() != font ) downloadView->setFont( font );
    if ( downloadedView->font() != font ) downloadedView->setFont( font );

    QListViewItemIterator it( downloadView );
    for ( ; it.current(); ++it )
    {
        DownloadFile* cl = dynamic_cast<DownloadFile*>( it.current() );
        if ( cl )
            cl->loseCache();
    }
    downloadView->update();

    if ( !prefs )
        return;

    if ( prefs->listsPage->hidePausedCheckbox->isChecked() != hidePausedAction->isChecked() )
         actionHidePaused( prefs->listsPage->hidePausedCheckbox->isChecked() );
    if ( prefs->listsPage->hideUnpausedCheckbox->isChecked() != hideUnpausedAction->isChecked() )
         actionHideUnpaused( prefs->listsPage->hideUnpausedCheckbox->isChecked() );

    if ( prefs->listsPage->SortDownloadingFirstCheckBox->isChecked() != sortDownloadingFirstAction->isChecked() )
         actionSortDownloadingFirst( prefs->listsPage->SortDownloadingFirstCheckBox->isChecked() );
    if ( prefs->listsPage->SortPausedLastCheckBox->isChecked() != sortPausedLastAction->isChecked() )
         actionSortPausedLast( prefs->listsPage->SortPausedLastCheckBox->isChecked() );

    if ( prefs->listsPage->autoDownloadResortCheckbox->isChecked() != ( downloadView->sortInterval() > 0) ||
         prefs->listsPage->autoDownloadResortCheckbox->isChecked() && ( downloadView->sortInterval() != prefs->listsPage->downloadResortEntry->value() ) )
            downloadView->setSortInterval( prefs->listsPage->autoDownloadResortCheckbox->isChecked() ? prefs->listsPage->downloadResortEntry->value() : 0 );

    bool b = prefs->renamerPage->enableAutorenameCheckbox->isChecked();
    if ( KMLDonkey::App->enableAutorename != b || prefs->renamerPage->renlisteditor->Modified )
    {
        KMLDonkey::App->enableAutorename = b;
        KMLDonkey::App->autorenameList = prefs->renamerPage->renlisteditor->getRows();

        KConfig* conf = KGlobal::config();
        conf->deleteGroup( "Autorename", true );
        conf->setGroup( "Autorename" );
        conf->writeEntry( "Enable", KMLDonkey::App->enableAutorename );
        int i = 0;
        for ( QValueList<QStringList>::Iterator it = KMLDonkey::App->autorenameList.begin();
             it != KMLDonkey::App->autorenameList.end();
             ++it )
        {
            if ( (*it).count() < 2 || !(*it)[0] )
                continue;

            conf->writeEntry( QString::number(i)+"s", (*it)[0] );
            conf->writeEntry( QString::number(i)+"r", (*it)[1] );
            i++;
        }

        if ( KMLDonkey::App->enableAutorename )
        {
            FileInfo* fi;
            QIntDictIterator<DownloadFile> it( downloadFileList );

            for ( ; it.current(); ++it )
            {
                fi = KMLDonkey::App->donkey->findDownloadFileNo( it.currentKey() );
                if ( fi )
                    autoRenameFile( fi->fileNo(), fi->fileName() );
            }
        }
    }
}


void
DownloadPage::saveState( KConfig* conf )
{
    conf->setGroup( "Options" );
    conf->writeEntry( "HidePausedDownloads", hidePausedAction->isChecked() );
    conf->writeEntry( "HideUnpausedDownloads", hideUnpausedAction->isChecked() );
    conf->writeEntry( "SortDownloadingFirst", sortDownloadingFirstAction->isChecked() );
    conf->writeEntry( "SortPausedLast", sortPausedLastAction->isChecked() );
    conf->writeEntry( "DownloadViewSort", downloadView->sortInterval() );

    conf->setGroup( "Splitters");
    conf->writeEntry( "DownloadSplitter", downloadSplitter->sizes() );

    downloadView->saveLayout();
    downloadedView->saveLayout();
}


void
DownloadPage::restoreState( KConfig* conf )
{
    conf->setGroup( "Options" );
    hidePausedAction->setChecked( conf->readBoolEntry( "HidePausedDownloads", false ) );
    hideUnpausedAction->setChecked( conf->readBoolEntry( "HideUnpausedDownloads", false ) );
    sortDownloadingFirstAction->setChecked( conf->readBoolEntry( "SortDownloadingFirst", false ) );
    sortPausedLastAction->setChecked( conf->readBoolEntry( "SortPausedLast", false ) );
    downloadView->setSortInterval( conf->readNumEntry( "DownloadViewSort", 0 ) );

    conf->setGroup( "Splitters" );
    downloadSplitter->setSizes( conf->readIntListEntry( "DownloadSplitter" ) );

    downloadView->initialise();
    downloadedView->initialise();

    KMLDonkey::App->autorenameList.clear();
    if ( conf->hasGroup( "Autorename" ) )
    {
        conf->setGroup( "Autorename" );
        KMLDonkey::App->enableAutorename = conf->readBoolEntry( "Enable", false );
        QString s, r;
        int nr = 0;

        while ( 1 )
        {
            s = conf->readEntry( QString::number( nr ) + "s", QString::null );
            if ( s.isEmpty() )
                break;

            r = conf->readEntry( QString::number( nr ) + "r", QString( "" ) );
            KMLDonkey::App->autorenameList.append( QStringList() << s << r );
            nr++;
        }
    }
    else
    {
        // default Autorename-list
        KMLDonkey::App->enableAutorename = false;
        KMLDonkey::App->autorenameList.append( QStringList() << "&auml" << "ae" );
        KMLDonkey::App->autorenameList.append( QStringList() << "&Auml" << "Ae" );
        KMLDonkey::App->autorenameList.append( QStringList() << "&ouml" << "oe" );
        KMLDonkey::App->autorenameList.append( QStringList() << "&Ouml" << "Oe" );
        KMLDonkey::App->autorenameList.append( QStringList() << "&uuml" << "ue" );
        KMLDonkey::App->autorenameList.append( QStringList() << "&Uuml" << "Ue" );
        KMLDonkey::App->autorenameList.append( QStringList() << "&szlig" << "ss" );
        KMLDonkey::App->autorenameList.append( QStringList() << "(\\.)(?=.*\\.)" << " " );
        KMLDonkey::App->autorenameList.append( QStringList() << "%20|_|([\\s]+)" << " " );
    }

    applyPreferences();
}


void
DownloadPage::contextDownload( KListView*, QListViewItem*, const QPoint& pt )
{
    QPopupMenu *pop =
        static_cast<QPopupMenu*>( ( KMLDonkey::App->factory() )->container( "download_actions", KMLDonkey::App ) );

    if ( !pop )
        KMLDonkey::App->showBadInstallDialog();
    else
        pop->popup( pt );
}


void
DownloadPage::contextDownloaded( KListView*, QListViewItem*, const QPoint& pt )
{
    QPopupMenu *pop =
        static_cast<QPopupMenu*>( ( KMLDonkey::App->factory() )->container( "downloaded_actions", KMLDonkey::App ) );

    if ( !pop )
        KMLDonkey::App->showBadInstallDialog();
    else
        pop->popup( pt );
}


void
DownloadPage::downloadDoubleClick( QListViewItem* )
{
    actionFileInformation();
}


void
DownloadPage::actionActivatePage()
{
    KMLDonkey::App->activatePage( this );
}


void
DownloadPage::actionPauseFile()
{
    QPtrList<QListViewItem> list = downloadView->selectedItems();
    DownloadFile* it;

    for ( it = (DownloadFile*)list.first(); it; it = (DownloadFile*)list.next() )
    {
        FileInfo* fi = KMLDonkey::App->donkey->findDownloadFileNo( it->fileNo() );
        if ( !fi )
            continue;

        KMLDonkey::App->donkey->pauseFile( fi->fileNo(), 1 );
    }
}


void
DownloadPage::actionResumeFile()
{
    QPtrList<QListViewItem> list = downloadView->selectedItems();
    DownloadFile* it;

    for ( it = (DownloadFile*)list.first(); it; it = (DownloadFile*)list.next() )
    {
        FileInfo* fi = KMLDonkey::App->donkey->findDownloadFileNo( it->fileNo() );
        if ( !fi )
            continue;

        KMLDonkey::App->donkey->pauseFile( fi->fileNo(), 0 );
    }
}


void
DownloadPage::actionCancelFile()
{
    QPtrList<QListViewItem> list = downloadView->selectedItems();
    DownloadFile* it;
    QStringList files;

    for ( it = (DownloadFile*)list.first(); it; it = (DownloadFile*)list.next() )
    {
        FileInfo* fi = KMLDonkey::App->donkey->findDownloadFileNo( it->fileNo() );
        if ( fi )
            files << fi->fileName();
    }

    if ( KMessageBox::questionYesNoList( this, i18n( "Are you sure you want to cancel these files?" ),
         files, i18n( "Cancel Downloads" ) ) == KMessageBox::Yes )
    {
        for ( it = (DownloadFile*)list.first(); it; it = (DownloadFile*)list.next() )
        {
            FileInfo* fi = KMLDonkey::App->donkey->findDownloadFileNo( it->fileNo() );
            if ( !fi )
                continue;

            KMLDonkey::App->donkey->cancelFile( fi->fileNo() );
        }
    }
}


void
DownloadPage::setFilePriority( int pri )
{
    QPtrList<QListViewItem> list = downloadView->selectedItems();
    DownloadFile* it;

    for ( it = (DownloadFile*)list.first(); it; it = (DownloadFile*)list.next() )
    {
        FileInfo* fi = KMLDonkey::App->donkey->findDownloadFileNo(it->fileNo());
        if ( !fi )
            continue;

        KMLDonkey::App->donkey->setFilePriority( fi->fileNo(), pri );
    }
}


void
DownloadPage::actionRetryConnect()
{
    QPtrList<QListViewItem> list = downloadView->selectedItems();
    DownloadFile* it;

    for ( it = (DownloadFile*)list.first(); it; it = (DownloadFile*)list.next() )
    {
        FileInfo* fi = KMLDonkey::App->donkey->findDownloadFileNo( it->fileNo() );
        if ( !fi )
            continue;

        KMLDonkey::App->donkey->retryFile( fi->fileNo() );
    }
}


void
DownloadPage::actionPreviewFile()
{
    QPtrList<QListViewItem> list = downloadView->selectedItems();
    DownloadFile* it;

    for ( it = (DownloadFile*)list.first(); it; it = (DownloadFile*)list.next() )
    {
        FileInfo* fi = KMLDonkey::App->donkey->findDownloadFileNo( it->fileNo() );
        if ( !fi )
            continue;

        KMLDonkey::App->donkey->previewFile( fi->fileNo() );
    }
}


void
DownloadPage::actionOpenFile()
{
    QPtrList<QListViewItem> list = downloadedView->selectedItems();
    DownloadedFile* it;

    for ( it = (DownloadedFile*)list.first(); it; it = (DownloadedFile*)list.next() )
    {
        FileInfo* fi = KMLDonkey::App->donkey->findDownloadFileNo( it->fileNo() );
        if ( !fi )
            continue;

        KMLDonkey::App->donkey->previewFile( fi->fileNo() );
    }
}


void
DownloadPage::actionVerifyFile()
{
    QPtrList<QListViewItem> list = downloadView->selectedItems();
    DownloadFile* it;

    for ( it = (DownloadFile*)list.first(); it; it = (DownloadFile*)list.next() )
    {
        FileInfo* fi = KMLDonkey::App->donkey->findDownloadFileNo( it->fileNo() );
        if ( !fi )
            continue;

        KMLDonkey::App->donkey->verifyFileChunks( fi->fileNo() );
    }
}


void
DownloadPage::actionGetFileFormat()
{
    QPtrList<QListViewItem> list = downloadView->selectedItems();
    DownloadFile* it;

    for ( it = (DownloadFile*)list.first(); it; it = (DownloadFile*)list.next() )
    {
        FileInfo* fi = KMLDonkey::App->donkey->findDownloadFileNo( it->fileNo() );
        if ( !fi )
            continue;

        KMLDonkey::App->donkey->getFileFormat( fi->fileNo() );
    }
}


void
DownloadPage::actionFileInformation()
{
    QPtrList<QListViewItem> list = downloadView->selectedItems();
    DownloadFile* it;

    for ( it = (DownloadFile*)list.first(); it; it = (DownloadFile*)list.next() )
    {
        FileInfo* fi = KMLDonkey::App->donkey->findDownloadFileNo( it->fileNo() );
        if ( !fi )
            continue;

        FileInfoDialog* d = new FileInfoDialog( fi->fileNo() );
        d->show();
    }
}


void
DownloadPage::actionCompleteFileInformation()
{
    QPtrList<QListViewItem> list = downloadedView->selectedItems();
    DownloadedFile* it;

    for ( it = (DownloadedFile*)list.first(); it; it = (DownloadedFile*)list.next() )
    {
        FileInfo* fi = KMLDonkey::App->donkey->findDownloadFileNo( it->fileNo() );
        if ( !fi )
            continue;

        FileInfoDialog* d = new FileInfoDialog( fi->fileNo() );
        d->show();
    }
}


void
DownloadPage::actionCommitFile()
{
    QPtrList<QListViewItem> list = downloadedView->selectedItems();
    DownloadedFile* it;

    for ( it = (DownloadedFile*)list.first(); it; it = (DownloadedFile*)list.next() )
    {
        FileInfo* fi = KMLDonkey::App->donkey->findDownloadFileNo( it->fileNo() );
        if ( !fi )
            continue;

        KMLDonkey::App->donkey->saveFile( fi->fileNo(), fi->fileName() );
    }
}


void
DownloadPage::actionCommitFileAs()
{
    QPtrList<QListViewItem> list = downloadedView->selectedItems();
    DownloadedFile* it;

    for ( it = (DownloadedFile*)list.first(); it; it = (DownloadedFile*)list.next() )
    {
        FileInfo* fi = KMLDonkey::App->donkey->findDownloadFileNo( it->fileNo() );
        if ( !fi )
            continue;

        RenameDialog* d = new RenameDialog( KMLDonkey::App->donkey, fi->fileNo() );
        connect( d, SIGNAL( renameFile( int, const QString& ) ), this, SLOT( commitFileAs( int, const QString& ) ) );
        d->show();
    }
}


void
DownloadPage::commitFileAs( int fileno, const QString& name )
{
    KMLDonkey::App->donkey->saveFile( fileno, name );
}


void
DownloadPage::actionRenameFile()
{
    QPtrList<QListViewItem> list = downloadView->selectedItems();
    DownloadFile* it;

    for ( it = (DownloadFile*)list.first(); it; it = (DownloadFile*)list.next() )
    {
        FileInfo* fi = KMLDonkey::App->donkey->findDownloadFileNo( it->fileNo() );
        if ( !fi )
            continue;

        RenameDialog* d = new RenameDialog( KMLDonkey::App->donkey, fi->fileNo() );
        connect( d, SIGNAL( renameFile( int, const QString& ) ), this, SLOT( renameFile( int, const QString& ) ) );
        d->show();
    }
}


void
DownloadPage::actionRenameFileInPlace()
{
    QPtrList<QListViewItem> list = downloadView->selectedItems();
    DownloadFile* it;

    for ( it = (DownloadFile*)list.first(); it; it = (DownloadFile*)list.next() )
    {
        FileInfo* fi = KMLDonkey::App->donkey->findDownloadFileNo( it->fileNo() );
        if ( !fi )
            continue;

        it->startRename( 0 );
        return;
    }
}


void
DownloadPage::fileRenamed( int fileno, const QString& name )
{
    KMLDonkey::App->donkey->renameFile( fileno, name );
}


void
DownloadPage::copyFileToClipboard( ClipFormat format )
{
    QStringList l;
    QPtrList<QListViewItem> list = downloadView->selectedItems();
    DownloadFile* it;

    for ( it = (DownloadFile*)list.first(); it; it = (DownloadFile*)list.next() )
    {
        FileInfo* fi = KMLDonkey::App->donkey->findDownloadFileNo( it->fileNo() );
        if ( !fi )
            continue;

        l.append( fi->fileName() );
        l.append( fi->fileUid( "ed2k" ) );
        l.append( QString::number( (long int)fi->fileSize() ) );
    }
    copyToClipboard(l, format);
}


void
DownloadPage::copyCompleteToClipboard(ClipFormat format)
{
    QStringList l;
    QPtrList<QListViewItem> list = downloadedView->selectedItems();
    DownloadedFile* it;

    for ( it = (DownloadedFile*)list.first(); it; it = (DownloadedFile*)list.next() )
    {
        FileInfo* fi = KMLDonkey::App->donkey->findDownloadFileNo(it->fileNo() );
        if ( !fi )
            continue;

        l.append( fi->fileName() );
        l.append( fi->fileUid( "ed2k" ) );
        l.append( QString::number( (long int)fi->fileSize() ) );
    }
    copyToClipboard(l, format);
}


void
DownloadPage::fileUpdated( int fn )
{
    FileInfo* fi = KMLDonkey::App->donkey->findDownloadFileNo( fn );
    if ( !fi )
        return;

    bool completed = false;
    bool del;

    switch ( fi->fileState() )
    {
        case FileInfo::Complete:
            completed = true;

        case FileInfo::Cancelled:
        case FileInfo::Aborted:
        case FileInfo::Shared:
            del = true;
            break;

        case FileInfo::Paused:
            del = hidePausedAction->isChecked() ? true : false;
            break;

        default:
            del = false;
            break;
    }

    // check if we really want to display this item
    if ( ( hideUnpausedAction->isChecked() && fi->fileState() != FileInfo::Paused ) ||
         ( !m_filter.isEmpty() && !fi->fileName().lower().contains( m_filter.lower() ) ) )
        del = true;

    DownloadFile* df = downloadFileList[fn];
    if ( df )
    {
        if ( del )
            downloadFileList.remove( fn );
        else
        {
            df->flush();
            df->refresh();
            del = true;
        }

        if ( completed )
            KNotifyClient::event( winId(), "KMLDonkeyDownloadFinished", i18n( "Download completed: %1" ).arg( fi->fileName() ) );
    }

    if ( !del )
    {
        df = new DownloadFile( downloadView, fn );
        downloadFileList.insert( fn, df );

        if ( KMLDonkey::App->enableAutorename )
            autoRenameFile( fn, fi->fileName() );
        return;
    }

    switch ( fi->fileState() )
    {
        case FileInfo::Complete:
            del = false;
            break;

        default:
            del = true;
            break;
    }

    DownloadedFile* foo = downloadedFileList[fn];
    if ( foo )
    {
        if ( del )
            downloadedFileList.remove( fn );
        else
        {
            foo->refresh();
            return;
        }
    }

    if ( !del )
    {
        foo = new DownloadedFile( downloadedView, fn );
        downloadedFileList.insert( fn, foo );
    }
}


void
DownloadPage::fileAdded( int fn, bool downloadstarted )
{
    if ( downloadstarted )
    {
        FileInfo* fi = KMLDonkey::App->donkey->findDownloadFileNo( fn );
        if ( fi )
            KNotifyClient::event( winId(), "KMLDonkeyDownloadAdded", i18n( "Download added: %1" ).arg( fi->fileName() ) );
    }
}


void
DownloadPage::fileRemoved( int fn )
{
    downloadFileList.remove( fn );
    downloadedFileList.remove( fn );
}


void
DownloadPage::autoRenameFile( int filenum, const QString& filename )
{
    QString name = filename;
    QValueList<QStringList>::Iterator it;

    for ( it = KMLDonkey::App->autorenameList.begin(); it != KMLDonkey::App->autorenameList.end(); ++it )
    {
        if ( (*it).count() < 2 || (*it)[0].isEmpty() )
            continue;

        name.replace( QRegExp( (*it)[0] ), (*it)[1] );
    }

    if ( name != filename && ! name.isEmpty() )
    {
        fileRenamed( filenum, name );
        //kdDebug() << "autorename: |" << filename << "| => |" << name << "|" << endl;
    }
}


void
DownloadPage::actionHidePaused( bool hide )
{
    hidePausedAction->setChecked( hide );
    updateDownloadView();
}


void
DownloadPage::actionHideUnpaused( bool hide )
{
    hideUnpausedAction->setChecked( hide );
    updateDownloadView();
}


void
DownloadPage::actionSortDownloadingFirst( bool b )
{
    sortDownloadingFirstAction->setChecked( b );
    downloadView->sort();
}


void
DownloadPage::actionSortPausedLast( bool b )
{
    sortPausedLastAction->setChecked( b );
    downloadView->sort();
}
