/*
 *
 * This file is part of the KDE project, module tdefile.
 * Copyright (C) 2006 Luke Sandell <lasandell@gmail.com>
 *           (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
 *           (C) 2000 Geert Jansen <jansen@kde.org>
 *           (C) 2000 Kurt Granroth <granroth@kde.org>
 *           (C) 1997 Christoph Neerfeld <chris@kde.org>
 *
 * This is free software; it comes under the GNU Library General
 * Public License, version 2. See the file "COPYING.LIB" for the
 * exact licensing terms.
 */

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

#include "kiconcanvas.h"
#include "kicondialog.h"

#include <kiconviewsearchline.h>

#include <tdeapplication.h>
#include <kdebug.h>
#include <tdelocale.h>
#include <tdeglobal.h>
#include <tdestandarddirs.h>
#include <kiconloader.h>
#include <kimagefilepreview.h>
#include <kurldrag.h>
#include <tdemultipledrag.h>

#include <tqimage.h>
#include <tqpixmap.h>
#include <tqtimer.h>
#include <tqfileinfo.h>
#include <tqdragobject.h>
#include <cmath>
#include <math.h>
#include <algorithm>

#ifdef HAVE_LIBART
#include <ksvgiconengine.h>
#endif

class TDEIconCanvasItem : public TQIconViewItem
{
  public:
    TDEIconCanvasItem ( TQIconView * parent, const TQString & key, const TQPixmap & pixmap )
        : TQIconViewItem(parent)
    {
        setText(TQFileInfo(key).baseName());
        setKey(key);
        setPixmap(pixmap);
        setDragEnabled(true);
        setDropEnabled(false);

    }

    int compare(TQIconViewItem *rhs) const
    {
        return TQString::localeAwareCompare(text().lower(), rhs->text().lower());
    }
};

class TDEIconCanvas::TDEIconCanvasPrivate
{
  public:
    TDEIconCanvasPrivate()
    {
        m_bLoading = false;
        mSize = 0;
    }
    ~TDEIconCanvasPrivate()
    {
    }
    bool m_bLoading;
    TQString mSetCurrent;
    int mSize;
#ifdef HAVE_LIBART
    KSVGIconEngine mSvgEngine;
#endif
    bool mStrictIconSize;
};

/*
 * TDEIconCanvas: Iconview for the iconloader dialog.
 */

TDEIconCanvas::TDEIconCanvas(TQWidget *parent, const char *name)
    : TDEIconView(parent, name)
{
    d = new TDEIconCanvasPrivate;
    mpLoader = TDEGlobal::iconLoader();
    mpTimer = new TQTimer(this);
    connect(mpTimer, TQ_SIGNAL(timeout()), TQ_SLOT(slotLoadFiles()));
    connect(this, TQ_SIGNAL(currentChanged(TQIconViewItem *)),
	    TQ_SLOT(slotCurrentChanged(TQIconViewItem *)));
    setAcceptDrops(false);
    setShowToolTips(true);
    setStrictIconSize(false);
}

TDEIconCanvas::~TDEIconCanvas()
{
    delete mpTimer;
    delete d;
}

void TDEIconCanvas::setIconLoader(TDEIconLoader *loader)
{
    mpLoader = loader;
}

void TDEIconCanvas::loadIcon(const TQString &name)
{
    TQImage img;
    TQString path = mpLoader->iconPath(name,-d->mSize);
    // Use the extension as the format. Works for XPM and PNG, but not for SVG
    TQString ext = path.right(3).upper();
    int maxSize = std::min(d->mSize, 60);

    if (ext != "SVG" && ext != "VGZ")
        img.load(path);
#ifdef HAVE_LIBART
   else
       if (d->mSvgEngine.load(maxSize, maxSize, path))
        img = *d->mSvgEngine.image();
#endif

   if (img.isNull())
       return;

   // For non-KDE icons
   if (d->mStrictIconSize && (img.width() != d->mSize || img.height() != d->mSize))
       return;

   if (img.width() > maxSize || img.height() > maxSize)
   {
       if (img.width() > img.height()) {
           int height = (int) ((float(maxSize) / img.width()) * img.height());
           img = img.smoothScale(maxSize, height);
       } else {
           int width = (int) ((float(maxSize) / img.height()) * img.width());
           img = img.smoothScale(width, maxSize);
       }
   }
   TQPixmap pm;
   pm.convertFromImage(img);

   (void) new TDEIconCanvasItem(this, name, pm);
}

void TDEIconCanvas::loadFiles(const TQStringList& files)
{
    clear();
    mFiles = files;
    emit startLoading(mFiles.count());
    mpTimer->start(10, true); // #86680
    d->m_bLoading = false;
}

void TDEIconCanvas::slotLoadFiles()
{
    setResizeMode(Fixed);
    TQApplication::setOverrideCursor(waitCursor);

    // disable updates to not trigger paint events when adding child items
    setUpdatesEnabled( false );

    d->m_bLoading = true;
    int count;
    TQStringList::ConstIterator it;
    TQStringList::ConstIterator end(mFiles.end());
    for (it=mFiles.begin(), count=0; it!=end; ++it, count++)
    {
        loadIcon(*it);

        // Calling tdeApp->processEvents() makes the iconview flicker like hell
        // (it's being repainted once for every new item), so we don't do this.
        // Instead, we directly repaint the progress bar without going through
        // the event-loop. We do that just once for every 10th item so that
        // the progress bar doesn't flicker in turn. (pfeiffer)
        // FIXME: TQt4 will have double buffering
        if ( count % 10 == 0) {
            emit progress(count);
        }
        if ( !d->m_bLoading ) // user clicked on a button that will load another set of icons
            break;
    }

    // enable updates since we have to draw the whole view now
    sort();
    d->m_bLoading = false;
    setUpdatesEnabled( true );
    TQApplication::restoreOverrideCursor();
    emit finished();
    setResizeMode(Adjust);
}

TQString TDEIconCanvas::getCurrent() const
{
   return currentItem() ? currentItem()->key() : TQString();
}

void TDEIconCanvas::stopLoading()
{
    d->m_bLoading = false;
}

void TDEIconCanvas::slotCurrentChanged(TQIconViewItem *item)
{
    emit nameChanged((item != 0L) ? item->text() : TQString());
}

void TDEIconCanvas::setGroupOrSize( int groupOrSize )
{
    d->mSize = ((int)groupOrSize >= 0) ?
            mpLoader->currentSize((TDEIcon::Group)groupOrSize) :
            -groupOrSize;
}

void TDEIconCanvas::setStrictIconSize( bool strictIconSize )
{
    d->mStrictIconSize = strictIconSize;
}

TQDragObject *TDEIconCanvas::dragObject()
{
    // We use TQImageDrag rather than KURLDrag so that the user can't drag an icon out of the theme!
    // TODO: support SVG?
    TQPixmap *pixmap = currentItem()->pixmap();
    TQPoint pos = viewportToContents( viewport()->mapFromGlobal( TQCursor::pos() ) );
    TQPoint hot;
    hot.setX(pos.x() - currentItem()->pos().x() - (currentItem()->width() - pixmap->width()) / 2);
    hot.setY(pos.y() - currentItem()->pos().y() - (currentItem()->height() - pixmap->height()) / 2);
    TQImageDrag *drag = new TQImageDrag( pixmap->convertToImage(), this );
    drag->setPixmap(*pixmap, hot);
    return drag;
}

#include "kiconcanvas.moc"
