/***************************************************************************
                          ksquirrel.cpp  -  description
                             -------------------
    begin                : Dec 10 2003
    copyright            : (C) 2003 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 <tqapplication.h>
#include <tqeventloop.h>
#include <tqpixmap.h>
#include <tqcolor.h>
#include <tqlabel.h>
#include <tqvbox.h>
#include <tqvaluevector.h>
#include <tqvaluelist.h>
#include <tqcursor.h>
#include <tqpainter.h>
#include <tqfile.h>
#include <tqtoolbutton.h>
#include <tqfileinfo.h>
#include <tqtimer.h>
#include <tqstylesheet.h>
#include <tqwidgetstack.h>

#include <tdeapplication.h>
#include <khelpmenu.h>
#include <tdepopupmenu.h>
#include <twin.h>
#include <kstatusbar.h>
#include <tdemenubar.h>
#include <tdetoolbar.h>
#include <tdeaction.h>
#include <kbookmarkmanager.h>
#include <kbookmarkmenu.h>
#include <kstandarddirs.h>
#include <kcombobox.h>
#include <kstdaction.h>
#include <tdelocale.h>
#include <kdebug.h>
#include <tdemessagebox.h>
#include <tdefiledialog.h>
#include <krun.h>
#include <kanimwidget.h>
#include <tdeglobalsettings.h>
#include <tdeactioncollection.h>
#include <tdemultitabbar.h>
#include <kurlcompletion.h>
#include <konq_pixmapprovider.h>
#include <tdeio/job.h>
#include <tdeio/netaccess.h>
#include <kinputdialog.h>
#include <ksystemtray.h>
#include <ksqueezedtextlabel.h>
#include <ktabbar.h>
#include <kprocess.h>

#include "ksquirrel.h"
#include "sq_iconloader.h"
#include "sq_widgetstack.h"
#include "sq_treeview.h"
#include "sq_options.h"
#include "sq_glview.h"
#include "sq_glwidget.h"
#include "sq_libraryhandler.h"
#include "sq_externaltool.h"
#include "sq_externaltools.h"
#include "sq_config.h"
#include "sq_filters.h"
#include "sq_bookmarkowner.h"
#include "sq_hloptions.h"
#include "sq_pixmapcache.h"
#include "sq_thumbnailsize.h"
#include "sq_pixmapcache.h"
#include "sq_archivehandler.h"
#include "sq_dir.h"
#include "sq_dirthumbs.h"
#include "sq_thumbnailloadjob.h"
#include "sq_navigatordropmenu.h"
#include "sq_errorstring.h"
#include "sq_thumbnailcachemaster.h"
#include "sq_glwidget_helpers.h"
#include "sq_pluginsinfo.h"
#include "sq_imageloader.h"
#include "sq_multibar.h"
#include "sq_glinfo.h"
#include "sq_splashscreen.h"
#include "sq_previewwidget.h"
#include "sq_progress.h"
#include "sq_thumbnailsunused.h"
#include "sq_downloader.h"
#include "sq_dragprovider.h"

#include "sq_slideshow.h"
#include "sq_slideshowwidget.h"
#include "sq_slideshowlisting.h"
#include "sq_categoriesview.h"
#include "sq_mountview.h"
#include "sq_imagebasket.h"
#include "sq_directorybasket.h"
#include "sq_converter.h"

#ifdef SQ_HAVE_KIPI
#include "sq_kipimanager.h"
#endif

#include <cstdlib>
#include <iostream>

static const int menuParam = 100000;

KSquirrel * KSquirrel::m_instance = 0;

KSquirrel::KSquirrel(TQWidget *parent, const char *name) 
    : TDEMainWindow (parent, name), DCOPObject(name)
{
    // singleton setup
    m_instance = this;

    kdDebug() << "+KSquirrel" << endl;

    slideShowStop = true;
    slideShowPaused = false;
    m_intray = false;
    waitForShow = true;
    m_demo = false;

    writeDefaultEntries();

    // create TDEConfig instance.
    // It will help us to read and write config entries
    tdeconf = new SQ_Config(this);

    old_id = 0;

    tdeconf->setGroup("Thumbnails");

    thumbSize = new SQ_ThumbnailSize(this, static_cast<SQ_ThumbnailSize::Size>(tdeconf->readNumEntry("size",
                            SQ_ThumbnailSize::Large)));
    thumbSize->setExtended(tdeconf->readBoolEntry("extended", false));

    sqFiltersName = 0;
    pCurrentURL = 0;
    mainPage = 0;

    SQ_SplashScreen::advance();

    fillMessages();

    preCreate();
}

KSquirrel::~KSquirrel()
{
    kdDebug() << "-KSquirrel" << endl;

    delete sqFiltersExt;
    delete sqFiltersName;
    delete gl_view;
    delete tdeconf;
}

/*
 *  Restore saved position & size
 */
void KSquirrel::handlePositionSize()
{
    TQPoint p_def(0,0);
    TQSize  sz_def(800, 600);

    tdeconf->setGroup("Interface");

    TQPoint p = SQ_Config::instance()->readPointEntry("pos", &p_def);
    TQSize sz = SQ_Config::instance()->readSizeEntry("size", &sz_def);

    resize(sz);
    move(p);
}

/*
 *  Invoke 'Options' dialog.
 */
void KSquirrel::slotOptions()
{
    // create dialog
    SQ_Options optd(this, "sq_options", true);

    tdeconf->setGroup("Fileview");
    old_disable = tdeconf->readBoolEntry("disable_dirs", false);
    old_calc = tdeconf->readBoolEntry("calculate", true);

    tdeconf->setGroup("Thumbnails");

    tdeconf->setGroup("GL view");
    old_marks = tdeconf->readBoolEntry("marks", true);

    // if user clicked "OK", apply new settings
    if(optd.start() == TQDialog::Accepted)
    {
        applyDefaultSettings();

        if(SQ_HLOptions::instance()->have_mountview)
            SQ_MountView::instance()->setupColumns();

        SQ_TreeView::instance()->setupRecursion();
        SQ_PreviewWidget::instance()->rereadColor();
        SQ_PreviewWidget::instance()->update();
        emit resetToolTip();

        // create or delete animated logo
        configAnime(false);
    }
}

bool KSquirrel::eventFilter(TQObject *o, TQEvent *e)
{
    if(o == mainPage && e->type() == TQEvent::Show)
    {
        // delayed init, hehe...
        if(waitForShow)
        {
            kdDebug() << "Creating additional widgets..." << endl;

            tdeconf->setGroup("Thumbnails");
            SQ_PixmapCache::instance()->setCacheLimit(tdeconf->readNumEntry("cache", 1024*10));

#ifdef SQ_HAVE_KIPI
            tdeconf->setGroup("Main");

            // load KIPI plugins on demand ?
            if(!tdeconf->readBoolEntry("kipi_ondemand", true))
                kipiManager->loadPlugins();
#endif

            if(SQ_HLOptions::instance()->have_mountview)
            {
                sideBar->addWidget(new SQ_MountView, i18n("Mount points"), "blockdevice");
                connect(SQ_MountView::instance(), TQ_SIGNAL(path(const TQString &)), pWidgetStack, TQ_SLOT(setURLForCurrent(const TQString &)));
            }

            if(SQ_HLOptions::instance()->have_categories)
                sideBar->addWidget(new SQ_CategoriesBox, i18n("Categories"), "bookmark");

            if(SQ_HLOptions::instance()->have_imagebasket)
                sideBar->addWidget(new SQ_ImageBasket, i18n("Image basket"), "folder_image");

            if(SQ_HLOptions::instance()->have_directorybasket)
                sideBar->addWidget(new SQ_DirectoryBasket, i18n("Folder basket"), "folder");

            tdeconf->setGroup("Interface");

            // restore opened page in sidebar
            int pg = tdeconf->readNumEntry("last page", -1);

            TQPushButton *b = sideBar->multiBar()->tab(pg);

            if(pg >= 0 && !b)
            {
                pg = 0;
                b = sideBar->multiBar()->tab(0);
                tdeconf->writeEntry("last page", 0);
            }

            if(pg >= 0 && b)
                b->animateClick();

            waitForShow = false;
        }
    }

    return false;
}

/*
 *  Catches close events.
 */
void KSquirrel::closeEvent(TQCloseEvent *ev)
{
    tdeconf->setGroup("Main");

    if((m_demo && !m_intray) || kapp->sessionSaving())
    {
        // finalActions() called by slotSaveYourself()
        if(!kapp->sessionSaving())
            finalActions();

        ev->accept();
    }
    else
    {
        // Minimize to tray ?
        if(tdeconf->readBoolEntry("minimize to tray", false) || m_intray)
        {
            // Yes, let's hide to tray
            slotGotoTray();
            // ignore close event
            ev->ignore();
        }
        else // No, close app
        {
            // do final stuff
            finalActions();
            // accept close event - exit
            ev->accept();
        }
    }
}

// Show List view
void KSquirrel::slotRaiseListView()
{
    pWidgetStack->raiseWidget(SQ_DirOperator::TypeList);
}

// Show icon view
void KSquirrel::slotRaiseIconView()
{
    pWidgetStack->raiseWidget(SQ_DirOperator::TypeIcons);
}

// Show Detailed view
void KSquirrel::slotRaiseDetailView()
{
    pWidgetStack->raiseWidget(SQ_DirOperator::TypeDetailed);
}

// Show Thumbnail view
void KSquirrel::slotRaiseThumbView()
{
    pWidgetStack->raiseWidget(SQ_DirOperator::TypeThumbs);
}

// Create location toolbar
void KSquirrel::createLocationToolbar(TDEToolBar *pTLocation)
{
    // create new KHistoryCombo
    pCurrentURL = new KHistoryCombo(true, pTLocation, "history combobox");

    // some additional setup
    pTLocation->setFullSize();
    pTLocation->insertButton("button_cancel", 0, TQ_SIGNAL(clicked()), pCurrentURL, TQ_SLOT(clearHistory()), true, i18n("Clear history"));
    pTLocation->insertButton("locationbar_erase", 1, TQ_SIGNAL(clicked()), pCurrentURL, TQ_SLOT(clearEdit()), true, i18n("Clear address"));
    pTLocation->insertWidget(2, 10, new TQLabel("URL:", pTLocation, "tde toolbar widget"));
    pTLocation->setItemAutoSized(2);
    pTLocation->insertWidget(3, 10, pCurrentURL);
    pTLocation->setItemAutoSized(3);
    pTLocation->insertButton("goto", 4, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotGo()), true, i18n("Go!"));

    tdeconf->setGroup("History");

    // some additional setup

    pCurrentURL->setPixmapProvider(KonqPixmapProvider::self());
    pCurrentURL->setCompletionObject(new KURLCompletion(KURLCompletion::DirCompletion));
    pCurrentURL->setDuplicatesEnabled(false);
    pCurrentURL->setSizeLimit(20);
    pCurrentURL->setHistoryItems(tdeconf->readListEntry("items"), true);
}

// Create menu with filters
void KSquirrel::initFilterMenu()
{
    TQString ext, tmp;
    unsigned int i = menuParam;

    TQString last;

    tdeconf->setGroup("Filters");

    // create TQStringLists with names and extensions
    // of custom filters
    if(!sqFiltersName)
    {
        sqFiltersName = new TQStringList(tdeconf->readListEntry("items"));
        sqFiltersExt = new TQStringList(tdeconf->readListEntry("extensions"));

        // last used filter
        last = tdeconf->readEntry("last", "*");

        // allow user to check/uncheck menuitems
        actionFilterMenu->setCheckable(true);
    }
    else // if TQStringLists already exist
        last = pWidgetStack->nameFilter();

    actionFilterMenu->clear();
    int id, Id = old_id;
    bool both = tdeconf->readBoolEntry("menuitem both", true);
    TQStringList quickInfo;

    // Get extensions and names of libraries' filters
    libhandler->allFilters(libFilters, quickInfo);

    actionFilterMenu->insertTitle(i18n("Libraries' filters"));

    // insert libraries' filters to menu
    for(TQValueList<TQString>::iterator it = libFilters.begin(), it1 = quickInfo.begin();
                it != libFilters.end();++it, ++it1)
    {
        // show both name and extension ?
        if(both)
            id = actionFilterMenu->insertItem(*it1 + " (" + *it + ')');
        else
            id = actionFilterMenu->insertItem(*it1);

        actionFilterMenu->setItemParameter(id, i++);

        if(last == *it && !last.isEmpty())
            Id = id;
    }

    // all filters' extension in one string
    TQString allF = libhandler->allFiltersString();

    libFilters.append(allF);

    id = actionFilterMenu->insertItem(i18n("All supported formats"));
    actionFilterMenu->setItemParameter(id, i++);

    if(last == allF && !last.isEmpty())
        Id = id;

    TQValueList<TQString>::iterator nEND = sqFiltersName->end();
    TQValueList<TQString>::iterator it_name = sqFiltersName->begin();
    TQValueList<TQString>::iterator it_ext = sqFiltersExt->begin();

    actionFilterMenu->insertTitle(i18n("User's filters"));
    i = 0;
//    actionFilterMenu->setItemParameter(id, i++);

    // add custom filters
    for(;it_name != nEND;it_name++,it_ext++)
    {
        if(both)
            id = actionFilterMenu->insertItem(*it_name + "  (" + *it_ext + ')');
        else
            id = actionFilterMenu->insertItem(*it_name);

        if(last == *it_ext && !last.isEmpty())
            Id = id;

        actionFilterMenu->setItemParameter(id, i++);
    }

    disconnect(actionFilterMenu, TQ_SIGNAL(activated(int)), 0, 0);
    connect(actionFilterMenu, TQ_SIGNAL(activated(int)), this, TQ_SLOT(slotSetFilter(int)));

    // finally, set current filter
    setFilter(last, Id);
}

// "Go" clicked in url box
void KSquirrel::slotGo()
{
    pWidgetStack->setURLForCurrent(pCurrentURL->currentText());
}

// Set filter for a filemanager and check appropriate
// menuitem (by 'id')
void KSquirrel::setFilter(const TQString &f, const int id)
{
    if(pWidgetStack->nameFilter() != f)
        pWidgetStack->setNameFilter(f);

//    actionFilterMenu->setItemChecked(old_id, false);
    actionFilterMenu->setItemChecked(id, true);
    old_id = id;
}

// User seleced some filter from menu
void KSquirrel::slotSetFilter(int id)
{
    // uncheck old item being checked
    actionFilterMenu->setItemChecked(old_id, false);

    // new item's index
    int index = actionFilterMenu->itemParameter(id);

    TQString filt;

    // Is it libraries' filter or custom ?
    if(index >= menuParam)
        filt = libFilters[index - menuParam];
    else
        filt = (*sqFiltersExt)[index];

    // If new filter differences from current -
    // let's apply it
    if(pWidgetStack->nameFilter() != filt)
        pWidgetStack->setNameFilter(filt);

    // finally, check new item
    actionFilterMenu->setItemChecked(id, true);
    old_id = id;
}

// Create all widgets (toolbar, menubar, image window ...)
void KSquirrel::createWidgets(int createFirst)
{
    // check if location toolbar should be separated
    m_urlbox = tdeconf->readBoolEntry("has_url", false);

    // main TQVBox
    mainPage = new TQVBox(this, "SQ_BROWSER_VBOX");
    mainPage->resize(size());

    SQ_SplashScreen::advance();

    mainPage->installEventFilter(this);

    // menubar & toolbar
    menubar = new KMenuBar(mainPage);
    tools = new TDEToolBar(mainPage);

    // location toolbar
    pTLocation = new TDEToolBar(mainPage, "Location toolbar");
    pTLocation->setSizePolicy(TQSizePolicy::Fixed, TQSizePolicy::Minimum);

    // main splitter
    mainView = new TQSplitter(TQt::Horizontal, mainPage); Q_ASSERT(mainView);

    KStatusBar *s = new KStatusBar(mainPage);

    createLocationToolbar(pTLocation);
    createStatusBar(s);

    new SQ_NavigatorDropMenu(this);

    sideBar = new SQ_MultiBar(mainView);

    SQ_SplashScreen::advance();

    // create widgetstack containing views
    pWidgetStack = new SQ_WidgetStack(mainView, createFirst);

    tdeconf->setGroup("Interface");
    TQValueList<int> sz = SQ_Config::instance()->readIntListEntry("splitter");

    if(sz.count() != 2)
    {
        sz.clear();
        sz.append(1500);
        sz.append(3500);
    }

    mainView->setSizes(sz);

    SQ_SplashScreen::advance();

    ptree = new SQ_TreeView;

    SQ_SplashScreen::advance();

    sideBar->addWidget(ptree, i18n("Folder tree"), "view_tree");
    sideBar->updateLayout();

    connect(ptree, TQ_SIGNAL(urlAdded(const KURL &)), pWidgetStack->diroperator(), TQ_SLOT(urlAdded(const KURL &)));
    connect(ptree, TQ_SIGNAL(urlRemoved(const KURL &)), pWidgetStack->diroperator(), TQ_SLOT(urlRemoved(const KURL &)));
    connect(pWidgetStack->diroperator(), TQ_SIGNAL(urlEntered(const KURL &)), ptree, TQ_SLOT(slotClearChecked()));
    connect(pWidgetStack, TQ_SIGNAL(newLastURL(const TQString &)), pWidgetStack->action("dirop_repeat"), TQ_SLOT(setText(const TQString &)));
    connect(SQ_PreviewWidget::instance(), TQ_SIGNAL(first()), pWidgetStack, TQ_SLOT(slotSelectFirstFile()));
    connect(SQ_PreviewWidget::instance(), TQ_SIGNAL(last()), pWidgetStack, TQ_SLOT(slotSelectLastFile()));
    connect(SQ_PreviewWidget::instance(), TQ_SIGNAL(next()), this, TQ_SLOT(slotPreviewWidgetNext()));
    connect(SQ_PreviewWidget::instance(), TQ_SIGNAL(previous()), this, TQ_SLOT(slotPreviewWidgetPrevious()));
    connect(SQ_PreviewWidget::instance(), TQ_SIGNAL(execute()), this, TQ_SLOT(slotPreviewWidgetExecute()));

    pWidgetStack->init();

    pTLocation->setShown(m_urlbox);
    pAURL->setChecked(m_urlbox);
    mainPage->setStretchFactor(mainView, 1);

    // connect signals from location toolbar
    connect(pCurrentURL, TQ_SIGNAL(returnPressed(const TQString&)), pWidgetStack, TQ_SLOT(setURLForCurrent(const TQString&)));
    connect(pCurrentURL, TQ_SIGNAL(activated(const TQString&)), pWidgetStack, TQ_SLOT(setURLForCurrent(const TQString&)));

    gl_view = new SQ_GLView;

    SQ_SplashScreen::advance();

// KIPI support
#ifdef SQ_HAVE_KIPI
    kipiManager = new SQ_KIPIManager(this);
#endif

    // insert actions in toolbar and menu
    createToolbar(tools);
    createMenu(menubar);

    switch(createFirst)
    {
        case 1: pARaiseIconView->setChecked(true); break;
        case 2: pARaiseDetailView->setChecked(true); break;
        case 3: pARaiseThumbView->setChecked(true); break;

        default:
            pARaiseListView->setChecked(true);
    }

    // connect signals from widgets
    connect(pAURL, TQ_SIGNAL(toggled(bool)), pTLocation, TQ_SLOT(setShown(bool)));
    connect(pASelectGroup, TQ_SIGNAL(activated()), pWidgetStack, TQ_SLOT(slotSelectGroup()));
    connect(pADeselectGroup, TQ_SIGNAL(activated()), pWidgetStack, TQ_SLOT(slotDeselectGroup()));
    connect(pASelectAll, TQ_SIGNAL(activated()), pWidgetStack, TQ_SLOT(slotSelectAll()));
    connect(pADeselectAll, TQ_SIGNAL(activated()), pWidgetStack, TQ_SLOT(slotDeselectAll()));

    SQ_SplashScreen::advance();

#if 0
    KWin::setState(gl_view->winId(), NET::SkipTaskbar | NET::SkipPager);
#endif
}

// Create statusbar and all needed TQLabels
void KSquirrel::createStatusBar(KStatusBar *bar)
{
    sbar = bar;
    sbar->setSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Fixed);
    sbar->setSizeGripEnabled(true);
    sbar->show();

    // directory information (for example "3 dirs, 12 files")
    dirInfo = new TQLabel(TQString(), sbar, "dirInfo");

    TQHBox *vb = new TQHBox(sbar);

    // mime icon of current file
    fileIcon = new TQLabel(TQString(), vb, "fileIcon");
    fileIcon->setScaledContents(false);

    // name of current file
    fileName = new KSqueezedTextLabel(TQString::fromLatin1("----"), vb, "fileName");
    fileName->setTextFormat(TQt::RichText);
    fileName->setAlignment(TQt::AlignAuto | TQt::AlignVCenter | TQt::ExpandTabs);

    diskSpace = new TQLabel(TQString(), sbar, "diskSpace");

    // insert pointers to map, now it is possible
    // to call KSquirrel::sbarWidget(name)
    sbarwidgets["dirInfo"] = dirInfo;
    sbarwidgets["fileIcon"] = fileIcon;
    sbarwidgets["fileName"] = fileName;
    sbarwidgets["diskSpace"] = diskSpace;

    // finally, add TQLabels to statusbar
    sbar->addWidget(dirInfo, 0, true);
    sbar->addWidget(vb, 1, true);

    TQToolButton *fireDisk = new TQToolButton(sbar, "reload disk size");
    fireDisk->setIconSet(SQ_IconLoader::instance()->loadIcon("reload", TDEIcon::Desktop, TDEIcon::SizeSmall));
    fireDisk->setTextLabel(i18n("Reload"));
    fireDisk->setUsesTextLabel(false);
    connect(fireDisk, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotFireDisk()));

    diskProg = new SQ_Progress(sbar, "SQ_Progress [disk space]");
    diskProg->setFixedWidth(150);

    sbar->addWidget(fireDisk, 0, true);
    sbar->addWidget(diskSpace, 0, true);
    sbar->addWidget(diskProg, 0, true);
}

void KSquirrel::slotFireDisk()
{
    pWidgetStack->diroperator()->fireDiskSize(pWidgetStack->diroperator()->url());
}

// Create menu
void KSquirrel::createMenu(KMenuBar *menubar)
{
    pop_file = new TDEPopupMenu(menubar);
    pop_view = new TDEPopupMenu(menubar);
    pop_action = new TDEPopupMenu(menubar);
    pop_nav = new TDEPopupMenu(menubar);

    // create bookmarks and filters
    initBookmarks();
    initFilterMenu();

    // inset new submenus
    menubar->insertItem(i18n("&File"), pop_file);
    menubar->insertItem(i18n("&View"), pop_view);
    menubar->insertItem(i18n("&Navigator"), pop_nav);
    menubar->insertItem(i18n("&Action"), pop_action);

#ifdef SQ_HAVE_KIPI
    menubar->insertItem(i18n("&KIPI Plugins"), kipiManager->popup());
#endif

    bookmarks->plug(menubar);
    menubar->insertItem(i18n("&Help"), helpMenu());

    // plug actions to menus
    pAOpen->plug(pop_file);
    pAOpenAndSet->plug(pop_file);
    pop_file->insertSeparator();
    pARename->plug(pop_file);
    pWidgetStack->action("properties")->plug(pop_file);
    pWidgetStack->action("delete")->plug(pop_file);
    pop_file->insertSeparator();
    pAExit->plug(pop_file);

    pWidgetStack->action("home")->plug(pop_nav);
    pWidgetStack->action("up")->plug(pop_nav);
    pWidgetStack->action("back")->plug(pop_nav);
    pWidgetStack->action("forward")->plug(pop_nav);
    pWidgetStack->action("mkdir")->plug(pop_nav);
    pop_nav->insertSeparator();
    pWidgetStack->action("show hidden")->plug(pop_nav);
    pop_nav->insertSeparator();
    pASelectAll->plug(pop_nav);
    pADeselectAll->plug(pop_nav);
    pASelectGroup->plug(pop_nav);
    pADeselectGroup->plug(pop_nav);
    pop_nav->insertSeparator();
    pop_nav->insertItem(i18n("Fi&lter"), actionFilterMenu);

    pAGotoTray->plug(pop_view);
    pop_view->insertSeparator();
    pARaiseListView->plug(pop_view);
    pARaiseIconView->plug(pop_view);
    pARaiseDetailView->plug(pop_view);
    pARaiseThumbView->plug(pop_view);
    pop_view->insertSeparator();
    pAURL->plug(pop_view);

    pASlideShow->plug(pop_action);
    pASlideShowDialog->plug(pop_action);
    pop_action->insertSeparator();

    pATCMaster->plug(pop_action);
    pARescan->plug(pop_action);
    pAExtTools->plug(pop_action);
    pAFilters->plug(pop_action);
    pAPluginsInfo->plug(pop_action);
    pAPluginsDel->plug(pop_action);
    pAGLInfo->plug(pop_action);
    pop_action->insertSeparator();
    pAConfigure->plug(pop_action);
}

// Create toolbar
void KSquirrel::createToolbar(TDEToolBar *tools)
{
    pWidgetStack->action("back")->plug(tools);
    pWidgetStack->action("forward")->plug(tools);
    pWidgetStack->action("up")->plug(tools);
    pWidgetStack->action("home")->plug(tools);
    pWidgetStack->action("dirop_repeat")->plug(tools);

    pASlideShow->plug(tools);

    tools->insertLineSeparator();
    pARaiseListView->plug(tools);
    pARaiseIconView->plug(tools);
    pARaiseDetailView->plug(tools);
    pARaiseThumbView->plug(tools);
    pAThumbs->plug(tools);

    tools->insertLineSeparator();
    pAGLView->plug(tools);
    pAExtTools->plug(tools);
    pAFilters->plug(tools);

    tools->insertLineSeparator();
    pAURL->plug(tools);
    pAConfigure->plug(tools);
    pAExit->plug(tools);

    // insert animated widget
    configAnime();
}

// Create all TDEActions
void KSquirrel::createActions()
{
    pAThumbs = new TDEActionMenu(i18n("Thumbnail size"), "thumbnail");
    pAExit = KStdAction::quit(this, TQ_SLOT(slotClose()), actionCollection(), "SQ close");
    pAConfigure = KStdAction::preferences(this, TQ_SLOT(slotOptions()), actionCollection(), "SQ Configure");
    pAGLView = new TDEAction(i18n("Image window"), "raise", CTRL+TQt::Key_I, this, TQ_SLOT(raiseGLWidget()), actionCollection(), "SQ gl view widget");
    pARescan = KStdAction::redisplay(this, TQ_SLOT(slotRescan()), actionCollection(), "SQ rescan libraries");
    pARescan->setText(i18n("Reload codecs from disk"));
    pAExtTools = new TDEAction(i18n("Configure external tools..."), "launch", 0, this, TQ_SLOT(slotExtTools()), actionCollection(), "SQ external tools");
    pAFilters = new TDEAction(i18n("Configure filters..."), "filefind", 0, this, TQ_SLOT(slotFilters()), actionCollection(), "SQ filters");
    pAGotoTray = new TDEAction(i18n("Go to tray"), "background", CTRL+TQt::Key_T, this, TQ_SLOT(slotGotoTray()), actionCollection(), "SQ goto tray");
    pAOpenAndSet = new TDEAction(i18n("Open file and change directory"), "document-open", CTRL+ALT+TQt::Key_O, this, TQ_SLOT(slotOpenFileAndSet()), actionCollection(), "SQ open and set");
    pAOpen = new TDEAction(i18n("Open file"), "document-open", CTRL+TQt::Key_O, this, TQ_SLOT(slotOpenFile()), actionCollection(), "SQ open file");
    pATCMaster = new TDEAction(i18n("Thumbnail cache manager..."), "cache", 0, this, TQ_SLOT(slotTCMaster()), actionCollection(), "SQ TC Master");
    pASelectAll = KStdAction::selectAll(0, 0, actionCollection(), "SQ Select All");
    pADeselectAll = KStdAction::deselect(0, 0, actionCollection(), "SQ Deselect All");

    pARaiseListView = new TDERadioAction(i18n("List"), "view_multicolumn", 0, this, TQ_SLOT(slotRaiseListView()), actionCollection(), "SQ raise list view");
    pARaiseIconView = new TDERadioAction(i18n("Icons"), "view_icon", 0, this, TQ_SLOT(slotRaiseIconView()), actionCollection(), "SQ raise icon view");
    pARaiseDetailView = new TDERadioAction(i18n("Details"), "view_detailed", 0, this, TQ_SLOT(slotRaiseDetailView()), actionCollection(), "SQ raise detailed view");
    pARaiseThumbView = new TDERadioAction(i18n("Thumbnails"), "view_icon", 0, this, TQ_SLOT(slotRaiseThumbView()), actionCollection(), "SQ raise thumbs view");

    pAURL = new TDEToggleAction(i18n("Show URL box"), "history", CTRL+TQt::Key_U, 0, 0, actionCollection(), "SQ toggle url box");

    pASlideShow = new TDEAction(i18n("Slideshow"), "folder_video", CTRL+TQt::Key_S, this, TQ_SLOT(slotSlideShowStart()), actionCollection(), "SQ Slideshow");
    pASlideShowDialog = new TDEAction(i18n("Slideshow advanced"), 0, CTRL+ALT+TQt::Key_S, this, TQ_SLOT(slotSlideShowDialog()), actionCollection(), "SQ SlideShow Dialog");
    pARename = new TDEAction(i18n("Rename"), "file_move", TQt::Key_F2, this, TQ_SLOT(slotRename()), actionCollection(), "SQ Rename");
    pAPluginsInfo = new TDEAction(i18n("Codec information..."), "application-vnd.tde.info", 0, this, TQ_SLOT(slotPluginsInfo()), actionCollection(), "SQ Plugins Info");
    pAPluginsDel = new TDEAction(i18n("Codec manager..."), 0, 0, this, TQ_SLOT(slotPluginsDel()), actionCollection(), "SQ Plugins Deleter");
    pAGLInfo = new TDEAction(i18n("OpenGL information..."), 0, 0, this, TQ_SLOT(slotGLInfo()), actionCollection(), "SQ OpenGL Info");

    pAThumb1 = new TDERadioAction(i18n("Medium thumbnails"), locate("data", "images/thumbs/thumbs_medium.png"), 0, this, TQ_SLOT(slotThumbsMedium()), actionCollection(), "SQ thumbs1");
    pAThumb2 = new TDERadioAction(i18n("Large thumbnails"), locate("data", "images/thumbs/thumbs_large.png"), 0, this, TQ_SLOT(slotThumbsLarge()), actionCollection(), "SQ thumbs2");
    pAThumb3 = new TDERadioAction(i18n("Huge thumbnails"), locate("data", "images/thumbs/thumbs_huge.png"), 0, this, TQ_SLOT(slotThumbsHuge()), actionCollection(), "SQ thumbs3");

    pASelectGroup = new TDEAction(i18n("Select group"), "zoom-in", CTRL+TQt::Key_Plus, 0, 0, actionCollection(), "SQ Select Group");
    pADeselectGroup = new TDEAction(i18n("Deselect group"), "zoom-out", CTRL+TQt::Key_Minus, 0, 0, actionCollection(), "SQ Deselect Group");

    const TQString thumbs_size__ = TQString::fromLatin1("thumbs_size__");
    pAThumb1->setExclusiveGroup(thumbs_size__);
    pAThumb2->setExclusiveGroup(thumbs_size__);
    pAThumb3->setExclusiveGroup(thumbs_size__);

    switch(thumbSize->value())
    {
        case SQ_ThumbnailSize::Medium: pAThumb1->setChecked(true); break;
        case SQ_ThumbnailSize::Large:  pAThumb2->setChecked(true); break;

        default: pAThumb3->setChecked(true);
    }

    pAThumbs->insert(pAThumb1);
    pAThumbs->insert(pAThumb2);
    pAThumbs->insert(pAThumb3);
    pAThumbs->insert(new TDEActionSeparator(actionCollection()));

    pAThumbsE = new TDEToggleAction(i18n("Extended thumbnails"), "", CTRL+TQt::Key_E, 0, 0, actionCollection(), "SQ Extended thumbs");
    tdeconf->setGroup("Thumbnails");
    pAThumbsE->setChecked(tdeconf->readBoolEntry("extended", false));
    connect(pAThumbsE, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(slotExtendedToggled(bool)));
    pAThumbs->insert(pAThumbsE);

    pAThumbs->setDelayed(false);

    TQString raise_some_widget_from_stack = TQString::fromLatin1("raise_some_widget_from_stack");
    pARaiseListView->setExclusiveGroup(raise_some_widget_from_stack);
    pARaiseIconView->setExclusiveGroup(raise_some_widget_from_stack);
    pARaiseDetailView->setExclusiveGroup(raise_some_widget_from_stack);
    pARaiseThumbView->setExclusiveGroup(raise_some_widget_from_stack);
}

// Goto tray
void KSquirrel::slotGotoTray()
{
    // show tray icon
    tray->show();

    // hide image window
    gl_view->hide();

    m_intray = true;

    // hide main window
    hide();
}

// create external tools
void KSquirrel::initExternalTools()
{
    // create SQ_ExternalTool and create new
    // popup menu with tools
    extool = new SQ_ExternalTool(this);
    extool->newPopupMenu();
}

// Edit custom filters
void KSquirrel::slotFilters()
{
    SQ_Filters f(this);

    if(f.start() != TQDialog::Accepted) return;

    // Recreate menu with filters
    initFilterMenu();
}

// Edit external tools
void KSquirrel::slotExtTools()
{
    SQ_ExternalTools etd(this, "sq_exttools", true);

    // If user clicked "OK", recreate menu with
    // tools
    if(etd.start() == TQDialog::Accepted)
        extool->newPopupMenu();
}

// Show image window
void KSquirrel::raiseGLWidget()
{
    // if image window is separate, just show and raise it
    gl_view->show();
    gl_view->raise();
    KWin::forceActiveWindow(gl_view->winId());

    if(SQ_GLWidget::window()->fullscreen())
    {
        gl_view->statusbar()->setShown(false);
        gl_view->boxBar()->setShown(false);
    }
}

// Hide image window
void KSquirrel::closeGLWidget()
{
    gl_view->hide();

    if(m_demo)
    {
        finalActions();
        tqApp->quit();
    }
    else
    {
        tdeconf->setGroup("GL view");

        if(tdeconf->readBoolEntry("closeall", false))
            SQ_GLWidget::window()->closeAllTabsFull();
    }
}

// create bookmarks
void KSquirrel::initBookmarks()
{
    // locate bookmarks file
    TQString file = locate("data", "tdefile/bookmarks.xml");

    if(file.isEmpty())
        file = locateLocal("data", "tdefile/bookmarks.xml");

    KBookmarkManager *bmanager = KBookmarkManager::managerForFile(file, false);
    bmanager->setUpdate(true);
    bmanager->setShowNSBookmarks(false);

    SQ_BookmarkOwner *bookmarkOwner = new SQ_BookmarkOwner(this);

    // setup menu
    bookmarks = new TDEActionMenu(i18n("&Bookmarks"), "bookmark", actionCollection(), "bookmarks");
    bookmarkMenu = new KBookmarkMenu(bmanager, bookmarkOwner, bookmarks->popupMenu(), actionCollection(), true);

    connect(bookmarkOwner, TQ_SIGNAL(openURL(const KURL&)), pWidgetStack, TQ_SLOT(setURLForCurrent(const KURL&)));

    bookmarkOwner->setURL(pWidgetStack->diroperator()->url());
}

// Create new config file in
// local directory (~/.trinity/share/config)
void KSquirrel::writeDefaultEntries()
{
    TDEConfig conf("ksquirrelrc");

    if(!conf.hasGroup("External tools"))
    {
        conf.setGroup("External tools");
        conf.writeEntry("names", "Run within KDE,View in hexadecimal mode,Print file,Set as wallpaper on desktop,Set as tiled wallpaper on desktop,Open with GIMP,Open with GQview,Open with ShowImg,Open with KuickShow,Open with KView,Open with Opera,Open with Konqueror,Open with KWrite");
        conf.writeEntry("commands", "kfmclient exec %f,khexedit %f,kprinter %f,dcop kdesktop KBackgroundIface setWallpaper %f 6,dcop kdesktop KBackgroundIface setWallpaper %f 2,gimp %F,gqview %F,showimg %F,kuickshow %F,kview %F,opera %F,konqueror %F,kwrite %F");
        conf.writeEntry("icons", "kfm,khexedit,tdeprintfax,mac,mac,gimp,gqview,showimg,kuickshow,kview,opera,konqueror,kwrite");
    }

    if(!conf.hasGroup("Filters"))
    {
        conf.setGroup("Filters");
        conf.writeEntry("extensions", "*,*.mpg *.mpeg *.avi *.asf *.divx,*.mp3 *.ogg *.wma *.wav *.it");
        conf.writeEntry("items", "All files,Video tapes,Audio files");
        conf.writeEntry("last", "*");
        conf.writeEntry("menuitem both", "false");
    }

    if(!conf.hasGroup("Navigator Icons"))
    {
        conf.setGroup("Navigator Icons");
        conf.writeEntry("ShowPreviews", "false");
        conf.writeEntry("ViewMode", "LargeRows");
    }

    if(!conf.hasGroup("Navigator List"))
    {
        conf.setGroup("Navigator List");
        conf.writeEntry("ShowPreviews", "false");
        conf.writeEntry("ViewMode", "SmallColumns");
    }

    conf.setGroup("Main");
    conf.writeEntry("version", VERSION);

    conf.sync();
}

// Apply settings
void KSquirrel::applyDefaultSettings()
{
    bool updateDirs;

    tdeconf->setGroup("GL view");

    // set background color, zoom & move factors
    SQ_GLWidget::window()->setClearColor();
    SQ_GLWidget::window()->updateFactors();

    // Show/hide tickmarks if needed
    if(old_marks != tdeconf->readBoolEntry("marks", true))
        SQ_GLWidget::window()->updateGLA();

    gl_view->setupTabbar();

    tdeconf->setGroup("Fileview");

    // switching from 'off' to 'on' requires recalculating size
    if(!old_calc && tdeconf->readBoolEntry("calculate", true))
        pWidgetStack->diroperator()->calcTotalSize();

    updateDirs = (old_disable != tdeconf->readBoolEntry("disable_dirs", false));

    updateDirs &= (bool)pWidgetStack->diroperator()->numDirs();

    tdeconf->setGroup("Thumbnails");
    bool lazy = tdeconf->readBoolEntry("lazy", true);
    int lazyDelay = tdeconf->readNumEntry("lazy_delay", 500);
    int lazyRows = tdeconf->readNumEntry("rows", 2);

    pWidgetStack->updateGrid(updateDirs);

    // set cache limit for pixmap cache
    SQ_PixmapCache::instance()->setCacheLimit(tdeconf->readNumEntry("cache", 1024*10));

    tdeconf->setGroup("Main");

    if(tdeconf->readBoolEntry("sync", false))
        tdeconf->sync();

    pWidgetStack->diroperator()->setLazy(lazy, lazyDelay, lazyRows);

    // reload directory
    if(updateDirs)
        pWidgetStack->updateView();
}

void KSquirrel::slotExtendedToggled(bool e)
{
    thumbSize->setExtended(e);
    pWidgetStack->diroperator()->slotSetThumbSize(SQ_ThumbnailSize::instance()->pixelSizeString());
}

// Toggle fullscreen state for image window
void KSquirrel::slotFullScreen(bool full)
{
    WId id = gl_view->winId();

    tdeconf->setGroup("GL view");

    // avoid automatic image resizing
    gl_view->statusbar()->setShown(!full);
    gl_view->boxBar()->setShown(!full);

    // goto fullscreen
    if(full)
    {
        gl_view->saveGeometry();
        KWin::setState(id, NET::FullScreen);
    }
    else // leave fullscreen
        KWin::clearState(id, NET::FullScreen);
}

// Save parameters to config file
void KSquirrel::saveValues()
{
    extool->writeEntries();

    tdeconf->setGroup("Filters");
    tdeconf->writeEntry("items", *sqFiltersName);
    tdeconf->writeEntry("extensions", *sqFiltersExt);
    tdeconf->writeEntry("last", pWidgetStack->nameFilter());

    tdeconf->setGroup("Fileview");
    pWidgetStack->saveState();

    if(SQ_HLOptions::instance()->have_imagebasket)
        if(!waitForShow)
            SQ_ImageBasket::instance()->saveConfig();

    if(tdeconf->readBoolEntry("history", true) && pCurrentURL)
    {
        tdeconf->setGroup("History");
        tdeconf->writeEntry("items", pCurrentURL->historyItems());
    }

    tdeconf->setGroup("GL view");

    if(!SQ_GLWidget::window()->fullscreen())
        gl_view->saveGeometry();

    tdeconf->writeEntry("ignore", dynamic_cast<TDEToggleAction *>(SQ_GLWidget::window()->actionCollection()->action("if less"))->isChecked());
    tdeconf->writeEntry("zoom type", SQ_GLWidget::window()->zoomType());

    tdeconf->setGroup("Interface");
    tdeconf->writeEntry("last view", pWidgetStack->diroperator()->viewType());
    if(!waitForShow) tdeconf->writeEntry("last page", sideBar->currentPage());
    tdeconf->writeEntry("pos", pos());
    tdeconf->writeEntry("size", size());
    tdeconf->writeEntry("has_url", pTLocation->isShown());

    // splitter sizes are saved automatically
    // only when all sidebar pages are closed
    if(sideBar->currentPage() != -1 && !waitForShow)
        saveLayout();

    tdeconf->setGroup("Thumbnails");
    tdeconf->writeEntry("size", thumbSize->value());
    tdeconf->writeEntry("extended", thumbSize->extended());
}

// Reload libraries from disk
void KSquirrel::slotRescan()
{
    libhandler->reload();
}

// Create a final splash screen, if needed (if pixmap cache is not empty)
void KSquirrel::createPostSplash()
{
    TQColor cc(255,255,255);
    TQHBox *hbox = new TQHBox(0, 0, TQt::WStyle_StaysOnTop | TQt::WStyle_Customize | TQt::WStyle_NoBorder | TQt::WX11BypassWM);
    hbox->setFrameShape(TQFrame::Box);

    TQLabel *pp = new TQLabel(hbox);
    pp->setPalette(TQPalette(cc, cc));
    pp->setAlignment(TQt::AlignCenter);

    TQPixmap todo = TQPixmap::fromMimeSource(locate("data", "images/tray.png"));

    if(todo.isNull())
        todo = SQ_IconLoader::instance()->loadIcon("ksquirrel", TDEIcon::Desktop, 16);

    pp->setPixmap(todo);
    pp->setFixedWidth(18);

    TQLabel *l = new TQLabel(i18n(" writing settings and thumbnails...  "), hbox);
    l->setPalette(TQPalette(cc, cc));
    l->setAlignment(TQt::AlignLeft | TQt::AlignVCenter);

    hbox->setStretchFactor(pp, 0);
    hbox->setStretchFactor(l, 1);

    TQRect rc = TDEGlobalSettings::splashScreenDesktopGeometry();

    int w = 200, h = 20;
    hbox->setGeometry(rc.center().x() - w/2, rc.center().y() - h/2, w, h);

    hbox->show();
}

void KSquirrel::slotThumbsMedium()
{
    emit thumbSizeChanged("medium");
}

void KSquirrel::slotThumbsLarge()
{
    emit thumbSizeChanged("large");
}

void KSquirrel::slotThumbsHuge()
{
    emit thumbSizeChanged("huge");
}

// Final actions before exiting
void KSquirrel::finalActions()
{
    gl_view->hide();

    // save parameters to config file
    saveValues();

    hide();

    diskProg->flush();

    tdeconf->setGroup("Thumbnails");

    bool create_splash = !waitForShow && !tdeconf->readBoolEntry("dont write", false) && !SQ_PixmapCache::instance()->empty();

    // create post splash
    if(create_splash)
    {
        createPostSplash();
        TDEApplication::eventLoop()->processEvents(TQEventLoop::ExcludeUserInput | TQEventLoop::ExcludeSocketNotifiers);
    }

    // write config file to disk (it is currently in memory cache)
    tdeconf->sync();

    // Save thumbnails from memory cache to disk
    if(create_splash)
        SQ_PixmapCache::instance()->sync();
}

/*
 *  Enable/disable popup menu with thumnail sizes. Called
 *  from SQ_WidgetStack, when user changed current view
 *  type (for example Thumbnail view -> Icon view).
 */
void KSquirrel::enableThumbsMenu(bool enable)
{
    pAThumbsE->setEnabled(enable); // extended thumbnails
    pAThumbs->setEnabled(enable);
}

/*
 *  Create all needed objects
 */
void KSquirrel::preCreate()
{
    new SQ_IconLoader(this);
    new SQ_PixmapCache(this);
    new SQ_ArchiveHandler(this);
    new SQ_ImageLoader(this);
    new SQ_DragProvider(this);

    libhandler = new SQ_LibraryHandler(this);

    initExternalTools();

    new SQ_ErrorString(this);
    new SQ_ThumbnailsUnused(this);
    new SQ_Converter(this);

    listingDialog = new SQ_SlideShowListing(this, "SlideShow Listing", true, TQt::WStyle_Customize | TQt::WStyle_NoBorder);
    connect(listingDialog, TQ_SIGNAL(kill()), this, TQ_SLOT(slotSlideShowListingKill()));

    slideShowItems.setAutoDelete(true);

    down = new SQ_Downloader(this);

    connect(down, TQ_SIGNAL(result(const KURL &)), this, TQ_SLOT(slotDownloaderResult(const KURL &)));

    SQ_SlideShowWidget *sls = new SQ_SlideShowWidget(0, "ksquirrel-slideshow");

    connect(sls, TQ_SIGNAL(stopSlideShow()), this, TQ_SLOT(slotStopSlideShow()));
    connect(sls, TQ_SIGNAL(pause()), this, TQ_SLOT(slotPauseSlideShow()));
    connect(sls, TQ_SIGNAL(next()), this, TQ_SLOT(slotNextSlideShow()));
    connect(sls, TQ_SIGNAL(previous()), this, TQ_SLOT(slotPreviousSlideShow()));

    // timer for slideshow
    slideShowTimer = new TQTimer(this);
    timerShowListing = new TQTimer(this);
    connect(timerShowListing, TQ_SIGNAL(timeout()), listingDialog, TQ_SLOT(show()));

    SQ_SplashScreen::advance();

    // create main actions
    createActions();

    SQ_SplashScreen::advance();

    actionFilterMenu = new TDEPopupMenu;

    actionViews = new TDEPopupMenu;

    pARaiseListView->plug(actionViews);
    pARaiseIconView->plug(actionViews);
    pARaiseDetailView->plug(actionViews);
    pARaiseThumbView->plug(actionViews);

    SQ_SplashScreen::advance();

    // if -l option specified, exit
    if(SQ_HLOptions::instance()->showLibsAndExit)
        exit(0);

    if(!SQ_HLOptions::instance()->param.isEmpty())
    {
        // at first try to stat as local url
        KURL url;

        if(TQDir::isRelativePath(SQ_HLOptions::instance()->param))
        {
            url = KURL::fromPathOrURL(TQDir::currentDirPath());
            url.addPath(SQ_HLOptions::instance()->param);
        }
        else
            url.setPath(SQ_HLOptions::instance()->param);

        statStage = false;
        TDEIO::StatJob *job = TDEIO::stat(url, false);
        job->setSide(true);
        job->setDetails(0);
        connect(job, TQ_SIGNAL(result(TDEIO::Job *)), this, TQ_SLOT(slotStatResult(TDEIO::Job *)));
    }
    else
        continueLoading();
}

void KSquirrel::slotStatResult(TDEIO::Job *_job)
{
    if(_job)
    {
        TDEIO::StatJob *job = static_cast<TDEIO::StatJob *>(_job);

        if(job->error())
        {
            // both local and remote urls are failed
            if(statStage)
            {
                job->showErrorDialog(this);
                continueLoading();
                return;
            }
        }

        // found local/remote URL
        TDEIO::UDSEntry udsEntry = job->statResult();
        TDEIO::UDSEntry::ConstIterator itEnd = udsEntry.end();

        for(TDEIO::UDSEntry::ConstIterator it = udsEntry.begin(); it != itEnd;++it)
        {
            // we need just file type...
            if((*it).m_uds == TDEIO::UDS_FILE_TYPE)
            {
                if(S_ISDIR((mode_t)((*it).m_long)))
                {
                    SQ_HLOptions::instance()->dir = job->url();
                }
                else
                {
                    SQ_HLOptions::instance()->file = job->url();
                    SQ_HLOptions::instance()->dir = job->url();
                    SQ_HLOptions::instance()->dir.cd("..");
                }

                m_demo = !SQ_HLOptions::instance()->file.isEmpty();

                // Ok, it's existing URL
                continueLoading();
                return;
            }
        }

        // this should not occur, but for safety reasons...
        if(statStage)
        {
            continueLoading();
            return;
        }

        // local url is not found. construct remote url and stat() it again
        KURL url = KURL::fromPathOrURL(SQ_HLOptions::instance()->param);
        statStage = true;
        TDEIO::StatJob *job2 = TDEIO::stat(url, false);
        job2->setSide(true);
        job2->setDetails(0);
        connect(job2, TQ_SIGNAL(result(TDEIO::Job *)), this, TQ_SLOT(slotStatResult(TDEIO::Job *)));
    }
    else
        continueLoading();
}

void KSquirrel::resizeEvent(TQResizeEvent *e)
{
    if(mainPage)
        mainPage->resize(e->size());
}

void KSquirrel::continueLoading()
{
    tdeconf->setGroup("Interface");
    int createFirst = tdeconf->readNumEntry("last view", 0);

    // create toolbar, menubar, tree, filemanager ...
    createWidgets(createFirst);

    // set position & size
    handlePositionSize();

    if(m_demo)
        raiseGLWidget();

    // don't show navigator when running with file argument
    if(!m_demo && !kapp->isRestored())
        show();

    // in demo mode may be invisible
    if(mainPage->isVisible())
    {
        TQEvent e(TQEvent::Show);
        eventFilter(mainPage, &e);
    }

    tray = new KSystemTray(this);
    tray->setPixmap(TQPixmap(locate("data", "images/tray.png")));

    connect(tray, TQ_SIGNAL(quitSelected()), this, TQ_SLOT(slotTrayQuit()));

    SQ_SplashScreen::advance();
    SQ_SplashScreen::finish();

    // Check if we need to load a file at startup
    // (if one was specified in command line)
    if(!SQ_HLOptions::instance()->file.isEmpty())
    {
        raiseGLWidget();

        if(libhandler->maybeSupported(SQ_HLOptions::instance()->file) != SQ_LibraryHandler::No)
        {
            pWidgetStack->diroperator()->setPendingFile(SQ_HLOptions::instance()->file.fileName(false));
            KFileItem fi(KFileItem::Unknown, KFileItem::Unknown, SQ_HLOptions::instance()->file);
            pWidgetStack->diroperator()->execute(&fi);
        }
    }

    pWidgetStack->diroperator()->setFocus();

    // show tray icon when restored
    if(kapp->isRestored())
        slotGotoTray();

    connect(kapp, TQ_SIGNAL(saveYourself()), this, TQ_SLOT(slotSaveYourself()));
}

// Set caption to main window or to image window
void KSquirrel::setCaption(const TQString &cap)
{
#if 0
    TDEMainWindow::setCaption(cap);
#endif

    gl_view->setCaption(cap.isEmpty() ? "ksquirrel" : kapp->makeStdCaption(cap));
}

// User selected "Open file" or "Open file #2" from menu.
// Let's load file and set new URL for filemanager (if parseURL == true)
void KSquirrel::openFile(bool parseURL)
{
    KURL url = KFileDialog::getOpenURL();

    if(url.isEmpty())
        return;

    // if it is known file type
    if(libhandler->maybeSupported(url) != SQ_LibraryHandler::No)
    {
        if(parseURL)
        {
            KURL d = url;
            d.cd("..");
            pWidgetStack->diroperator()->setPendingFile(url.fileName());
            pWidgetStack->setURLForCurrent(d);
        }

        KFileItem fi(KFileItem::Unknown, KFileItem::Unknown, url);
        pWidgetStack->diroperator()->execute(&fi);
    }
    else
    {
        tdeconf->setGroup("Fileview");

        if(tdeconf->readBoolEntry("run unknown", false))
            new KRun(url);
    }
}

// "Open file" in menu
void KSquirrel::slotOpenFile()
{
    openFile();
}

// "Open file #2" in menu
void KSquirrel::slotOpenFileAndSet()
{
    openFile(true);
}

// User clicked animated widget in toolbar,
// let's goto KSquirrel's homepage
void KSquirrel::slotAnimatedClicked()
{
    // invoke default browser
    kapp->invokeBrowser(TQString::fromLatin1("http://ksquirrel.sourceforge.net/"));
}

// Create SQ_ThumbnailCacheMaster, which can do something with thumbnails
// and thumbnail cache
void KSquirrel::slotTCMaster()
{
    SQ_ThumbnailCacheMaster m(this);

    m.exec();
}

// Return a pointer to widget in statusbar by name
TQLabel* KSquirrel::sbarWidget(const TQString &name)
{
    return sbarwidgets[name];
}

// Convert TQByteArray to TQString
TQString KSquirrel::getArg(const TQByteArray &data)
{
    TQDataStream args(data, IO_ReadOnly);

    TQString arg;

    args >> arg;

    return arg;
}

// Process incoming DCOP messages
bool KSquirrel::process(const TQCString &fun, const TQByteArray &data, TQCString& replyType, TQByteArray &replyData)
{
    if(fun == "control(TQString)")
    {
        // Yes, user wants to call our "control" method
        control(getArg(data));

        replyType = "void";

        return true;
    }
    else if(fun == "navigator(TQString)")
    {
        navigatorSend(getArg(data));

        replyType = "void";

        return true;
    }
    else if(fun == "activate()")
    {
        activate();

        replyType = "void";

        return true;
    }
    else if(fun == "activate_image_window()")
    {
        raiseGLWidget();

        replyType = "void";

        return true;
    }
    else if(fun == "reload_codecs()")
    {
        slotRescan();

        replyType = "void";

        return true;
    }
    // load specified image
    else if(fun == "load(TQString)")
    {
        TQString arg = getArg(data);

        KURL url = KURL::fromPathOrURL(arg);

        TDEIO::StatJob *job = TDEIO::stat(url, false);
        job->setSide(true);
        job->setDetails(0);
        connect(job, TQ_SIGNAL(result(TDEIO::Job *)), this, TQ_SLOT(slotDCOPStatResult(TDEIO::Job *)));

        replyType = "void";

        return true;
    }

    // we have to call it
    return DCOPObject::process(fun, data, replyType, replyData);
}

void KSquirrel::slotDCOPStatResult(TDEIO::Job *_job)
{
    if(_job)
    {
        TDEIO::StatJob *job = static_cast<TDEIO::StatJob *>(_job);

        if(job->error())
        {
            job->showErrorDialog(this);
            return;
        }

        KURL url = job->url();
        bool isdir = false, setc = true;
        KURL dir = url;

        TDEIO::UDSEntry udsEntry = job->statResult();
        TDEIO::UDSEntry::ConstIterator itEnd = udsEntry.end();

        for(TDEIO::UDSEntry::ConstIterator it = udsEntry.begin(); it != itEnd;++it)
        {
            // we need just file type...
            if((*it).m_uds == TDEIO::UDS_FILE_TYPE)
            {
                isdir = S_ISDIR((mode_t)((*it).m_long));
                break;
            }
        }

        if(!isdir) dir.cd("..");

        if(!pWidgetStack->diroperator()->url().equals(dir, true))
        {
            // don't set current item
            setc = false;
            pWidgetStack->diroperator()->setPendingFile(url.fileName(false));
            pWidgetStack->diroperator()->setURL(dir, true);
        }

        // activate this window
        if(isdir)
            activate();
        else
        {
            raiseGLWidget();

            if(setc)
            {
                KFileView *v = pWidgetStack->diroperator()->view();

                if(v)
                {
                    v->clearSelection();
                    v->setCurrentItem(url.fileName(false));
                    pWidgetStack->diroperator()->setCurrentItem(v->currentFileItem());
                }
            }

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

            if(libhandler->maybeSupported(fi.url()) != SQ_LibraryHandler::No)
            {
                // stop slideshow if running
                slotStopSlideShow();

                // load
                pWidgetStack->diroperator()->execute(&fi);
            }
        }
    }
}

// Returnes all available DCOP methods.
// Used by DCOP infrastructure
QCStringList KSquirrel::functions()
{
    QCStringList result = DCOPObject::functions();

    result << "void control(TQString)";
    result << "void navigator(TQString)";
    result << "void load(TQString)";
    result << "void activate()";
    result << "void activate_image_window()";
    result << "void reload_codecs()";

    return result;
}

// Activate this instance
void KSquirrel::activate()
{
    m_demo = false;

    // just in case
    show();

    // force activation
    KWin::forceActiveWindow(winId());
}

void KSquirrel::printDCOP()
{
    navigatorSend("duuummmmyyyyy");
    control("duuummmmyyyyy");

    std::cerr << "Other:" << std::endl;
    std::cerr << "*****************************"  << std::endl;
    std::cerr << "activate"                       << std::endl;
    std::cerr << "activate_image_window"          << std::endl;
    std::cerr << "load <file or directory>"       << std::endl;
    std::cerr << "******************************" << std::endl;
}

void KSquirrel::navigatorSend(const TQString &command)
{
    if(command == "next")
        pWidgetStack->moveTo(SQ_WidgetStack::Next, 0, false);
    else if(command == "previous")
        pWidgetStack->moveTo(SQ_WidgetStack::Previous, 0, false);
    else if(command == "execute")
    {
        KFileItem *fi = pWidgetStack->diroperator()->view()->currentFileItem();

        if(fi)
        {
            if(fi->isFile())
                pWidgetStack->diroperator()->execute(fi);
            else
                pWidgetStack->diroperator()->setURL(fi->url(), true);
        }
    }
    else // unknown parameter !
    {
        std::cerr << "List of available DCOP parameters for navigator() method:" << std::endl;
        std::cerr << "*****************************"  << std::endl;
        std::cerr << "next"                           << std::endl;
        std::cerr << "previous"                       << std::endl;
        std::cerr << "execute"                        << std::endl;
        std::cerr << "******************************" << std::endl;
    }
}

// User sent us some message through DCOP, let's determine
// what he wants to do.
//
// The main idea is that SQ_GLWidget already has all needed actions,
// located in keyPressEvent() handler. Let's construct TQKeyEvent and send
// it to SQ_GLWidget - SQ_GLWidget will catch this event and will do what
// user wants.
//
void KSquirrel::control(const TQString &command)
{
    TQMap<TQString, int>::iterator it = messages.find(command);

    // known action
    if(it != messages.end())
    {
        int id = it.data();

        TDEAction *a = SQ_GLWidget::window()->actionCollection()->action(TQString("action_%1").arg(id).utf8());

        if(a) a->activate();
    }
    else // unknown parameter !
    {
        std::cerr << "List of available DCOP parameters for control() method:" << std::endl;
        std::cerr << "*****************************" << std::endl;

        for(TQMap<TQString, int>::iterator it = messages.begin();it != messages.end();++it)
        {
            std::cerr << it.key().local8Bit() << std::endl;
        }

        std::cerr << "******************************" << std::endl;
    }
}

void KSquirrel::fillMessages()
{
    messages.insert("image_next", TQt::Key_PageDown);
    messages.insert("image_previous", TQt::Key_PageUp);
    messages.insert("image_first", TQt::Key_Home);
    messages.insert("image_last", TQt::Key_End);
    messages.insert("image_reset", TQt::Key_R);
    messages.insert("image_information", TQt::Key_I);
    messages.insert("image_delete", TQt::Key_Delete);

    messages.insert("image_animation_toggle", TQt::Key_A);

    messages.insert("image_page_first", TQt::Key_F1);
    messages.insert("image_page_last", TQt::Key_F4);
    messages.insert("image_page_next", TQt::Key_F3);
    messages.insert("image_page_previous", TQt::Key_F2);

    messages.insert("image_window_fullscreen", TQt::Key_F);
    messages.insert("image_window_quickbrowser", TQt::Key_Q);
    messages.insert("image_window_close", TQt::Key_X);
    messages.insert("image_window_help", TQt::Key_Slash);

    messages.insert("zoom_plus", TQt::Key_Plus);
    messages.insert("zoom_minus", TQt::Key_Minus);
    messages.insert("zoom_1", TQt::Key_1);
    messages.insert("zoom_2", TQt::Key_2);
    messages.insert("zoom_3", TQt::Key_3);
    messages.insert("zoom_4", TQt::Key_4);
    messages.insert("zoom_5", TQt::Key_5);
    messages.insert("zoom_6", TQt::Key_6);
    messages.insert("zoom_7", TQt::Key_7);
    messages.insert("zoom_8", TQt::Key_8);
    messages.insert("zoom_9", TQt::Key_9);
    messages.insert("zoom_10", TQt::Key_0);
}

// Start/stop slideshow
void KSquirrel::slotSlideShowStart()
{
    if(slideShowDir.isEmpty())
        slideShowDir = SQ_WidgetStack::instance()->url().prettyURL();

    tdeconf->setGroup("Slideshow");

    // recursion ?
    bool recurs = tdeconf->readBoolEntry("recurs", false);

    listing = recurs ? TDEIO::listRecursive(slideShowDir, false, false)
                     : TDEIO::listDir(slideShowDir, false, false);

    connect(listing, TQ_SIGNAL(entries(TDEIO::Job *, const TDEIO::UDSEntryList &)),
            this, TQ_SLOT(slotSlideShowEntries(TDEIO::Job *, const TDEIO::UDSEntryList &)));

    connect(listing, TQ_SIGNAL(result(TDEIO::Job *)), this, TQ_SLOT(slotSlideShowJobResult(TDEIO::Job *)));

    timerShowListing->start(1000, true);
}

void KSquirrel::slotSlideShowListingKill()
{
    if(listing) listing->kill();

    slideShowItems.clear();
    listingDialog->setFile(0, TQString());
    listingDialog->hide();
}

void KSquirrel::slotSlideShowEntries(TDEIO::Job *, const TDEIO::UDSEntryList &list)
{
    TDEIO::UDSEntryListConstIterator itEnd = list.end();

    KURL url = KURL::fromPathOrURL(slideShowDir);
    TQString sfile;

    // go through list of TDEIO::UDSEntrys
    for(TDEIO::UDSEntryListConstIterator it = list.begin(); it != itEnd; ++it)
    {
        KFileItem *file = new KFileItem(*it, url, true, true);

        if(file && file->isFile())
        {
            slideShowItems.append(file);

            if(sfile.isEmpty()) sfile = file->name();
        }
        else
            delete file;
    }

    if(!sfile.isEmpty())
        listingDialog->setFile(slideShowItems.count(), sfile);
}

void KSquirrel::slotSlideShowJobResult(TDEIO::Job *job)
{
    listingDialog->setFile(0, TQString());
    listingDialog->hide();
    timerShowListing->stop();

    if(!job->error())
        slideShowPrivate();

    listing = 0;
}

// Invoke dialog for advanced slideshow
void KSquirrel::slotSlideShowDialog()
{
    SQ_SlideShow s(this);

    if(s.exec(slideShowDir) == TQDialog::Accepted)
        slotSlideShowStart();
}

// Start new slidehsow!
void KSquirrel::slideShowPrivate()
{
    // stop timer, if active
    slideShowTimer->stop();
    slideShowStop = false;
    slideShowInit = true;
    slideShowDirection = KSquirrel::Default;

    disconnect(slideShowTimer, TQ_SIGNAL(timeout()), 0, 0);
    connect(slideShowTimer, TQ_SIGNAL(timeout()), this, TQ_SLOT(slotSlideShowNextImage()));

    tdeconf->setGroup("Slideshow");

    // determine delay
    slideShowDelay = tdeconf->readNumEntry("delay", 1000);
    slideShowRepeat = tdeconf->readNumEntry("repeat", 0);

    if(slideShowDelay < 0)     slideShowDelay = 1000;
    if(slideShowRepeat < 0)    slideShowRepeat = 0;
    if(slideShowRepeat > 1000) slideShowRepeat = 1000;

    slideShowTotal = slideShowItems.count();

    // No files to show ?
    if(!slideShowTotal)
    {
        slotStopSlideShow();
        return;
    }

    // initial setup
    slideShowIndex = -1;

    // start!
    SQ_SlideShowWidget::instance()->beginSlideShow(slideShowTotal);

    TQTimer::singleShot(1, this, TQ_SLOT(slideShowDetermine()));
}

void KSquirrel::slotDownloaderResult(const KURL &u)
{
    if(u.isEmpty()) // error occured
        slideShowDetermine();
    else
    {
        KURL u2 = u;
        slideShowName = u2;
        int delay = slideShowInit ? 0 : slideShowDelay;

        if(libhandler->libraryForFile(slideShowName.path()))
        {
            slideShowInit = false;
            slideShowTimer->start(delay, true);
        }
        else
            slideShowDetermine();
    }
}

void KSquirrel::slideShowDetermine()
{
    do
    {
        // goto next file
        if(slideShowDirection == KSquirrel::Default)
        {
            slideShowIndex++;

            // all files loaded ?
            if(slideShowIndex == slideShowTotal)
            {
                // slideshow done
                if(!slideShowRepeat)
                {
                    // nice hack to make final delay
                    disconnect(slideShowTimer, TQ_SIGNAL(timeout()), 0, 0);
                    connect(slideShowTimer, TQ_SIGNAL(timeout()), this, TQ_SLOT(slotStopSlideShow()));
                    slideShowTimer->start(slideShowDelay, true);
                    return;
                }
                // we should repeat slideshow
                else
                {
                    slideShowRepeat--;
                    slideShowIndex = 0;
                }
            }
        }
        else // KSquirrel::MBack
        {
            slideShowIndex--;

            if(slideShowIndex < 0)
            {
                slideShowDirection = KSquirrel::Default;
                slideShowIndex = -1;
                continue;
            }
        }

        // construct new file name
        slideShowFile = slideShowItems.at(slideShowIndex);
        slideShowName = slideShowFile->url();
    }
    while(libhandler->maybeSupported(slideShowName) == SQ_LibraryHandler::No);

    slideShowDirection = KSquirrel::Default;

    if(slideShowName.isLocalFile())
        slotDownloaderResult(slideShowName);
    else
        down->start(slideShowFile);
}

// Load the next image
void KSquirrel::slotSlideShowNextImage()
{
    // stopped ?
    if(slideShowStop)
        return;

    SQ_SlideShowWidget::instance()->loadImage(slideShowName.path(), slideShowIndex);

    slideShowDetermine();
}

void KSquirrel::slotNextSlideShow()
{
    slideShowTimer->stop();
    slideShowTimer->start(0, true);
}

void KSquirrel::slotPreviousSlideShow()
{
    slideShowTimer->stop();
    slideShowDirection = KSquirrel::MBack;
    int ssi = slideShowIndex;
    KURL ssn;

    do
    {
        // goto next file
        ssi--;

        if(ssi < 0)
        {
            slideShowDirection = KSquirrel::Default;
            slideShowTimer->start(0, true);
            return;
        }

        // construct new file name
        ssn = slideShowItems.at(ssi)->url();
    }
    while(libhandler->maybeSupported(ssn) == SQ_LibraryHandler::No);

    slideShowIndex = ssi;
    slideShowName = ssn;

    slideShowInit = true;
    slideShowDetermine();
}

// Stop slideshow, if running
void KSquirrel::slotStopSlideShow()
{
    if(!slideShowRunning())
        return;

    // reset values
    slideShowStop = true;
    slideShowTimer->stop();
    slideShowDir = TQString();
    slideShowPaused = false;
    slideShowItems.clear();
    slideShowDirection = KSquirrel::Default;

    tdeconf->setGroup("Slideshow");

    SQ_SlideShowWidget::instance()->endSlideShow();
}

// Show information on libraries
void KSquirrel::slotPluginsInfo()
{
    SQ_PluginsInfo pi(this);

    pi.exec();
}

void KSquirrel::slotPluginsDel()
{
    KShellProcess proc;

    proc << "ksquirrel-libs-configurator";

    proc.start(TDEProcess::DontCare);
}

void KSquirrel::slotPauseSlideShow()
{
    if(!slideShowRunning())
        return;

    if(slideShowPaused)
    {
        slideShowTimer->start(slideShowDelay, true);
        slideShowPaused = false;
    }
    else
    {
        slideShowTimer->stop();
        slideShowPaused = true;
    }
}

// show imformation on OpenGL
void KSquirrel::slotGLInfo()
{
    SQ_GLInfo gi(this);

    gi.exec();
}

void KSquirrel::saveLayout()
{
    if(!waitForShow)
    {
        tdeconf->setGroup("Interface");
        tdeconf->writeEntry("splitter", mainView->sizes());
    }
}

void KSquirrel::configAnime(bool init)
{
    KAnimWidget *anim = tools->animatedWidget(1000); // get animated widget, if exist

    tdeconf->setGroup("Main");

    // show animated logo in toolbar if needed
    if(!tdeconf->readBoolEntry("anime_dont", false) && (init || (!init && !anim)))
    {
        tools->insertAnimatedWidget(1000, this, TQ_SLOT(slotAnimatedClicked()), locate("data", "images/anime.png"));
        tools->alignItemRight(1000);
        tools->animatedWidget(1000)->start();
    }
    else if(!init && tdeconf->readBoolEntry("anime_dont", false) && anim)
        delete anim;
}

void KSquirrel::slotTrayQuit()
{
    m_demo = true;
    m_intray = false;
}

void KSquirrel::slotClose()
{
    m_demo = true;
    m_intray = false;

    close();
}

void KSquirrel::slotRename()
{
    bool ok;

    KFileItemList *items = const_cast<KFileItemList *>(pWidgetStack->diroperator()->view()->selectedItems());

    if(!items || !items->count())
        return;

    renameSrcURL = items->first()->url();

    TQString filename = TQStyleSheet::escape(renameSrcURL.filename());

    TQString mNewFilename = KInputDialog::getText(i18n("Renaming File"),
            i18n("<p>Rename file <b>%1</b> to:</p>").arg(filename),
            renameSrcURL.filename(), &ok, this);

    if(!ok) return;

    renameDestURL = renameSrcURL;
    renameDestURL.setFileName(mNewFilename);

    TDEIO::Job *job = TDEIO::move(renameSrcURL, renameDestURL);
    connect(job, TQ_SIGNAL(result(TDEIO::Job*)), this, TQ_SLOT(slotRenameResult(TDEIO::Job*)));
}

void KSquirrel::slotRenameResult(TDEIO::Job *job)
{
    if(job->error())
    {
        job->showErrorDialog(this);
        return;
    }

    SQ_PixmapCache::instance()->removeEntryFull(renameSrcURL);
}

void KSquirrel::slotRepeat()
{
    pWidgetStack->repeat();
}

void KSquirrel::slotSaveYourself()
{
    finalActions();
}

void KSquirrel::slotPreviewWidgetNext()
{
    pWidgetStack->moveTo(SQ_WidgetStack::Next);
}

void KSquirrel::slotPreviewWidgetPrevious()
{
    pWidgetStack->moveTo(SQ_WidgetStack::Previous);
}

void KSquirrel::slotPreviewWidgetExecute()
{
    KURL u = SQ_PreviewWidget::instance()->url();

    if(!u.isEmpty())
    {
        KFileItem fi(KFileItem::Unknown, KFileItem::Unknown, u);
        pWidgetStack->diroperator()->execute(&fi);
    }
}

#include "ksquirrel.moc"
