/***************************************************************************
                          sq_diroperator.cpp  -  description
                             -------------------
    begin                : Mon Mar 15 2004
    copyright            : (C) 2004 by Baryshev Dmitry
    email                : ksquirrel.iv@gmail.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <tqtimer.h>
#include <tqlabel.h>
#include <tqfileinfo.h>
#include <tqapplication.h>
#include <tqtooltip.h>
#include <tqclipboard.h>

#include <tdeapplication.h>
#include <kstringhandler.h>
#include <tdelocale.h>
#include <kprogress.h>
#include <tdeglobal.h>
#include <tdestdaccel.h>
#include <kdiskfreesp.h>
#include <konq_operations.h>
#include <kiconeffect.h>

#include "ksquirrel.h"
#include "sq_archivehandler.h"
#include "sq_diroperator.h"
#include "sq_fileiconview.h"
#include "sq_filethumbview.h"
#include "sq_filethumbviewitem.h"
#include "sq_filedetailview.h"
#include "sq_widgetstack.h"
#include "sq_config.h"
#include "sq_glview.h"
#include "sq_glwidget.h"
#include "sq_thumbnailsize.h"
#include "sq_pixmapcache.h"
#include "sq_libraryhandler.h"
#include "sq_externaltool.h"
#include "sq_popupmenu.h"
#include "sq_navigatordropmenu.h"
#include "sq_previewwidget.h"
#include "sq_treeview.h"
#include "sq_progress.h"
#include "sq_downloader.h"
#include "sq_hloptions.h"

#include "sq_categoriesview.h"
#include "sq_categorybrowsermenu.h"
#include "sq_imagebasket.h"
#include "sq_converter.h"
#include "sq_directorybasket.h"

static const int  SQ_MAX_WORD_LENGTH = 50;

SQ_DirOperator::SQ_DirOperator(const KURL &url, ViewT type_, TQWidget *parent, const char *name)
    : KDirOperator(url, parent, name), type(type_)
{
    usenew = false;

    totalSize = static_cast<TDEIO::filesize_t>(0);

    // create and insert new actions in context menu
    setupActionsMy();

    connect(TQT_TQOBJECT(this), TQT_SIGNAL(finishedLoading()), TQT_TQOBJECT(this), TQT_SLOT(slotFinishedLoading()));
    connect(TQT_TQOBJECT(this), TQT_SIGNAL(updateInformation(int,int)), TQT_TQOBJECT(this), TQT_SLOT(slotUpdateInformation(int,int)));
    connect(TQT_TQOBJECT(this), TQT_SIGNAL(urlEntered(const KURL&)), TQT_TQOBJECT(this), TQT_SLOT(slotUrlEntered(const KURL&)));
    connect(TQT_TQOBJECT(this), TQT_SIGNAL(dropped(const KFileItem *, TQDropEvent*, const KURL::List&)),
            TQT_TQOBJECT(this), TQT_SLOT(slotDropped(const KFileItem *, TQDropEvent*, const KURL::List&)));
    connect(TQT_TQOBJECT(this), TQT_SIGNAL(fileSelected(const KFileItem *)), TQT_TQOBJECT(this), TQT_SLOT(slotExecutedConst(const KFileItem *)));

    connect(dirLister(), TQT_SIGNAL(deleteItem(KFileItem *)), TQT_TQOBJECT(this), TQT_SLOT(slotItemDeleted(KFileItem *)));
    connect(dirLister(), TQT_SIGNAL(newItems(const KFileItemList &)), TQT_TQOBJECT(this), TQT_SLOT(slotNewItems(const KFileItemList &)));
    connect(dirLister(), TQT_SIGNAL(refreshItems(const KFileItemList &)), TQT_TQOBJECT(this), TQT_SLOT(slotRefreshItems(const KFileItemList &)));

    timer_preview = new TQTimer(this);
    connect(timer_preview, TQT_SIGNAL(timeout()), TQT_TQOBJECT(this), TQT_SLOT(slotPreview()));

    setAcceptDrops(true);

    fileview = 0;
    oldCurrentItem = 0;

    fireDiskSize(url);

    down = new SQ_Downloader(TQT_TQOBJECT(this), "SQ_Downloader [dirop]");
    connect(down, TQT_SIGNAL(result(const KURL &)), TQT_TQOBJECT(this), TQT_SLOT(slotDownloaderResult(const KURL &)));
    connect(down, TQT_SIGNAL(percents(int)), TQT_TQOBJECT(this), TQT_SLOT(slotDownloadPercents(int)));

    connect(SQ_ArchiveHandler::instance(), TQT_SIGNAL(unpack(const KURL &)), TQT_TQOBJECT(this), TQT_SLOT(slotSetURL(const KURL &)));

    // read sorting settings
    SQ_Config::instance()->setGroup("Fileview");
    int sorting = 0;

    if(SQ_Config::instance()->readBoolEntry("sorting_name", true))      sorting |= TQDir::Name;
    if(SQ_Config::instance()->readBoolEntry("sorting_time", false))     sorting |= TQDir::Time;
    if(SQ_Config::instance()->readBoolEntry("sorting_size", false))     sorting |= TQDir::Size;
    if(SQ_Config::instance()->readBoolEntry("sorting_dirs", true))      sorting |= TQDir::DirsFirst;
    if(SQ_Config::instance()->readBoolEntry("sorting_reverse", false))  sorting |= TQDir::Reversed;
    if(SQ_Config::instance()->readBoolEntry("sorting_ignore", false))   sorting |= TQDir::IgnoreCase;

    actionHidden = dynamic_cast<TDEToggleAction *>(actionCollection()->action("show hidden"));

    if(SQ_Config::instance()->readBoolEntry("show hidden", false) && actionHidden)
    {
        actionHidden->setChecked(false);
        actionHidden->activate();
    }

    setSorting(static_cast<TQDir::SortSpec>(sorting));
    setEnableDirHighlighting(true);
}

SQ_DirOperator::~SQ_DirOperator()
{}

void SQ_DirOperator::slotUrlEntered(const KURL &url)
{
    usenew = false;

    totalSize = static_cast<TDEIO::filesize_t>(0);

    clearListers();

    SQ_WidgetStack::instance()->setURLForCurrent(url);

    fireDiskSize(url);
}

void SQ_DirOperator::fireDiskSize(const KURL &url)
{
    if(url.isLocalFile())
    {
        KDiskFreeSp *sp = KDiskFreeSp::findUsageInfo(url.path());

        connect(sp, TQT_SIGNAL(foundMountPoint(const unsigned long&,
                                        const unsigned long&,
                                        const unsigned long&,
                                        const TQString&)),
                                        TQT_TQOBJECT(this), TQT_SLOT(slotFoundMountPoint(const unsigned long&,
                                        const unsigned long&,
                                        const unsigned long&,
                                        const TQString&)));
    }
    else
    {
        KSquirrel::app()->diskProgress()->flush();
        KSquirrel::app()->diskProgress()->setTotalSteps(1);
        KSquirrel::app()->diskProgress()->setIndicator(0);
        KSquirrel::app()->diskProgress()->update();
        KSquirrel::app()->sbarWidget("diskSpace")->setText(i18n("remote filesystem"));
        TQToolTip::remove(KSquirrel::app()->sbarWidget("diskSpace"));
    }
}

void SQ_DirOperator::slotFoundMountPoint(const unsigned long &kbSize,
                    const unsigned long &kbUsed,
                    const unsigned long &kbAvail,
                    const TQString &mount)
{
    // clear any previous drawing
    KSquirrel::app()->diskProgress()->flush();

    KSquirrel::app()->diskProgress()->setTotalSteps(kbSize);
    KSquirrel::app()->diskProgress()->setIndicator(kbSize-kbAvail); // kbSize != kbAvail+kbUsed
    KSquirrel::app()->sbarWidget("diskSpace")->setText(TQString::fromLatin1("%1: %2/%3")
                                                        .arg(mount)
                                                        .arg(TDEIO::convertSizeFromKB(kbAvail))
                                                        .arg(TDEIO::convertSizeFromKB(kbSize)));

    TQToolTip::add(KSquirrel::app()->sbarWidget("diskSpace"), i18n("<table><tr><td>Mount point:</td><td>%1</td></tr><tr><td>Total size:</td><td>%2</td></tr><tr><td>Used:</td><td>%3</td></tr><tr><td>Available:</td><td>%4</td></tr></table>")
                                                                .arg(mount)
                                                                .arg(TDEIO::convertSizeFromKB(kbSize))
                                                                .arg(TDEIO::convertSizeFromKB(kbUsed))
                                                                .arg(TDEIO::convertSizeFromKB(kbAvail))
                                                                );
}

void SQ_DirOperator::slotExecutedConst(const KFileItem *fi)
{
    execute(const_cast<KFileItem *>(fi));
}

void SQ_DirOperator::execute(KFileItem *fi)
{
    down->kill();

    SQ_GLWidget::window()->setOriginalURL(fi->url());

    if(fi->url().isLocalFile())
        executePrivate(fi);
    else if(SQ_LibraryHandler::instance()->maybeSupported(fi->url(), fi->mimetype()) != SQ_LibraryHandler::No)
        down->start(fi);
}

void SQ_DirOperator::slotDownloaderResult(const KURL &url)
{
    SQ_GLWidget::window()->setDownloadPercents(-1);

    if(url.isEmpty())
        return;    

    KFileItem fi(KFileItem::Unknown, KFileItem::Unknown, url);

    executePrivate(&fi);
}

void SQ_DirOperator::prepareView(ViewT t)
{
    type = t;

    if(fileview)
    {
        oldSelected = *fileview->selectedItems();
        oldCurrentItem = fileview->currentFileItem();
    }

    switch(type)
    {
        case  SQ_DirOperator::TypeDetailed:
        {
            SQ_FileDetailView *dv;
            fileview = dv = new SQ_FileDetailView(this, "detail view");

            connect(dv, TQT_SIGNAL(currentChanged(TQListViewItem *)), TQT_TQOBJECT(this), TQT_SLOT(slotCurrentChanged(TQListViewItem *)));
            connect(dv, TQT_SIGNAL(selectionChanged()), TQT_TQOBJECT(this), TQT_SLOT(slotSelectionChanged()));
            connect(dv, TQT_SIGNAL(invokeBrowser()), TQT_TQOBJECT(this), TQT_SLOT(slotInvokeBrowser()));
            connect(KSquirrel::app(), TQT_SIGNAL(resetToolTip()), dv, TQT_SLOT(slotResetToolTip()));
        }
        break;

        case  SQ_DirOperator::TypeList:
        case  SQ_DirOperator::TypeIcons:
        {
            SQ_FileIconView *iv;
            fileview = iv = new SQ_FileIconView(this, (type == SQ_DirOperator::TypeIcons) ? "icon view":"list view");

            connect(iv, TQT_SIGNAL(currentChanged(TQIconViewItem *)), TQT_TQOBJECT(this), TQT_SLOT(slotCurrentChanged(TQIconViewItem *)));
            connect(iv, TQT_SIGNAL(selectionChanged()), TQT_TQOBJECT(this), TQT_SLOT(slotSelectionChanged()));
            connect(iv, TQT_SIGNAL(invokeBrowser()), TQT_TQOBJECT(this), TQT_SLOT(slotInvokeBrowser()));
            connect(KSquirrel::app(), TQT_SIGNAL(resetToolTip()), iv, TQT_SLOT(slotResetToolTip()));

            disableSpecificActions(iv);
        }
        break;

        case  SQ_DirOperator::TypeThumbs:
        {
            SQ_FileThumbView *tv;
            fileview = tv = new SQ_FileThumbView(this, "thumb view");

            connect(tv, TQT_SIGNAL(currentChanged(TQIconViewItem *)), TQT_TQOBJECT(this), TQT_SLOT(slotCurrentChanged(TQIconViewItem *)));
            connect(tv, TQT_SIGNAL(selectionChanged()), TQT_TQOBJECT(this), TQT_SLOT(slotSelectionChanged()));
            connect(tv, TQT_SIGNAL(invokeBrowser()), TQT_TQOBJECT(this), TQT_SLOT(slotInvokeBrowser()));
            connect(dirLister(), TQT_SIGNAL(canceled()), tv, TQT_SLOT(stopThumbnailUpdate()));
            connect(KSquirrel::app(), TQT_SIGNAL(resetToolTip()), tv, TQT_SLOT(slotResetToolTip()));

            disableSpecificActions(tv);
        }
        break;
    }
}

void SQ_DirOperator::slotCurrentChanged(TQListViewItem *)
{
    timer_preview->start(SQ_PreviewWidget::instance()->delay(), true);
}

void SQ_DirOperator::slotCurrentChanged(TQIconViewItem *)
{
    timer_preview->start(SQ_PreviewWidget::instance()->delay(), true);
}

void SQ_DirOperator::slotSelectionChanged()
{
    TQString str = i18n("no files selected");
    TQPixmap px;
    TDEIO::filesize_t sz = static_cast<TDEIO::filesize_t>(0);
    int add = 0;
    KFileItem *fi = 0;

    // which items are selected ?
    for(KFileItem *it = fileview->firstFileItem();it;it = fileview->nextItem(it))
    {
        if(fileview->isSelected(it))
        {
            // _current_ fileitem and currently _selected_ fileitem
            // may differ, so lets count only first _selected_ item
            if(!fi)
                fi = it;

            add++;

            // count only files
            if(it->isFile())
                sz += it->size();
        }
    }

    if(fi)
    {
        // determine pixmap
        px = fi->pixmap(TDEIcon::SizeSmall);

        // costruct name and size
        str = TQString("%1 %2 %3")
                .arg(KStringHandler::csqueeze(fi->name(), SQ_MAX_WORD_LENGTH))
                .arg(TDEIO::convertSize(fi->size()))
                .arg(add > 1 ? TQString("<b>[%1/%2]</b>").arg(TDEIO::convertSize(sz)).arg(add):"");
    }

    // update statusbar
    KSquirrel::app()->sbarWidget("fileIcon")->setPixmap(px);
    KSquirrel::app()->sbarWidget("fileName")->setText(str);
}

void SQ_DirOperator::setPreparedView()
{
    setView(fileview);

    fileview->setOnlyDoubleClickSelectsFiles(true);
}

void SQ_DirOperator::slotDropped(const KFileItem *i, TQDropEvent*, const KURL::List &urls)
{
    KURL u = i ? i->url() : url();

    // setup and show popup menu with actions
    SQ_NavigatorDropMenu::instance()->setupFiles(urls, u);
    SQ_NavigatorDropMenu::instance()->exec(TQCursor::pos());
}

// Insert new actions in context menu.
void SQ_DirOperator::setupActionsMy()
{
    new TDEAction(i18n("Edit file type"), 0, 0, TQT_TQOBJECT(this), TQT_SLOT(slotEditMime()), actionCollection(), "dirop_edit_mime");

    if(SQ_HLOptions::instance()->have_imagebasket)
        new TDEAction(i18n("Add to Basket"), "folder_image", CTRL+TQt::Key_B, TQT_TQOBJECT(this), TQT_SLOT(slotAddToBasket()), actionCollection(), "dirop_tobasket");

    if(SQ_HLOptions::instance()->have_directorybasket)
        new TDEAction(i18n("Add to Folder Basket"), "folder_image", CTRL+TQt::Key_D, TQT_TQOBJECT(this), TQT_SLOT(slotAddToDirectoryBasket()), actionCollection(), "dirop_todirbasket");

    TDEActionMenu *file = new TDEActionMenu(i18n("File actions"), actionCollection(), "dirop_file_menu");
    TDEAction *prop = actionCollection()->action("properties");

    TDEAction *reload = actionCollection()->action("mkdir");
    if(reload && reload->shortcut().isNull()) reload->setShortcut(TDEShortcut(CTRL+TQt::Key_N));
    reload = actionCollection()->action("reload");

    connect(prop, TQT_SIGNAL(enabled(bool)), TQT_TQOBJECT(this), TQT_SLOT(slotEnableFileActions(bool)));

    TDEAction *sep = actionCollection()->action("separator");

    file->insert(new TDEAction(i18n("Copy"), "edit-copy", TDEStdAccel::copy(), SQ_WidgetStack::instance(), TQT_SLOT(slotFileCopy()), actionCollection(), "dirop_copy"));
    file->insert(new TDEAction(i18n("Cut"), "edit-cut", TDEStdAccel::cut(), SQ_WidgetStack::instance(), TQT_SLOT(slotFileCut()), actionCollection(), "dirop_cut"));
    file->insert(new TDEAction(i18n("Paste"), "edit-paste", TDEStdAccel::paste(), SQ_WidgetStack::instance(), TQT_SLOT(slotFilePaste()), actionCollection(), "dirop_paste"));
    file->insert(sep);
    file->insert(new TDEAction(i18n("Copy to..."), 0, TQt::Key_F5, SQ_WidgetStack::instance(), TQT_SLOT(slotFileCopyTo()), actionCollection(), "dirop_copyto"));
    file->insert(new TDEAction(i18n("Move to..."), 0, TQt::Key_F6, SQ_WidgetStack::instance(), TQT_SLOT(slotFileMoveTo()),actionCollection(), "dirop_cutto"));
    file->insert(new TDEAction(i18n("Link to..."), 0, TQt::Key_F7, SQ_WidgetStack::instance(), TQT_SLOT(slotFileLinkTo()), actionCollection(), "dirop_linkto"));
    file->insert(sep);
    file->insert(new TDEAction(i18n("Run"), "launch", CTRL+Key_J, SQ_WidgetStack::instance(), TQT_SLOT(slotRunSeparately()), actionCollection(), "dirop_runsepar"));
    file->insert(new TDEAction(i18n("Repeat (nothing to repeat)"), "go-down", TQt::Key_F10, TQT_TQOBJECT(KSquirrel::app()), TQT_SLOT(slotRepeat()), actionCollection(), "dirop_repeat"));
    file->insert(new TDEAction(i18n("Convert..."), 0, CTRL+TQt::Key_K, SQ_Converter::instance(), TQT_SLOT(slotStartEdit()), actionCollection(), "dirop_convert"));

    file->insert(sep);
    file->insert(new TDEAction(i18n("Recreate selected thumbnails"), "reload", CTRL+TQt::Key_R, SQ_WidgetStack::instance(),
        TQT_SLOT(slotRecreateThumbnail()), actionCollection(), "dirop_recreate_thumbnails"));
    file->insert(sep);
    file->insert(new TDEAction(i18n("Copy file path"), 0, TQt::Key_F8, TQT_TQOBJECT(this), TQT_SLOT(slotCopyPath()), actionCollection(), "dirop_copypath"));
    file->insert(new TDEAction(i18n("Copy file url"), 0, TQt::Key_F9, TQT_TQOBJECT(this), TQT_SLOT(slotCopyURL()), actionCollection(), "dirop_copyurl"));

    if(reload) reload->setShortcut(CTRL+TQt::Key_F5);
}

void SQ_DirOperator::slotEnableFileActions(bool e)
{
    actionCollection()->action("dirop_tobasket")->setEnabled(e);
    actionCollection()->action("dirop_todirbasket")->setEnabled(e);

    actionCollection()->action("dirop_copy")->setEnabled(e);
    actionCollection()->action("dirop_cut")->setEnabled(e);
    actionCollection()->action("dirop_copyto")->setEnabled(e);
    actionCollection()->action("dirop_cutto")->setEnabled(e);
    actionCollection()->action("dirop_linkto")->setEnabled(e);

    actionCollection()->action("dirop_runsepar")->setEnabled(e);
    actionCollection()->action("dirop_convert")->setEnabled(e);

    actionCollection()->action("dirop_copypath")->setEnabled(e);
    actionCollection()->action("dirop_copyurl")->setEnabled(e);

    actionCollection()->action("dirop_recreate_thumbnails")->setEnabled(type == SQ_DirOperator::TypeThumbs && e);
    SQ_ExternalTool::instance()->constPopupMenu()->setEnabled(e);

    if(SQ_HLOptions::instance()->have_categories)
        SQ_CategoriesBox::instance()->popupMenu()->setEnabled(e);
}

void SQ_DirOperator::slotCopyPath()
{
    KFileItem *f = fileview->currentFileItem();

    if(f)
        TQApplication::clipboard()->setText(f->url().path());
}

void SQ_DirOperator::slotCopyURL()
{
    KFileItem *f = fileview->currentFileItem();

    if(f)
        TQApplication::clipboard()->setText(f->url().prettyURL());
}

void SQ_DirOperator::slotEditMime()
{
    KFileItem *f = fileview->currentFileItem();

    if(f)
        KonqOperations::editMimeType(f->mimetype());
}

void SQ_DirOperator::slotAddToBasket()
{
    SQ_ImageBasket::instance()->add(*selectedItems());
}

void SQ_DirOperator::slotAddToDirectoryBasket()
{
    SQ_DirectoryBasket::instance()->add(*selectedItems());
}

void SQ_DirOperator::slotFinishedLoading()
{
    // force sort if invisible
    if(!isVisible())
    {
        // derived from KFileDetailView
        if(type ==  SQ_DirOperator::TypeDetailed)
        {
            KFileDetailView *dv = dynamic_cast<KFileDetailView *>(fileview);
            if(dv) dv->sort();
        }
        // derived from KFileIconView
        else
        {
            KFileIconView *tv = dynamic_cast<KFileIconView *>(fileview);
            if(tv) tv->sort(!tv->isReversed());
        }
    }

    int dirs = numDirs(), files = numFiles();
    int total = dirs+files;

    slotUpdateInformation(files, dirs);

    if(lasturl.equals(url(), true))
        return;
    else
    {
        lasturl = url();
        usenew = true;
    }

    // clear TQLabels in statusbar, if current directory has
    // no files/directories
    if(!total)
    {
        lasturl = KURL();
        usenew = false;
        m_pending = TQString();
        KSquirrel::app()->sbarWidget("fileIcon")->clear();
        KSquirrel::app()->sbarWidget("fileName")->clear();
        return;
    }

    // setting current file directly doesn't work. let
    // events to be processed and only then set current file
    TQTimer::singleShot(0, TQT_TQOBJECT(this), TQT_SLOT(slotDelayedFinishedLoading()));
}

void SQ_DirOperator::slotDelayedFinishedLoading()
{
    // select pending file if any
    if(!m_pending.isEmpty())
    {
        if(fileview)
        {
            fileview->clearSelection();
            fileview->setCurrentItem(m_pending);
            setCurrentItem(fileview->currentFileItem());
        }

        m_pending = TQString();
        startOrNotThumbnailUpdate();

        return;
    }

    KURL up_url = url().upURL();

    KFileItem *first = fileview->firstFileItem();

    if(!first) return;

    // ignore ".." item
    if(up_url.equals(first->url(), true))
        first = fileview->nextItem(first);

    // hell!
    if(!first) return;

    SQ_Config::instance()->setGroup("Fileview");

    bool goto_first = false;

    // SQ_WidgetStack will select first supported image for us
    if(SQ_Config::instance()->readBoolEntry("tofirst", true))
        goto_first = SQ_WidgetStack::instance()->moveTo(SQ_WidgetStack::Next, first) == SQ_WidgetStack::moveFailed;
    else
        goto_first = true;

    if(goto_first)
    {
        KFileItem *fi = fileview->currentFileItem();

        if(fi && !up_url.equals(fi->url(), true))
            setCurrentItem(fileview->currentFileItem());
        else
            setCurrentItem(first);
    }

    startOrNotThumbnailUpdate();
}

void SQ_DirOperator::slotUpdateInformation(int files, int dirs)
{
    int total = dirs + files;

    SQ_Config::instance()->setGroup("Fileview");

    TQString str = i18n("Total %1 in %2 (%3, %4)")
                    .arg(TDEIO::convertSize(totalSize))
                    .arg(i18n("1 item", "%n items", total))
                    .arg(i18n("1 folder", "%n folders", dirs))
                    .arg(i18n("1 file", "%n files", files));

    KSquirrel::app()->sbarWidget("dirInfo")->setText(str);
}

/*
 *  Deselect all items, set current item, select this item,
 *  and ensure it visible.
 */
void SQ_DirOperator::setCurrentItem(KFileItem *item)
{
    // for safety...
    if(!item)
        return;

    // clear selection
    fileview->clearSelection();

    // set current item and select it
    fileview->setCurrentItem(item);
    fileview->setSelected(item, true);

    // make this item visible
    fileview->ensureItemVisible(item);
}

/*
 *  Change thumbnail size. KSquirrel will emit thumbSizeChanged() signal, and
 *  diroperator will catch it. Only diroperator, which manages SQ_FileThumbView
 *  won't ignore this signal. See also SQ_WidgetStack::raiseWidget().
 */
void SQ_DirOperator::slotSetThumbSize(const TQString &size)
{
    // for safety...
    if(type != SQ_DirOperator::TypeThumbs)
        return;

    SQ_FileThumbView *tv = dynamic_cast<SQ_FileThumbView *>(fileview);

    SQ_ThumbnailSize::instance()->setPixelSize(size);

    tv->rebuildCachedPixmaps();

    // reinsert files
    removeCdUpItem();
    smartUpdate();

    // finally, update thumbnails
    startOrNotThumbnailUpdate();
}

/*
 *  Smart update. Store all file items, reset view,
 *  and transfer all items back.
 *
 *  Taken from tdelibs-3.2.3/tdeio/tdefile/tdediroperator.cpp
 */
void SQ_DirOperator::smartUpdate()
{
    // store old file items
    KFileItemList items = *fileview->items();
    oldSelected = *fileview->selectedItems();
    oldCurrentItem = fileview->currentFileItem();

    // heh, 'items' now contains "..", we should remove it!
    removeCdUpItem();

    // clear view and add items (see SQ_FileThumbView::insertItem() for more)
    fileview->clear();

    if(type == SQ_DirOperator::TypeThumbs)
    {
        SQ_Config::instance()->setGroup("Thumbnails");

        int newgrid = SQ_ThumbnailSize::instance()->extended() ?
                        SQ_ThumbnailSize::instance()->extendedSize().width()
                        : SQ_ThumbnailSize::instance()->pixelSize();

        newgrid += (SQ_Config::instance()->readNumEntry("margin", 2) + 2);

        SQ_FileThumbView *tv = dynamic_cast<SQ_FileThumbView *>(fileview);

        tv->setGridX(newgrid);
        tv->arrangeItemsInGrid();
    }

    fileview->addItemList(items);

    selectOld();
}

void SQ_DirOperator::selectOld()
{
    // set current item...
    fileview->setCurrentItem(oldCurrentItem);

    // restore selection
    KFileItemListIterator it(oldSelected);

    fileview->ensureItemVisible(it.current());

    for(; it.current();++it)
        fileview->setSelected(it.current(), true);

    oldSelected.clear();

    stopPreview();
}

/*
 *  Remove ".." from currently listed items
 */
void SQ_DirOperator::removeCdUpItem()
{
    // for safety...
    if(!fileview)
        return;

    KFileItemList m_items = *fileview->items();
    KFileItemListIterator it_s(m_items);
    KURL up_url = url().upURL();

    for(; it_s.current();++it_s)
    {
        if(it_s.current()->url() == up_url)
        {
            fileview->removeItem(it_s.current());
            break;
        }
    }
}

void SQ_DirOperator::startOrNotThumbnailUpdate()
{
    // start delayed thumbnail update, if needed
    if(type == SQ_DirOperator::TypeThumbs)
    {
        SQ_FileThumbView *tv = dynamic_cast<SQ_FileThumbView *>(fileview);

        // start thumbnail update only when this
        // diroperator is visible
        if(tv)
        {
            if(tv->isVisible())
                tv->startThumbnailUpdate();
            else
                tv->waitForShowEvent();
        }
    }
}

void SQ_DirOperator::clearListers()
{
    SQ_Listers::iterator itEnd = listers.end();

    // delete all listers
    for(SQ_Listers::iterator it = listers.begin();it != itEnd;++it)
        delete it.data();

    listers.clear();
}

void SQ_DirOperator::urlAdded(const KURL &_url)
{
    // avoid duplications
    if(listers.contains(_url) || _url.equals(url(), true))
        return;

    KDirLister *lister = new KDirLister(true);

    lister->setMainWindow(dirLister()->mainWindow());

    // redirect all signals to dirLister() - nice hack
    connect(lister, TQT_SIGNAL(refreshItems(const KFileItemList &)), dirLister(), TQT_SIGNAL(refreshItems(const KFileItemList &)));
    connect(lister, TQT_SIGNAL(deleteItem(KFileItem *)), dirLister(), TQT_SIGNAL(deleteItem(KFileItem *)));
    connect(lister, TQT_SIGNAL(newItems(const KFileItemList &)), dirLister(), TQT_SIGNAL(newItems(const KFileItemList &)));

    connect(lister, TQT_SIGNAL(started(const KURL &)), dirLister(), TQT_SIGNAL(started(const KURL &)));
    connect(lister, TQT_SIGNAL(completed()), dirLister(), TQT_SIGNAL(completed()));
    connect(lister, TQT_SIGNAL(canceled()), dirLister(), TQT_SIGNAL(canceled()));

    // save this lister for us
    listers[_url] = lister;

    lister->openURL(_url);
}

void SQ_DirOperator::urlRemoved(const KURL &url)
{
    // for safety
    SQ_Listers::iterator it = listers.find(url);

    if(it == listers.end())
        return;

    KDirLister *lister = it.data();

    KFileItemList list = lister->items();

    // start delayed thumbnail update, if needed
    if(type == SQ_DirOperator::TypeThumbs)
    {
        SQ_FileThumbView *tv = dynamic_cast<SQ_FileThumbView *>(fileview);

        if(tv && tv->updateRunning())
            tv->itemsRemoved(list);
    }

    SQ_Config::instance()->setGroup("Fileview");
    bool c = SQ_Config::instance()->readBoolEntry("calculate", true);

    for(KFileItem *itit_tvoyu_mats = list.first();itit_tvoyu_mats;itit_tvoyu_mats = list.next())
    {
        itemDeleted(itit_tvoyu_mats);

        if(c) totalSize -= itit_tvoyu_mats->size();
    }

    slotUpdateInformation(numFiles(), numDirs());

    // remove this lister from map
    listers.remove(url);

    delete lister;

    // update view
    KFileIconView *vi = dynamic_cast<KFileIconView *>(fileview);

    if(vi)
       vi->arrangeItemsInGrid();
}

void SQ_DirOperator::executePrivate(KFileItem *fi)
{
    KURL url = fi->url();
    TQString fullpath = url.path();
    TQFileInfo fm(fullpath);

    // Ok, this file is image file. Let's try to load it
    if(SQ_LibraryHandler::instance()->libraryForFile(fullpath))
        SQ_GLWidget::window()->startDecoding(fullpath);
    else
    {
        SQ_Config::instance()->setGroup("Fileview");

        // archive ?
        if(!SQ_ArchiveHandler::instance()->findProtocolByFile(fi).isEmpty())
            if(SQ_Config::instance()->readBoolEntry("archives", true))
                SQ_ArchiveHandler::instance()->tryUnpack(fi);
            else;
        // not image, not archive. Read settings and run this file separately
        // with default application (if needed).
        else if(SQ_Config::instance()->readBoolEntry("run unknown", false))
            emit runSeparately(fi);
    }
}

void SQ_DirOperator::disableSpecificActions(KFileIconView *v)
{
    TDEAction *a;

    a = v->actionCollection()->action("zoomIn");
    if(a) a->setEnabled(false);

    a = v->actionCollection()->action("zoomOut");
    if(a) a->setEnabled(false);

    a = v->actionCollection()->action("show previews");
    if(a) a->setEnabled(false);
}

void SQ_DirOperator::slotPreview()
{
    KFileItem *fi = fileview ? fileview->currentFileItem() : 0;

    if(fi) SQ_PreviewWidget::instance()->load(fi->url());
}

void SQ_DirOperator::slotNewItems(const KFileItemList &list)
{
    SQ_Config::instance()->setGroup("Fileview");

    if(SQ_Config::instance()->readBoolEntry("calculate", true))
    {
        KFileItemListIterator it(list);
        KFileItem *fi;

        while((fi = it.current()) != 0)
        {
            ++it;
            if(fi->isFile()) totalSize += fi->size();
        }
    }

    // start delayed thumbnail update, if needed
    if(type == SQ_DirOperator::TypeThumbs && usenew)
    {
        SQ_FileThumbView *tv = dynamic_cast<SQ_FileThumbView *>(fileview);

        if(tv)
            tv->addItemsToJob(list);
    }
}

void SQ_DirOperator::slotRefreshItems(const KFileItemList &list)
{
    KFileItemListIterator it(list);
    KFileItem *fci = fileview ? fileview->currentFileItem() : 0;
    KFileItem *fi;

    // refresh image been previewed
    while((fi = it.current()))
    {
        if(fi == fci)
        {
            timer_preview->start(SQ_PreviewWidget::instance()->delay(), true);
            break;
        }

        ++it;
    }

    // start delayed thumbnail update, if needed
    if(type == SQ_DirOperator::TypeThumbs)
    {
        SQ_FileThumbView *tv = dynamic_cast<SQ_FileThumbView *>(fileview);

        if(tv)
        {
            KFileItemListIterator it(list);
            SQ_FileThumbViewItem *tfi;

            if(tv->updateRunning())
                tv->itemsRemoved(list);

            while((fi = it.current()))
            {
                // force thumbnail to be updated by setting listed = false
                tfi = reinterpret_cast<SQ_FileThumbViewItem *>(fi->extraData(tv));

                if(tfi)
                    tfi->setListed(false);

                // remove thumbnail from pixmap cache and from disk
                SQ_PixmapCache::instance()->removeEntryFull(fi->url().path());
                ++it;
            }

            tv->addItemsToJob(list, false);
        }
    }
}

/*
 *  Invoked, when some item has been deleted. We should
 *  remove appropriate thumbnail from pixmap cache.
 */
void SQ_DirOperator::slotItemDeleted(KFileItem *item)
{
    if(!item) return;

    itemKill(item);

    // remove thumbnail from cache,
    SQ_PixmapCache::instance()->removeEntryFull(item->url());
}

void SQ_DirOperator::itemKill(KFileItem *item)
{
    if(!item) return;

    SQ_Config::instance()->setGroup("Fileview");
    if(SQ_Config::instance()->readBoolEntry("calculate", true))
        totalSize -= item->size();

    slotUpdateInformation(numFiles(), numDirs());

    // start delayed thumbnail update, if needed
    if(type == SQ_DirOperator::TypeThumbs)
    {
        SQ_FileThumbView *tv = dynamic_cast<SQ_FileThumbView *>(fileview);

        if(tv && tv->updateRunning())
            tv->itemRemoved(item);
    }
}

void SQ_DirOperator::stopPreview()
{
    timer_preview->stop();
}

void SQ_DirOperator::activatedMenu(const KFileItem *, const TQPoint &pos)
{
    // remove "View" submenu, since we will insert our's one.
    setupMenu(KDirOperator::AllActions ^ KDirOperator::ViewActions);
    updateSelectionDependentActions();

    TDEActionMenu *pADirOperatorMenu = dynamic_cast<TDEActionMenu *>(actionCollection()->action("popupMenu"));

    pADirOperatorMenu->insert(actionCollection()->action("dirop_edit_mime"));
    pADirOperatorMenu->insert(actionCollection()->action("separator"));

    if(SQ_HLOptions::instance()->have_categories)
        pADirOperatorMenu->popupMenu()->insertItem(i18n("Add to &Category"), SQ_CategoriesBox::instance()->popupMenu());

    if(SQ_HLOptions::instance()->have_imagebasket)
        pADirOperatorMenu->insert(actionCollection()->action("dirop_tobasket"));

    if(SQ_HLOptions::instance()->have_directorybasket)
        pADirOperatorMenu->insert(actionCollection()->action("dirop_todirbasket"));

    pADirOperatorMenu->popupMenu()->insertItem(i18n("File actions"), dynamic_cast<TDEActionMenu *>(actionCollection()->action("dirop_file_menu"))->popupMenu(), -1, 0);
    pADirOperatorMenu->popupMenu()->insertItem(i18n("&External tools"), SQ_ExternalTool::instance()->constPopupMenu(), -1, 1);
    pADirOperatorMenu->popupMenu()->insertSeparator(2);

    KFileItemList *items = const_cast<KFileItemList *>(selectedItems());

    if(items)
        SQ_ExternalTool::instance()->setItems(*items);

    pADirOperatorMenu->popup(pos);
}

void SQ_DirOperator::slotSetURL(const KURL &url)
{
    setURL(url, true);
}

void SQ_DirOperator::calcTotalSize()
{
    totalSize = static_cast<TDEIO::filesize_t>(0);

    KFileItemList *list = const_cast<KFileItemList *>(fileview->items());

    if(!list) return;

    KFileItemListIterator it(*list);
    KFileItem *fi;

    while((fi = it.current()) != 0)
    {
        ++it;

        if(fi->isFile())
            totalSize += fi->size();
    }

    slotUpdateInformation(numFiles(), numDirs());
}

void SQ_DirOperator::saveConfig()
{
    TQDir::SortSpec sort = sorting();

    SQ_Config::instance()->writeEntry("sorting_name", KFile::isSortByName(sort));
    SQ_Config::instance()->writeEntry("sorting_time", KFile::isSortByDate(sort));
    SQ_Config::instance()->writeEntry("sorting_size", KFile::isSortBySize(sort));
    SQ_Config::instance()->writeEntry("sorting_dirs", KFile::isSortDirsFirst(sort));
    SQ_Config::instance()->writeEntry("sorting_reverse", (sort & TQDir::Reversed) == TQDir::Reversed);
    SQ_Config::instance()->writeEntry("sorting_ignore", KFile::isSortCaseInsensitive(sort));

    SQ_Config::instance()->writeEntry("show hidden", showHiddenFiles());
}

void SQ_DirOperator::setLazy(bool l, int delay, int rows)
{
    if(type == SQ_DirOperator::TypeThumbs)
    {
        SQ_FileThumbView *tv = dynamic_cast<SQ_FileThumbView *>(fileview);

        if(tv)
        {
            if(tv->lazy() != l)
                tv->setLazy(l, delay);

            tv->setAddRows(rows);

            if(tv->updateRunning())
                tv->startThumbnailUpdate();
        }
    }
}

void SQ_DirOperator::slotInvokeBrowser()
{
    kapp->invokeBrowser(url().prettyURL());
}

void SQ_DirOperator::enableThumbnailActions(bool enable)
{
    actionCollection()->action("dirop_recreate_thumbnails")->setEnabled(enable);
}

void SQ_DirOperator::stopThumbnailUpdate()
{
    if(type == SQ_DirOperator::TypeThumbs)
    {
        SQ_FileThumbView *tv = dynamic_cast<SQ_FileThumbView *>(fileview);

        if(tv && tv->updateRunning())
            tv->stopThumbnailUpdate();
    }
}

void SQ_DirOperator::slotDownloadPercents(int p)
{
    SQ_GLWidget::window()->setDownloadPercents(p);
}

#include "sq_diroperator.moc"
