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

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

#include <config.h>

#include <kiconviewsearchline.h>

#include <kdebug.h>
#include <tdeapplication.h>
#include <tdelocale.h>
#include <tdeglobal.h>
#include <tdestandarddirs.h>
#include <kiconloader.h>
#include <kprogress.h>
#include <kiconview.h>
#include <tdefiledialog.h>
#include <kimagefilepreview.h>
#include <kpushbutton.h>
#include <tdemessagebox.h>

#include <tqstring.h>
#include <tqstringlist.h>
#include <tqimage.h>
#include <tqpixmap.h>
#include <tqlabel.h>
#include <tqcombobox.h>
#include <tqtimer.h>
#include <tqbuttongroup.h>
#include <tqradiobutton.h>
#include <tqfileinfo.h>
#include <tqtoolbutton.h>
#include <tqwhatsthis.h>
#include <tqhbuttongroup.h>
#include <tqdragobject.h>

/* NOTE: Must be in the same order as listbox */
enum ExtendedContext
{
    ALL = 0,
    RECENT = 1,
    // Action thru MimeType, subtract 1 to convert to TDEIcon::Context
    OTHER = 7
};

class TDEIconDialog::TDEIconDialogPrivate
{
  public:
    TDEIconDialogPrivate() {
       	m_bStrictIconSize = true;
    }
    ~TDEIconDialogPrivate() {}
    bool m_bStrictIconSize;
    TQString custom;
    TQString customLocation;
    int recentMax;
    TQStringList recentList;
    ExtendedContext extendedContext;
    TDEIconDialogUI *ui; /* FIXME: KDE4 probably move this to the main class */
};

/*
 * TDEIconDialog: Dialog for selecting icons. Both system and user
 * specified icons can be chosen.
 */

TDEIconDialog::TDEIconDialog(TQWidget *parent, const char*)
    : KDialogBase(parent, "IconDialog", true, i18n("Select Icon"), Ok|Cancel, Ok)
{
    d = new TDEIconDialogPrivate;
    mpLoader = TDEGlobal::iconLoader();
    init();
    resize(minimumSize());
}

TDEIconDialog::TDEIconDialog(TDEIconLoader *loader, TQWidget *parent,
	const char *name)
    : KDialogBase(parent, name, true, i18n("Select Icon"), Ok|Cancel, Ok)
{
    d = new TDEIconDialogPrivate;
    mpLoader = loader;
    init();
}

void TDEIconDialog::init()
{
    mGroupOrSize = TDEIcon::Desktop;
    d->extendedContext = ALL;
    mType = 0;
    setCustomLocation(TQString()); // Initialize mFileList

    // Read configuration
    TDEConfig *config = TDEGlobal::config();
    TDEConfigGroupSaver saver(config, "TDEIconDialog");
    d->recentMax = config->readNumEntry("RecentMax", 10);
    d->recentList = config->readPathListEntry("RecentIcons");

    d->ui = new TDEIconDialogUI( this );
    setMainWidget(d->ui);

    d->ui->searchLine->setIconView(d->ui->iconCanvas);
    d->ui->searchLine->setCaseSensitive(false);

    // Hack standard Gui item, as KDevDesigner won't let us
    d->ui->browseButton->setText(i18n("&Browse..."));

    connect(d->ui->browseButton, TQ_SIGNAL(clicked()), TQ_SLOT(slotBrowse()));
    connect(d->ui->listBox, TQ_SIGNAL(highlighted(int)), TQ_SLOT(slotContext(int)));
    connect(d->ui->iconCanvas, TQ_SIGNAL(executed(TQIconViewItem *)), TQ_SLOT(slotOk()));
    connect(d->ui->iconCanvas, TQ_SIGNAL(returnPressed(TQIconViewItem *)), TQ_SLOT(slotOk()));
    connect(d->ui->iconCanvas, TQ_SIGNAL(startLoading(int)), TQ_SLOT(slotStartLoading(int)));
    connect(d->ui->iconCanvas, TQ_SIGNAL(progress(int)), TQ_SLOT(slotProgress(int)));
    connect(d->ui->iconCanvas, TQ_SIGNAL(finished()), TQ_SLOT(slotFinished()));
    connect(this, TQ_SIGNAL(hidden()), d->ui->iconCanvas, TQ_SLOT(stopLoading()));

    // NOTE: this must be consistent with the IconType enum (see above)
    d->ui->listBox->insertItem(i18n("(All Icons)"));
    d->ui->listBox->insertItem(i18n("(Recent)"));
    d->ui->listBox->insertItem(i18n("Actions"));
    d->ui->listBox->insertItem(i18n("Applications"));
    d->ui->listBox->insertItem(i18n("Devices"));
    d->ui->listBox->insertItem(i18n("Filesystem"));
    d->ui->listBox->insertItem(i18n("File Types"));
    d->ui->listBox->insertItem(i18n("Miscellaneous"));
}

TDEIconDialog::~TDEIconDialog()
{
    // Write configuration
    TDEConfig *config = TDEGlobal::config();
    TDEConfigGroupSaver saver(config, "TDEIconDialog");
    config->writeEntry("RecentMax", d->recentMax, true, true);
    config->writePathEntry("RecentIcons", d->recentList, ',', true, true);

    delete d;
}

void TDEIconDialog::slotAcceptIcons()
{
    //FIXME: not used anymore
}

void TDEIconDialog::showIcons()
{
    d->ui->iconCanvas->clear();
    TQStringList filelist;

    TDEIcon::Context context = static_cast<TDEIcon::Context>(d->extendedContext - 1);
    switch (d->extendedContext)
    {
        case RECENT:
            filelist = d->recentList;
            break;
        case OTHER:
            filelist = mFileList;
            break;
        case ALL:
            filelist = mFileList;
            context = TDEIcon::Any;
            // ** Fallthrough to next case **
        default:
            TQStringList list;
            if (d->m_bStrictIconSize)
                list=mpLoader->queryIcons(mGroupOrSize, context);
            else
                list=mpLoader->queryIconsByContext(mGroupOrSize, context);

            // Remove path & extension
            for ( TQStringList::iterator it = list.begin(); it != list.end(); ++it)
                filelist.append(TQFileInfo(*it).baseName());
    }

    // Remove duplicate icons FIXME: TQt4 we can just use TQSet
    filelist.sort();
    TQString prev;
    for ( TQStringList::iterator it = filelist.begin(); it != filelist.end(); )
    {
        if (*it == prev)
        {
            it = filelist.remove(it);
        }
        else
        {
            prev = *it;
            ++it;
        }
    }

    d->ui->iconCanvas->setGroupOrSize(mGroupOrSize);
    d->ui->iconCanvas->loadFiles(filelist);
}

void TDEIconDialog::setStrictIconSize(bool b)
{
    d->m_bStrictIconSize=b;
}

bool TDEIconDialog::strictIconSize() const
{
    return d->m_bStrictIconSize;
}

void TDEIconDialog::setIconSize( int size )
{
    // see TDEIconLoader, if you think this is weird
    if ( size == 0 )
        mGroupOrSize = TDEIcon::Desktop; // default Group
    else
        mGroupOrSize = -size; // yes, TDEIconLoader::queryIconsByContext is weird
}

int TDEIconDialog::iconSize() const
{
    // 0 or any other value ==> mGroupOrSize is a group, so we return 0
    return (mGroupOrSize < 0) ? -mGroupOrSize : 0;
}

#ifndef KDE_NO_COMPAT
TQString TDEIconDialog::selectIcon(TDEIcon::Group group, TDEIcon::Context context, bool user)
{
    setup( group, context, false, 0, user );
    return openDialog();
}
#endif

void TDEIconDialog::setup(TDEIcon::Group group, TDEIcon::Context context,
                        bool strictIconSize, int iconSize, bool user )
{
    setup(group, context, strictIconSize, iconSize, user, false, false);
}

void TDEIconDialog::setup(TDEIcon::Group group, TDEIcon::Context context,
                        bool strictIconSize, int iconSize, bool user,
                        bool lockContext, bool lockBrowse )
{
    d->m_bStrictIconSize = strictIconSize;
    d->ui->iconCanvas->setStrictIconSize(strictIconSize);
    mGroupOrSize = (iconSize == 0) ? group : -iconSize;
    mType = user;

    d->extendedContext = static_cast<ExtendedContext>( ( context == TDEIcon::Any ) ? ALL : context + 1 );

    // We cannot change layout because it is protected ;-(
    // FIXME: TQt4 we will be able to inherit from both TQDialog and our GUI
    d->ui->listBox->setEnabled(!lockContext);
    d->ui->browseButton->setEnabled(!lockBrowse);
    d->ui->listBox->setHidden(lockContext && lockBrowse);
    d->ui->browseButton->setHidden(lockContext && lockBrowse);

    d->ui->listBox->setCurrentItem(d->extendedContext);
}

const TQString & TDEIconDialog::customLocation( ) const
{
    return d->customLocation;
}

void TDEIconDialog::setCustomLocation( const TQString& location )
{
    d->customLocation = location;

    if (location.isEmpty())
    {
        mFileList = TDEGlobal::dirs()->findAllResources("appicon", TQString::fromLatin1("*.png"));
    } else {
        mFileList = mpLoader->queryIconsByDir(location);
    }
}

TQString TDEIconDialog::openDialog()
{
    showIcons();

    if ( exec() == Accepted )
    {
         if (!d->custom.isEmpty())
             return d->custom;
         else
             return d->ui->iconCanvas->getCurrent();
    }
    else
    {
        return TQString();
    }
}

void TDEIconDialog::showDialog()
{
    d->custom = TQString();

    // Make it so minimumSize returns correct value
    d->ui->filterLabel->hide();
    d->ui->searchLine->hide();
    d->ui->progressBar->show();

    setModal(false);
    show();

    // FIXME: this should be before show() but it doesn't work ;-(
    resize(minimumSize());

    showIcons();
}

void TDEIconDialog::slotOk()
{
    TQString key = !d->custom.isEmpty() ? d->custom : d->ui->iconCanvas->getCurrent();

    // Append to list of recent icons
    if (!d->recentList.contains(key))
    {
        d->recentList.push_back(key);

        // Limit recent list in size
        while ( (int)d->recentList.size() > d->recentMax )
            d->recentList.pop_front();
    }

    emit newIconName(key);
    KDialogBase::slotOk();
}

TQString TDEIconDialog::getIcon(TDEIcon::Group group, TDEIcon::Context context,
                             bool strictIconSize, int iconSize, bool user,
                             TQWidget *parent, const TQString &caption)
{
    TDEIconDialog dlg(parent, "icon dialog");
    dlg.setup( group, context, strictIconSize, iconSize, user );
    if (!caption.isNull())
        dlg.setCaption(caption);

    return dlg.openDialog();
}

void TDEIconDialog::slotBrowse()
{
    // Create a file dialog to select a PNG, XPM or SVG file,
    // with the image previewer shown.
    // KFileDialog::getImageOpenURL doesn't allow svg.
    KFileDialog dlg(TQString(), i18n("*.png *.xpm *.svg *.svgz|Icon Files (*.png *.xpm *.svg *.svgz)"),
                    this, "filedialog", true);
    dlg.setOperationMode( KFileDialog::Opening );
    dlg.setCaption( i18n("Open") );
    dlg.setMode( KFile::File | KFile::ExistingOnly | KFile::LocalOnly );
    KImageFilePreview *ip = new KImageFilePreview( &dlg );
    dlg.setPreviewWidget( ip );
    dlg.exec();

    TQString file = dlg.selectedFile();
    if (!file.isEmpty())
    {
        d->custom = file;
        if ( mType == 1 )
            setCustomLocation(TQFileInfo( file ).dirPath( true ));
        slotOk();
    }
}

void TDEIconDialog::slotContext(int id)
{
    d->extendedContext = static_cast<ExtendedContext>(id);
    showIcons();
}

void TDEIconDialog::slotStartLoading(int steps)
{
    if (steps < 10)
    	d->ui->progressBar->hide();
    else
    {
        d->ui->progressBar->setTotalSteps(steps);
        d->ui->progressBar->setProgress(0);
        d->ui->progressBar->show();
        d->ui->filterLabel->hide();
        d->ui->searchLine->hide();
    }
}

void TDEIconDialog::slotProgress(int p)
{
    d->ui->progressBar->setProgress(p);
}

void TDEIconDialog::slotFinished()
{
    d->ui->progressBar->hide();
    d->ui->filterLabel->show();
    d->ui->searchLine->show();
}

class TDEIconButton::TDEIconButtonPrivate
{
  public:
    TDEIconButtonPrivate() {
        m_bStrictIconSize = false;
        iconSize = 0; // let TDEIconLoader choose the default
    }
    ~TDEIconButtonPrivate() {}
    bool m_bStrictIconSize;
    bool lockUser;
    bool lockCustom;
    int iconSize;
};


/*
 * TDEIconButton: A "choose icon" pushbutton.
 */

TDEIconButton::TDEIconButton(TQWidget *parent, const char *name)
    : TQPushButton(parent, name)
{
    init( TDEGlobal::iconLoader() );
}

TDEIconButton::TDEIconButton(TDEIconLoader *loader,
	TQWidget *parent, const char *name)
    : TQPushButton(parent, name)
{
    init( loader );
}

void TDEIconButton::init( TDEIconLoader *loader )
{
    d = new TDEIconButtonPrivate;
    mGroup = TDEIcon::Desktop;
    mContext = TDEIcon::Application;
    mbUser = false;

    mpLoader = loader;
    mpDialog = 0L;
    connect(this, TQ_SIGNAL(clicked()), TQ_SLOT(slotChangeIcon()));
}

TDEIconButton::~TDEIconButton()
{
    delete mpDialog;
    delete d;
}

void TDEIconButton::setStrictIconSize(bool b)
{
    d->m_bStrictIconSize=b;
}

bool TDEIconButton::strictIconSize() const
{
    return d->m_bStrictIconSize;
}

void TDEIconButton::setIconSize( int size )
{
    d->iconSize = size;
}

int TDEIconButton::iconSize() const
{
    return d->iconSize;
}

void TDEIconButton::setIconType(TDEIcon::Group group, TDEIcon::Context context, bool user)
{
    mGroup = group;
    mContext = context;
    mbUser = user;
    d->lockUser = false;
    d->lockCustom = false;
}

void TDEIconButton::setIconType(TDEIcon::Group group, TDEIcon::Context context, bool user, bool lockUser, bool lockCustom)
{
    mGroup = group;
    mContext = context;
    mbUser = user;
    d->lockUser = lockUser;
    d->lockCustom = lockCustom;
}

void TDEIconButton::setIcon(const TQString& icon)
{
    mIcon = icon;
    setIconSet(mpLoader->loadIconSet(mIcon, mGroup, d->iconSize));

    if (!mpDialog)
    {
        mpDialog = new TDEIconDialog(mpLoader, this);
        connect(mpDialog, TQ_SIGNAL(newIconName(const TQString&)), TQ_SLOT(newIconName(const TQString&)));
    }
}

const TQString & TDEIconButton::customLocation( ) const
{
    return mpDialog ? mpDialog->customLocation() : TQString();
}

void TDEIconButton::setCustomLocation(const TQString &custom)
{
    if (!mpDialog)
    {
        mpDialog = new TDEIconDialog(mpLoader, this);
        connect(mpDialog, TQ_SIGNAL(newIconName(const TQString&)), TQ_SLOT(newIconName(const TQString&)));
    }

    mpDialog->setCustomLocation(custom);
}

void TDEIconButton::resetIcon()
{
    mIcon = TQString();
    setIconSet(TQIconSet());
}

void TDEIconButton::slotChangeIcon()
{
    if (!mpDialog)
    {
        mpDialog = new TDEIconDialog(mpLoader, this);
        connect(mpDialog, TQ_SIGNAL(newIconName(const TQString&)), TQ_SLOT(newIconName(const TQString&)));
    }

    mpDialog->setup( mGroup, mContext, d->m_bStrictIconSize, d->iconSize, mbUser, d->lockUser, d->lockCustom );
    mpDialog->showDialog();
}

void TDEIconButton::newIconName(const TQString& name)
{
    if (name.isEmpty())
        return;

    TQIconSet iconset = mpLoader->loadIconSet(name, mGroup, d->iconSize);
    setIconSet(iconset);
    mIcon = name;

    emit iconChanged(name);
}

void TDEIconCanvas::virtual_hook( int id, void* data )
{ TDEIconView::virtual_hook( id, data ); }

void TDEIconDialog::virtual_hook( int id, void* data )
{ KDialogBase::virtual_hook( id, data ); }

#include "kicondialog.moc"
