]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/kfilepreviewgenerator.cpp
* renamed AbstractViewAdapter to KAbstractViewAdapter
[dolphin.git] / src / kfilepreviewgenerator.cpp
index e81f66980efecdf49746510a815279a3cfe9197f..cb93a7f071c219137170186c96b6784f76dcd2cc 100644 (file)
 
 #include "kfilepreviewgenerator.h"
 
+#include <kabstractviewadapter_p.h>
+#include <kfileitem.h>
 #include <kiconeffect.h>
 #include <kio/previewjob.h>
 #include <kdirlister.h>
 #include <kdirmodel.h>
-#include <kdirsortfilterproxymodel.h>
 #include <kmimetyperesolver.h>
 #include <konqmimedata.h>
 
 #include <QApplication>
 #include <QAbstractItemView>
+#include <QAbstractProxyModel>
 #include <QClipboard>
 #include <QColor>
+#include <QList>
 #include <QListView>
 #include <QPainter>
+#include <QPixmap>
 #include <QScrollBar>
 #include <QIcon>
 
+#ifdef Q_WS_X11
+#  include <QX11Info>
+#  include <X11/Xlib.h>
+#  include <X11/extensions/Xrender.h>
+#endif
+
+/**
+ * Implementation of the view adapter for the default case when
+ * an instance of QAbstractItemView is used as view.
+ */
+class DefaultViewAdapter : public KAbstractViewAdapter
+{
+public:
+    DefaultViewAdapter(QAbstractItemView* view, QObject* parent);
+    virtual QObject* createMimeTypeResolver(KDirModel* model) const;
+    virtual QSize iconSize() const;
+    virtual QPalette palette() const;
+    virtual QRect visibleArea() const;
+    virtual QRect visualRect(const QModelIndex& index) const;
+    virtual void connect(Signal signal, QObject* receiver, const char* slot);
+
+private:
+    QAbstractItemView* m_view;
+};
+
+DefaultViewAdapter::DefaultViewAdapter(QAbstractItemView* view, QObject* parent) :
+    KAbstractViewAdapter(parent),
+    m_view(view)
+{
+}
+
+QObject* DefaultViewAdapter::createMimeTypeResolver(KDirModel* model) const
+{
+    return new KMimeTypeResolver(m_view, model);
+}
+
+QSize DefaultViewAdapter::iconSize() const
+{
+    return m_view->iconSize();
+}
+
+QPalette DefaultViewAdapter::palette() const
+{
+    return m_view->palette();
+}
+
+QRect DefaultViewAdapter::visibleArea() const
+{
+    return m_view->viewport()->rect();
+}
+
+QRect DefaultViewAdapter::visualRect(const QModelIndex& index) const
+{
+    return m_view->visualRect(index);
+}
+
+void DefaultViewAdapter::connect(Signal signal, QObject* receiver, const char* slot)
+{
+    if (signal == ScrollBarValueChanged) {
+        QObject::connect(m_view->horizontalScrollBar(), SIGNAL(valueChanged(int)), receiver, slot);
+        QObject::connect(m_view->verticalScrollBar(), SIGNAL(valueChanged(int)), receiver, slot);
+    }
+}
+
 /**
  * If the passed item view is an instance of QListView, expensive
  * layout operations are blocked in the constructor and are unblocked
@@ -80,13 +148,155 @@ private:
     QListView* m_view;
 };
 
-KFilePreviewGenerator::KFilePreviewGenerator(QAbstractItemView* parent, KDirSortFilterProxyModel* model) :
-    QObject(parent),
-    m_showPreview(false),
+class KFilePreviewGenerator::Private
+{
+public:
+    Private(KFilePreviewGenerator* parent,
+            KAbstractViewAdapter* viewAdapter,
+            QAbstractProxyModel* model);
+    ~Private();
+    
+    /**
+     * Generates previews for the items \a items asynchronously.
+     */
+    void generatePreviews(const KFileItemList& items);
+
+    /**
+     * Adds the preview \a pixmap for the item \a item to the preview
+     * queue and starts a timer which will dispatch the preview queue
+     * later.
+     */
+    void addToPreviewQueue(const KFileItem& item, const QPixmap& pixmap);
+
+    /**
+     * Is invoked when the preview job has been finished and
+     * removes the job from the m_previewJobs list.
+     */
+    void slotPreviewJobFinished(KJob* job);
+
+    /** Synchronizes the item icon with the clipboard of cut items. */
+    void updateCutItems();
+
+    /**
+     * Dispatches the preview queue  block by block within
+     * time slices.
+     */
+    void dispatchPreviewQueue();
+
+    /**
+     * Pauses all preview jobs and invokes KFilePreviewGenerator::resumePreviews()
+     * after a short delay. Is invoked as soon as the user has moved
+     * a scrollbar.
+     */
+    void pausePreviews();
+
+    /**
+     * Resumes the previews that have been paused after moving the
+     * scrollbar. The previews for the current visible area are
+     * generated first.
+     */
+    void resumePreviews();
+    
+    /**
+     * Returns true, if the item \a item has been cut into
+     * the clipboard.
+     */
+    bool isCutItem(const KFileItem& item) const;
+
+    /** Applies an item effect to all cut items. */
+    void applyCutItemEffect();
+
+    /**
+     * Applies a frame around the icon. False is returned if
+     * no frame has been added because the icon is too small.
+     */
+    bool applyImageFrame(QPixmap& icon);
+
+    /**
+     * Resizes the icon to \a maxSize if the icon size does not
+     * fit into the maximum size. The aspect ratio of the icon
+     * is kept.
+     */
+    void limitToSize(QPixmap& icon, const QSize& maxSize);
+
+    /**
+     * Starts a new preview job for the items \a to m_previewJobs
+     * and triggers the preview timer.
+     */
+    void startPreviewJob(const KFileItemList& items);
+
+    /** Kills all ongoing preview jobs. */
+    void killPreviewJobs();
+
+    /**
+     * Orders the items \a items in a way that the visible items
+     * are moved to the front of the list. When passing this
+     * list to a preview job, the visible items will get generated
+     * first.
+     */
+    void orderItems(KFileItemList& items);
+    
+    /** Remembers the pixmap for an item specified by an URL. */
+    struct ItemInfo
+    {
+        KUrl url;
+        QPixmap pixmap;
+    };
+
+    bool m_showPreview;
+
+    /**
+     * True, if m_pendingItems and m_dispatchedItems should be
+     * cleared when the preview jobs have been finished.
+     */
+    bool m_clearItemQueues;
+
+    /**
+     * True if a selection has been done which should cut items.
+     */
+    bool m_hasCutSelection;
+
+    int m_pendingVisiblePreviews;
+
+    KAbstractViewAdapter* m_viewAdapter;
+    QAbstractItemView* m_itemView;
+    QTimer* m_previewTimer;
+    QTimer* m_scrollAreaTimer;
+    QList<KJob*> m_previewJobs;
+    KDirModel* m_dirModel;
+    QAbstractProxyModel* m_proxyModel;
+
+    QObject* m_mimeTypeResolver;
+
+    QList<ItemInfo> m_cutItemsCache;
+    QList<ItemInfo> m_previews;
+
+    /**
+     * Contains all items where a preview must be generated, but
+     * where the preview job has not dispatched the items yet.
+     */
+    KFileItemList m_pendingItems;
+
+    /**
+     * Contains all items, where a preview has already been
+     * generated by the preview jobs.
+     */
+    KFileItemList m_dispatchedItems;
+    
+private:
+    KFilePreviewGenerator* const q;
+
+};
+
+KFilePreviewGenerator::Private::Private(KFilePreviewGenerator* parent,
+                                        KAbstractViewAdapter* viewAdapter,
+                                        QAbstractProxyModel* model) :
+    m_showPreview(true),
     m_clearItemQueues(true),
     m_hasCutSelection(false),
     m_pendingVisiblePreviews(0),
-    m_view(parent),
+    m_viewAdapter(viewAdapter),
+    m_itemView(0),
     m_previewTimer(0),
     m_scrollAreaTimer(0),
     m_previewJobs(),
@@ -96,39 +306,40 @@ KFilePreviewGenerator::KFilePreviewGenerator(QAbstractItemView* parent, KDirSort
     m_cutItemsCache(),
     m_previews(),
     m_pendingItems(),
-    m_dispatchedItems()
+    m_dispatchedItems(),
+    q(parent)
 {
-    Q_ASSERT(m_view->iconSize().isValid());  // each view must provide its current icon size
+    if (!m_viewAdapter->iconSize().isValid()) {
+        m_showPreview = false;
+    }
 
     m_dirModel = static_cast<KDirModel*>(m_proxyModel->sourceModel());
     connect(m_dirModel->dirLister(), SIGNAL(newItems(const KFileItemList&)),
-            this, SLOT(generatePreviews(const KFileItemList&)));
+            q, SLOT(generatePreviews(const KFileItemList&)));
 
     QClipboard* clipboard = QApplication::clipboard();
     connect(clipboard, SIGNAL(dataChanged()),
-            this, SLOT(updateCutItems()));
+            q, SLOT(updateCutItems()));
 
-    m_previewTimer = new QTimer(this);
+    m_previewTimer = new QTimer(q);
     m_previewTimer->setSingleShot(true);
-    connect(m_previewTimer, SIGNAL(timeout()), this, SLOT(dispatchPreviewQueue()));
+    connect(m_previewTimer, SIGNAL(timeout()), q, SLOT(dispatchPreviewQueue()));
 
     // Whenever the scrollbar values have been changed, the pending previews should
     // be reordered in a way that the previews for the visible items are generated
     // first. The reordering is done with a small delay, so that during moving the
     // scrollbars the CPU load is kept low.
-    m_scrollAreaTimer = new QTimer(this);
+    m_scrollAreaTimer = new QTimer(q);
     m_scrollAreaTimer->setSingleShot(true);
     m_scrollAreaTimer->setInterval(200);
     connect(m_scrollAreaTimer, SIGNAL(timeout()),
-            this, SLOT(resumePreviews()));
-    connect(m_view->horizontalScrollBar(), SIGNAL(valueChanged(int)),
-            this, SLOT(pausePreviews()));
-    connect(m_view->verticalScrollBar(), SIGNAL(valueChanged(int)),
-            this, SLOT(pausePreviews()));
+            q, SLOT(resumePreviews()));
+    m_viewAdapter->connect(KAbstractViewAdapter::ScrollBarValueChanged,
+                           q, SLOT(pausePreviews()));
 }
 
-KFilePreviewGenerator::~KFilePreviewGenerator()
-{
+KFilePreviewGenerator::Private::~Private()
+{        
     killPreviewJobs();
     m_pendingItems.clear();
     m_dispatchedItems.clear();
@@ -138,60 +349,7 @@ KFilePreviewGenerator::~KFilePreviewGenerator()
     }
 }
 
-void KFilePreviewGenerator::setShowPreview(bool show)
-{
-    if (m_showPreview != show) {
-        m_showPreview = show;
-        m_cutItemsCache.clear();
-        updateCutItems();
-        if (show) {
-            updatePreviews();
-        }
-    }
-
-    if (show && (m_mimeTypeResolver != 0)) {
-        // don't resolve the MIME types if the preview is turned on
-        m_mimeTypeResolver->deleteLater();
-        m_mimeTypeResolver = 0;
-    } else if (!show && (m_mimeTypeResolver == 0)) {
-        // the preview is turned off: resolve the MIME-types so that
-        // the icons gets updated
-        m_mimeTypeResolver = new KMimeTypeResolver(m_view, m_dirModel);
-    }
-}
-
-void KFilePreviewGenerator::updatePreviews()
-{
-    if (!m_showPreview) {
-        return;
-    }
-
-    killPreviewJobs();
-    m_cutItemsCache.clear();
-    m_pendingItems.clear();
-    m_dispatchedItems.clear();
-
-    KFileItemList itemList;
-    const int rowCount = m_dirModel->rowCount();
-    for (int row = 0; row < rowCount; ++row) {
-        const QModelIndex index = m_dirModel->index(row, 0);
-        KFileItem item = m_dirModel->itemForIndex(index);
-        itemList.append(item);
-    }
-
-    generatePreviews(itemList);
-    updateCutItems();
-}
-
-void KFilePreviewGenerator::cancelPreviews()
-{
-    killPreviewJobs();
-    m_cutItemsCache.clear();
-    m_pendingItems.clear();
-    m_dispatchedItems.clear();
-}
-
-void KFilePreviewGenerator::generatePreviews(const KFileItemList& items)
+void KFilePreviewGenerator::Private::generatePreviews(const KFileItemList& items)
 {
     applyCutItemEffect();
 
@@ -209,7 +367,7 @@ void KFilePreviewGenerator::generatePreviews(const KFileItemList& items)
     startPreviewJob(orderedItems);
 }
 
-void KFilePreviewGenerator::addToPreviewQueue(const KFileItem& item, const QPixmap& pixmap)
+void KFilePreviewGenerator::Private::addToPreviewQueue(const KFileItem& item, const QPixmap& pixmap)
 {
     if (!m_showPreview) {
         // the preview has been canceled in the meantime
@@ -238,7 +396,7 @@ void KFilePreviewGenerator::addToPreviewQueue(const KFileItem& item, const QPixm
     const QString mimeType = item.mimetype();
     const QString mimeTypeGroup = mimeType.left(mimeType.indexOf('/'));
     if ((mimeTypeGroup != "image") || !applyImageFrame(icon)) {
-        limitToSize(icon, m_view->iconSize());
+        limitToSize(icon, m_viewAdapter->iconSize());
     }
 
     if (m_hasCutSelection && isCutItem(item)) {
@@ -270,7 +428,7 @@ void KFilePreviewGenerator::addToPreviewQueue(const KFileItem& item, const QPixm
     m_dispatchedItems.append(item);
 }
 
-void KFilePreviewGenerator::slotPreviewJobFinished(KJob* job)
+void KFilePreviewGenerator::Private::slotPreviewJobFinished(KJob* job)
 {
     const int index = m_previewJobs.indexOf(job);
     m_previewJobs.removeAt(index);
@@ -279,11 +437,11 @@ void KFilePreviewGenerator::slotPreviewJobFinished(KJob* job)
         m_pendingItems.clear();
         m_dispatchedItems.clear();
         m_pendingVisiblePreviews = 0;
-        QMetaObject::invokeMethod(this, "dispatchPreviewQueue", Qt::QueuedConnection);
+        QMetaObject::invokeMethod(q, "dispatchPreviewQueue", Qt::QueuedConnection);
     }
 }
 
-void KFilePreviewGenerator::updateCutItems()
+void KFilePreviewGenerator::Private::updateCutItems()
 {
     // restore the icons of all previously selected items to the
     // original state...
@@ -299,7 +457,7 @@ void KFilePreviewGenerator::updateCutItems()
     applyCutItemEffect();
 }
 
-void KFilePreviewGenerator::dispatchPreviewQueue()
+void KFilePreviewGenerator::Private::dispatchPreviewQueue()
 {
     const int previewsCount = m_previews.count();
     if (previewsCount > 0) {
@@ -307,7 +465,7 @@ void KFilePreviewGenerator::dispatchPreviewQueue()
         // in larger blocks: Applying a preview immediately when getting the signal
         // 'gotPreview()' from the PreviewJob is too expensive, as a relayout
         // of the view would be triggered for each single preview.
-        LayoutBlocker blocker(m_view);
+        LayoutBlocker blocker(m_itemView);
         for (int i = 0; i < previewsCount; ++i) {
             const ItemInfo& preview = m_previews.first();
 
@@ -331,7 +489,7 @@ void KFilePreviewGenerator::dispatchPreviewQueue()
     }
 }
 
-void KFilePreviewGenerator::pausePreviews()
+void KFilePreviewGenerator::Private::pausePreviews()
 {
     foreach (KJob* job, m_previewJobs) {
         Q_ASSERT(job != 0);
@@ -340,7 +498,7 @@ void KFilePreviewGenerator::pausePreviews()
     m_scrollAreaTimer->start();
 }
 
-void KFilePreviewGenerator::resumePreviews()
+void KFilePreviewGenerator::Private::resumePreviews()
 {
     // Before creating new preview jobs the m_pendingItems queue must be
     // cleaned up by removing the already dispatched items. Implementation
@@ -377,7 +535,7 @@ void KFilePreviewGenerator::resumePreviews()
     startPreviewJob(orderedItems);
 }
 
-bool KFilePreviewGenerator::isCutItem(const KFileItem& item) const
+bool KFilePreviewGenerator::Private::isCutItem(const KFileItem& item) const
 {
     const QMimeData* mimeData = QApplication::clipboard()->mimeData();
     const KUrl::List cutUrls = KUrl::List::fromMimeData(mimeData);
@@ -392,7 +550,7 @@ bool KFilePreviewGenerator::isCutItem(const KFileItem& item) const
     return false;
 }
 
-void KFilePreviewGenerator::applyCutItemEffect()
+void KFilePreviewGenerator::Private::applyCutItemEffect()
 {
     const QMimeData* mimeData = QApplication::clipboard()->mimeData();
     m_hasCutSelection = KonqMimeData::decodeIsCutSelection(mimeData);
@@ -413,7 +571,7 @@ void KFilePreviewGenerator::applyCutItemEffect()
             const QVariant value = m_dirModel->data(index, Qt::DecorationRole);
             if (value.type() == QVariant::Icon) {
                 const QIcon icon(qvariant_cast<QIcon>(value));
-                const QSize actualSize = icon.actualSize(m_view->iconSize());
+                const QSize actualSize = icon.actualSize(m_viewAdapter->iconSize());
                 QPixmap pixmap = icon.pixmap(actualSize);
 
                 // remember current pixmap for the item to be able
@@ -432,9 +590,9 @@ void KFilePreviewGenerator::applyCutItemEffect()
     }
 }
 
-bool KFilePreviewGenerator::applyImageFrame(QPixmap& icon)
+bool KFilePreviewGenerator::Private::applyImageFrame(QPixmap& icon)
 {
-    const QSize maxSize = m_view->iconSize();
+    const QSize maxSize = m_viewAdapter->iconSize();
     const bool applyFrame = (maxSize.width()  > KIconLoader::SizeSmallMedium) &&
                             (maxSize.height() > KIconLoader::SizeSmallMedium) &&
                             ((icon.width()  > KIconLoader::SizeLarge) ||
@@ -451,7 +609,7 @@ bool KFilePreviewGenerator::applyImageFrame(QPixmap& icon)
     limitToSize(icon, QSize(maxSize.width() - doubleFrame, maxSize.height() - doubleFrame));
 
     QPainter painter;
-    const QPalette palette = m_view->palette();
+    const QPalette palette = m_viewAdapter->palette();
     QPixmap framedIcon(icon.size().width() + doubleFrame, icon.size().height() + doubleFrame);
     framedIcon.fill(palette.color(QPalette::Normal, QPalette::Base));
     const int width = framedIcon.width() - 1;
@@ -482,14 +640,42 @@ bool KFilePreviewGenerator::applyImageFrame(QPixmap& icon)
     return true;
 }
 
-void KFilePreviewGenerator::limitToSize(QPixmap& icon, const QSize& maxSize)
+void KFilePreviewGenerator::Private::limitToSize(QPixmap& icon, const QSize& maxSize)
 {
     if ((icon.width() > maxSize.width()) || (icon.height() > maxSize.height())) {
+#ifdef Q_WS_X11
+        // Assume that the texture size limit is 2048x2048
+        if ((icon.width() <= 2048) && (icon.height() <= 2048)) {
+            QSize size = icon.size();
+            size.scale(maxSize, Qt::KeepAspectRatio);
+
+            const qreal factor = size.width() / qreal(icon.width());
+
+            XTransform xform = {{
+                { XDoubleToFixed(1 / factor), 0, 0 },
+                { 0, XDoubleToFixed(1 / factor), 0 },
+                { 0, 0, XDoubleToFixed(1) }
+            }};
+
+            QPixmap pixmap(size);
+            pixmap.fill(Qt::transparent);
+
+            Display *dpy = QX11Info::display();
+            XRenderSetPictureFilter(dpy, icon.x11PictureHandle(), FilterBilinear, 0, 0);
+            XRenderSetPictureTransform(dpy, icon.x11PictureHandle(), &xform);
+            XRenderComposite(dpy, PictOpOver, icon.x11PictureHandle(), None, pixmap.x11PictureHandle(),
+                             0, 0, 0, 0, 0, 0, pixmap.width(), pixmap.height());
+            icon = pixmap;
+        } else {
+            icon = icon.scaled(maxSize, Qt::KeepAspectRatio, Qt::FastTransformation);
+        }
+#else
         icon = icon.scaled(maxSize, Qt::KeepAspectRatio, Qt::FastTransformation);
+#endif
     }
 }
 
-void KFilePreviewGenerator::startPreviewJob(const KFileItemList& items)
+void KFilePreviewGenerator::Private::startPreviewJob(const KFileItemList& items)
 {
     if (items.count() == 0) {
         return;
@@ -498,7 +684,7 @@ void KFilePreviewGenerator::startPreviewJob(const KFileItemList& items)
     const QMimeData* mimeData = QApplication::clipboard()->mimeData();
     m_hasCutSelection = KonqMimeData::decodeIsCutSelection(mimeData);
 
-    const QSize size = m_view->iconSize();
+    const QSize size = m_viewAdapter->iconSize();
 
     // PreviewJob internally caches items always with the size of
     // 128 x 128 pixels or 256 x 256 pixels. A downscaling is done 
@@ -508,15 +694,15 @@ void KFilePreviewGenerator::startPreviewJob(const KFileItemList& items)
     const int cacheSize = (size.width() > 128) || (size.height() > 128) ? 256 : 128;
     KIO::PreviewJob* job = KIO::filePreview(items, cacheSize, cacheSize);
     connect(job, SIGNAL(gotPreview(const KFileItem&, const QPixmap&)),
-            this, SLOT(addToPreviewQueue(const KFileItem&, const QPixmap&)));
+            q, SLOT(addToPreviewQueue(const KFileItem&, const QPixmap&)));
     connect(job, SIGNAL(finished(KJob*)),
-            this, SLOT(slotPreviewJobFinished(KJob*)));
+            q, SLOT(slotPreviewJobFinished(KJob*)));
 
     m_previewJobs.append(job);
     m_previewTimer->start(200);
 }
 
-void KFilePreviewGenerator::killPreviewJobs()
+void KFilePreviewGenerator::Private::killPreviewJobs()
 {
     foreach (KJob* job, m_previewJobs) {
         Q_ASSERT(job != 0);
@@ -525,7 +711,7 @@ void KFilePreviewGenerator::killPreviewJobs()
     m_previewJobs.clear();
 }
 
-void KFilePreviewGenerator::orderItems(KFileItemList& items)
+void KFilePreviewGenerator::Private::orderItems(KFileItemList& items)
 {
     // Order the items in a way that the preview for the visible items
     // is generated first, as this improves the feeled performance a lot.
@@ -539,7 +725,7 @@ void KFilePreviewGenerator::orderItems(KFileItemList& items)
 
     const int itemCount = items.count();
     const int rowCount = m_proxyModel->rowCount();
-    const QRect visibleArea = m_view->viewport()->rect();
+    const QRect visibleArea = m_viewAdapter->visibleArea();
 
     int insertPos = 0;
     if (itemCount * 10 > rowCount) {
@@ -547,7 +733,7 @@ void KFilePreviewGenerator::orderItems(KFileItemList& items)
         // and check whether the received row is part of the item list.
         for (int row = 0; row < rowCount; ++row) {
             const QModelIndex proxyIndex = m_proxyModel->index(row, 0);
-            const QRect itemRect = m_view->visualRect(proxyIndex);
+            const QRect itemRect = m_viewAdapter->visualRect(proxyIndex);
             const QModelIndex dirIndex = m_proxyModel->mapToSource(proxyIndex);
 
             KFileItem item = m_dirModel->itemForIndex(dirIndex);  // O(1)
@@ -578,7 +764,7 @@ void KFilePreviewGenerator::orderItems(KFileItemList& items)
         for (int i = 0; i < itemCount; ++i) {
             const QModelIndex dirIndex = m_dirModel->indexForItem(items.at(i)); // O(n) (n = number of rows)
             const QModelIndex proxyIndex = m_proxyModel->mapFromSource(dirIndex);
-            const QRect itemRect = m_view->visualRect(proxyIndex);
+            const QRect itemRect = m_viewAdapter->visualRect(proxyIndex);
 
             if (itemRect.intersects(visibleArea)) {
                 // The current item is (at least partly) visible. Move it
@@ -593,4 +779,86 @@ void KFilePreviewGenerator::orderItems(KFileItemList& items)
     }
 }
 
+KFilePreviewGenerator::KFilePreviewGenerator(QAbstractItemView* parent, QAbstractProxyModel* model) :
+    QObject(parent),
+    d(new Private(this, new DefaultViewAdapter(parent, this), model))
+{
+    d->m_itemView = parent;
+}
+
+KFilePreviewGenerator::KFilePreviewGenerator(KAbstractViewAdapter* parent, QAbstractProxyModel* model) :
+    QObject(parent),
+    d(new Private(this, parent, model))
+{
+}
+
+KFilePreviewGenerator::~KFilePreviewGenerator()
+{
+    delete d;
+}
+
+void KFilePreviewGenerator::setShowPreview(bool show)
+{
+    if (show && !d->m_viewAdapter->iconSize().isValid()) {
+        // the view must provide an icon size, otherwise the showing
+        // off previews will get ignored
+        return;
+    }
+    
+    if (d->m_showPreview != show) {
+        d->m_showPreview = show;
+        d->m_cutItemsCache.clear();
+        d->updateCutItems();
+        if (show) {
+            updatePreviews();
+        }
+    }
+
+    if (show && (d->m_mimeTypeResolver != 0)) {
+        // don't resolve the MIME types if the preview is turned on
+        d->m_mimeTypeResolver->deleteLater();
+        d->m_mimeTypeResolver = 0;
+    } else if (!show && (d->m_mimeTypeResolver == 0)) {
+        // the preview is turned off: resolve the MIME-types so that
+        // the icons gets updated
+        d->m_mimeTypeResolver = d->m_viewAdapter->createMimeTypeResolver(d->m_dirModel);
+    }
+}
+
+bool KFilePreviewGenerator::showPreview() const
+{
+    return d->m_showPreview;
+}
+
+void KFilePreviewGenerator::updatePreviews()
+{
+    if (!d->m_showPreview) {
+        return;
+    }
+
+    d->killPreviewJobs();
+    d->m_cutItemsCache.clear();
+    d->m_pendingItems.clear();
+    d->m_dispatchedItems.clear();
+
+    KFileItemList itemList;
+    const int rowCount = d->m_dirModel->rowCount();
+    for (int row = 0; row < rowCount; ++row) {
+        const QModelIndex index = d->m_dirModel->index(row, 0);
+        KFileItem item = d->m_dirModel->itemForIndex(index);
+        itemList.append(item);
+    }
+
+    d->generatePreviews(itemList);
+    d->updateCutItems();
+}
+
+void KFilePreviewGenerator::cancelPreviews()
+{
+    d->killPreviewJobs();
+    d->m_cutItemsCache.clear();
+    d->m_pendingItems.clear();
+    d->m_dispatchedItems.clear();
+}
+
 #include "kfilepreviewgenerator.moc"