/*
 * This file is part of the KFTPGrabber project
 *
 * Copyright (C) 2003-2004 by the KFTPGrabber developers
 * Copyright (C) 2003-2004 Jernej Kos <kostko@jweb-network.net>
 * Copyright (C) 2005 Markus Brueffer <markus@brueffer.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
 * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
 * NON-INFRINGEMENT.  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.
 *
 * In addition, as a special exception, the copyright holders give
 * permission to link the code of portions of this program with the
 * OpenSSL library under certain conditions as described in each
 * individual source file, and distribute linked combinations
 * including the two.
 * You must obey the GNU General Public License in all respects
 * for all of the code used other than OpenSSL.  If you modify
 * file(s) with this exception, you may extend this exception to your
 * version of the file(s), but you are not obligated to do so.  If you
 * do not wish to do so, delete this exception statement from your
 * version.  If you delete this exception statement from all source
 * files in the program, then also delete it here.
 */

#include "misc.h"

#include "listview.h"
#include "queueview.h"
#include "kftpqueue.h"
#include "kftpapi.h"
#include "queueeditor.h"
#include "widgets/searchdialog.h"
#include "misc/config.h"

#include <kapplication.h>
#include <kfiledialog.h>
#include <kiconloader.h>
#include <kio/job.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kmimetype.h>
#include <kpopupmenu.h>
#include <klistviewsearchline.h>
#include <kdebug.h>

#include <qspinbox.h>
#include <qtooltip.h>

using namespace KFTPGrabberBase;
using namespace KFTPCore;

namespace KFTPWidgets {

QueueViewItem::QueueViewItem(QueueView *view, KFTPQueue::QueueObject *object, QListView *parent)
  : QListViewItem(parent),
    m_lastChild(0),
    m_queueObject(object),
    m_queueView(view),
    m_queueId(object->getId())
{
  init();
}

QueueViewItem::QueueViewItem(QueueView *view, KFTPQueue::QueueObject *object, QListViewItem *parent)
  : QListViewItem(parent, static_cast<QueueViewItem*>(parent)->lastChild()),
    m_lastChild(0),
    m_queueObject(object),
    m_queueView(view),
    m_queueId(object->getId())
{
  init();
}

QueueViewItem::~QueueViewItem()
{
  m_queueView->m_queuedItems.remove(m_queueId);
}

void QueueViewItem::insertItem(QListViewItem *newChild)
{
  QListViewItem::insertItem(newChild);
  m_lastChild = newChild;
}

void QueueViewItem::takeItem(QListViewItem *item)
{
  if (item == m_lastChild) {
    QListViewItem *above = item->itemAbove();
    
    if (above->parent() == m_lastChild->parent())
      m_lastChild = above;
    else
      m_lastChild = 0;
  }
  
  QListViewItem::takeItem(item);
}

void QueueViewItem::moveUp()
{
  QListViewItem *above = itemAbove();
  
  if (above && above->parent() == QListViewItem::parent()) {
    QListViewItem *previous = above->itemAbove();
    
    if (previous && previous->parent() == QListViewItem::parent()) {
      QueueViewItem *parent = static_cast<QueueViewItem*>(QListViewItem::parent());
      moveItem(previous);
      
      if (parent && this == parent->lastChild())
        parent->m_lastChild = above;
    } else {
      moveToTop();
    }
  }
}

void QueueViewItem::moveDown()
{
  QueueViewItem *parent = static_cast<QueueViewItem*>(QListViewItem::parent());
  QueueViewItem *next = static_cast<QueueViewItem*>(nextSibling());
  
  if (next) {
    moveItem(next);
    
    if (parent && parent->lastChild() == next)
      parent->m_lastChild = this;
  }
}

void QueueViewItem::moveToTop()
{
  QueueViewItem *parent = static_cast<QueueViewItem*>(QListViewItem::parent());
  
  // Just reinsert the item
  if (parent) {
    if (this == parent->lastChild())
      parent->m_lastChild = itemAbove();
    
    parent->QListViewItem::takeItem(this);
    parent->QListViewItem::insertItem(this);
  } else {
    ListView *view = m_queueView->m_queue;
    view->QListView::takeItem(this);
    view->QListView::insertItem(this);
  }
}

void QueueViewItem::moveToBottom()
{
  QueueViewItem *parent = static_cast<QueueViewItem*>(QListViewItem::parent());
  
  // Just reinsert the item
  if (parent) {
    QListViewItem *last = parent->lastChild();
    
    parent->takeItem(this);
    parent->insertItem(this);
    moveItem(last);
  } else {
    ListView *view = m_queueView->m_queue;
    view->takeItem(this);
    view->insertItem(this);
  }
}

void QueueViewItem::paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int alignment)
{
  QColorGroup _cg(cg);
  QColor c = _cg.text();

  QColor n_color;
  
  if (m_queueObject && m_queueObject->isTransfer()) {
    switch (m_queueObject->getStatus()) {
      case KFTPQueue::Transfer::Running: n_color.setRgb(255, 0, 0); break;
      case KFTPQueue::Transfer::Connecting: n_color.setRgb(0, 0, 255); break;
      case KFTPQueue::Transfer::Waiting: n_color.setRgb(0, 0, 255); break;
      case KFTPQueue::Transfer::Locked: n_color.setRgb(0, 150, 0); break;
      default: break;
    }
  }
  
  if (n_color.isValid())
    _cg.setColor(QColorGroup::Text, n_color);

  QListViewItem::paintCell(p, _cg, column, width, alignment);
  _cg.setColor(QColorGroup::Text, c);
}

void QueueViewItem::init()
{
  if (m_queueObject->isTransfer()) {
    KFTPQueue::Transfer *transfer = static_cast<KFTPQueue::Transfer*>(getObject());

    setText(0, transfer->getSourceUrl().fileName());
    setText(1, KIO::convertSize(transfer->getActualSize()));
    setText(2, transfer->getSourceUrl().pathOrURL());
    setText(3, transfer->getDestUrl().pathOrURL());
    
    // Icon
    QString iconText;
    if (transfer->isDir()) {
      iconText = "folder";
    } else {
      KMimeType::Ptr theType = KMimeType::findByURL("/" + transfer->getSourceUrl().path(), 0, false, true);
      iconText = theType->icon(QString::null, false);
    }
  
    setPixmap(0, loadSmallPixmap(iconText));
  } else if (m_queueObject->getType() == KFTPQueue::QueueObject::Site) {
    KFTPQueue::Site *site = static_cast<KFTPQueue::Site*>(getObject());
    
    setText(0, QString("%1:%2").arg(site->getUrl().host()).arg(site->getUrl().port()));
    setText(1, KIO::convertSize(site->getActualSize()));
    
    // Set the pixmap
    setPixmap(0, loadSmallPixmap("server"));
  }
}

void QueueViewItem::refresh()
{
  if (!m_queueObject)
    return;

  if (m_queueObject->isTransfer()) {
    KFTPQueue::Transfer *transfer = static_cast<KFTPQueue::Transfer*>(getObject());
    
    // Speed
    bool noSpeed = transfer->getStatus() == KFTPQueue::Transfer::Waiting || transfer->getStatus() == KFTPQueue::Transfer::Connecting;
    QString speed;
    if ((!transfer->isDir() || !isOpen()) && transfer->isRunning() && !noSpeed) {
      speed.sprintf( "%lld B/s", (transfer->getSpeed()) );
  
      if (transfer->getSpeed() > 1024)
        speed.sprintf( "%lld KB/s", (transfer->getSpeed() / 1024) );
      
      if (transfer->getSpeed() > 1024*1024)
        speed.sprintf("%lld MB/s", (transfer->getSpeed() / 1024) / 1024);
    
      if (transfer->getSpeed() == 0 && transfer->getTransferType() != KFTPQueue::FXP)
        speed = i18n("stalled");
      
      if (transfer->getSpeed() == 0 && transfer->getTransferType() == KFTPQueue::FXP)
        speed = i18n("running");
    }
  
    // ETA
    QString eta;
  
    if (transfer->isRunning() && transfer->getSpeed() > 0) {
      eta = KIO::convertSeconds(KIO::calculateRemainingSeconds(transfer->getSize(),
                                                               transfer->getCompleted(),
                                                               transfer->getSpeed()));
    } else {
      eta = QString::null;
    }
  
    // Set the columns
    setText(0, transfer->getSourceUrl().fileName());
    setText(1, KIO::convertSize(transfer->getActualSize()));
    setText(2, transfer->getSourceUrl().pathOrURL());
    setText(3, transfer->getDestUrl().pathOrURL());
    setText(5, speed);
    setText(6, eta);
    
    // Don't show the file:// for local src/dest
    if (transfer->getSourceUrl().isLocalFile()) {
      setText(2, transfer->getSourceUrl().path());
    } else if (transfer->getDestUrl().isLocalFile()) {
      setText(3, transfer->getDestUrl().path());
    }
  
    // Progress
    int progress;
    int r_progress;
  
    if (transfer->getSize() == 0)
      progress = 0;
    else
      progress = transfer->getCompleted()*100/transfer->getSize();
  
    if (transfer->getResumed() == 0)
      r_progress = 0;
    else
      r_progress = transfer->getResumed()*100/transfer->getSize();
  
    if (transfer->getStatus() == KFTPQueue::Transfer::Waiting) {
      // Transfer is waiting for a free connection
      setText(4, i18n("Waiting for connection..."));
      setPixmap(4, NULL);
    } else if (transfer->getStatus() == KFTPQueue::Transfer::Connecting) {
      // Transfer is not yet connected,
      setText(4, i18n("Connecting..."));
      setPixmap(4, NULL);
    } else if (progress > 0) {
      setPixmap(4, createProgressPixmap(progress, r_progress));
  
      QString progressText;
      progressText.sprintf("%d %%", progress);
      setText(4, progressText);
    } else {
      setPixmap(4, NULL);
      setText(4, QString::null);
    }
  
    // Icon
    QString iconText;
    if (transfer->isDir()) {
      iconText = "folder";
    } else {
      KMimeType::Ptr theType = KMimeType::findByURL("/" + transfer->getSourceUrl().path(), 0, false, true);
      iconText = theType->icon(QString::null, false);
    }
  
    setPixmap(0, loadSmallPixmap(iconText));
  } else if (m_queueObject->getType() == KFTPQueue::QueueObject::Site) {
    KFTPQueue::Site *site = static_cast<KFTPQueue::Site*>(getObject());
    
    // Speed
    QString speed;
    speed.sprintf( "%lld B/s", (site->getSpeed()) );

    if (site->getSpeed() > 1024)
      speed.sprintf( "%lld KB/s", (site->getSpeed() / 1024) );
    
    if (site->getSpeed() > 1024*1024)
      speed.sprintf("%lld MB/s", (site->getSpeed() / 1024) / 1024);
  
    if (site->getSpeed() == 0)
      speed = QString::null;
  
    // ETA
    QString eta;
  
    if (site->isRunning() && site->getSpeed() > 0) {
      eta = KIO::convertSeconds(KIO::calculateRemainingSeconds(site->getSize(),
                                                               site->getCompleted(),
                                                               site->getSpeed()));
    } else {
      eta = "";
    }
    
    // Progress
    if (site->isRunning()) {
      int progress = 0;
    
      if (site->getSize() > 0)
        progress = site->getCompleted()*100/site->getSize();
      
      setPixmap(4, createProgressPixmap(progress, 0));
    
      QString progressText;
      progressText.sprintf("%d %%", progress);
      setText(4, progressText);
    } else {
      setPixmap(4, NULL);
      setText(4, QString::null);
    }
    
    // Set the columns
    setText(0, QString("%1:%2").arg(site->getUrl().host()).arg(site->getUrl().port()));
    setText(1, KIO::convertSize(site->getActualSize()));
    setText(5, speed);
    setText(6, eta);
    
    // Set the pixmap
    setPixmap(0, loadSmallPixmap("server"));
  }
}

QueueListView::QueueListView(QWidget *parent)
  : ListView(parent)
{
}

void QueueListView::insertItem(QListViewItem *item)
{
  QListViewItem *last = lastChild();
  QListView::insertItem(item);
  
  if (last)
    item->moveItem(last);
}

QueueView::QueueView(QWidget *parent, const char *name)
 : QWidget(parent, name)
{
  QVBoxLayout *layout = new QVBoxLayout(this);

  m_toolBar = new KToolBar(this, "queueToolBar");
  m_toolBar->setIconSize(16);
  layout->addWidget(m_toolBar);
  
  m_searchToolBar = new KToolBar(this, "searchToolBar");
  m_searchToolBar->setEnableContextMenu(false);
  m_searchToolBar->setMovingEnabled(false);
  m_searchToolBar->setFullSize(true);

  // Create the erase button
  m_searchToolBar->insertButton(QApplication::reverseLayout() ? "clear_left" :"locationbar_erase", 0, SIGNAL(clicked()), this, SLOT(slotSearchEraseClicked()), true);
  
  // Create the labels
  QLabel *searchLabel = new QLabel(i18n("Filter: "), m_searchToolBar);
  m_searchToolBar->insertWidget(1, 35, searchLabel);
  
  // Create the list view
  m_queue = new QueueListView(this);
  
  // Create the search field
  m_searchField = new KListViewSearchLine(m_searchToolBar, m_queue);
  
  // Do some more stuff
  m_searchToolBar->setItemAutoSized(1, true);
  m_searchToolBar->setStretchableWidget(m_searchField);
  m_searchToolBar->updateRects(true);
  m_searchToolBar->hide();
  
  layout->addWidget(m_searchToolBar);
  
  // Create the columns
  m_queue->addColumn(i18n("Name"), 150);
  m_queue->addColumn(i18n("Size"), 75);
  m_queue->addColumn(i18n("Source"), 250);
  m_queue->addColumn(i18n("Destination"), 250);
  m_queue->addColumn(i18n("Progress"), 140);
  m_queue->addColumn(i18n("Speed"), 70);
  m_queue->addColumn(i18n("ETA"), 80);
  
  // Text when there is nothing queued
  m_queue->setEmptyListText(i18n("You do not have any files in the queue."));

  // Multi-select
  m_queue->setSelectionModeExt(KListView::FileManager);
  m_queue->setAllColumnsShowFocus(true);
  m_queue->setRootIsDecorated(true);
  m_queue->QListView::setSorting(-1);
  m_queue->QListView::setSortColumn(-1);
  
  layout->addWidget(m_queue);

  // The signals
  connect(m_queue, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)), this,
          SLOT(contextMenuRequested(KListView*, QListViewItem*, const QPoint&)));
  connect(m_queue, SIGNAL(selectionChanged()), this, SLOT(updateActions()));

  // Let us be up-to-date
  connect(KFTPQueue::Manager::self(), SIGNAL(transferRemoved(long)), this, SLOT(slotObjectRemoved(long)));
  connect(KFTPQueue::Manager::self(), SIGNAL(siteRemoved(long)), this, SLOT(slotObjectRemoved(long)));
  connect(KFTPQueue::Manager::self(), SIGNAL(newTransfer(KFTPQueue::Transfer*)), this, SLOT(slotTransferAdded(KFTPQueue::Transfer*)));
  connect(KFTPQueue::Manager::self(), SIGNAL(newSite(KFTPQueue::Site*)), this, SLOT(slotSiteAdded(KFTPQueue::Site*)));
  connect(KFTPQueue::Manager::self(), SIGNAL(queueUpdate()), this, SLOT(updateActions()));
  
  // Load the listview layout
  loadLayout();
  
  // Create the context menu actions
  initActions();
  initToolBar();
  updateActions();
  
  setMinimumHeight(150);
}

void QueueView::saveLayout()
{
  m_queue->saveLayout(kapp->config(), "queueViewLayout");
}

void QueueView::loadLayout()
{
  m_queue->restoreLayout(kapp->config(), "queueViewLayout");
}

void QueueView::initToolBar()
{
  // Plug all actions
  m_loadAction->plug(m_toolBar);
  m_saveAction->plug(m_toolBar);
  m_toolBar->insertSeparator();
  m_startAction->plug(m_toolBar);
  m_pauseAction->plug(m_toolBar);
  m_stopAction->plug(m_toolBar);
  m_toolBar->insertSeparator();
  m_addAction->plug(m_toolBar);
  m_removeAction->plug(m_toolBar);
  m_searchAction->plug(m_toolBar);
  m_toolBar->insertSeparator();
  m_filterAction->plug(m_toolBar);
  
  // Create speed control widgets
  m_toolBar->insertSeparator();
  
  QSpinBox *downloadSpeed = new QSpinBox(0, 10240, 1, m_toolBar);
  QToolTip::add(downloadSpeed, i18n("Limit download transfer speed"));
  m_toolBar->insertWidget(1, 35, new QLabel(i18n("Down: "), m_toolBar));
  m_toolBar->insertWidget(2, 35, downloadSpeed);
  downloadSpeed->setValue(Config::downloadSpeedLimit());
  connect(downloadSpeed, SIGNAL(valueChanged(int)), this, SLOT(slotDownloadLimitChanged(int)));
  
  m_toolBar->insertSeparator();
  
  QSpinBox *uploadSpeed = new QSpinBox(0, 10240, 1, m_toolBar);
  QToolTip::add(uploadSpeed, i18n("Limit upload transfer speed"));
  m_toolBar->insertWidget(3, 35, new QLabel(i18n("Up: "), m_toolBar));
  m_toolBar->insertWidget(4, 35, uploadSpeed);
  uploadSpeed->setValue(Config::uploadSpeedLimit());
  connect(uploadSpeed, SIGNAL(valueChanged(int)), this, SLOT(slotUploadLimitChanged(int)));
  
  // Create thread count control widget
  m_toolBar->insertSeparator();
  
  QSpinBox *threadCount = new QSpinBox(1, 10, 1, m_toolBar);
  QToolTip::add(threadCount, i18n("Per-session transfer thread count"));
  m_toolBar->insertWidget(5, 35, new QLabel(i18n("Threads: "), m_toolBar));
  m_toolBar->insertWidget(6, 35, threadCount);
  threadCount->setValue(Config::threadCount());
  connect(threadCount, SIGNAL(valueChanged(int)), this, SLOT(slotThreadCountChanged(int)));
}

void QueueView::slotDownloadLimitChanged(int value)
{
  Config::setDownloadSpeedLimit(value);
  Config::self()->emitChange();
}

void QueueView::slotUploadLimitChanged(int value)
{
  Config::setUploadSpeedLimit(value);
  Config::self()->emitChange();
}

void QueueView::slotThreadCountChanged(int value)
{
  Config::setThreadCount(value);
  Config::self()->emitChange();
}

void QueueView::initActions()
{
  m_actionCollection = new KActionCollection(this, this);
  
  // Create all the actions
  m_launchAction = new KAction(i18n("&Start Transfer"), "launch", KShortcut(), this, SLOT(slotLaunch()), m_actionCollection, "launch");
  m_abortAction = new KAction(i18n("&Abort Transfer"), KShortcut(), this, SLOT(slotAbort()), m_actionCollection, "abort");
  m_removeAction = new KAction(i18n("&Remove"), "editdelete", KShortcut(Qt::Key_Delete), this, SLOT(slotRemove()), m_actionCollection, "remove");
  m_removeAllAction = new KAction(i18n("Remove &All"), KShortcut(), this, SLOT(slotRemoveAll()), m_actionCollection, "removeAll");
  m_moveUpAction = new KAction(i18n("Move &Up"), "up", KShortcut(), this, SLOT(slotMoveUp()), m_actionCollection, "moveUp");
  m_moveDownAction = new KAction(i18n("Move &Down"), "down", KShortcut("del"), this, SLOT(slotMoveDown()), m_actionCollection, "moveDown");
  m_moveTopAction = new KAction(i18n("Move To &Top"), "top", KShortcut(), this, SLOT(slotMoveTop()), m_actionCollection, "moveTop");
  m_moveBottomAction = new KAction(i18n("Move To &Bottom"), "bottom", KShortcut(), this, SLOT(slotMoveBottom()), m_actionCollection, "moveBottom");
  m_editAction = new KAction(i18n("&Change Transfer Info"), KShortcut(), this, SLOT(slotEdit()), m_actionCollection, "changeTransfer");

  // Create the toolbar actions
  m_loadAction = new KAction(i18n("&Load Queue From File"), "fileopen", KShortcut(), this, SLOT(slotLoad()), m_actionCollection, "load");
  m_saveAction = new KAction(i18n("&Save Queue to File"), "filesaveas", KShortcut(), this, SLOT(slotSave()), m_actionCollection, "save");
  m_startAction = new KAction(i18n("S&tart"), "player_play", KShortcut(), this, SLOT(slotStart()), m_actionCollection, "start");
  m_pauseAction = new KAction(i18n("&Pause"), "player_pause", KShortcut(), this, SLOT(slotPause()), m_actionCollection, "pause");
  m_stopAction = new KAction(i18n("St&op"), "player_stop", KShortcut(), this, SLOT(slotStop()), m_actionCollection, "stop");
  m_addAction = new KAction(i18n("&Add Transfer..."), "filenew", KShortcut(), this, SLOT(slotAdd()), m_actionCollection, "add");
  m_searchAction = new KAction(i18n("&Search && Replace..."), "find", KShortcut(), this, SLOT(slotSearch()), m_actionCollection, "search");
  m_filterAction = new KToggleAction(i18n("Show &Filter"), "filter", KShortcut(), this, SLOT(slotFilter()), m_actionCollection, "filter");
    
  m_saveAction->setEnabled( false );
  m_startAction->setEnabled(false);
  m_pauseAction->setEnabled(false);
  m_stopAction->setEnabled(false);
  m_addAction->setEnabled(false);
  m_removeAction->setEnabled(false);
  m_searchAction->setEnabled(false);
  m_filterAction->setEnabled(true);
}

void QueueView::updateActions()
{
  m_startAction->setEnabled(!KFTPQueue::Manager::self()->isProcessing() && KFTPQueue::Manager::self()->topLevelObject()->hasChildren() && !KFTPQueue::Manager::self()->getNumRunning());
  m_stopAction->setEnabled(KFTPQueue::Manager::self()->isProcessing());
  m_removeAllAction->setEnabled(!KFTPQueue::Manager::self()->isProcessing());
  
  QPtrList<QListViewItem> selection = m_queue->selectedItems();
  QueueViewItem *firstItem = static_cast<QueueViewItem*>(selection.first());
  
  m_removeAction->setEnabled((bool) firstItem);
  
  if (!firstItem || !firstItem->getObject())
    return;
    
  bool locked = firstItem->getObject()->isLocked();
  bool parentRunning = false;
  
  if (firstItem->getObject()->hasParentObject())
    parentRunning = firstItem->getObject()->parentObject()->isRunning();
  
  m_launchAction->setEnabled(!firstItem->getObject()->isRunning() && !KFTPQueue::Manager::self()->isProcessing() && !locked);
  m_abortAction->setEnabled(firstItem->getObject()->isRunning() && !KFTPQueue::Manager::self()->isProcessing());
  m_removeAction->setEnabled(!firstItem->getObject()->isRunning() && !KFTPQueue::Manager::self()->isProcessing() && !locked);
  m_editAction->setEnabled(!firstItem->getObject()->isRunning() && firstItem->getObject()->parentObject()->getType() == KFTPQueue::QueueObject::Site && !locked);
  
  // Only allow moving of multi selections if they have the same parent
  bool allowMove = true;
  for (QListViewItem *i = selection.first(); i; i = selection.next()) {
    if (i->parent() != static_cast<QListViewItem*>(firstItem)->parent()) {
      allowMove = false;
      break;
    }
  }
  
  m_moveUpAction->setEnabled(allowMove && KFTPQueue::Manager::self()->canBeMovedUp(firstItem->getObject()) && !locked);
  m_moveDownAction->setEnabled(allowMove && KFTPQueue::Manager::self()->canBeMovedDown(static_cast<QueueViewItem*>(selection.last())->getObject()) && !locked);
  
  m_moveTopAction->setEnabled(allowMove && KFTPQueue::Manager::self()->canBeMovedUp(firstItem->getObject()) && !locked);
  m_moveBottomAction->setEnabled(allowMove && KFTPQueue::Manager::self()->canBeMovedDown(static_cast<QueueViewItem*>(selection.last())->getObject()) && !locked);
}

void QueueView::slotSiteAdded(KFTPQueue::Site *site)
{
  // The site should be inserted top-level
  m_queuedItems.insert(site->getId(), new QueueViewItem(this, site, m_queue));
  connect(site, SIGNAL(objectUpdated()), this, SLOT(slotObjectUpdated()));
}

void QueueView::slotTransferAdded(KFTPQueue::Transfer *transfer)
{
  // This transfer should be inserted under some other transfer
  QueueViewItem *parent = m_queuedItems.find(transfer->parentObject()->getId());
  
  if (parent) {
    m_queuedItems.insert(transfer->getId(), new QueueViewItem(this, transfer, parent));
    connect(transfer, SIGNAL(objectUpdated()), this, SLOT(slotObjectUpdated()));
  }
  
  // Update actions
  m_saveAction->setEnabled(true);
  m_removeAllAction->setEnabled(true);
  m_searchAction->setEnabled(true);
}

void QueueView::slotObjectRemoved(long id)
{
  // Delete the transfer
  QueueViewItem *item = m_queuedItems.find(id);
  
  if (item)
    delete item;

  // Update actions
  bool empty = (m_queue->childCount() == 0);

  m_saveAction->setEnabled(!empty);
  if (empty) m_removeAction->setEnabled(false);
  m_removeAllAction->setEnabled(!empty);
  m_searchAction->setEnabled(!empty);
}

void QueueView::slotObjectUpdated()
{
  KFTPQueue::QueueObject *object = (KFTPQueue::QueueObject*) QObject::sender();
  
  if (object) {
    QueueViewItem *item = m_queuedItems.find(object->getId());
    
    if (item)
      item->refresh();
  }
}

void QueueView::contextMenuRequested(KListView*, QListViewItem* item, const QPoint& p)
{
  if (!item)
    return;

  QueueViewItem *firstItem = static_cast<QueueViewItem*>(m_queue->selectedItems().first());
  KPopupMenu *contextMenu = new KPopupMenu(m_queue);
  
  // Populate context menu
  if (firstItem->getObject()->isTransfer()) {
    contextMenu->insertTitle(item->text(0) + ((m_queue->selectedItems().count() > 1) ? "..." : "" ));
    m_launchAction->plug(contextMenu);
    m_abortAction->plug(contextMenu);
    contextMenu->insertSeparator();
    m_removeAction->plug(contextMenu);
    m_removeAllAction->plug(contextMenu);
    contextMenu->insertSeparator();
    m_moveTopAction->plug(contextMenu);
    m_moveUpAction->plug(contextMenu);
    m_moveDownAction->plug(contextMenu);
    m_moveBottomAction->plug(contextMenu);
    contextMenu->insertSeparator();
    m_editAction->plug(contextMenu);
  } else if (firstItem->getObject()->getType() == KFTPQueue::QueueObject::Site) {
    contextMenu->insertTitle(i18n("Site"));
    m_launchAction->plug(contextMenu);
    m_abortAction->plug(contextMenu);
    contextMenu->insertSeparator();
    m_moveUpAction->plug(contextMenu);
    m_moveDownAction->plug(contextMenu);
  }
  
  // Update the actions
  updateActions();
  
  // Show the context menu
  contextMenu->exec(p);
}

void QueueView::slotLaunch()
{
  // Reset a possible preconfigured default action
  KFTPQueue::Manager::self()->setDefaultFileExistsAction();
  
  static_cast<QueueViewItem*>(m_queue->selectedItems().first())->getObject()->execute();
}

void QueueView::slotAbort()
{
  static_cast<QueueViewItem*>(m_queue->selectedItems().first())->getObject()->abort();
}

void QueueView::slotRemove()
{
  if (KMessageBox::questionYesNo(this, i18n("Are you sure you want to remove queued file(s)?")) == KMessageBox::Yes) {
    KFTPQueue::Manager::self()->setEmitUpdate(false);
   
    QPtrList<QListViewItem> selection = m_queue->selectedItems();
    for (QListViewItem *item = selection.first(); item; item = selection.next()) {
      if (item && static_cast<QueueViewItem*>(item)->getObject())
        KFTPQueue::Manager::self()->removeTransfer(static_cast<KFTPQueue::Transfer*>(static_cast<QueueViewItem*>(item)->getObject()));
    }
    
    KFTPQueue::Manager::self()->setEmitUpdate(true);
    KFTPQueue::Manager::self()->doEmitUpdate();
  }
}

void QueueView::slotRemoveAll()
{
  if (KMessageBox::questionYesNo(this, i18n("Are you sure you want to remove ALL queued files?")) == KMessageBox::Yes) {
    KFTPQueue::Manager::self()->clearQueue();
  }
}

void QueueView::slotMoveUp()
{
  QPtrList<QListViewItem> selection = m_queue->selectedItems();
  
  for (QListViewItem *item = selection.first(); item; item = selection.next()) {
    QueueViewItem *queueItem = static_cast<QueueViewItem*>(item);
    
    // Move the transfer
    KFTPQueue::Manager::self()->moveTransferUp(queueItem->getObject());
    queueItem->moveUp();
  }
}

void QueueView::slotMoveDown()
{
  QPtrList<QListViewItem> selection = m_queue->selectedItems();
  
  for (QListViewItem *item = selection.last(); item; item = selection.prev()) {
    QueueViewItem *queueItem = static_cast<QueueViewItem*>(item);
    
    // Move the transfer
    KFTPQueue::Manager::self()->moveTransferDown(queueItem->getObject());
    queueItem->moveDown();
  }
}

void QueueView::slotMoveTop()
{
  QPtrList<QListViewItem> selection = m_queue->selectedItems();
  
  for (QListViewItem *item = selection.last(); item; item = selection.prev()) {
    QueueViewItem *queueItem = static_cast<QueueViewItem*>(item);
    
    // Move the transfer
    KFTPQueue::Manager::self()->moveTransferTop(queueItem->getObject());
    queueItem->moveToTop();
  }
}

void QueueView::slotMoveBottom()
{
  QPtrList<QListViewItem> selection = m_queue->selectedItems();
  
  for (QListViewItem *item = selection.first(); item; item = selection.next()) {
    QueueViewItem *queueItem = static_cast<QueueViewItem*>(item);
    
    // Move the transfer
    KFTPQueue::Manager::self()->moveTransferBottom(queueItem->getObject());
    queueItem->moveToBottom();
  }
}

void QueueView::slotEdit()
{
  QueueEditor *editor = new QueueEditor(this);
  
  QueueViewItem* item = static_cast<QueueViewItem*>(m_queue->selectedItems().first());
  editor->setData(static_cast<KFTPQueue::Transfer*>(item->getObject()));
  
  // Show the queue editor
  if (editor->exec() == QDialog::Accepted) {
    editor->saveData();
    
    KFTPQueue::Manager::self()->revalidateTransfer(static_cast<KFTPQueue::Transfer*>(item->getObject()));
    KFTPQueue::Manager::self()->doEmitUpdate();
    item->refresh();
  }
}

void QueueView::slotSearch()
{
  SearchDialog *dialog = new SearchDialog();
  
  dialog->exec();
  delete dialog;
}

void QueueView::slotLoad()
{
  if (m_queue->childCount() && KMessageBox::warningContinueCancel(0L, i18n("Loading a new queue will overwrite the existing one; are you sure you want to continue?"), i18n("Load Queue")) == KMessageBox::Cancel)
    return;

  QString loadPath = KFileDialog::getOpenFileName();
  
  if (!loadPath.isEmpty()) {
    KFTPQueue::Manager::self()->getConverter()->importQueue(loadPath);
  }
}

void QueueView::slotSave()
{
  QString savePath = KFileDialog::getSaveFileName();
  
  if (!savePath.isEmpty()) {
    KFTPQueue::Manager::self()->getConverter()->exportQueue(savePath);
  }
}

void QueueView::slotStart()
{
  // Begin queue processing
  KFTPQueue::Manager::self()->start();
}

void QueueView::slotPause()
{
}

void QueueView::slotStop()
{
  // Abort queue processing
  KFTPQueue::Manager::self()->abort();
}

void QueueView::slotAdd()
{
}

void QueueView::slotSearchEraseClicked()
{
  m_searchField->clear();
}

void QueueView::slotFilter()
{
  if (m_filterAction->isChecked())
    m_searchToolBar->show();
  else
    m_searchToolBar->hide();
}

}

#include "queueview.moc"
