/*
 * 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>
 *
 * 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 "browser/actions.h"
#include "browser/view.h"
#include "browser/detailsview.h"
#include "browser/propsplugin.h"
#include "browser/filterwidget.h"

#include "widgets/quickconnect.h"
#include "widgets/popupmessage.h"

#include "kftpbookmarks.h"
#include "kftpqueue.h"
#include "kftpapi.h"
#include "kftpsession.h"
#include "verifier.h"
#include "mainactions.h"

#include "misc.h"
#include "misc/kftpconfig.h"
#include "misc/filter.h"
#include "misc/customcommands/manager.h"

#include <tdeglobal.h>
#include <kcharsets.h>
#include <tdeapplication.h>
#include <tdemainwindow.h>
#include <tdelocale.h>
#include <tdemessagebox.h>
#include <tdepopupmenu.h>
#include <kinputdialog.h>
#include <kpropertiesdialog.h>
#include <tdeio/job.h>
#include <kshred.h>
#include <klineedit.h>
#include <tdefiledialog.h>
#include <kstandarddirs.h>

#include <tqdir.h>
#include <tqclipboard.h>

using namespace KFTPGrabberBase;
using namespace KFTPEngine;
using namespace KFTPCore;
using namespace KFTPCore::Filter;

namespace KFTPWidgets {

namespace Browser {

Actions::Actions(View *parent)
 : TQObject(parent),
   m_view(parent)
{
}

void Actions::initActions()
{
  m_actionCollection = new TDEActionCollection(m_view, this);
  
  // Create all the actions
  m_goUpAction = KStdAction::up(this, TQ_SLOT(slotGoUp()), m_actionCollection, "go_up");
  m_goBackAction = KStdAction::back(this, TQ_SLOT(slotGoBack()), m_actionCollection, "go_back");
  m_goForwardAction = KStdAction::forward(this, TQ_SLOT(slotGoForward()), m_actionCollection, "go_forward");
  m_goHomeAction = KStdAction::home(this, TQ_SLOT(slotGoHome()), m_actionCollection, "go_home");

  m_reloadAction = KStdAction::redisplay(this, TQ_SLOT(slotReload()), m_actionCollection, "reload");
  m_reloadAction->setText(i18n("&Reload"));
  m_reloadAction->setShortcut(TDEShortcut(TQt::Key_F5));
  
  m_abortAction = new TDEAction(i18n("&Abort"), "process-stop", TDEShortcut(), this, TQ_SLOT(slotAbort()), m_actionCollection, "abort");
  m_toggleTreeViewAction = new TDEToggleAction(i18n("&Show Tree View"), "view_tree", TDEShortcut(), this, TQ_SLOT(slotShowHideTree()), m_actionCollection, "toggle_tree_view");
  m_toggleFilterAction = new TDEToggleAction(i18n("Show &Filter"), "filter", TDEShortcut(), this, TQ_SLOT(slotShowHideFilter()), m_actionCollection, "toggle_filter");
  
  m_renameAction = new TDEAction(i18n("&Rename"), TDEShortcut(TQt::Key_F2), this, TQ_SLOT(slotRename()), m_actionCollection, "edit_rename");
  m_deleteAction = new TDEAction(i18n("&Delete"), "edit-delete", TDEShortcut(TQt::Key_Delete), this, TQ_SLOT(slotDelete()), m_actionCollection, "edit_delete");
  m_propsAction = new TDEAction(i18n("&Properties"), TDEShortcut(), this, TQ_SLOT(slotProps()), m_actionCollection, "edit_properties");
  m_shredAction = new TDEAction(i18n("&Shred"), "editshred", TDEShortcut(), this, TQ_SLOT(slotShred()), m_actionCollection, "edit_shred");
  
  m_copyAction = KStdAction::copy(this, TQ_SLOT(slotCopy()), m_actionCollection, "edit_copy");
  m_pasteAction = KStdAction::paste(this, TQ_SLOT(slotPaste()), m_actionCollection, "edit_paste");
  
  m_filterActions = new TDEActionMenu(i18n("&Filter Options"), "", m_actionCollection, "edit_filter_options");
  m_alwaysSkipAction = new TDEAction(i18n("Always &skip this file when queuing"), TDEShortcut(), this, TQ_SLOT(slotAlwaysSkip()), m_actionCollection);
  m_topPriorityAction = new TDEAction(i18n("Make this file &top priority"), TDEShortcut(), this, TQ_SLOT(slotTopPriority()), m_actionCollection);
  m_lowPriorityAction = new TDEAction(i18n("Make this file &lowest priority"), TDEShortcut(), this, TQ_SLOT(slotLowPriority()), m_actionCollection);
  
  m_filterActions->insert(m_alwaysSkipAction);
  m_filterActions->insert(m_topPriorityAction);
  m_filterActions->insert(m_lowPriorityAction);
  
  m_transferAction = new TDEAction(i18n("&Transfer"), TDEShortcut(), this, TQ_SLOT(slotTransfer()), m_actionCollection, "transfer");
  m_queueTransferAction = new TDEAction(i18n("&Queue Transfer"), "queue", TDEShortcut(), this, TQ_SLOT(slotQueueTransfer()), m_actionCollection, "queue_transfer");
  m_createDirAction = new TDEAction(i18n("&Create Directory..."), "folder-new", TDEShortcut(), this, TQ_SLOT(slotCreateDir()), m_actionCollection, "create_dir");
  m_fileEditAction = new TDEAction(i18n("&Open file"), "document-open", TDEShortcut(), this, TQ_SLOT(slotFileEdit()), m_actionCollection, "open_file");
  m_verifyAction = new TDEAction(i18n("&Verify..."), "ok", TDEShortcut(), this, TQ_SLOT(slotVerify()), m_actionCollection, "verify");

  populateEncodings();
  
  m_moreActions = new TDEActionMenu(i18n("&More Actions"), "configure", this);
  m_rawCmdAction = new TDEAction(i18n("&Manual Command Entry..."), "openterm", TDEShortcut(), this, TQ_SLOT(slotRawCmd()), m_actionCollection, "send_raw_cmd");
  m_exportListingAction = new TDEAction(i18n("&Export Directory Listing..."), "", TDEShortcut(), this, TQ_SLOT(slotExportListing()), m_actionCollection, "export_listing");
  m_showHiddenFilesAction = new TDEToggleAction(i18n("Show &Hidden Files && Directories"), TDEShortcut(), this, TQ_SLOT(slotShowHiddenFiles()), m_actionCollection, "show_hidden");
  m_openExternalAction = new TDEAction(i18n("Open current directory in &Konqueror..."), "konqueror", TDEShortcut(), this, TQ_SLOT(slotOpenExternal()), m_actionCollection, "open_konqi");
  
  m_markItemsAction = new TDEAction(i18n("Compare &selected items"), "", TDEShortcut(TQt::Key_Space), this, TQ_SLOT(slotMarkItems()), m_actionCollection, "compare_selected");
  m_compareAction = new TDEAction(i18n("Compare &directories"), "", TDEShortcut(), this, TQ_SLOT(slotCompare()), m_actionCollection, "compare_dirs");
  
  m_showHiddenFilesAction->setChecked(KFTPCore::Config::showHiddenFiles());
  
  m_rawCommandsMenu = CustomCommands::Manager::self()->categories(i18n("Send &Raw Command"), m_view->getSession());
  m_rawCommandsMenu->insert(m_rawCmdAction, 0);
  m_rawCommandsMenu->popupMenu()->insertSeparator(1);
  
  m_moreActions->insert(m_rawCommandsMenu);
  m_moreActions->insert(m_changeEncodingAction);
  m_moreActions->popupMenu()->insertSeparator();
  m_moreActions->insert(m_exportListingAction);
  m_moreActions->insert(m_openExternalAction);
  m_moreActions->insert(m_markItemsAction);
  m_moreActions->insert(m_compareAction);
  m_moreActions->popupMenu()->insertSeparator();
  m_moreActions->insert(m_showHiddenFilesAction);
  
  m_moreActions->setStickyMenu(true);
  m_moreActions->setDelayed(false);

  m_siteChangeAction = new TDEActionMenu(i18n("&Change Site"), "goto", this);
  m_quickConnectAction = new TDEAction(i18n("&Quick Connect..."), "connect_creating", TDEShortcut(), this, TQ_SLOT(slotQuickConnect()), m_actionCollection, "quick_connect");
  m_connectAction = new TDEActionMenu(i18n("&Connect To"), this);
  m_disconnectAction = new TDEAction(i18n("&Disconnect"), "connect_no", TDEShortcut(), this, TQ_SLOT(slotDisconnect()), m_actionCollection, "disconnect");

  m_siteChangeAction->insert(m_quickConnectAction);
  m_siteChangeAction->insert(m_connectAction);
  m_siteChangeAction->insert(m_disconnectAction);
  m_siteChangeAction->setStickyMenu(true);
  m_siteChangeAction->setDelayed(false);

  // Populate bookmarks
  KFTPBookmarks::Manager::self()->guiPopulateBookmarksMenu(m_connectAction, TQDomNode(), false, m_view->m_session);
}

void Actions::populateEncodings()
{
  // Charsets
  m_changeEncodingAction = new TDEActionMenu(i18n("Change Remote &Encoding"), "charset", m_actionCollection, "changeremoteencoding");
  m_changeEncodingAction->setDelayed(false);
  
  TDEPopupMenu *menu = m_changeEncodingAction->popupMenu();
  menu->clear();
  
  TQStringList charsets = TDEGlobal::charsets()->descriptiveEncodingNames();
  int count = 0;
  for (TQStringList::iterator i = charsets.begin(); i != charsets.end(); ++i)
    menu->insertItem(*i, this, TQ_SLOT(slotCharsetChanged(int)), 0, ++count);
  
  menu->insertSeparator();
  menu->insertItem(i18n("Default"), this, TQ_SLOT(slotCharsetReset(int)), 0, ++count);
  menu->setItemChecked(count, true);
  
  m_defaultCharsetOption = count;
  m_curCharsetOption = count;
}

void Actions::updateActions()
{
  m_goUpAction->setEnabled(m_view->url().upURL() != m_view->url());

  // History
  int index = 0;
  const TQValueList<LocationNavigator::Element> list = m_view->history(index);
  
  m_goBackAction->setEnabled(index < static_cast<int>(list.count()) - 1);
  m_goForwardAction->setEnabled(index > 0);
  
  m_abortAction->setEnabled(m_view->m_ftpClient->socket()->isBusy());
  m_toggleTreeViewAction->setEnabled(true);
  m_toggleFilterAction->setEnabled(true);

  m_quickConnectAction->setEnabled(m_view->url().isLocalFile());
  m_connectAction->setEnabled(true);
  m_disconnectAction->setEnabled(m_view->m_ftpClient->socket()->isConnected());
  
  const KFileItemList *selectedItems = m_view->selectedItems();
  
  if (selectedItems->count() == 1) {
    m_fileEditAction->setEnabled(!selectedItems->getFirst()->isDir());
    m_verifyAction->setEnabled(selectedItems->getFirst()->isLocalFile() && selectedItems->getFirst()->name(true).right(3) == "sfv");
  } else {
    m_fileEditAction->setEnabled(false);
    m_verifyAction->setEnabled(false);
  }
  
  // Check if we can transfer anything
  KFTPSession::Session *session = m_view->m_session;
  KFTPSession::Session *opposite = KFTPSession::Manager::self()->getActive(oppositeSide(m_view->m_session->getSide()));
  
  m_renameAction->setEnabled(session->isConnected());
  m_deleteAction->setEnabled(session->isConnected());
  m_propsAction->setEnabled(true);
  m_shredAction->setEnabled(!session->isRemote());
  m_copyAction->setEnabled(true);
  m_pasteAction->setEnabled(true);
  
  if ((!session->isRemote() && !opposite->isRemote()) ||
      (
        (session->isRemote() && opposite->isRemote()) &&
        (
          session->getClient()->socket()->protocolName() != opposite->getClient()->socket()->protocolName() ||
          !(session->getClient()->socket()->features() & SF_FXP_TRANSFER)
        )
      )
     ) {
    m_queueTransferAction->setEnabled(false);
    m_transferAction->setEnabled(false);
  } else {
    m_queueTransferAction->setEnabled(true);
    m_transferAction->setEnabled(true);
  }

  if (!session->isRemote() || session->getClient()->socket()->isConnected())
    m_createDirAction->setEnabled(true);
  else
    m_createDirAction->setEnabled(false);

  m_changeEncodingAction->setEnabled(session->isRemote());
  m_rawCmdAction->setEnabled(!m_view->url().isLocalFile() && m_view->m_ftpClient->socket()->features() & SF_RAW_COMMAND);
  m_rawCommandsMenu->setEnabled(m_rawCmdAction->isEnabled());
  m_openExternalAction->setEnabled(!session->isRemote());
}

void Actions::slotGoUp()
{
  m_view->goUp();
}

void Actions::slotGoBack()
{
  m_view->goBack();
}

void Actions::slotGoForward()
{
  m_view->goForward();
}

void Actions::slotReload()
{
  m_view->reload();
}

void Actions::slotGoHome()
{
  m_view->goHome();
}

void Actions::slotQuickConnect()
{
  // Create/get the new dialog
  QuickConnectDialog *quickConnect = new QuickConnectDialog(m_view);

  if (quickConnect->exec() == KDialogBase::Accepted) {
    // Get the url and connect
    if (m_view->m_ftpClient->socket()->isConnected()) {
      if (KFTPCore::Config::confirmDisconnects() && KMessageBox::warningYesNo(0, i18n("Do you want to drop current connection?")) == KMessageBox::No)
        return;
      
      m_view->m_session->disconnectAllConnections();
    }

    m_view->m_session->setSite(0);
    
    quickConnect->setupClient(m_view->m_ftpClient);
    m_view->m_ftpClient->connect(quickConnect->getUrl());
  }

  delete quickConnect;
}

void Actions::slotDisconnect()
{
  if (m_view->m_ftpClient->socket()->isConnected()) {
    if (KFTPCore::Config::confirmDisconnects() && KMessageBox::warningYesNo(0, i18n("Do you want to drop current connection?")) == KMessageBox::No)
      return;

    m_view->m_session->disconnectAllConnections();
  }
}

void Actions::slotShred()
{
  // Shred the file
  if (KMessageBox::warningContinueCancel(0, i18n("Are you sure you want to SHRED this file?"), i18n("Shred File"),KGuiItem(i18n("&Shred"), "editshred")) == KMessageBox::Cancel)
    return;
  
  KShred::shred(m_view->selectedItems()->getFirst()->url().path());
}

void Actions::slotRename()
{
  KFTPWidgets::Browser::DetailsView *view = m_view->getDetailsView();
  
  // Rename the first file in the current selection
  view->rename(view->TDEListView::selectedItems().at(0), 0);
  
  // Enhanced rename: Don't highlight the file extension. (from Konqueror)
  KLineEdit *le = view->renameLineEdit();
  
  if (le) {
    const TQString txt = le->text();
    TQString pattern;
    KMimeType::diagnoseFileName(txt, pattern);
    
    if (!pattern.isEmpty() && pattern.at(0) == '*' && pattern.find('*',1) == -1)
      le->setSelection(0, txt.length()-pattern.stripWhiteSpace().length()+1);
    else {
      int lastDot = txt.findRev('.');
      
      if (lastDot > 0)
        le->setSelection(0, lastDot);
    }
  }
}

void Actions::slotDelete()
{
  KFTPSession::Session *session = m_view->getSession();
  
  // Delete a file or directory
  KURL::List selection = m_view->selectedURLs();
  KURL::List::ConstIterator i = selection.begin();
  TQStringList prettyList;
  for (; i != selection.end(); ++i) {
    prettyList.append((*i).pathOrURL());
  }

  if (KMessageBox::warningContinueCancelList(0,
                                            i18n("Do you really want to delete this item?", "Do you really want to delete these %n items?", prettyList.count()),
                                            prettyList,
                                            i18n("Delete Files"),
                                            KStdGuiItem::del(),
                                            TQString::null,
                                            KMessageBox::Dangerous) == KMessageBox::Cancel)
    return;

  // Go trough all files and delete them
  if (!session->isRemote()) {
    TDEIO::del(selection);
  } else {
    KURL::List::Iterator end(selection.end());
    
    for (KURL::List::Iterator i(selection.begin()); i != end; ++i) {
      if (!(*i).isLocalFile())
        session->getClient()->remove(KURL((*i).url()));
    }
  }
}

void Actions::slotCopy()
{
  TQClipboard *cb = TQApplication::clipboard();
  cb->setData(m_view->getDetailsView()->dragObject(), TQClipboard::Clipboard);
}

void Actions::slotPaste()
{
  // Decode the data and try to init transfer
  TDEIO::MetaData p_meta;
  KURL::List p_urls;
  
  if (KURLDrag::decode(TQApplication::clipboard()->data(), p_urls, p_meta)) {
    // Add destination url and call the QueueManager
    p_meta.insert("DestURL", m_view->url().url());
    KURLDrag *drag = new KURLDrag(p_urls, p_meta, m_view, name());
    KFTPQueue::Manager::self()->insertTransfer(drag);
  }
}

void Actions::slotProps()
{
  // Show file properties
  const KFileItemList *selectedItems = m_view->selectedItems();
  KFileItem *item = selectedItems->getFirst();
  
  if (selectedItems->count() == 0) {
    if (m_view->url().isLocalFile())
      item = new KFileItem(m_view->url(), 0, 0);
    else
      return;
  }

  // Show the dialog
  KPropertiesDialog *propsDialog;
  
  if (item->isLocalFile()) {
    if (selectedItems->count() == 0)
      propsDialog = new KPropertiesDialog(item);
    else
      propsDialog = new KPropertiesDialog(*selectedItems);
  } else {
    propsDialog = new KPropertiesDialog(item->name());
    propsDialog->insertPlugin(new KFTPWidgets::Browser::PropsPlugin(propsDialog, *selectedItems));
    propsDialog->insertPlugin(new KFTPWidgets::Browser::PermissionsPropsPlugin(propsDialog, *selectedItems, m_view->getSession()));
  }
  
  propsDialog->exec();
}

void Actions::addPriorityItems(int priority)
{
  // Add the files to skiplist
  KURL::List selection = m_view->selectedURLs();
  KURL::List::Iterator end(selection.end());
    
  for (KURL::List::Iterator i(selection.begin()); i != end; ++i) {
    Rule *rule = new Rule();
    
    if (priority == 0) {
      rule->setName(i18n("Skip '%1'").arg((*i).filename()));
      const_cast<ConditionChain*>(rule->conditions())->append(new Condition(Filename, Condition::Is, (*i).filename()));
      const_cast<ActionChain*>(rule->actions())->append(new Action(Action::Skip, TQVariant()));
    } else {
      rule->setName(i18n("Priority '%1'").arg((*i).filename()));
      const_cast<ConditionChain*>(rule->conditions())->append(new Condition(Filename, Condition::Is, (*i).filename()));
      const_cast<ActionChain*>(rule->actions())->append(new Action(Action::Priority, priority));
    }
    
    Filters::self()->append(rule);
  }
}

void Actions::slotAlwaysSkip()
{
  addPriorityItems(0);
}

void Actions::slotTopPriority()
{
  addPriorityItems(1);
}

void Actions::slotLowPriority()
{
  addPriorityItems(-1);
}

void Actions::slotTransfer()
{
  // Queue a transfer
  KFileItemList list(*m_view->selectedItems());
  KFileItemListIterator i(list);
  KFileItem *item;  
  KFTPSession::Session *opposite = KFTPSession::Manager::self()->getActive(oppositeSide(m_view->m_session->getSide()));
  KFTPQueue::Transfer *transfer = 0L;

  while ((item = i.current()) != 0) {
    KURL destinationUrl = opposite->getFileView()->url();
    destinationUrl.addPath(item->name());

    transfer = KFTPQueue::Manager::self()->spawnTransfer(
      item->url(),
      destinationUrl,
      item->size(),
      item->isDir(),
      list.count() == 1,
      true,
      0L,
      true
    );
    
    ++i;
  }

  // Execute transfer
  if (transfer)
    static_cast<KFTPQueue::Site*>(transfer->parentObject())->delayedExecute();
}

void Actions::slotQueueTransfer()
{
  // Queue a transfer
  KFileItemList list(*m_view->selectedItems());
  KFileItemListIterator i(list);
  KFileItem *item;  
  KFTPSession::Session *opposite = KFTPSession::Manager::self()->getActive(oppositeSide(m_view->m_session->getSide()));

  while ((item = i.current()) != 0) {
    KURL destinationUrl = opposite->getFileView()->url();
    destinationUrl.addPath(item->name());

    KFTPQueue::Manager::self()->spawnTransfer(
      item->url(),
      destinationUrl,
      item->size(),
      item->isDir(),
      list.count() == 1,
      true,
      0L,
      list.count() > 1
    );
    
    ++i;
  }
}

void Actions::slotCreateDir()
{
  // Create new directory
  bool ok;
  TQString newDirName = KInputDialog::getText(i18n("Create Directory"), i18n("Directory name:"), "", &ok);
  
  if (ok) {
    KURL url = m_view->url();
    url.addPath(newDirName);
    
    if (url.isLocalFile())
      TDEIO::mkdir(url);
    else
      m_view->m_ftpClient->mkdir(url);
  }
}

void Actions::slotFileEdit()
{
  KFileItem *item = m_view->selectedItems()->getFirst();
  
  if (!item->isDir()) {
    if (item->isLocalFile()) {
      item->run();
    } else {
      // Create a new transfer to download the file and open it
      KFTPQueue::TransferFile *transfer = new KFTPQueue::TransferFile(KFTPQueue::Manager::self());
      transfer->setSourceUrl(item->url());
      transfer->setDestUrl(KURL(TDEGlobal::dirs()->saveLocation("tmp") + TQString("%1-%2").arg(TDEApplication::randomString(7)).arg(item->name())));
      transfer->addSize(item->size());
      transfer->setTransferType(KFTPQueue::Download);
      transfer->setOpenAfterTransfer(true);
      KFTPQueue::Manager::self()->insertTransfer(transfer);
      
      // Execute the transfer
      transfer->delayedExecute();
    }
  }
}

void Actions::slotAbort()
{
  KFTPSession::Session *session = KFTPSession::Manager::self()->find(m_view);

  // Abort the session
  if (session)
    session->abort();
}

void Actions::slotRawCmd()
{
  bool ok;
  TQString rawCmd = KInputDialog::getText(i18n("Send Raw Command"), i18n("Command:"), "", &ok);

  if (ok)
    m_view->m_ftpClient->raw(rawCmd);
}

void Actions::slotShowHideTree()
{
  m_view->setTreeVisible(m_toggleTreeViewAction->isChecked());
}

void Actions::slotShowHideFilter()
{
  if (m_toggleFilterAction->isChecked()) {
    m_view->m_searchToolBar->show();
    m_view->m_searchFilter->clear();
    m_view->m_searchFilter->setFocus();
  } else {
    m_view->m_searchFilter->clear();
    m_view->m_searchToolBar->hide();
  }
}

void Actions::slotCharsetChanged(int id)
{
  if (!m_changeEncodingAction->popupMenu()->isItemChecked(id)) {
    TQStringList charsets = TDEGlobal::charsets()->descriptiveEncodingNames();
    TQString charset = TDEGlobal::charsets()->encodingForName(charsets[id - 1]);
    
    // Set the current socket's charset
    m_view->m_ftpClient->socket()->changeEncoding(charset);
    
    // Update checked items
    m_changeEncodingAction->popupMenu()->setItemChecked(id, true);
    m_changeEncodingAction->popupMenu()->setItemChecked(m_curCharsetOption, false);
    m_curCharsetOption = id;
  }
}

void Actions::slotCharsetReset(int id)
{
  // Revert to default charset if possible
  KFTPBookmarks::Site *site = m_view->m_session->getSite();
  
  if (site) {
    // Set the current socket's charset
    m_view->m_ftpClient->socket()->changeEncoding(site->getProperty("encoding"));
    
    // Update checked items
    m_changeEncodingAction->popupMenu()->setItemChecked(id, true);
    m_changeEncodingAction->popupMenu()->setItemChecked(m_curCharsetOption, false);
    m_curCharsetOption = id;
  }
}

void Actions::slotExportListing()
{
  TQString savePath = KFileDialog::getSaveFileName(TQString::null, "*.txt|Directory Dump", 0, i18n("Export Directory Listing"));
  
  if (!savePath.isEmpty()) {
    TQFile file(savePath);
    
    if (!file.open(IO_WriteOnly))
      return;
      
    TQTextStream stream(&file);
      
    KFileItemList list(*m_view->items());
    KFileItemListIterator i(list);
    KFileItem *item;
    
    while ((item = i.current()) != 0) {
      stream << item->permissionsString() << "\t";
      stream << item->user() << "\t" << item->group() << "\t";
      stream << item->timeString() << "\t";
      stream << item->name() << "\t";
      stream << "\n";
      
      ++i;
    }
      
    file.flush();
    file.close();
  }
}

void Actions::slotVerify()
{
  KFTPWidgets::Verifier *verifier = new KFTPWidgets::Verifier();
  verifier->setFile(m_view->selectedItems()->getFirst()->url().path());
  verifier->exec();
  
  delete verifier;
}

void Actions::slotShowHiddenFiles()
{
  m_view->setShowHidden(m_showHiddenFilesAction->isChecked());
  m_view->reload();
}

void Actions::slotOpenExternal()
{
  KFileItem *folder = new KFileItem(m_view->url(), "inode/directory", S_IFDIR);
  folder->run();
}

void Actions::slotMarkItems()
{
  KFileItemList list(*m_view->selectedItems());
  KFileItemListIterator i(list);
  KFileItem *item;  
  KFTPSession::Session *opposite = KFTPSession::Manager::self()->getActive(oppositeSide(m_view->m_session->getSide()));
  
  DetailsView *tView = m_view->getDetailsView();
  DetailsView *oView = opposite->getFileView()->getDetailsView();
  
  while ((item = i.current()) != 0) {
    tView->markItem(item);
    oView->markItem(item->name());
    ++i;
  }
}

void Actions::slotCompare()
{
  KFTPSession::Session *opposite = KFTPSession::Manager::self()->getActive(oppositeSide(m_view->m_session->getSide()));
  
  DetailsView *tView = m_view->getDetailsView();
  DetailsView *oView = opposite->getFileView()->getDetailsView();
  
  // All items in the other list view should be visible by default
  TQListViewItemIterator j(oView);
  while (j.current()) {
    KFileItem *oItem = static_cast<KFileListViewItem*>(*j)->fileInfo();
    oView->setItemVisibility(oItem, true);
    
    ++j;
  }
  
  // Compare the two listviews
  TQListViewItemIterator i(tView);
  while (i.current()) {
    KFileItem *tItem = static_cast<KFileListViewItem*>(*i)->fileInfo();
    
    if (tItem) {
      KFileItem *oItem = oView->fileItem(tItem->name());
      
      if (oItem && (oItem->size() == tItem->size() || oItem->isDir())) {
        tView->setItemVisibility(tItem, false);
        oView->setItemVisibility(oItem, false);
      } else {
        tView->setItemVisibility(tItem, true);
      }
    }
    
    ++i;
  }
  
  PopupMessage *popup = new PopupMessage(m_view->getStatusLabel(), m_view);
  popup->setText(i18n("Identical files on both sides have been hidden. Only <b>different files</b> are now visible."));
  popup->setImage(SmallIcon("application-vnd.tde.info"));
  popup->setShowCloseButton(false);
  popup->setShowCounter(false);
  
  popup->reposition();
  popup->display();
}

}

}

#include "actions.moc"
