/***************************************************************************
 *   Copyright (C) 2011 by Peter Penz <peter.penz19@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.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA            *
 ***************************************************************************/

#ifndef KFILEITEMMODELROLESUPDATER_H
#define KFILEITEMMODELROLESUPDATER_H

#include <libdolphin_export.h>

#include <KFileItem>
#include <kitemviews/kitemmodelbase.h>

#include <QObject>
#include <QSet>
#include <QSize>
#include <QStringList>

class KFileItemModel;
class KJob;
class QPixmap;
class QTimer;

/**
 * @brief Resolves expensive roles asynchronously and applies them to the KFileItemModel.
 *
 * KFileItemModel only resolves roles that are inexpensive like e.g. the file name or
 * the permissions. Creating previews or determining the MIME-type can be quite expensive
 * and KFileItemModelRolesUpdater takes care to update such roles asynchronously.
 */
class LIBDOLPHINPRIVATE_EXPORT KFileItemModelRolesUpdater : public QObject
{
    Q_OBJECT

public:
    KFileItemModelRolesUpdater(KFileItemModel* model, QObject* parent = 0);
    virtual ~KFileItemModelRolesUpdater();

    void setIconSize(const QSize& size);
    QSize iconSize() const;

    /**
     * Sets the range of items that are visible currently. The roles
     * of visible items are resolved first.
     */
    void setVisibleIndexRange(int index, int count);

    /**
     * If \a show is set to true, the "iconPixmap" role will be filled with a preview
     * of the file. If \a show is false the MIME type icon will be used for the "iconPixmap"
     * role.
     */
    void setPreviewShown(bool show);
    bool isPreviewShown() const;

    /**
     * If \a paused is set to true the asynchronous resolving of roles will be paused.
     * State changes during pauses like changing the icon size or the preview-shown
     * will be remembered and handled after unpausing.
     */
    void setPaused(bool paused);
    bool isPaused() const;

    /**
     * Sets the roles that should be resolved asynchronously.
     */
    void setRoles(const QSet<QByteArray>& roles);
    QSet<QByteArray> roles() const;

    /**
     * Sets the list of enabled thumbnail plugins.
     * Per default all plugins enabled in the KConfigGroup "PreviewSettings"
     * are used.
     *
     * Note that this method doesn't cause already generated previews
     * to be regenerated.
     *
     * For a list of available plugins, call KServiceTypeTrader::self()->query("ThumbCreator").
     *
     * @see enabledPlugins
     */
    void setEnabledPlugins(const QStringList& list);

    /**
     * Returns the list of enabled thumbnail plugins.
     * @see setEnabledPlugins
     */
    QStringList enabledPlugins() const;

private slots:
    void slotItemsInserted(const KItemRangeList& itemRanges);
    void slotItemsRemoved(const KItemRangeList& itemRanges);
    void slotItemsChanged(const KItemRangeList& itemRanges,
                          const QSet<QByteArray>& roles);

    void slotGotPreview(const KFileItem& item, const QPixmap& pixmap);
    void slotPreviewFailed(const KFileItem& item);

    /**
     * Is invoked when the preview job has been finished and
     * removes the job from the m_previewJobs list.
     */
    void slotPreviewJobFinished(KJob* job);

    void resolvePendingRoles();
    void resolveNextPendingRoles();

private:
    void startPreviewJob(const KFileItemList& items);

    bool hasPendingRoles() const;
    void resetPendingRoles();
    void triggerPendingRolesResolving(int count);
    void sortAndResolveAllRoles();
    void sortAndResolvePendingRoles();

    enum ResolveHint {
        ResolveFast,
        ResolveAll
    };
    bool applyResolvedRoles(const KFileItem& item, ResolveHint hint);
    QHash<QByteArray, QVariant> rolesData(const KFileItem& item) const;

    KFileItemList sortedItems(const QSet<KFileItem>& items) const;

    static int subDirectoriesCount(const QString& path);

private:
    // Property for setPaused()/isPaused().
    bool m_paused;

    // Property changes during pausing must be remembered to be able
    // to react when unpausing again:
    bool m_previewChangedDuringPausing;
    bool m_iconSizeChangedDuringPausing;
    bool m_rolesChangedDuringPausing;

    // Property for setPreviewShown()/previewShown().
    bool m_previewShown;

    // True if the role "iconPixmap" should be cleared when resolving the next
    // role with resolveRole(). Is necessary if the preview gets disabled
    // during the roles-updater has been paused by setPaused().
    bool m_clearPreviews;

    KFileItemModel* m_model;
    QSize m_iconSize;
    int m_firstVisibleIndex;
    int m_lastVisibleIndex;
    QSet<QByteArray> m_roles;
    QStringList m_enabledPlugins;

    QSet<KFileItem> m_pendingVisibleItems;
    QSet<KFileItem> m_pendingInvisibleItems;
    QList<KJob*> m_previewJobs;

    QTimer* m_resolvePendingRolesTimer;
};

#endif


