/***************************************************************************
                          sq_glwidget_stuff.cpp  -  description
                             -------------------
    begin                : Wed Oct 31 2007
    copyright            : (C) 2007 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 <tqclipboard.h>
#include <tqslider.h>
#include <tqdragobject.h>
#include <tqtimer.h>
#include <tqlabel.h>
#include <tqpainter.h>
#include <tqpaintdevicemetrics.h>

#include <tdeapplication.h>
#include <tdeaction.h>
#include <kstandarddirs.h>
#include <tdelocale.h>
#include <tdepopupmenu.h>
#include <ktabbar.h>
#include <kcursor.h>
#include <tdetempfile.h>
#include <tdemessagebox.h>
#include <tdefileitem.h>
#include <kprinter.h>

#include <algorithm>

#ifndef KSQUIRREL_PART
#include "ksquirrel.h"
#include "sq_widgetstack.h"
#endif

#include "sq_config.h"
#include "sq_libraryhandler.h"
#include "sq_glview.h"
#include "sq_glwidget.h"
#include "sq_glwidget_helpers.h"
#include "sq_imageproperties.h"
#include "sq_helpwidget.h"
#include "sq_filedialog.h"
#include "sq_iconloader.h"
#include "sq_codecsettingsskeleton.h"
#include "sq_externaltool.h"
#include "sq_diroperator.h"
#include "sq_popupmenu.h"
#include "sq_glselectionpainter.h"
#include "sq_utils.h"
#include "sq_imagefilter.h"
#include "sq_imagebcg.h"
#include "fmt_filters.h"

#ifdef SQ_HAVE_KEXIF
#include <libkexif/kexifdata.h>
#include <libexif/exif-data.h>
#endif

#include <ksquirrel-libs/fmt_codec_base.h>
#include <ksquirrel-libs/error.h>

#include "file_broken.xpm"

// Create actions
void SQ_GLWidget::createActions()
{
    pASelectionRect = new TDEToggleAction(i18n("Rectangle"), TQPixmap(locate("data", "images/actions/glselection_rect.png")), 0, this, TQ_SLOT(slotSelectionRect()), ac, "SQ Selection Rect");
    pASelectionEllipse = new TDEToggleAction(i18n("Ellipse"), TQPixmap(locate("data", "images/actions/glselection_ellipse.png")), 0, this, TQ_SLOT(slotSelectionEllipse()), ac, "SQ Selection Ellipse");
    pASelectionClear = new TDEAction(i18n("Clear"), 0, 0, this, TQ_SLOT(slotSelectionClear()), ac, "SQ Selection Clear");

    pAZoomW = new TDEToggleAction(i18n("Fit width"), TQPixmap(locate("data", "images/actions/zoomW.png")), 0, this, TQ_SLOT(slotZoomW()), ac, "SQ ZoomW");
    pAZoomH = new TDEToggleAction(i18n("Fit height"), TQPixmap(locate("data", "images/actions/zoomH.png")), 0, this, TQ_SLOT(slotZoomH()), ac, "SQ ZoomH");
    pAZoomWH = new TDEToggleAction(i18n("Fit image"), TQPixmap(locate("data", "images/actions/zoomWH.png")), 0, this, TQ_SLOT(slotZoomWH()), ac, "SQ ZoomWH");
    pAZoom100 = new TDEToggleAction(i18n("Zoom 100%"), TQPixmap(locate("data", "images/actions/zoom100.png")), 0, this, TQ_SLOT(slotZoom100()), ac, "SQ Zoom100");
    pAZoomLast = new TDEToggleAction(i18n("Leave previous zoom"), TQPixmap(locate("data", "images/actions/zoomlast.png")), 0, this, TQ_SLOT(slotZoomLast()), ac, "SQ ZoomLast");
    pAIfLess = new TDEToggleAction(i18n("Ignore, if image is smaller than window"), TQPixmap(locate("data", "images/actions/ifless.png")), 0, 0, 0, ac, "if less");

    pAFull = new TDEToggleAction(TQString(), 0, 0, 0, ac, "SQ GL Full");

    TQString squirrel_zoom_actions = TQString::fromLatin1("squirrel_zoom_actions");
    pAZoomW->setExclusiveGroup(squirrel_zoom_actions);
    pAZoomH->setExclusiveGroup(squirrel_zoom_actions);
    pAZoomWH->setExclusiveGroup(squirrel_zoom_actions);
    pAZoom100->setExclusiveGroup(squirrel_zoom_actions);
    pAZoomLast->setExclusiveGroup(squirrel_zoom_actions);

    TQString squirrel_selection_type = TQString::fromLatin1("squirrel_selection_type");
    pASelectionEllipse->setExclusiveGroup(squirrel_selection_type);
    pASelectionRect->setExclusiveGroup(squirrel_selection_type);

    connect(pAIfLess, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(slotZoomIfLess()));

#ifndef KSQUIRREL_PART
    connect(pAFull, TQ_SIGNAL(toggled(bool)), KSquirrel::app(), TQ_SLOT(slotFullScreen(bool)));
#endif

    SQ_Config::instance()->setGroup("GL view");

    pAIfLess->setChecked(SQ_Config::instance()->readBoolEntry("ignore", true));
}

void SQ_GLWidget::createToolbar()
{
    zoomMenu = new TDEPopupMenu;

#ifndef KSQUIRREL_PART
    selectionMenu = new TDEPopupMenu;

    SQ_ToolButton    *pATool;

    SQ_ToolBar *toolbar = SQ_GLView::window()->toolbar();

    pASelectionRect->plug(selectionMenu);
    pASelectionEllipse->plug(selectionMenu);
    selectionMenu->insertSeparator();
    pASelectionClear->plug(selectionMenu);

    // hack to show accels
    selectionMenu->changeItem(pASelectionRect->itemId(0), pASelectionRect->text() + "\tCtrl+R");
    selectionMenu->changeItem(pASelectionEllipse->itemId(0), pASelectionEllipse->text() + "\tCtrl+E");
    selectionMenu->changeItem(pASelectionClear->itemId(0), pASelectionClear->text() + "\tCtrl+C");

    pAZoom100->plug(zoomMenu);
    pAZoomLast->plug(zoomMenu);
    zoomMenu->insertSeparator();
    pAZoomW->plug(zoomMenu);
    pAZoomH->plug(zoomMenu);
    pAZoomWH->plug(zoomMenu);
    zoomMenu->insertSeparator();
    pAIfLess->plug(zoomMenu);

    switch(zoom_type)
    {
        case 0: pAZoomW->setChecked(true); break;
        case 1: pAZoomH->setChecked(true); break;
        case 3: pAZoom100->setChecked(true); break;
        case 4: pAZoomLast->setChecked(true); break;

        // "case 2" too
        default: pAZoomWH->setChecked(true);
    }

/*
 * We will create TQToolButtons and put them in toolbar.
 * Of course, we can just TDEAction::plug(), BUT plugged TDEActions
 * will produce buttons, which cann't be clicked twise! I think
 * plugged TDEActions will treat our attempt as double-click, not two single-clicks.
 * On the other hand, we can click TQToolButton as frequently as we want.
 *
 * Plugged TDEActions also don't know about autorepeat :(
 */
    new SQ_ToolButton(TQPixmap(locate("data", "images/actions/file_first.png")), i18n("Go to first image"), this, TQ_SLOT(slotFirst()), toolbar);
    pATool = new SQ_ToolButton(TQPixmap(locate("data", "images/actions/file_prev.png")), i18n("Previous image"), this, TQ_SLOT(slotPrev()), toolbar);
    pATool->setAutoRepeat(true);
    pATool = new SQ_ToolButton(TQPixmap(locate("data", "images/actions/file_next.png")), i18n("Next image"), this, TQ_SLOT(slotNext()), toolbar);
    pATool->setAutoRepeat(true);
    new SQ_ToolButton(TQPixmap(locate("data", "images/actions/file_last.png")), i18n("Go to last image"), this, TQ_SLOT(slotLast()), toolbar);

    // some toolbuttons need autorepeat...
    pATool = new SQ_ToolButton(TQPixmap(locate("data", "images/actions/zoom+.png")), i18n("Zoom +"), this, TQ_SLOT(slotZoomPlus()), toolbar);
    pATool->setAutoRepeat(true);
    pATool = new SQ_ToolButton(TQPixmap(locate("data", "images/actions/zoom-.png")), i18n("Zoom -"), this, TQ_SLOT(slotZoomMinus()), toolbar);
    pATool->setAutoRepeat(true);
    pAToolZoom = new SQ_ToolButtonPopup(TQPixmap(locate("data", "images/actions/zoom_template.png")), i18n("Zoom"), toolbar);
    pAToolZoom->setPopup(zoomMenu);
    pATool = new SQ_ToolButton(TQPixmap(locate("data", "images/actions/rotateL.png")), i18n("Rotate left"), this, TQ_SLOT(slotRotateLeft()), toolbar);
    pATool->setAutoRepeat(true);
    pATool = new SQ_ToolButton(TQPixmap(locate("data", "images/actions/rotateR.png")), i18n("Rotate right"), this, TQ_SLOT(slotRotateRight()), toolbar);
    pATool->setAutoRepeat(true);
    pATool = new SQ_ToolButton(TQPixmap(locate("data", "images/actions/flipV.png")), i18n("Flip vertically"), this, TQ_SLOT(slotFlipV()), toolbar);
    pATool->setAutoRepeat(true);
    pATool = new SQ_ToolButton(TQPixmap(locate("data", "images/actions/flipH.png")), i18n("Flip horizontally"), this, TQ_SLOT(slotFlipH()), toolbar);
    pATool->setAutoRepeat(true);
    new SQ_ToolButton(TQPixmap(locate("data", "images/actions/reload.png")), i18n("Normalize"), this, TQ_SLOT(slotMatrixReset()), toolbar);

    pAToolFull = new SQ_ToolButton(TQPixmap(locate("data", "images/actions/fullscreen.png")), i18n("Fullscreen"), pAFull, TQ_SLOT(activate()), toolbar);
    pAToolFull->setToggleButton(true);
    pAToolImages = new SQ_ToolButtonPopup(TQPixmap(locate("data", "images/actions/images.png")), i18n("Select image"), toolbar);
    pAToolImages->setPopup(images);
    SQ_ToolButtonPopup *pAToolSel = new SQ_ToolButtonPopup(TQPixmap(locate("data", "images/actions/glselection.png")), i18n("Selection"), toolbar);
    pAToolSel->setPopup(selectionMenu);
    pAToolQuick = new SQ_ToolButton(TQPixmap(locate("data", "images/actions/configure.png")), i18n("Codec settings"), this, TQ_SLOT(slotShowCodecSettings()), toolbar);
    pAToolQuick->setEnabled(false);
    pAToolProp = new SQ_ToolButton(TQPixmap(locate("data", "images/actions/prop.png")), i18n("Image Properties"), this, TQ_SLOT(slotProperties()), toolbar);
    pAToolPrint = new SQ_ToolButton(TQPixmap(locate("data", "images/actions/print.png")), i18n("Print"), this, TQ_SLOT(slotPrint()), toolbar);
    new SQ_ToolButton(TQPixmap(locate("data", "images/actions/shownav.png")), i18n("Show navigator"), this, TQ_SLOT(slotShowNav()), toolbar);

    slider_zoom = new TQSlider(1, 38, 2, 19, TQt::Horizontal, toolbar);
    slider_zoom->setTickmarks(TQSlider::Below);
    slider_zoom->setTickInterval(19);
    connect(slider_zoom, TQ_SIGNAL(valueChanged(int)), this, TQ_SLOT(slotSetZoomPercents(int)));
    toolbar->insertWidget(1000, 0, slider_zoom);
    toolbar->setItemAutoSized(1000);
    toolbar->alignItemRight(1000);

    changeSlider(1.0);
#endif
}

// Show image properties.
void SQ_GLWidget::slotProperties()
{
    if(tab->broken || tab->finfo.image.empty()) return;

    // Stop animation...
    stopAnimation();

    const int real_size = tab->finfo.image[tab->current].w * tab->finfo.image[tab->current].h * sizeof(RGBA);
    TQString sz = TDEIO::convertSize(real_size);
    TQStringList list;

    TQValueVector<TQPair<TQString,TQString> > meta;

    if(!tab->finfo.meta.empty())
    {
        for(std::vector<fmt_metaentry>::iterator it = tab->finfo.meta.begin();it != tab->finfo.meta.end();++it)
        {
            meta.append(TQPair<TQString,TQString>((*it).group.c_str(), (*it).data.c_str()));
        }
    }

    // save tab->current image parameters and some additioanl information
    // in list
    list    << tab->quickImageInfo
            << TQString::fromLatin1("%1x%2").arg(tab->finfo.image[tab->current].w).arg(tab->finfo.image[tab->current].h)
            << TQString::fromLatin1("%1").arg(tab->finfo.image[tab->current].bpp)
            << tab->finfo.image[tab->current].colorspace.c_str()
            << tab->finfo.image[tab->current].compression.c_str()
            << sz
            << TQString::fromLatin1("%1").arg((double)real_size / tab->fmt_size, 0, 'f', 2)
            << ((tab->finfo.image[tab->current].interlaced) ? i18n("yes") : i18n("no"))
            << TQString::fromLatin1("%1").arg(errors)
            << TQString::fromLatin1("%1").arg(tab->finfo.image.size())
            << TQString::fromLatin1("#%1").arg(tab->current+1)
            << TQString::fromLatin1("%1").arg(tab->finfo.image[tab->current].delay);

    // create dialog and setup it
    SQ_ImageProperties prop(this);
    prop.setFile(tab->m_File);
    prop.setURL(tab->m_original);
    prop.setParams(list);
    prop.setMetaInfo(meta);

    // show!
    prop.exec();

    // restore animation
    if(!manualBlocked())
        startAnimation();
}

void SQ_GLWidget::findCloserTiles(int w, int h, std::vector<int> &x, std::vector<int> &y)
{
    static int s = 9;
    static int dims[10] = { 2, 4, 8, 16, 32, 64, 128, 256, 512 };

    int *dd[2] = { &w, &h };
    std::vector<int> *dv[2] = { &x, &y };
    int del;

    for(int ff = 0;ff < 2;ff++)
    {
        if(*dd[ff] == 1) *dd[ff]=2;
        else if((*dd[ff])%2) (*dd[ff])++;

        while((*dd[ff]) >= 512)
        {
            (*dv[ff]).push_back(512);
            (*dd[ff]) -= 512;
        }

        for(int i = 0;i < s-1;i++)
            if((*dd[ff]) >= dims[i] && (*dd[ff]) < dims[i+1])
            {
                del = dims[i] + (dims[i]>>1);

                if((*dd[ff]) <= del)
                {
                    (*dv[ff]).push_back(dims[i]);
                    (*dd[ff]) -= dims[i];
                }
                else
                {
                    (*dv[ff]).push_back(dims[i+1]);
                    (*dd[ff]) -= dims[i+1];
                }

                i = -1;
            }
    }
}

TQPair<int, int> SQ_GLWidget::calcRealDimensions(Parts &p, int y, int x)
{
    int rw = 0, rh = 0;
    int toy = y == -1 ? p.tilesy.size() : y;
    int tox = x == -1 ? p.tilesx.size() : x;

    std::vector<int>::iterator itEnd = p.tilesx.end();

    for(std::vector<int>::iterator it = p.tilesx.begin();it != itEnd && tox--;++it)
        rw += (*it);

    itEnd = p.tilesy.end();

    for(std::vector<int>::iterator it = p.tilesy.begin();it != itEnd && toy--;++it)
        rh += (*it);

    return TQPair<int, int>(rw, rh);
}

void SQ_GLWidget::slotShowCodecSettings()
{
    tab->lib = SQ_LibraryHandler::instance()->libraryForFile(tab->m_File);

    if(!tab->lib || tab->lib->config.isEmpty()) // oops ?
    {
        enableSettingsButton(false);
        return;
    }

    SQ_CodecSettingsSkeleton skel(this);

    connect(&skel, TQ_SIGNAL(apply()), this, TQ_SLOT(slotApplyCodecSettings()));

    skel.addSettingsWidget(tab->lib->config);
    skel.setCodecInfo(tab->lib->mime, tab->lib->quickinfo);
    skel.adjustSize();

    if(skel.exec(tab->lib->settings) == TQDialog::Accepted)
        tab->lib->codec->set_settings(tab->lib->settings);
}

void SQ_GLWidget::slotApplyCodecSettings()
{
    if(tab->lib)
    {
        // new settings are already set by SQ_CodecSettingsSkeleton
        tab->lib->codec->set_settings(tab->lib->settings);
        m_original = tab->m_original;
        startDecoding(TQString(tab->m_File));
    }
}

void SQ_GLWidget::slotSetCurrentImage(int id)
{
    if(tab->total == 1)
        return;

    images->setItemChecked(old_id, false);
    tab->current = images->itemParameter(id);

    images->setItemChecked(id, true);
    old_id = id;

    updateCurrentFileInfo();
    updateGL();
}

void SQ_GLWidget::slotImagesShown()
{
    if(tab->finfo.animated)
    {
        if(!timer_anim->isActive())
            blocked = false;
        else
        {
            stopAnimation();
            blocked = true;
        }
    }

    images->setItemChecked(old_id, false);
    int id = images->idAt(tab->current);
    images->setItemChecked(id, true);
    old_id = id;
}

void SQ_GLWidget::slotShowImages()
{
    images->exec(TQCursor::pos());
}

void SQ_GLWidget::slotImagesHidden()
{
    if(blocked && tab->finfo.animated)
        startAnimation();
}

void SQ_GLWidget::slotShowHelp()
{
    SQ_HelpWidget help_w(this);

    help_w.exec();
}

void SQ_GLWidget::showExternalTools()
{
    bool v_ogorogde_buzina_a_v_kieve_dzyadka = SQ_ExternalTool::instance()->constPopupMenu()->isEnabled();
    SQ_ExternalTool::instance()->constPopupMenu()->setEnabled(true);

    KFileItemList items;
    KFileItem fi(KFileItem::Unknown, KFileItem::Unknown, tab->m_original);

    if(!tab->m_original.isEmpty())
    {
        items.append(&fi);
        SQ_ExternalTool::instance()->setItems(items);
    }

    SQ_ExternalTool::instance()->constPopupMenu()->exec(TQCursor::pos());
    SQ_ExternalTool::instance()->constPopupMenu()->setEnabled(v_ogorogde_buzina_a_v_kieve_dzyadka);
}

// Delete current image (user pressed 'Delete' key).
void SQ_GLWidget::deleteWrapper()
{
    if(tab->m_original.isEmpty())
        return;

#ifndef KSQUIRREL_PART
    KFileItemList list;
    KFileItem fi(KFileItem::Unknown, KFileItem::Unknown, tab->m_original);
    list.append(&fi);
    SQ_WidgetStack::instance()->diroperator()->del(list, this);
#else
    SQ_DirOperator::instance()->del(tab->m_original, this);
#endif
}

void SQ_GLWidget::enableSettingsButton(bool enab)
{
#ifndef KSQUIRREL_PART
    pAToolQuick->setEnabled(enab);
#endif

    menuImage->setItemEnabled(id_settings, enab);
}

void SQ_GLWidget::saveAs()
{
    if(!tab->lib || tab->finfo.image.empty()) // nothing to save
        return;

    SQ_Config::instance()->setGroup("GL view");
    TQString lastPath = SQ_Config::instance()->readEntry("saveasPath");
    TQString lastFilt = SQ_Config::instance()->readEntry("saveasFilter");

    if(lastPath.isEmpty())
    {
        KURL u = tab->m_original;
        u.cd("..");
        lastPath = u.prettyURL();
    }

    SQ_FileDialog d(lastPath, this);

    // set filter: writable codecs without *.*
    d.setFilter(SQ_LibraryHandler::instance()->allFiltersFileDialogString(false, false));
    d.setOperationMode(KFileDialog::Saving);
    d.setSelection(tab->m_original.fileName());
    d.setCurrentFilter(lastFilt);
    d.updateCombo(false);

    if(d.exec() == TQDialog::Rejected || d.selectedURL().isEmpty())
        return;

    KURL url = d.selectedURL();

    // cut off file name
    KURL u = url;
    u.cd("..");
    SQ_Config::instance()->writeEntry("saveasPath", u.prettyURL());
    SQ_Config::instance()->writeEntry("saveasFilter", d.nameFilter());

    TQString path = url.isLocalFile() ? url.path() : tmp->name();

    SQ_LIBRARY *wlib = SQ_LibraryHandler::instance()->libraryByName(d.nameFilter());

    if(!wlib || !wlib->writestatic)
    {
        KMessageBox::error(this, i18n("Sorry, could not perform write operation\nfor codec \"%1\"").arg(d.nameFilter()));
        return;
    }

    SQ_GLHelpers::scanLineGetter scgetter;
    int flp = 0;
    int curangle = SQ_GLHelpers::roundAngle((int)tab->curangle);

    fmt_image im = tab->finfo.image[tab->current];

/*
 *  The easiest way to rotate image is to use TQImage + TQImage::xForm(),
 *  but this method is VERY memory inefficient. We will use our own tranformation
 *  routins... Yes, they will be a little bit slower, but they require only
 *  one scaline in stack.
 */

    int w = im.w, h = im.h;
    int rw = tab->parts[tab->current].realw;

#ifdef SQ_HAVE_KEXIF
    switch(tab->orient)
    {
        case KExifData::HFLIP:
        case KExifData::ROT_90_HFLIP:
            flp = 1;
        break;

        case KExifData::VFLIP:
        case KExifData::ROT_90_VFLIP:
            flp = 2;
        break;

        default: ;
    }
#endif

    switch(curangle)
    {
        case -270:
        case 90:  scgetter = SQ_GLHelpers::scanLine90;  std::swap(w, h); break;

        case -180:
        case 180: scgetter = SQ_GLHelpers::scanLine180; break;

        case -90:
        case 270: scgetter = SQ_GLHelpers::scanLine270; std::swap(w, h); break;

        default: scgetter = SQ_GLHelpers::scanLine0;
    }

    RGBA *scan = new RGBA[w];
    RGBA *data = tab->parts[tab->current].buffer->data();

    fmt_image im2 = im;
    im2.w = w;
    im2.h = h;

    fmt_writeoptions opt;
    opt.interlaced = false;
    opt.alpha = im.hasalpha;
    opt.bitdepth = im.bpp;
    opt.compression_scheme = (wlib->opt.compression_scheme & CompressionNo) ? CompressionNo : CompressionInternal;
    opt.compression_level = wlib->opt.compression_def;

    int err = wlib->codec->write_init(TQString(TQFile::encodeName(path)).ascii(), im2, opt);

    if(err != SQE_OK)
    {
        KMessageBox::error(this, i18n("Error writing image"));
        delete [] scan;
        return;
    }

    err = wlib->codec->write_next();

    if(err != SQE_OK)
    {
        KMessageBox::error(this, i18n("Error writing image"));
        delete [] scan;
        return;
    }

    wlib->codec->write_next_pass();

    int H = im2.h;
    int Y0 = wlib->opt.needflip ? (-H+1):0;
    int Y = wlib->opt.needflip ? 1:H;
    int f;

    for(int j = Y0;j < Y;j++)
    {
        f = (j < 0) ? -j : j;

        scgetter(data, scan, rw, im.w, im.h, f, flp);

        err = wlib->codec->write_scanline(scan);

        if(err != SQE_OK)
        {
            wlib->codec->write_close();
            KMessageBox::error(this, i18n("Error writing image"));
            delete [] scan;
            return;
        }
    }

    wlib->codec->write_close();
    delete [] scan;

    // copy to non-local directory
    if(!url.isLocalFile())
    {
        //                           src   dst  perm  overwrite resume  progress
        TDEIO::Job *j = TDEIO::file_copy(path, url, -1,   true,     false,  false);

        connect(j, TQ_SIGNAL(result(TDEIO::Job *)), this, TQ_SLOT(slotCopyResult(TDEIO::Job *)));
    }
}

void SQ_GLWidget::slotCopyResult(TDEIO::Job *job)
{
    if(job->error())
    {
        if(KMessageBox::questionYesNoCancel(this, job->errorString() + '\n' + i18n("Try another location?")) == KMessageBox::Yes)
        {
            SQ_FileDialog d(TQString(), this);

            // set filter: writable codecs without *.*
            d.setFilter(SQ_LibraryHandler::instance()->allFiltersFileDialogString(false, false));
            d.setOperationMode(KFileDialog::Saving);
            d.updateCombo(false);

            int result = d.exec();

            if(result == TQDialog::Rejected || d.selectedURL().isEmpty())
                return;

            TDEIO::Job *j = TDEIO::file_copy(tmp->name(), d.selectedURL(), -1, true, false, false);
            connect(j, TQ_SIGNAL(result(TDEIO::Job *)), this, TQ_SLOT(slotCopyResult(TDEIO::Job *)));
        }
    }
}

void SQ_GLWidget::toClipboard()
{
    if(!decoded || tab->broken)
        return;

    TQImage im((uchar *)tab->parts[tab->current].buffer->data(), tab->parts[tab->current].realw, tab->parts[tab->current].realh, 32, 0, 0, TQImage::LittleEndian);

    im = im.swapRGB();

    // image doesn't have extra regions
    if(tab->parts[tab->current].realw == tab->parts[tab->current].w && tab->parts[tab->current].realh == tab->parts[tab->current].h)
        TDEApplication::clipboard()->setImage(im, TQClipboard::Clipboard);
    else
        TDEApplication::clipboard()->setImage(im.copy(0, 0, tab->parts[tab->current].w, tab->parts[tab->current].h), TQClipboard::Clipboard);
}

void SQ_GLWidget::bcg()
{
    if(tab->broken || tab->finfo.image.empty()) return;

    SQ_ImageBCG _bcg(this);

    stopAnimation();

    _bcg.setPreviewImage(generatePreview());

    connect(&_bcg, TQ_SIGNAL(bcg(SQ_ImageBCGOptions *)), this, TQ_SLOT(slotBCG(SQ_ImageBCGOptions *)));

    _bcg.exec();

    if(!manualBlocked())
        startAnimation();
}

void SQ_GLWidget::filter()
{
    if(tab->broken || tab->finfo.image.empty()) return;

    SQ_ImageFilter flt(this);

    stopAnimation();

    flt.setPreviewImage(generatePreview());

    connect(&flt, TQ_SIGNAL(filter(SQ_ImageFilterOptions *)), this, TQ_SLOT(slotFilter(SQ_ImageFilterOptions *)));

    flt.exec();

    if(!manualBlocked())
        startAnimation();
}

void SQ_GLWidget::slotFilter(SQ_ImageFilterOptions *filtopt)
{
    TQImage im((uchar *)tab->parts[tab->current].buffer->data(), tab->parts[tab->current].realw, tab->parts[tab->current].realh, 32, 0, 0, TQImage::LittleEndian);
    TQImage img = gls->valid() ? im.copy(tab->sx, tab->sy, tab->sw, tab->sh) : im;

    fmt_filters::image image =
        gls->valid() ? fmt_filters::image((unsigned char *)img.bits(), img.width(), img.height())
                     : fmt_filters::image((unsigned char *)img.bits(), tab->parts[tab->current].w, tab->parts[tab->current].h, img.width(), img.height());

    fmt_filters::rgba c = fmt_filters::white;

    switch(filtopt->type)
    {
        case F::fblend:      fmt_filters::blend(image, filtopt->rgb1, filtopt->_float); break;
        case F::fblur:       fmt_filters::blur(image, filtopt->_double1, filtopt->_double2);break;
        case F::fdesaturate: fmt_filters::desaturate(image, filtopt->_float); break;
        case F::fdespeckle:  fmt_filters::despeckle(image); break;
        case F::fedge:       fmt_filters::edge(image, filtopt->_double1); break;
        case F::femboss:     fmt_filters::emboss(image, filtopt->_double1, filtopt->_double2); break;
        case F::fequalize:   fmt_filters::equalize(image); break;
        case F::ffade:       fmt_filters::fade(image, filtopt->rgb1, filtopt->_float); break;
        case F::fflatten:    fmt_filters::flatten(image, filtopt->rgb1, filtopt->rgb2); break;
        case F::fimplode:    fmt_filters::implode(image, filtopt->_double1, c); break;
        case F::fnegative:   fmt_filters::negative(image); break;
        case F::fnoise:      fmt_filters::noise(image, (fmt_filters::NoiseType)filtopt->_uint); break;
        case F::foil:        fmt_filters::oil(image, filtopt->_double1); break;
        case F::fshade:      fmt_filters::shade(image, filtopt->_bool, filtopt->_double1, filtopt->_double2); break;
        case F::fsharpen:    fmt_filters::sharpen(image, filtopt->_double1, filtopt->_double2); break;
        case F::fsolarize:   fmt_filters::solarize(image, filtopt->_double1); break;
        case F::fspread:     fmt_filters::spread(image, filtopt->_uint); break;
        case F::fswapRGB:    fmt_filters::swapRGB(image, filtopt->_uint); break;
        case F::fswirl:      fmt_filters::swirl(image, filtopt->_double1, c); break;
        case F::fthreshold:  fmt_filters::threshold(image, filtopt->_uint); break;
        case F::fgray:       fmt_filters::gray(image); break;
        case F::fredeye:     fmt_filters::redeye(image, image.w, image.h, 0, 0, filtopt->_uint); break;
    }

    if(gls->valid()) bitBlt(&im, tab->sx, tab->sy, &img, 0, 0, img.width(), img.height());

    editUpdate();

    SQ_ImageFilter::instance()->setPreviewImage(generatePreview());
}

void SQ_GLWidget::slotBCG(SQ_ImageBCGOptions *bcgopt)
{
    TQImage im((uchar *)tab->parts[tab->current].buffer->data(), tab->parts[tab->current].realw, tab->parts[tab->current].realh, 32, 0, 0, TQImage::LittleEndian);
    TQImage img = gls->valid() ? im.copy(tab->sx, tab->sy, tab->sw, tab->sh) : im;

    fmt_filters::image image =
        gls->valid() ? fmt_filters::image((unsigned char *)img.bits(), img.width(), img.height())
                     : fmt_filters::image((unsigned char *)img.bits(), tab->parts[tab->current].w, tab->parts[tab->current].h, img.width(), img.height());
    if(bcgopt->b)
        fmt_filters::brightness(image, bcgopt->b);

    if(bcgopt->c)
        fmt_filters::contrast(image, bcgopt->c);

    if(bcgopt->g != 100)
        fmt_filters::gamma(image, (double)bcgopt->g / 100.0);

    if(bcgopt->red || bcgopt->green || bcgopt->blue)
        fmt_filters::colorize(image, bcgopt->red, bcgopt->green, bcgopt->blue);

    if(gls->valid()) bitBlt(&im, tab->sx, tab->sy, &img, 0, 0, img.width(), img.height());

    editUpdate();

    SQ_ImageBCG::instance()->setPreviewImage(generatePreview());
}

bool SQ_GLWidget::calcSelection()
{
    TQSize sz = gls->size();
    TQPoint pt = gls->pos();

    float z = getZoom();
    float x = pt.x(), y = pt.y(), w = sz.width(), h = sz.height();
    x = x - (float)width()/2 - MATRIX_X + (float)tab->parts[tab->current].w/2 * z;
    y = y - (float)height()/2 + MATRIX_Y + (float)tab->parts[tab->current].h/2 * z;

    int sx = (int)(x/z + 0.5);
    int sy = (int)(y/z + 0.5);
    int sw = (int)(w/z + 0.5);
    int sh = (int)(h/z + 0.5);

    if(!sw || !sh)
    {
        gls->end();
        return false;
    }
    else
    {
        if(SQ_GLHelpers::normalizeSelection(sx,
                                            sy,
                                            sw,
                                            sh,
                                            tab->parts[tab->current].w,
                                            tab->parts[tab->current].h,
                                            tab->wm,
                                            (int)tab->curangle,
                                            tab->orient))
        {
            tab->srect = TQRect(pt, sz);
            tab->sx = sx;
            tab->sy = sy;
            tab->sw = sw;
            tab->sh = sh;
        }
        else
            return false;
    }

    return true;
}

TQImage SQ_GLWidget::generatePreview()
{
    TQImage im((uchar *)tab->parts[tab->current].buffer->data(), tab->parts[tab->current].realw, tab->parts[tab->current].realh, 32, 0, 0, TQImage::LittleEndian);
    TQImage img, ret;

    if(gls->valid() && calcSelection())
        img = im.copy(tab->sx, tab->sy, tab->sw, tab->sh);
    else
    {
        if(tab->parts[tab->current].realw == tab->parts[tab->current].w && tab->parts[tab->current].realh == tab->parts[tab->current].h)
            img = im;
        else
            img = im.copy(0, 0, tab->parts[tab->current].w, tab->parts[tab->current].h);
    }

    ret = SQ_Utils::scaleImage((unsigned char *)img.bits(), img.width(), img.height(), 160).swapRGB();

    SQ_Utils::exifRotate(TQString(), ret, tab->orient);

    return ret;
}

void SQ_GLWidget::editUpdate()
{
    int tlsy = tab->parts[tab->current].tilesy.size();

    glDeleteLists(tab->parts[tab->current].m_parts[0].list, tlsy);

    for(int i = 0;i < tlsy;i++)
        showFrames(i, &tab->parts[tab->current], false);

    updateGL();
}

void SQ_GLWidget::slotShowNav()
{
#ifndef KSQUIRREL_PART
    KSquirrel::app()->activate();
#endif
}

void SQ_GLWidget::initAccelsAndMenu()
{
    TQPopupMenu *menuRotate = new TQPopupMenu(menu);
    TQPopupMenu *menuZoom = new TQPopupMenu(menu);
    TQPopupMenu *menuMove = new TQPopupMenu(menu);

#ifndef KSQUIRREL_PART
    TQPopupMenu *menuWindow = new TQPopupMenu(menu);
#endif

    menuImage = new TQPopupMenu(menu);
    menuFile = new TQPopupMenu(menu);

    menu->insertItem(SQ_IconLoader::instance()->loadIcon("icons", TDEIcon::Desktop, TDEIcon::SizeSmall), i18n("File"), menuFile);
    menu->insertItem(SQ_IconLoader::instance()->loadIcon("view_orientation", TDEIcon::Desktop, TDEIcon::SizeSmall), i18n("Rotate"), menuRotate);
    menu->insertItem(SQ_IconLoader::instance()->loadIcon("viewmag", TDEIcon::Desktop, TDEIcon::SizeSmall), i18n("Zoom"), menuZoom);
    menu->insertItem(i18n("Move"), menuMove);

#ifndef KSQUIRREL_PART
    menu->insertItem(i18n("Window"), menuWindow);
#endif

    menu->insertItem(i18n("Image"), menuImage);

#define SQ_ADD_KACTION(b) \
    (new TDEAction(TQString(), b, this, TQ_SLOT(slotAccelActivated()), ac, TQString::fromLatin1("action_%1").arg(b).utf8()))

    id_saveas = menuFile->insertItem(SQ_IconLoader::instance()->loadIcon("document-save-as", TDEIcon::Desktop, TDEIcon::SizeSmall), i18n("Save As...") + "\tS", SQ_ADD_KACTION(TQt::Key_S), TQ_SLOT(activate()));

#ifndef KSQUIRREL_PART
    menuFile->insertSeparator();
    menuFile->insertItem(TQPixmap(locate("data", "images/menu/next16.png")), i18n("Next") + "\tPageDown", SQ_ADD_KACTION(TQt::Key_PageDown), TQ_SLOT(activate()));
    menuFile->insertItem(TQPixmap(locate("data", "images/menu/prev16.png")), i18n("Previous") + "\tPageUp", SQ_ADD_KACTION(TQt::Key_PageUp), TQ_SLOT(activate()));
    menuFile->insertItem(TQPixmap(locate("data", "images/menu/first16.png")), i18n("First") + "\tHome", SQ_ADD_KACTION(TQt::Key_Home), TQ_SLOT(activate()));
    menuFile->insertItem(TQPixmap(locate("data", "images/menu/last16.png")), i18n("Last") + "\tEnd", SQ_ADD_KACTION(TQt::Key_End), TQ_SLOT(activate()));
#endif

    menuFile->insertSeparator();
    id_f5 = menuFile->insertItem(i18n("Copy to...") + "\tF5", SQ_ADD_KACTION(TQt::Key_F5), TQ_SLOT(activate()));
    id_f6 = menuFile->insertItem(i18n("Move to...") + "\tF6", SQ_ADD_KACTION(TQt::Key_F7), TQ_SLOT(activate()));
    id_f7 = menuFile->insertItem(i18n("Copy to last folder") + "\tF7", SQ_ADD_KACTION(TQt::Key_F6), TQ_SLOT(activate()));
    id_f8 = menuFile->insertItem(i18n("Move to last folder") + "\tF8", SQ_ADD_KACTION(TQt::Key_F8), TQ_SLOT(activate()));
    menuFile->insertSeparator();
    id_del = menuFile->insertItem(i18n("Delete") + "\tDelete", SQ_ADD_KACTION(TQt::Key_Delete), TQ_SLOT(activate()));

    menuRotate->insertItem(TQPixmap(locate("data", "images/menu/rotateLeft16.png")), i18n("Rotate left") + "\tCtrl+Left", SQ_ADD_KACTION(TQt::Key_Left+CTRL), TQ_SLOT(activate()));
    menuRotate->insertItem(TQPixmap(locate("data", "images/menu/rotateRight16.png")), i18n("Rotate right") + "\tCtrl+Right", SQ_ADD_KACTION(TQt::Key_Right+CTRL), TQ_SLOT(activate()));
    menuRotate->insertSeparator();
    menuRotate->insertItem(TQPixmap(locate("data", "images/menu/18016.png")), i18n("Rotate 180'") + "\tCtrl+Up", SQ_ADD_KACTION(TQt::Key_Up+CTRL), TQ_SLOT(activate()));
    menuRotate->insertSeparator();
    menuRotate->insertItem(i18n("Rotate 1' left") + "\tAlt+Left", SQ_ADD_KACTION(TQt::Key_Left+ALT), TQ_SLOT(activate()));
    menuRotate->insertItem(i18n("Rotate 1' right") + "\tAlt+Right", SQ_ADD_KACTION(TQt::Key_Right+ALT), TQ_SLOT(activate()));

    menuZoom->insertItem(TQPixmap(locate("data", "images/menu/zoom+16.png")), i18n("Zoom +") + "\t+", SQ_ADD_KACTION(TQt::Key_Plus), TQ_SLOT(activate()));
    menuZoom->insertItem(TQPixmap(locate("data", "images/menu/zoom-16.png")), i18n("Zoom -") + "\t-", SQ_ADD_KACTION(TQt::Key_Minus), TQ_SLOT(activate()));
    menuZoom->insertItem(i18n("Zoom 2x") + "\tCtrl++", SQ_ADD_KACTION(TQt::Key_Plus+CTRL), TQ_SLOT(activate()));
    menuZoom->insertItem(i18n("Zoom 1/2x") + "\tCtrl+-", SQ_ADD_KACTION(TQt::Key_Minus+CTRL), TQ_SLOT(activate()));
    menuZoom->insertSeparator();
    menuZoom->insertItem(TQPixmap(locate("data", "images/menu/zoom10016.png")), TQString::fromLatin1("100%") + "\t1", SQ_ADD_KACTION(TQt::Key_1), TQ_SLOT(activate()));
    menuZoom->insertItem(TQPixmap(locate("data", "images/menu/zoom20016.png")), TQString::fromLatin1("200%") + "\t2", SQ_ADD_KACTION(TQt::Key_2), TQ_SLOT(activate()));
    menuZoom->insertItem(TQPixmap(locate("data", "images/menu/zoom30016.png")), TQString::fromLatin1("300%") + "\t3", SQ_ADD_KACTION(TQt::Key_3), TQ_SLOT(activate()));
    menuZoom->insertItem(TQPixmap(locate("data", "images/menu/zoom50016.png")), TQString::fromLatin1("500%") + "\t5", SQ_ADD_KACTION(TQt::Key_5), TQ_SLOT(activate()));
    menuZoom->insertItem(TQPixmap(locate("data", "images/menu/zoom70016.png")), TQString::fromLatin1("700%") + "\t7", SQ_ADD_KACTION(TQt::Key_7), TQ_SLOT(activate()));
    menuZoom->insertItem(TQPixmap(locate("data", "images/menu/zoom90016.png")), TQString::fromLatin1("900%") + "\t9", SQ_ADD_KACTION(TQt::Key_9), TQ_SLOT(activate()));
    menuZoom->insertItem(TQPixmap(locate("data", "images/menu/zoom100016.png")), TQString::fromLatin1("1000%") + "\t0", SQ_ADD_KACTION(TQt::Key_0), TQ_SLOT(activate()));

    menuMove->insertItem(TQPixmap(locate("data", "images/menu/moveLeft16.png")), i18n("Move left") + "\tRight", SQ_ADD_KACTION(TQt::Key_Right), TQ_SLOT(activate()));
    menuMove->insertItem(TQPixmap(locate("data", "images/menu/moveRight16.png")), i18n("Move right") + "\tLeft", SQ_ADD_KACTION(TQt::Key_Left), TQ_SLOT(activate()));
    menuMove->insertItem(TQPixmap(locate("data", "images/menu/moveUp16.png")), i18n("Move up") + "\tDown", SQ_ADD_KACTION(TQt::Key_Down), TQ_SLOT(activate()));
    menuMove->insertItem(TQPixmap(locate("data", "images/menu/moveDown16.png")), i18n("Move down") + "\tUp", SQ_ADD_KACTION(TQt::Key_Up), TQ_SLOT(activate()));

    menuImage->insertItem(TQPixmap(locate("data", "images/menu/animate16.png")), i18n("Start/stop animation") + "\tA", SQ_ADD_KACTION(TQt::Key_A), TQ_SLOT(activate()));
    menuImage->insertItem(TQPixmap(locate("data", "images/menu/background16.png")), i18n("Hide/show background") + "\tB", SQ_ADD_KACTION(TQt::Key_B), TQ_SLOT(activate()));
    menuImage->insertItem(TQPixmap(locate("data", "images/menu/tickmarks16.png")), i18n("Hide/show tickmarks") + "\tK", SQ_ADD_KACTION(TQt::Key_K), TQ_SLOT(activate()));
    menuImage->insertSeparator();
    menuImage->insertItem(TQPixmap(locate("data", "images/menu/flipV16.png")), i18n("Flip vertically") + "\tV", SQ_ADD_KACTION(TQt::Key_V), TQ_SLOT(activate()));
    menuImage->insertItem(TQPixmap(locate("data", "images/menu/flipH16.png")), i18n("Flip horizontally") + "\tH", SQ_ADD_KACTION(TQt::Key_H), TQ_SLOT(activate()));
    menuImage->insertSeparator();
    menuImage->insertItem(TQPixmap(locate("data", "images/menu/page116.png")), i18n("First page") + "\tF1", SQ_ADD_KACTION(TQt::Key_F1), TQ_SLOT(activate()));
    menuImage->insertItem(TQPixmap(locate("data", "images/menu/page216.png")), i18n("Previous page") + "\tF2", SQ_ADD_KACTION(TQt::Key_F2), TQ_SLOT(activate()));
    menuImage->insertItem(TQPixmap(locate("data", "images/menu/page316.png")), i18n("Next page") + "\tF3", SQ_ADD_KACTION(TQt::Key_F3), TQ_SLOT(activate()));
    menuImage->insertItem(TQPixmap(locate("data", "images/menu/page416.png")), i18n("Last page") + "\tF4", SQ_ADD_KACTION(TQt::Key_F4), TQ_SLOT(activate()));
    menuImage->insertSeparator();
    menuImage->insertItem(i18n("Copy file url") + "\tF9", SQ_ADD_KACTION(TQt::Key_F9), TQ_SLOT(activate()));
    menuImage->insertItem(i18n("To clipboard") + "\tQ", SQ_ADD_KACTION(TQt::Key_Q), TQ_SLOT(activate()));
    menuImage->insertItem(i18n("Print") + "\tCtrl+P", SQ_ADD_KACTION(TQt::Key_P+CTRL), TQ_SLOT(activate()));
    menuImage->insertSeparator();
    id_settings = menuImage->insertItem(SQ_IconLoader::instance()->loadIcon("configure", TDEIcon::Desktop, TDEIcon::SizeSmall), i18n("Codec settings") + "\tC", SQ_ADD_KACTION(TQt::Key_C), TQ_SLOT(activate()));
    menuImage->setItemEnabled(id_settings, false);
    menuImage->insertSeparator();
    menuImage->insertItem(i18n("Color balance...") + "\tD", SQ_ADD_KACTION(TQt::Key_D), TQ_SLOT(activate()));
    menuImage->insertItem(i18n("Apply filter...") + "\tU", SQ_ADD_KACTION(TQt::Key_U), TQ_SLOT(activate()));

    menuImage->insertItem(i18n("Crop") + "\tY", SQ_ADD_KACTION(TQt::Key_Y), TQ_SLOT(activate()));

#ifndef KSQUIRREL_PART
    menuWindow->insertItem(TQPixmap(locate("data", "images/menu/fullscreen16.png")), i18n("Fullscreen") + "\tF", SQ_ADD_KACTION(TQt::Key_F), TQ_SLOT(activate()));
    menuWindow->insertSeparator();
    menuWindow->insertItem(i18n("Previous tab") + "\tShift+Left", SQ_ADD_KACTION(TQt::Key_Left+SHIFT), TQ_SLOT(activate()));
    menuWindow->insertItem(i18n("Next tab") + "\tShift+Right", SQ_ADD_KACTION(TQt::Key_Right+SHIFT), TQ_SLOT(activate()));
    menuWindow->insertSeparator();
    menuWindow->insertItem(i18n("Close tab") + "\tW", SQ_ADD_KACTION(TQt::Key_W), TQ_SLOT(activate()));

    menuWindow->insertItem(i18n("Close all tabs") + "\tCtrl+W", SQ_ADD_KACTION(TQt::Key_W+CTRL), TQ_SLOT(activate()));
#endif

    menu->insertSeparator();
    menu->insertItem(TQPixmap(locate("data", "images/menu/reset16.png")), i18n("Reset") + "\tR", SQ_ADD_KACTION(TQt::Key_R), TQ_SLOT(activate()));
    id_prop = menu->insertItem(TQPixmap(locate("data", "images/menu/prop16.png")), i18n("Properties") + "\tP", SQ_ADD_KACTION(TQt::Key_P), TQ_SLOT(activate()));
    menu->insertSeparator();
    menu->insertItem(i18n("Hotkeys") + "\t/", SQ_ADD_KACTION(TQt::Key_Slash), TQ_SLOT(activate()));

#ifndef KSQUIRREL_PART
    menu->insertSeparator();
    menu->insertItem(TQPixmap(locate("data", "images/menu/close16.png")), i18n("Close") + "\tX", SQ_ADD_KACTION(TQt::Key_X), TQ_SLOT(activate()));
#endif

    SQ_ADD_KACTION(TQt::Key_Down+CTRL);
    SQ_ADD_KACTION(TQt::Key_Equal);
    SQ_ADD_KACTION(TQt::Key_Equal+CTRL);
    SQ_ADD_KACTION(TQt::Key_N);
    SQ_ADD_KACTION(TQt::Key_Space);
    SQ_ADD_KACTION(TQt::Key_BackSpace);
    SQ_ADD_KACTION(TQt::Key_Escape);
    SQ_ADD_KACTION(TQt::Key_Return);
    SQ_ADD_KACTION(TQt::Key_Enter);
    SQ_ADD_KACTION(TQt::Key_Z);
    SQ_ADD_KACTION(TQt::Key_I);
    SQ_ADD_KACTION(TQt::Key_E);

#ifndef KSQUIRREL_PART
    SQ_ADD_KACTION(TQt::Key_R+CTRL);
    SQ_ADD_KACTION(TQt::Key_E+CTRL);
    SQ_ADD_KACTION(TQt::Key_C+CTRL);
#endif

    SQ_ADD_KACTION(TQt::Key_Menu);
    SQ_ADD_KACTION(TQt::Key_M);
    SQ_ADD_KACTION(TQt::Key_4);
    SQ_ADD_KACTION(TQt::Key_6);
    SQ_ADD_KACTION(TQt::Key_8);
    SQ_ADD_KACTION(TQt::Key_Comma);
    SQ_ADD_KACTION(TQt::Key_Period);
    SQ_ADD_KACTION(TQt::Key_Asterisk);
    SQ_ADD_KACTION(TQt::Key_L);
}


void SQ_GLWidget::slotAccelActivated()
{
    TDEAction *accel = static_cast<TDEAction *>(const_cast<TQObject *>(sender()));

    TDEShortcut ks = accel->shortcut();

         if(!ks.compare(TQt::Key_Left))        matrix_move(movefactor, 0);
    else if(!ks.compare(TQt::Key_Right))       matrix_move(-movefactor, 0);
    else if(!ks.compare(TQt::Key_Up))          matrix_move(0, -movefactor);
    else if(!ks.compare(TQt::Key_Down))        matrix_move(0, movefactor);
    else if(!ks.compare(TQt::Key_Equal) ||
            !ks.compare(TQt::Key_Plus))        slotZoomPlus();
    else if(!ks.compare(TQt::Key_Minus))       slotZoomMinus();
    else if(!ks.compare(TQt::Key_Equal+CTRL)  ||
            !ks.compare(TQt::Key_Plus+CTRL))   matrix_zoom(2.0f);
    else if(!ks.compare(TQt::Key_Minus+CTRL))  matrix_zoom(0.5f);
    else if(!ks.compare(TQt::Key_Q))           toClipboard();
    else if(!ks.compare(TQt::Key_V))           slotFlipV();
    else if(!ks.compare(TQt::Key_H))           slotFlipH();
    else if(!ks.compare(TQt::Key_Left+CTRL))   slotRotateLeft();
    else if(!ks.compare(TQt::Key_Right+CTRL))  slotRotateRight();
    else if(!ks.compare(TQt::Key_R))           slotMatrixReset();
    else if(!ks.compare(TQt::Key_Up+CTRL))     matrix_rotate(180.0f);
    else if(!ks.compare(TQt::Key_Down+CTRL))   matrix_rotate(-180.0f);
    else if(!ks.compare(TQt::Key_Left+ALT))    matrix_rotate(-1.0f);
    else if(!ks.compare(TQt::Key_Right+ALT))   matrix_rotate(1.0f);

#ifndef KSQUIRREL_PART
    else if(!ks.compare(TQt::Key_Left+SHIFT))  SQ_GLView::window()->leftTab();
    else if(!ks.compare(TQt::Key_Right+SHIFT)) SQ_GLView::window()->rightTab();
    else if(!ks.compare(TQt::Key_W))           slotCloseRequest(SQ_GLView::window()->tabbar()->indexOf(SQ_GLView::window()->tabbar()->currentTab()));
    else if(!ks.compare(TQt::Key_W+CTRL))      closeAllTabsFull();
#else
    else if(!ks.compare(TQt::Key_W))           closeAllTabsFull();
#endif

    else if(!ks.compare(TQt::Key_N))           updateFilter(!linear);
    else if(!ks.compare(TQt::Key_P))          slotProperties();
    else if(!ks.compare(TQt::Key_C))          slotShowCodecSettings();

#ifndef KSQUIRREL_PART
    else if(!ks.compare(TQt::Key_PageDown) ||
            !ks.compare(TQt::Key_Space))       slotNext();
    else if(!ks.compare(TQt::Key_PageUp) ||
            !ks.compare(TQt::Key_BackSpace))   slotPrev();
    else if(!ks.compare(TQt::Key_X)      ||
            !ks.compare(TQt::Key_Escape) ||
            !ks.compare(TQt::Key_Return) ||
            !ks.compare(TQt::Key_Enter))      KSquirrel::app()->closeGLWidget();
    else if(!ks.compare(TQt::Key_Home))       slotFirst();
    else if(!ks.compare(TQt::Key_End))        slotLast();
    else if(!ks.compare(TQt::Key_F))          toggleFullScreen();
#endif

    else if(!ks.compare(TQt::Key_Z))          slotZoomMenu();
    else if(!ks.compare(TQt::Key_S))          saveAs();
    else if(!ks.compare(TQt::Key_A))          slotToggleAnimate();
    else if(!ks.compare(TQt::Key_I))          slotShowImages();
    else if(!ks.compare(TQt::Key_F1))         jumpToImage(false);
    else if(!ks.compare(TQt::Key_F2))         prevImage();
    else if(!ks.compare(TQt::Key_F3))         nextImage();
    else if(!ks.compare(TQt::Key_F4))         jumpToImage(true);
    else if(!ks.compare(TQt::Key_F5) || !ks.compare(TQt::Key_F6))
    {
        // select a directory
        KURL url = KFileDialog::getExistingURL(lastCopy.prettyURL(), this);

        if(url.isEmpty())
            return;

        lastCopy = url;
        TDEIO::Job *job;

        if(!ks.compare(TQt::Key_F5))
            job = TDEIO::copy(tab->m_original, url);
        else
            job = TDEIO::move(tab->m_original, url);

        job->setWindow(this);
        connect(job, TQ_SIGNAL(result(TDEIO::Job *)), this, TQ_SLOT(slotCopyJobResult(TDEIO::Job *)));
    }
    else if(!ks.compare(TQt::Key_F7) || !ks.compare(TQt::Key_F8))
    {
        TDEIO::Job *job;

        if(!ks.compare(TQt::Key_F6))
            job = TDEIO::copy(tab->m_original, lastCopy);
        else
            job = TDEIO::move(tab->m_original, lastCopy);

        job->setWindow(this);
        connect(job, TQ_SIGNAL(result(TDEIO::Job *)), this, TQ_SLOT(slotCopyJobResult(TDEIO::Job *)));
    }
    else if(!ks.compare(TQt::Key_F9))         copyURL();
    else if(!ks.compare(TQt::Key_Slash))      slotShowHelp();
    else if(!ks.compare(TQt::Key_B))          toggleDrawingBackground();
    else if(!ks.compare(TQt::Key_K))          toogleTickmarks();
    else if(!ks.compare(TQt::Key_E))          showExternalTools();
    else if(!ks.compare(TQt::Key_Delete))     deleteWrapper();
    else if(!ks.compare(TQt::Key_D))          bcg();
    else if(!ks.compare(TQt::Key_U))          filter();
    else if(!ks.compare(TQt::Key_Y))          crop();

#ifndef KSQUIRREL_PART
    else if(!ks.compare(TQt::Key_R+CTRL))          slotSelectionRect();
    else if(!ks.compare(TQt::Key_E+CTRL))          slotSelectionEllipse();
    else if(!ks.compare(TQt::Key_C+CTRL))          slotSelectionClear();
#endif

    else if(!ks.compare(TQt::Key_P+CTRL))          slotPrint();
    else if(!ks.compare(TQt::Key_Menu) ||
            !ks.compare(TQt::Key_M))          menu->exec(TQCursor::pos());
    else if(!ks.compare(TQt::Key_Comma))      slotZoomW();
    else if(!ks.compare(TQt::Key_Period))     slotZoomH();
    else if(!ks.compare(TQt::Key_Asterisk))   slotZoomWH();
    else if(!ks.compare(TQt::Key_L))
    {
        bool b = pAIfLess->isChecked();
        pAIfLess->setChecked(!b);
        slotZoomIfLess();
    }
    else
    {
        int val = -1;

             if(!ks.compare(TQt::Key_1)) val = 1;
        else if(!ks.compare(TQt::Key_2)) val = 2;
        else if(!ks.compare(TQt::Key_3)) val = 3;
        else if(!ks.compare(TQt::Key_4)) val = 4;
        else if(!ks.compare(TQt::Key_5)) val = 5;
        else if(!ks.compare(TQt::Key_6)) val = 6;
        else if(!ks.compare(TQt::Key_7)) val = 7;
        else if(!ks.compare(TQt::Key_8)) val = 8;
        else if(!ks.compare(TQt::Key_9)) val = 9;
        else if(!ks.compare(TQt::Key_0)) val = 10;

        if(val != -1)
        {
            if(tab->broken || tab->finfo.image.empty())
                return;

            zoom(val);
        }
    }
}

void SQ_GLWidget::zoom(GLfloat val)
{
    oldZoom = getZoom();
    matrix_reset(false);
    matrix_zoom(val);
}

void SQ_GLWidget::slotCopyJobResult(TDEIO::Job *job)
{
    if(job->error())
        job->showErrorDialog(this);
}

void SQ_GLWidget::exifRotate(bool U)
{
#ifdef SQ_HAVE_KEXIF
    switch(tab->orient)
    {
        // flipping
        case KExifData::HFLIP: tab->isflippedH = !tab->isflippedH; flip(0, U); break;
        case KExifData::VFLIP: tab->isflippedV = !tab->isflippedV; flip(4, U); break;

        // rotating
        case KExifData::ROT_90:  matrix_rotate(90, U);  break;
        case KExifData::ROT_180: matrix_rotate(180, U); break;
        case KExifData::ROT_270: matrix_rotate(270, U); break;

        // flipping & rotating
        case KExifData::ROT_90_HFLIP: tab->isflippedH = !tab->isflippedH; flip(0, false); matrix_rotate(90, U); break;
        case KExifData::ROT_90_VFLIP: tab->isflippedV = !tab->isflippedV; flip(4, false); matrix_rotate(90, U); break;

        // normal rotation or unspecified
        default: if(U) updateGL();
    }
#else
    if(U)
        updateGL();
#endif
}

void SQ_GLWidget::enableActions(bool U)
{
#ifndef KSQUIRREL_PART
    pASelectionRect->setEnabled(U);
    pASelectionEllipse->setEnabled(U);
    pASelectionClear->setEnabled(U);
    pAToolProp->setEnabled(U);
    pAToolPrint->setEnabled(U);
#endif

    menuFile->setItemEnabled(id_f5, U);
    menuFile->setItemEnabled(id_f6, U);
    menuFile->setItemEnabled(id_f7, U);
    menuFile->setItemEnabled(id_f8, U);
    menuFile->setItemEnabled(id_del, U);
    menuFile->setItemEnabled(id_saveas, U);

    menu->setItemEnabled(id_prop, U);

    menuImage->setEnabled(U);
}

void SQ_GLWidget::crop()
{
    if(tab->broken
        || tab->finfo.image.empty()
        || !gls->valid()
        || !calcSelection()
        || (tab->sw == tab->parts[tab->current].w && tab->sh == tab->parts[tab->current].h))
        return;

    const int RW = tab->parts[tab->current].realw;
    RGBA *img = tab->parts[tab->current].buffer->data() + tab->sy * RW + tab->sx;

    Parts pp;
    memoryPart *pt;

    SQ_GLWidget::findCloserTiles(tab->sw, tab->sh, pp.tilesx, pp.tilesy);
    TQPair<int, int> pair = SQ_GLWidget::calcRealDimensions(pp);
    pp.realw = pair.first;
    pp.realh = pair.second;
    pp.w = tab->sw;
    pp.h = tab->sh;

    if(!pp.makeParts())
    {
        KMessageBox::error(this,
                    i18n("Memory allocation failed for %1 of memory")
                    .arg(TDEIO::convertSize(pp.realw * pp.realh * sizeof(RGBA))));
        return;
    }

    pt = new memoryPart(pp.realw * pp.realh);
    pt->create();

    if(!pt->valid())
    {
        pp.removeParts();
        return;
    }

    memset(pt->data(), 0, pp.realw * pp.realh * sizeof(RGBA));

    for(int i = 0;i < tab->sh;i++)
        memcpy(pt->data()+i*pp.realw, img + i*RW, tab->sw * sizeof(RGBA));

    pp.computeCoords();
    pp.buffer = pt;

    tab->parts[tab->current].removeParts();
    tab->parts[tab->current].deleteBuffer();
    tab->finfo.image[tab->current].w = tab->sw;
    tab->finfo.image[tab->current].h = tab->sh;

    int tlsy = pp.tilesy.size();
    for(int i = 0;i < tlsy;i++)
        showFrames(i, &pp, false);

    tab->parts[tab->current] = pp;

    slotSelectionClear();
    updateCurrentFileInfo();
    tab->isflippedH = tab->isflippedV = false;
    slotZoomIfLess();
    matrixChanged();
}

void SQ_GLWidget::slotChangeTab(int id)
{
#ifndef KSQUIRREL_PART
    id = SQ_GLView::window()->tabbar()->indexOf(id);

    Tab *newtab = (id == -1) ? &taborig : &tabs[id];

    if(tab == newtab)
        return;

    if(tab)
    {
        tab->removeParts();
        gls->setVisible(false);
    }

    tab = newtab;

    images->clear();
    old_id = -1;
    stopAnimation();

    enableSettingsButton(id != -1 && tab->lib && !tab->lib->config.isEmpty());
    enableActions(!tab->broken && id != -1);

    if(id == -1)
    {
        SQ_GLView::window()->resetStatusBar();
        KSquirrel::app()->setCaption(TQString());
        decoded = false;
        changeSlider(1.0);
    }
    else
    {
        changeSlider();
        KSquirrel::app()->setCaption(originalURL());
        enableActions(!tab->broken);

        if(!tab->broken)
        {
            SQ_GLView::window()->sbarWidget("SBDecodedI")->setPixmap(tab->lib->mime);

            // fill menu
            std::vector<fmt_image>::iterator itEnd = tab->finfo.image.end();
            std::vector<fmt_image>::iterator it = tab->finfo.image.begin();
            int mid, i = 0, first_id = 0;

            for(;it != itEnd;++it, ++i)
            {
                mid = images->insertItem(TQString::fromLatin1("#%1 [%2x%3@%4]").arg(i+1).arg((*it).w).arg((*it).h).arg((*it).bpp));
                images->setItemParameter(mid, i);

                if(i == tab->current)
                    old_id = first_id = mid;
            }

            images->setItemChecked(first_id, true);
            updateCurrentFileInfo();
            frameChanged();

#ifndef KSQUIRREL_PART
            SQ_GLView::window()->sbarWidget("SBFile")->setText(tab->m_original.fileName(false));
            SQ_GLView::window()->sbarWidget("SBLoaded")->setText(TDEGlobal::locale()->formatLong(tab->elapsed) + i18n(" ms."));
#else
            t_glv.sbarWidget("SBFile")->setText(tab->m_original.fileName(false));
            t_glv.sbarWidget("SBLoaded")->setText(TDEGlobal::locale()->formatLong(tab->elapsed) + i18n(" ms."));
#endif
        }
        else
            SQ_GLView::window()->resetStatusBar();

        std::vector<Parts>::iterator itp = tab->parts.begin();
        std::vector<Parts>::iterator itpEnd = tab->parts.end();
        int tlsy;

        tab->remakeParts();

        if(tab->glselection != -1)
        {
            if(!gls->valid())
                gls->begin(static_cast<SQ_GLSelectionPainter::Type>(tab->glselection), 0, 0, false);

            gls->setGeometry(tab->srect);
        }
        else
            gls->end();

        gls->setVisible(tab->glselection != -1);

        for(;itp != itpEnd;++itp)
        {
            tlsy = (*itp).tilesy.size();

            for(int i = 0;i < tlsy;i++)
                showFrames(i, &(*itp), false);
        }

        if(!manualBlocked())
            startAnimation();
    }

    matrixChanged();
    updateGL();
#endif
}

void SQ_GLWidget::slotCloseRequest(int index)
{
#ifndef KSQUIRREL_PART
    if(index < 0)
        return;

    SQ_GLView::window()->tabbar()->blockSignals(true);

    // prevent matrix from changing. When tab count == 1,
    // SQ_GLView will hide tabbar and SQ_GLWIdget will be resized.
    // We don't want it.
    if(SQ_GLView::window()->tabbar()->count() == 2)
        hackResizeGL = true;

    SQ_GLView::window()->removePage(index);
    emit tabCountChanged();
    SQ_GLView::window()->tabbar()->blockSignals(false);

    // workaround bug in KTabBar
    TQMouseEvent ev(TQEvent::MouseMove,
                        TQCursor::pos(),
                        SQ_GLView::window()->tabbar()->mapFromGlobal(TQCursor::pos()),
                        TQt::NoButton,
                        TQt::NoButton);

    TDEApplication::sendEvent(SQ_GLView::window()->tabbar(), &ev);

    std::vector<Tab>::iterator itEnd = tabs.end();
    std::vector<Tab>::iterator it = tabs.begin();
    int i = 0;

    for(;(it != itEnd && i != index);++it, ++i)
        ;

    (*it).clearParts();
    tabs.erase(it);
    tab = 0;

    gls->setVisible(false);

    slotChangeTab(SQ_GLView::window()->tabbar()->currentTab());
#endif
}

void SQ_GLWidget::initBrokenImage()
{
    memoryPart *pt;
    TQImage broken = TQPixmap(file_broken_xpm).convertToImage().swapRGB();
    broken.setAlphaBuffer(true);

    parts_broken = new Parts;

    // setup parts_broken. It will have only one 64x64 tile
    parts_broken->tilesx.push_back(broken.width());
    parts_broken->tilesy.push_back(broken.height());
    parts_broken->realw = broken.width();
    parts_broken->realh = broken.height();
    parts_broken->w = broken.width();
    parts_broken->h = broken.height();
    parts_broken->makeParts();
    parts_broken->computeCoords();

    pt = new memoryPart(broken.width() * broken.width());
    pt->create();

    memcpy(pt->data(), broken.bits(), broken.numBytes());

    parts_broken->buffer = pt;

    showFrames(0, parts_broken, false);

    image_broken.w = parts_broken->w;
    image_broken.h = parts_broken->h;
    image_broken.bpp = broken.depth();
    image_broken.compression = "-";
    image_broken.colorspace = "RGBA";
    image_broken.hasalpha = false;

    // we don't need memory buffer any more...
    parts_broken->deleteBuffer();
}

// Accept drop events.
void SQ_GLWidget::dropEvent(TQDropEvent *e)
{
    TQStringList files;

    if(TQUriDrag::decodeLocalFiles(e, files))
    {
        // go through array and find first supported image format
        for(TQStringList::iterator it = files.begin();it != files.end();++it)
        {
            if(SQ_LibraryHandler::instance()->libraryForFile(*it))
            {
                KURL u = KURL::fromPathOrURL(*it);
                m_expected = u;
                m_original = u;
                startDecoding(u);
                break;
            }
        }
    }
}

// Accept drag events.
void SQ_GLWidget::dragEnterEvent(TQDragEnterEvent *e)
{
    e->accept(TQUriDrag::canDecode(e));
}

/*
 *  Set clear color for context.
 */
void SQ_GLWidget::setClearColor()
{
    TQColor color;
    TQString path;

    SQ_Config::instance()->setGroup("GL view");

    switch(SQ_Config::instance()->readNumEntry("GL view background type", 1))
    {
        // system color
        case 0:
            color = colorGroup().color(TQColorGroup::Base);
        break;

        // custom color
        case 1:
            color.setNamedColor(SQ_Config::instance()->readEntry("GL view background", "#4e4e4e"));
        break;

        // repeated texture
        case 2:
            path = SQ_Config::instance()->readEntry("GL view custom texture", "");
            BGpixmap.load(path);

            if(BGpixmap.isNull())
            {
                SQ_Config::instance()->writeEntry("GL view background type", 0);
                setClearColor();
                return;
            }

            BGpixmap.convertDepth(32);
            BGpixmap = BGpixmap.swapRGB();

            changed = true;
        break;

        default: ;
    }

    // update clear color
    qglClearColor(color);

    if(decoded)
        updateGL();
}

void SQ_GLWidget::removeCurrentParts()
{
    // if tab->broken, 'tab->parts' has no members
    if(decoded && !tab->broken)
    {
        std::vector<Parts>::iterator itEnd = tab->parts.end();

        for(std::vector<Parts>::iterator it = tab->parts.begin();it != itEnd;++it)
        {
            // delete textures and memory buffers
            (*it).removeParts();
            (*it).deleteBuffer();
        }

        tab->parts.clear();
    }
}

void SQ_GLWidget::removeCurrentTabs()
{
    std::vector<Tab>::iterator itEnd = tabs.end();

    for(std::vector<Tab>::iterator it = tabs.begin();it != itEnd;++it)
        (*it).clearParts();

    tabs.clear();
    tab = &taborig;
}

void SQ_GLWidget::removeNonCurrentTabs(int index)
{
    std::vector<Tab>::iterator itEnd = tabs.end();
    Tab tm;
    int i = 0;

    for(std::vector<Tab>::iterator it = tabs.begin();it != itEnd;++it, ++i)
    {
        if(i == index)
        {
            tm = *it;
            continue;
        }

        (*it).clearParts();
    }

    tabs.clear();
    tabs.push_back(tm);
    tab = &tabs[0];
}

void SQ_GLWidget::startDecoding(const KURL &url)
{
    startDecoding(url.path());
}

// Show/hide background for transparent image.
void SQ_GLWidget::toggleDrawingBackground()
{
    SQ_Config::instance()->setGroup("GL view");

    bool b = SQ_Config::instance()->readBoolEntry("alpha_bkgr", true);

    b = !b;

    SQ_Config::instance()->writeEntry("alpha_bkgr", b);

    updateGL();
}

void SQ_GLWidget::createMarks()
{
    mm[0] = TQImage(locate("data", "images/marks/mark_1.png"));
    mm[1] = TQImage(locate("data", "images/marks/mark_2.png"));
    mm[2] = TQImage(locate("data", "images/marks/mark_3.png"));
    mm[3] = TQImage(locate("data", "images/marks/mark_4.png"));

    marks = (mm[0].isNull() || mm[1].isNull() || mm[2].isNull() || mm[3].isNull()) ? false : true;

    if(!marks)
        return;

    for(int i = 0;i < 4;i++)
    {
        mm[i] = mm[i].convertDepth(32);
        mm[i].setAlphaBuffer(true);
    }
}

/*
 *  Show current image's width, height and bpp in statusbar.
 */
void SQ_GLWidget::updateCurrentFileInfo()
{
    TQString status = TQString::fromLatin1("%1x%2@%3")
    .arg(tab->finfo.image[tab->current].w)
    .arg(tab->finfo.image[tab->current].h)
    .arg(tab->finfo.image[tab->current].bpp);

#ifndef KSQUIRREL_PART
    SQ_GLView::window()->sbarWidget("SBDecoded")->setText(status);
#else
    t_glv.sbarWidget("SBDecoded")->setText(status);
#endif
}

// Show/hide tickmarks around the image.
void SQ_GLWidget::toogleTickmarks()
{
    SQ_Config::instance()->setGroup("GL view");

    bool b = SQ_Config::instance()->readBoolEntry("marks", true);

    b = !b;

    SQ_Config::instance()->writeEntry("marks", b);

    updateGL();
}

void SQ_GLWidget::changeSlider(GLfloat z1)
{
#ifndef KSQUIRREL_PART
    GLfloat z = z1 < 0 ? getZoom() : z1;

    int i_zoom = (int)(z * 100);

    slider_zoom->blockSignals(true);
    slider_zoom->setValue((i_zoom <= 100) ? i_zoom/5 : (19+i_zoom/50));
    slider_zoom->blockSignals(false);
#endif
}

void SQ_GLWidget::calcFrameLabelWidth()
{
#ifndef KSQUIRREL_PART
    SQ_GLView::window()->sbarWidget("SBFrame")->setFixedWidth(
            SQ_GLView::window()->sbarWidget("SBFrame")->fontMetrics()
            .boundingRect(TQString::fromLatin1("0%1/0%2").arg(tab->total).arg(tab->total)).width());
#endif
}

/*
 *  Show current page number in multipaged images.
 *
 *  For example: "3/11" means that current page is the third in current image,
 *  which has 11 pages.
 */
void SQ_GLWidget::frameChanged()
{
#ifndef KSQUIRREL_PART
    SQ_GLView::window()->sbarWidget("SBFrame")->setText(TQString::fromLatin1("%1/%2").arg(tab->current+1).arg(tab->total));
#else
    t_glv.sbarWidget("SBFrame")->setText(TQString::fromLatin1("%1/%2").arg(tab->current+1).arg(tab->total));
#endif
}

void SQ_GLWidget::closeAllTabs()
{
    removeCurrentTabs();

#ifndef KSQUIRREL_PART
    SQ_GLView::window()->removeTabs();
#endif
}

void SQ_GLWidget::closeAllTabsFull()
{
    stopAnimation();

    closeAllTabs();

#ifndef KSQUIRREL_PART
    SQ_GLView::window()->resetStatusBar();
    SQ_GLView::window()->tabbar()->hide();

    KSquirrel::app()->setCaption(TQString());
#endif

    decoded = false;
    m_original = KURL();
    m_expected = KURL();

    images->clear();
    old_id = -1;

    enableSettingsButton(false);
    enableActions(false);
    changeSlider(1.0);

    updateGL();
}

void SQ_GLWidget::slotPrint()
{
    if(!decoded || tab->broken)
        return;

    TQImage im((uchar *)tab->parts[tab->current].buffer->data(), tab->parts[tab->current].realw, tab->parts[tab->current].realh, 32, 0, 0, TQImage::LittleEndian);
    TQImage img;

    if(gls->valid() && calcSelection())
        img = TQImage(im.copy(tab->sx, tab->sy, tab->sw, tab->sh)).swapRGB();
    else
    {
        if(tab->parts[tab->current].realw == tab->parts[tab->current].w && tab->parts[tab->current].realh == tab->parts[tab->current].h)
            img = im.swapRGB();
        else
            img = TQImage(im.copy(0, 0, tab->parts[tab->current].w, tab->parts[tab->current].h)).swapRGB();
    }

    img.setAlphaBuffer(true);

    KPrinter printer;

    printer.setCreator("KSquirrel");

    if(printer.setup(this))
    {
        TQPainter p(&printer);

        TQPaintDeviceMetrics mt(&printer);

        TQSize sz(img.width(), img.height());

        if(img.width() > mt.width() || img.height() > mt.height())
            sz.scale(mt.width(), mt.height(), TQSize::ScaleMin);

        int cp = printer.numCopies();

        for(int i = 0;i < cp;i++)
        {
            p.drawImage(TQRect((mt.width()-sz.width())/2, (mt.height()-sz.height())/2, sz.width(), sz.height()), img);

            if(i < cp-1)
                printer.newPage();
        }
    }
}

void SQ_GLWidget::copyURL()
{
    if(!decoded || tab->broken)
        return;

    TQApplication::clipboard()->setText(tab->m_original.prettyURL());
}
