I have made the following changes intended for :
  CE:MW:Shared / nemo-qml-plugins

Please review and accept or decline.
BOSS has already run some checks on this request.
See the "Messages from BOSS" section below.

https://build.pub.meego.com//request/show/7392

Thank You,
Marko Saukko

[This message was auto-generated]

---

Request # 7392:

Messages from BOSS:

State: review at 2012-11-16T10:49:36 by bossbot

Reviews:
       accepted by bossbot : Prechecks succeeded.
       new for CE-maintainers : Please replace this text with a review and 
approve/reject the review (not the SR). BOSS will take care of the rest

Changes:
  submit: Project:MTF:MW / nemo-qml-plugins -> CE:MW:Shared / nemo-qml-plugins
  
changes files:
--------------
--- nemo-qml-plugins.changes
+++ nemo-qml-plugins.changes
@@ -0,0 +1,6 @@
+* Wed Nov 16 2012 Johan Paul <[email protected]> - 0.1.6
+- Add a dedicated Thumbnail item. (by Andrew den Exter)
+- Move the gstreamer video thumbnailer into a separate binary. (by Andrew den 
Exter)
+- Add 'count' property to SeasideProxyModel. (by Johan Paul)
+- Add address detail types as enums. (by Johan Paul)
+

old:
----
  nemo-qml-plugins-0.1.5.tar.bz2

new:
----
  nemo-qml-plugins-0.1.6.tar.bz2

spec files:
-----------
--- nemo-qml-plugins.spec
+++ nemo-qml-plugins.spec
@@ -9,7 +9,7 @@
 # << macros
 
 Summary:    Nemo QML plugins source package.
-Version:    0.1.5
+Version:    0.1.6
 Release:    1
 Group:      System/Libraries
 License:    BSD

other changes:
--------------

++++++ nemo-qml-plugins-0.1.5.tar.bz2 -> nemo-qml-plugins-0.1.6.tar.bz2
--- contacts/src/seasideperson.h
+++ contacts/src/seasideperson.h
@@ -74,6 +74,12 @@
         AddressHomeType,
         AddressWorkType,
         AddressOtherType,
+        AddressStreetType,
+        AddressLocalityType,
+        AddressRegionType,
+        AddressPostcodeType,
+        AddressCountryType,
+        AddressPOBoxType,
         // Website
         WebsiteHomeType,
         WebsiteWorkType,
--- contacts/src/seasideproxymodel.cpp
+++ contacts/src/seasideproxymodel.cpp
@@ -32,6 +32,16 @@
     setDynamicSortFilter(true);
     setFilterKeyColumn(-1);
 
+
+    connect(this, SIGNAL(rowsInserted(QModelIndex,int,int)),
+            SIGNAL(countChanged()));
+
+    connect(this, SIGNAL(rowsRemoved(QModelIndex,int,int)),
+            SIGNAL(countChanged()));
+
+    connect(this, SIGNAL(layoutChanged()),
+            SIGNAL(countChanged()));
+
     setSourceModel(SeasidePeopleModel::instance());
     sort(0, Qt::AscendingOrder);
 }
@@ -147,4 +157,7 @@
     return m;
 }
 
-
+int SeasideProxyModel::count() const
+{
+    return rowCount(QModelIndex());
+}
--- contacts/src/seasideproxymodel.h
+++ contacts/src/seasideproxymodel.h
@@ -34,7 +34,6 @@
     };
 
     Q_INVOKABLE virtual void setFilter(FilterType filter);
-
     Q_INVOKABLE virtual void search(const QString &pattern);
 
     // for SectionScroller support
@@ -77,10 +76,12 @@
         SeasidePeopleModel *model = static_cast<SeasidePeopleModel 
*>(sourceModel());
         return model->exportContacts();
     }
-    Q_INVOKABLE int contactCount()
-    {
-        rowCount(QModelIndex());
-    }
+
+    Q_PROPERTY(int count READ count NOTIFY countChanged)
+    int count() const;
+
+signals:
+    void countChanged();
 
 protected:
     virtual bool filterAcceptsRow(int source_row, const QModelIndex& 
source_parent) const;
@@ -91,7 +92,7 @@
 
     friend class tst_SeasideProxyModel;
     SeasideProxyModelPriv *priv;
-    Q_DISABLE_COPY(SeasideProxyModel);
+    Q_DISABLE_COPY(SeasideProxyModel)
 };
 
 #endif // SEASIDEPROXYMODEL_H
--- thumbnailer/gstvideothumbnailer
+++ thumbnailer/gstvideothumbnailer
+(directory)
--- thumbnailer/gstvideothumbnailer/gstvideothumbnailer.cpp
+++ thumbnailer/gstvideothumbnailer/gstvideothumbnailer.cpp
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2012 Jolla Ltd
+ * Contact: Andrew den Exter <[email protected]>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * "Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Nemo Mobile nor the names of its contributors
+ *     may be used to endorse or promote products derived from this
+ *     software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+ */
+
+
+#include <gst/gst.h>
+#include <gst/app/gstappsink.h>
+
+#include <QImage>
+
+namespace {
+
+struct Thumbnailer
+{
+    Thumbnailer()
+        : pipeline(0)
+        , decodebin(0)
+        , transform(0)
+        , appsink(0)
+    {
+    }
+
+    ~Thumbnailer()
+    {
+        if (pipeline) {
+            gst_element_set_state(pipeline, GST_STATE_NULL);
+            gst_object_unref(GST_OBJECT(pipeline));
+        } else {
+            if (decodebin)
+                gst_object_unref(GST_OBJECT(decodebin));
+            if (transform)
+                gst_object_unref(GST_OBJECT(transform));
+            if (appsink)
+                gst_object_unref(GST_OBJECT(appsink));
+        }
+    }
+
+    GstElement *pipeline;
+    GstElement *decodebin;
+    GstElement *transform;
+    GstElement *appsink;
+};
+
+static gboolean decodebin_autoplug_continue(GstElement *, GstPad *, GstCaps 
*caps, gpointer)
+{
+    // Short cut audio streams as soon as possible so they're not decoded.
+    return qstrncmp(gst_structure_get_name(gst_caps_get_structure(caps, 0)), 
"audio/", 6) != 0;
+}
+
+static void decodebin_new_pad(GstElement *element, GstPad *pad, gpointer data)
+{
+    Q_UNUSED(element);
+    Thumbnailer *thumbnailer = static_cast<Thumbnailer *>(data);
+
+    GstCaps *caps = gst_pad_get_caps(pad);
+    GstStructure *structure = gst_caps_get_structure(caps, 0);
+
+    GstPad *sinkPad = gst_element_get_static_pad(thumbnailer->transform, 
"sink");
+
+    bool isFakeSink = false;
+    if (gst_pad_is_linked(sinkPad) || 
qstrncmp(gst_structure_get_name(structure), "video/x-raw-", 12) != 0) {
+        // Create a fake sink for any non video streams so they don't stall 
the pipeline.
+        GstElement *sink = gst_element_factory_make("fakesink", NULL);
+        sinkPad = gst_element_get_static_pad(sink, "sink");
+
+        gst_bin_add(GST_BIN(thumbnailer->pipeline), sink);
+        gst_element_set_state(sink, GST_STATE_PAUSED);
+
+        isFakeSink = true;
+    }
+
+    for (;;) {
+        switch (gst_pad_link(pad, sinkPad)) {
+        case GST_PAD_LINK_OK:
+            return;
+        default:
+            break;
+        }
+        if (isFakeSink)
+            return;
+
+        GstElement *sink = gst_element_factory_make("fakesink", NULL);
+        sinkPad = gst_element_get_static_pad(sink, "sink");
+
+        gst_bin_add(GST_BIN(thumbnailer->pipeline), sink);
+        gst_element_set_state(sink, GST_STATE_PAUSED);
+
+        isFakeSink = true;
+    }
+}
+
+}
+
+extern "C" Q_DECL_EXPORT QImage createThumbnail(const QString &fileName, const 
QSize &requestedSize, bool crop)
+{
+    static bool initialized = false;
+    if (!initialized) {
+        gst_init(0, 0);
+        initialized = true;
+    }
+
+    QImage image;
+    Thumbnailer thumbnailer;
+
+    thumbnailer.decodebin = gst_element_factory_make("uridecodebin", 
"decodebin");
+    thumbnailer.transform = gst_element_factory_make("ffmpegcolorspace", 
"transform");
+    thumbnailer.appsink = gst_element_factory_make("appsink", "sink");
+
+    if (!thumbnailer.decodebin || !thumbnailer.transform || 
!thumbnailer.appsink)
+        return image;
+
+    thumbnailer.pipeline = gst_pipeline_new(NULL);
+    if (!thumbnailer.pipeline)
+        return image;
+
+    gst_bin_add_many(GST_BIN(thumbnailer.pipeline), thumbnailer.decodebin, 
thumbnailer.transform, thumbnailer.appsink, NULL);
+
+    GstCaps *sinkCaps = gst_caps_new_simple(
+                "video/x-raw-rgb",
+                "bpp", G_TYPE_INT       , 32,
+                "depth", G_TYPE_INT     , 24,
+                "endianness", G_TYPE_INT, 4321,
+                "red_mask", G_TYPE_INT  , 0x0000FF00,
+                "green_mask", G_TYPE_INT, 0x00FF0000,
+                "blue_mask", G_TYPE_INT , 0xFF000000,
+                NULL);
+    gst_app_sink_set_caps(GST_APP_SINK(thumbnailer.appsink), sinkCaps);
+
+    gst_element_link_pads(thumbnailer.transform, "src", thumbnailer.appsink, 
"sink");
+    g_signal_connect(thumbnailer.decodebin, "autoplug-continue", 
G_CALLBACK(decodebin_autoplug_continue), &thumbnailer);
+    g_signal_connect(thumbnailer.decodebin, "pad-added", 
G_CALLBACK(decodebin_new_pad), &thumbnailer);
+
+    g_object_set(G_OBJECT(thumbnailer.decodebin), "uri", 
(QLatin1String("file://") + fileName).toLocal8Bit().constData(), NULL);
+
+    gst_element_set_state(thumbnailer.pipeline, GST_STATE_PAUSED);
+
+    GstState currentState;
+    GstState pendingState;
+    GstStateChangeReturn result = gst_element_get_state(
+                thumbnailer.pipeline,
+                &currentState,
+                &pendingState,
+                5 * GST_SECOND);
+    if (result == GST_STATE_CHANGE_SUCCESS) {
+        // Seek a little to hopefully capture something a little more 
meaningful than a fade
+        // from black.
+        gst_element_seek_simple(
+                    thumbnailer.pipeline,
+                    GST_FORMAT_TIME,
+                    GstSeekFlags(GST_SEEK_FLAG_KEY_UNIT | GST_SEEK_FLAG_FLUSH),
+                    2 * GST_SECOND);
+        if (GstBuffer *buffer = 
gst_app_sink_pull_preroll(GST_APP_SINK(thumbnailer.appsink))) {
+            GstStructure *structure = 
gst_caps_get_structure(GST_BUFFER_CAPS(buffer), 0);
+
+            int width = 0;
+            int height = 0;
+            gst_structure_get_int(structure, "width", &width);
+            gst_structure_get_int(structure, "height", &height);
+
+            if (width > 0 && height > 0) {
+                const int croppedWidth = crop ? height * requestedSize.width() 
/ requestedSize.height() : width;
+                const int croppedHeight = crop ? width * 
requestedSize.height() / requestedSize.width() : height;
+                const int bytesPerLine = width * 4;
+                QImage frame;
+
+                if (croppedWidth < width) {
+                    const uchar *data = GST_BUFFER_DATA(buffer) + (width - 
croppedWidth) * 2;
+                    frame = QImage(data, croppedWidth, height, bytesPerLine, 
QImage::Format_RGB32);
+                } else if (croppedHeight < height) {
+                    const uchar *data = GST_BUFFER_DATA(buffer) + bytesPerLine 
* ((height - croppedHeight) / 2);
+                    frame = QImage(data, width, croppedHeight, bytesPerLine, 
QImage::Format_RGB32);
+                } else {
+                    frame = QImage(GST_BUFFER_DATA(buffer), width, height, 
bytesPerLine, QImage::Format_RGB32);
+                }
+
+                image = frame.scaled(requestedSize, Qt::KeepAspectRatio, 
Qt::SmoothTransformation);
+                image.detach(); // Ensure a deep copy is made in the instance 
the image isn't scaled.
+            }
+
+            gst_buffer_unref(buffer);
+        }
+    }
+
+    return image;
+}
--- thumbnailer/gstvideothumbnailer/gstvideothumbnailer.pro
+++ thumbnailer/gstvideothumbnailer/gstvideothumbnailer.pro
@@ -0,0 +1,13 @@
+TEMPLATE = lib
+CONFIG += hide_symbols plugin
+TARGET = videothumbnailer
+
+target.path = $$[QT_INSTALL_IMPORTS]/org/nemomobile/thumbnailer/thumbnailers
+INSTALLS += target
+
+SOURCES += gstvideothumbnailer.cpp
+
+CONFIG += link_pkgconfig
+PKGCONFIG += \
+        gstreamer-0.10 \
+        gstreamer-app-0.10
--- thumbnailer/nemothumbnailitem.cpp
+++ thumbnailer/nemothumbnailitem.cpp
@@ -0,0 +1,455 @@
+/*
+ * Copyright (C) 2012 Jolla Ltd
+ * Contact: Andrew den Exter <[email protected]>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * "Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Nemo Mobile nor the names of its contributors
+ *     may be used to endorse or promote products derived from this
+ *     software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+ */
+
+#include "nemothumbnailitem.h"
+
+#include "nemothumbnailprovider.h"
+#include "nemovideothumbnailer.h"
+
+#include <QCoreApplication>
+#include <QPainter>
+#include <QPixmapCache>
+
+struct ThumbnailRequest
+{
+    ThumbnailRequest(NemoThumbnailItem *item, const QString &fileName, const 
QByteArray &cacheKey);
+    ~ThumbnailRequest();
+
+    static void enqueue(ThumbnailRequest *&queue, ThumbnailRequest *request);
+    static ThumbnailRequest *dequeue(ThumbnailRequest *&queue);
+
+    ThumbnailRequest **previous;
+    ThumbnailRequest *next;
+    NemoThumbnailItem *item;
+    QByteArray cacheKey;
+    QString fileName;
+    QString mimeType;
+    QSize size;
+    QImage image;
+    NemoThumbnailItem::FillMode fillMode;
+};
+
+ThumbnailRequest::ThumbnailRequest(
+        NemoThumbnailItem *item, const QString &fileName, const QByteArray 
&cacheKey)
+    : previous(0)
+    , next(0)
+    , item(item)
+    , cacheKey(cacheKey)
+    , fileName(fileName)
+    , mimeType(item->m_mimeType)
+    , size(item->m_sourceSize)
+    , fillMode(item->m_fillMode)
+{
+}
+
+ThumbnailRequest::~ThumbnailRequest()
+{
+    if (next)
+        next->previous = previous;
+    if (previous)
+        *previous = next;
+}
+
+void ThumbnailRequest::enqueue(ThumbnailRequest *&queue, ThumbnailRequest 
*request)
+{
+    // Remove from previous list.
+    if (request->next)
+        request->next->previous = request->previous;
+    if (request->previous)
+        *request->previous = request->next;
+
+    request->next = queue;
+    if (request->next)
+        request->next->previous = &request->next;
+    request->previous = &queue;
+    queue = request;
+}
+
+ThumbnailRequest *ThumbnailRequest::dequeue(ThumbnailRequest *&queue)
+{
+    ThumbnailRequest *request = queue;
+    if (request) {
+        if (request->next)
+            request->next->previous = &queue;
+        queue = request->next;
+        request->previous = 0;
+        request->next = 0;
+    }
+    return request;
+}
+
+NemoThumbnailItem::NemoThumbnailItem(QDeclarativeItem *parent)
+    : QDeclarativeItem(parent)
+    , m_request(0)
+    , m_priority(NormalPriority)
+    , m_status(Null)
+    , m_fillMode(PreserveAspectCrop)
+{
+    setFlag(ItemHasNoContents, false);
+}
+
+NemoThumbnailItem::~NemoThumbnailItem()
+{
+    if (m_request)
+        NemoThumbnailLoader::instance->cancelRequest(this);
+}
+
+void NemoThumbnailItem::componentComplete()
+{
+    QDeclarativeItem::componentComplete();
+
+    updateThumbnail(true);
+}
+
+QUrl NemoThumbnailItem::source() const
+{
+    return m_source;
+}
+
+void NemoThumbnailItem::setSource(const QUrl &source)
+{
+    if (m_source != source) {
+        m_source = source;
+        emit sourceChanged();
+        updateThumbnail(true);
+    }
+}
+
+QString NemoThumbnailItem::mimeType() const
+{
+    return m_mimeType;
+}
+
+void NemoThumbnailItem::setMimeType(const QString &mimeType)
+{
+    if (m_mimeType != mimeType) {
+        m_mimeType = mimeType;
+        emit mimeTypeChanged();
+        updateThumbnail(false);
+    }
+}
+
+NemoThumbnailItem::Priority NemoThumbnailItem::priority() const
+{
+    return m_priority;
+}
+
+void NemoThumbnailItem::setPriority(Priority priority)
+{
+    if (m_priority != priority) {
+        m_priority = priority;
+        emit priorityChanged();
+        if (m_request)
+            NemoThumbnailLoader::instance->updateRequest(this, false);
+    }
+}
+
+QSize NemoThumbnailItem::sourceSize() const
+{
+    return m_sourceSize;
+}
+
+void NemoThumbnailItem::setSourceSize(const QSize &size)
+{
+    if (m_sourceSize != size) {
+        m_sourceSize = size;
+        emit sourceSizeChanged();
+        updateThumbnail(true);
+    }
+}
+
+NemoThumbnailItem::FillMode NemoThumbnailItem::fillMode() const
+{
+    return m_fillMode;
+}
+
+void NemoThumbnailItem::setFillMode(FillMode mode)
+{
+    if (m_fillMode != mode) {
+        m_fillMode = mode;
+        emit fillModeChanged();
+        updateThumbnail(true);
+    }
+}
+
+NemoThumbnailItem::Status NemoThumbnailItem::status() const
+{
+    return m_status;
+}
+
+void NemoThumbnailItem::paint(QPainter *painter, const 
QStyleOptionGraphicsItem *, QWidget *)
+{
+    if (m_pixmap.isNull())
+        return;
+
+    painter->drawPixmap(QRect(0, 0, width(), height()), m_pixmap);
+}
+
+void NemoThumbnailItem::updateThumbnail(bool identityChanged)
+{
+    if (!isComponentComplete())
+        return;
+
+    if (m_source.isLocalFile() && !m_sourceSize.isEmpty())
+        NemoThumbnailLoader::instance->updateRequest(this, identityChanged);
+    else if (m_request)
+        NemoThumbnailLoader::instance->cancelRequest(this);
+
+    if (m_request && m_status != Loading) {
+        m_status = Loading;
+        emit statusChanged();
+    } else if (!m_request && !m_pixmap.isNull()) {
+        if (m_status != Ready) {
+            m_status = Ready;
+            emit statusChanged();
+        }
+        update();
+    } else if ((!m_source.isValid() || m_source.isEmpty()) && m_status != 
Null) {
+        m_status = Null;
+        emit statusChanged();
+    }
+}
+
+NemoThumbnailLoader *NemoThumbnailLoader::instance = 0;
+
+NemoThumbnailLoader::NemoThumbnailLoader(QObject *parent)
+    : QThread(parent)
+    , m_thumbnailHighPriority(0)
+    , m_thumbnailNormalPriority(0)
+    , m_thumbnailLowPriority(0)
+    , m_generateHighPriority(0)
+    , m_generateNormalPriority(0)
+    , m_generateLowPriority(0)
+    , m_completedRequests(0)
+    , m_quit(false)
+{
+    Q_ASSERT(!instance);
+    instance = this;
+}
+
+NemoThumbnailLoader::~NemoThumbnailLoader()
+{
+    shutdown();
+}
+
+void NemoThumbnailLoader::updateRequest(NemoThumbnailItem *item, bool 
identityChanged)
+{
+    QString fileName;
+    QByteArray cacheKey;
+    if (identityChanged) {
+        fileName = item->m_source.toLocalFile();
+        cacheKey = NemoThumbnailProvider::cacheKey(fileName, 
item->m_sourceSize);
+        if (item->m_fillMode == NemoThumbnailItem::PreserveAspectFit)
+            cacheKey += 'F';
+
+        QPixmap pixmap;
+        if (QPixmapCache::find(cacheKey, &pixmap)) {
+            if (item->m_request)
+                cancelRequest(item);
+            item->m_pixmap = pixmap;
+            item->setImplicitWidth(pixmap.width());
+            item->setImplicitHeight(pixmap.height());
+            return;
+        }
+    }
+
+    QMutexLocker locker(&m_mutex);
+
+    if (!item->m_request) {                     // There's no current request.
+        item->m_request = new ThumbnailRequest(item, fileName, cacheKey);
+    } else if (item->m_request->previous) {     // The current request is 
pending.
+        if (identityChanged) {
+            item->m_request->cacheKey = cacheKey;
+            item->m_request->fileName = fileName;
+            item->m_request->size = item->m_sourceSize;
+            item->m_request->fillMode = item->m_fillMode;
+        }
+        item->m_request->mimeType = item->m_mimeType;
+    } else {                                    // The current request is 
being processed. Replace it.
+        item->m_request->item = 0;
+        item->m_request = identityChanged
+                ? new ThumbnailRequest(item, fileName, cacheKey)
+                : new ThumbnailRequest(item, item->m_request->fileName, 
item->m_request->cacheKey);
+    }
+
+    ThumbnailRequest::enqueue(m_thumbnailRequests[item->m_priority], 
item->m_request);
+
+    m_waitCondition.wakeOne();
+}
+
+void NemoThumbnailLoader::cancelRequest(NemoThumbnailItem *item)
+{
+    Q_ASSERT(item->m_request);
+
+    QMutexLocker locker(&m_mutex);
+    // The only time a request doesn't belong to a list is while it is being 
processed.
+    if (item->m_request->previous)
+        delete item->m_request;
+    else
+        item->m_request->item = 0;
+    item->m_request = 0;
+}
+
+void NemoThumbnailLoader::shutdown()
+{
+    if (!instance)
+        return;
+
+    {
+        QMutexLocker locker(&instance->m_mutex);
+
+        instance->m_quit = true;
+
+        instance->m_waitCondition.wakeOne();
+    }
+
+    instance->wait();
+
+    for (int i = 0; i < NemoThumbnailItem::PriorityCount; ++i) {
+        while (instance->m_thumbnailRequests[i])
+            delete instance->m_thumbnailRequests[i];
+        while (instance->m_generateRequests[i])
+            delete instance->m_generateRequests[i];
+    }
+    while (instance->m_completedRequests)
+        delete instance->m_completedRequests;
+}
+
+bool NemoThumbnailLoader::event(QEvent *event)
+{
+    if (event->type() == QEvent::User) {
+        ThumbnailRequest *completedRequest;
+        {
+            QMutexLocker locker(&m_mutex);
+            completedRequest = m_completedRequests;
+            if (completedRequest)
+                completedRequest->previous = &completedRequest;
+            m_completedRequests = 0;
+        }
+
+        while (completedRequest) {
+            if (completedRequest->item) {
+                completedRequest->item->m_request = 0;
+                if (!completedRequest->image.isNull()) {
+                    completedRequest->item->m_pixmap = 
QPixmap::fromImage(completedRequest->image);
+                    QPixmapCache::insert(completedRequest->cacheKey, 
completedRequest->item->m_pixmap);
+                    completedRequest->item->m_status = 
NemoThumbnailItem::Ready;
+                    
completedRequest->item->setImplicitWidth(completedRequest->item->m_pixmap.width());
+                    
completedRequest->item->setImplicitHeight(completedRequest->item->m_pixmap.height());
+                    emit completedRequest->item->statusChanged();
+                } else {
+                    completedRequest->item->m_pixmap = QPixmap();
+                    completedRequest->item->m_status = 
NemoThumbnailItem::Error;
+                    emit completedRequest->item->statusChanged();
+                }
+                completedRequest->item->update();
+            }
+            delete completedRequest;
+        }
+
+        return true;
+    } else {
+        return NemoThumbnailLoader::event(event);
+    }
+}
+
+void NemoThumbnailLoader::run()
+{
+    NemoThumbnailProvider::setupCache();
+
+    QMutexLocker locker(&m_mutex);
+
+    for (;;) {
+        ThumbnailRequest *request = 0;
+        bool tryCache = true;
+        NemoThumbnailItem::Priority priority = NemoThumbnailItem::LowPriority;
+
+        // Grab the next request in priority order.  High and normal priority 
thumbnails are
+        // prioritized over generating any thumbnail, and low priority loading 
or generation
+        // is deprioritized over everything else.
+        if (m_quit) {
+            return;
+        } else if ((request = 
ThumbnailRequest::dequeue(m_thumbnailHighPriority))) {
+            priority = NemoThumbnailItem::HighPriority;
+        } else if ((request = 
ThumbnailRequest::dequeue(m_thumbnailNormalPriority))) {
+            priority = NemoThumbnailItem::NormalPriority;
+        } else if ((request = 
ThumbnailRequest::dequeue(m_generateHighPriority))) {
+            tryCache = false;
+        } else if ((request = 
ThumbnailRequest::dequeue(m_generateNormalPriority))) {
+            tryCache = false;
+        } else if ((request = 
ThumbnailRequest::dequeue(m_thumbnailLowPriority))) {
+            priority = NemoThumbnailItem::LowPriority;
+        } else if ((request = 
ThumbnailRequest::dequeue(m_generateLowPriority))) {
+            tryCache = false;
+        } else {
+            m_waitCondition.wait(&m_mutex);
+            continue;
+        }
+
+        Q_ASSERT(request);
+        const QByteArray cacheKey = request->cacheKey;
+        const QString fileName = request->fileName;
+        const QString mimeType = request->mimeType;
+        const QSize requestedSize = request->size;
+        const bool crop = request->fillMode == 
NemoThumbnailItem::PreserveAspectCrop;
+
+        locker.unlock();
+
+        if (tryCache) {
+            QImage image = NemoThumbnailProvider::loadThumbnail(fileName, 
cacheKey);
+
+            locker.relock();
+            if (!request->item) {
+                // The request was cancelled while the thumbnail was loading, 
delete it now so
+                // so to not spend time generating a thumbnail that won't be 
used.
+                delete request;
+            } else if (!image.isNull()) {
+                request->image = image;
+                if (!m_completedRequests)
+                    QCoreApplication::postEvent(this, new 
QEvent(QEvent::User));
+                ThumbnailRequest::enqueue(m_completedRequests, request);
+            } else {
+                ThumbnailRequest::enqueue(m_generateRequests[priority], 
request);
+            }
+        } else {
+            QImage image = !mimeType.startsWith(QLatin1String("video/"), 
Qt::CaseInsensitive)
+                    ? NemoThumbnailProvider::generateThumbnail(fileName, 
cacheKey, requestedSize, crop)
+                    : NemoVideoThumbnailer::generateThumbnail(fileName, 
cacheKey, requestedSize, crop);
+
+            locker.relock();
+            request->image = image;
+            if (!m_completedRequests)
+                QCoreApplication::postEvent(this, new QEvent(QEvent::User));
+            ThumbnailRequest::enqueue(m_completedRequests, request);
+        }
+    }
+}
--- thumbnailer/nemothumbnailitem.h
+++ thumbnailer/nemothumbnailitem.h
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2012 Jolla Ltd
+ * Contact: Andrew den Exter <[email protected]>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * "Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Nemo Mobile nor the names of its contributors
+ *     may be used to endorse or promote products derived from this
+ *     software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+ */
+
+#ifndef NEMOTHUMBNAILITEM_H
+#define NEMOTHUMBNAILITEM_H
+
+#include <QtCore/qmutex.h>
+#include <QtCore/qthread.h>
+#include <QtCore/qwaitcondition.h>
+#include <QtDeclarative/qdeclarativeitem.h>
+
+struct ThumbnailRequest;
+
+class NemoThumbnailItem : public QDeclarativeItem
+{
+    Q_OBJECT
+    Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+    Q_PROPERTY(QString mimeType READ mimeType WRITE setMimeType NOTIFY 
mimeTypeChanged)
+    Q_PROPERTY(QSize sourceSize READ sourceSize WRITE setSourceSize NOTIFY 
sourceSizeChanged)
+    Q_PROPERTY(FillMode fillMode READ fillMode WRITE setFillMode NOTIFY 
fillModeChanged)
+    Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY 
priorityChanged)
+    Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+    Q_ENUMS(Priority)
+    Q_ENUMS(Status)
+    Q_ENUMS(FillMode)
+public:
+    enum FillMode
+    {
+        PreserveAspectFit = 1,  // Use the same values as Image for 
compatibility.
+        PreserveAspectCrop
+    };
+
+    enum Priority
+    {
+        HighPriority,
+        NormalPriority,
+        LowPriority
+    };
+
+    enum
+    {
+        PriorityCount = 3
+    };
+
+    enum Status
+    {
+        Null,
+        Ready,
+        Loading,
+        Error
+    };
+
+    explicit NemoThumbnailItem(QDeclarativeItem *parent = 0);
+    ~NemoThumbnailItem();
+
+    void componentComplete();
+
+    QUrl source() const;
+    void setSource(const QUrl &source);
+
+    QString mimeType() const;
+    void setMimeType(const QString &mimeType);
+
+    QSize sourceSize() const;
+    void setSourceSize(const QSize &size);
+
+    FillMode fillMode() const;
+    void setFillMode(FillMode mode);
+
+    Priority priority() const;
+    void setPriority(Priority priority);
+
+    Status status() const;
+
+    void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
+
+Q_SIGNALS:
+    void sourceChanged();
+    void mimeTypeChanged();
+    void sourceSizeChanged();
+    void fillModeChanged();
+    void priorityChanged();
+    void statusChanged();
+
+private:
+    Q_DISABLE_COPY(NemoThumbnailItem)
+
+    void updateThumbnail(bool identityChanged);
+
+
+    ThumbnailRequest *m_request;
+    QUrl m_source;
+    QString m_mimeType;
+    QSize m_sourceSize;
+    QPixmap m_pixmap;
+    Priority m_priority;
+    Status m_status;
+    FillMode m_fillMode;
+
+    friend struct ThumbnailRequest;
+    friend class NemoThumbnailLoader;
+};
+
+class NemoThumbnailLoader : public QThread
+{
+public:
+    explicit NemoThumbnailLoader(QObject *parent = 0);
+    ~NemoThumbnailLoader();
+
+    void updateRequest(NemoThumbnailItem *item, bool identityChanged);
+    void cancelRequest(NemoThumbnailItem *item);
+
+    static void shutdown();
+
+    static NemoThumbnailLoader *instance;
+
+protected:
+    bool event(QEvent *event);
+    void run();
+
+private:
+    union {
+        struct {
+            ThumbnailRequest 
*m_thumbnailRequests[NemoThumbnailItem::PriorityCount];
+            ThumbnailRequest 
*m_generateRequests[NemoThumbnailItem::PriorityCount];
+        };
+        struct {
+            ThumbnailRequest *m_thumbnailHighPriority;
+            ThumbnailRequest *m_thumbnailNormalPriority;
+            ThumbnailRequest *m_thumbnailLowPriority;
+            ThumbnailRequest *m_generateHighPriority;
+            ThumbnailRequest *m_generateNormalPriority;
+            ThumbnailRequest *m_generateLowPriority;
+        };
+    };
+    ThumbnailRequest *m_completedRequests;
+
+    QMutex m_mutex;
+    QWaitCondition m_waitCondition;
+    bool m_quit;
+};
+
+#endif
--- thumbnailer/nemothumbnailprovider.cpp
+++ thumbnailer/nemothumbnailprovider.cpp
@@ -37,6 +37,7 @@
 #include <QImageReader>
 #include <QDateTime>
 #include <QtEndian>
+#include <QElapsedTimer>
 
 #undef THUMBNAILER_DEBUG
 
@@ -59,7 +60,7 @@
     return cachePath() + QDir::separator() + "raw";
 }
 
-static void setupCache()
+void NemoThumbnailProvider::setupCache()
 {
     // the syscalls make baby jesus cry; but this protects us against sins 
like users
     QDir d(cachePath());
@@ -86,7 +87,7 @@
            hashKey;
 }
 
-static QByteArray cacheKey(const QString &id, const QSize &requestedSize)
+QByteArray NemoThumbnailProvider::cacheKey(const QString &id, const QSize 
&requestedSize)
 {
     QByteArray baId = id.toLatin1(); // is there a more efficient way than a 
copy?
 
@@ -115,7 +116,7 @@
     return QImage();
 }
 
-static void writeCacheFile(const QByteArray &hashKey, const QImage &img)
+void NemoThumbnailProvider::writeCacheFile(const QByteArray &hashKey, const 
QImage &img)
 {
     QFile fi(cacheFileName(hashKey, true));
     if (!fi.open(QIODevice::WriteOnly)) {
@@ -187,7 +188,7 @@
 
     // needed for stupid things like gallery model, which pass us a url
     if (id.startsWith("file://")) {
-        qWarning() << Q_FUNC_INFO << "Removing file:// prefix, before: " << id;
+//        qWarning() << Q_FUNC_INFO << "Removing file:// prefix, before: " << 
id;
         QString &nid = const_cast<QString &>(id);
         nid = nid.remove(0, 7);
     }
@@ -209,32 +210,55 @@
         return img;
     }
 
+    return generateThumbnail(id, hashData, requestedSize);
+}
+
+QImage NemoThumbnailProvider::loadThumbnail(const QString &fileName, const 
QByteArray &cacheKey)
+{
+    return ::attemptCachedServe(fileName, cacheKey);
+}
+
+QImage NemoThumbnailProvider::generateThumbnail(const QString &id, const 
QByteArray &hashData, const QSize &requestedSize, bool crop)
+{
+    QImage img;
+    QSize originalSize;
+    QByteArray format;
+
     // image was not in cache thus we read it
     QImageReader ir(id);
-    QSize originalSize = ir.size();
-    QByteArray format = ir.format();
+    if (!ir.canRead())
+        return img;
+
+    originalSize = ir.size();
+    format = ir.format();
 
-    // scales arbitrary sized source image to requested size scaling either up 
or down
-    // keeping aspect ratio of the original image intact by maximizing either 
width or height
-    // and cropping the rest of the image away
     if (originalSize != requestedSize && originalSize.isValid()) {
-        QSize scaledSize(requestedSize);
-        // now scale it filling the original rectangle by keeping aspect ratio
-        scaledSize.scale(originalSize, Qt::KeepAspectRatio);
-
-        // set the adjusted clipping rectangle in the center of the original 
image
-        QRect clipRect(0, 0, scaledSize.width(), scaledSize.height());
-        QPoint originalCenterPoint(originalSize.width() / 2, 
originalSize.height() / 2);
-        clipRect.moveCenter(originalCenterPoint);
-        ir.setClipRect(clipRect);
-
-        // set requested target size of a thumbnail
-        // as clipping rectangle is of same aspect ratio as requestedSize no 
distortion should happen
-        ir.setScaledSize(requestedSize);
-        img = ir.read();
+        if (crop) {
+            // scales arbitrary sized source image to requested size scaling 
either up or down
+            // keeping aspect ratio of the original image intact by maximizing 
either width or height
+            // and cropping the rest of the image away
+            QSize scaledSize(requestedSize);
+            // now scale it filling the original rectangle by keeping aspect 
ratio
+            scaledSize.scale(originalSize, Qt::KeepAspectRatio);
+
+            // set the adjusted clipping rectangle in the center of the 
original image
+            QRect clipRect(0, 0, scaledSize.width(), scaledSize.height());
+            QPoint originalCenterPoint(originalSize.width() / 2, 
originalSize.height() / 2);
+            clipRect.moveCenter(originalCenterPoint);
+            ir.setClipRect(clipRect);
+
+            // set requested target size of a thumbnail
+            // as clipping rectangle is of same aspect ratio as requestedSize 
no distortion should happen
+            ir.setScaledSize(requestedSize);
+        } else {
+            // Maintains correct aspect ratio without cropping, as such the 
final image may
+            // be smaller than requested in one dimension.
+            QSize scaledSize(originalSize);
+            scaledSize.scale(requestedSize, Qt::KeepAspectRatio);
+            ir.setScaledSize(scaledSize);
+        }
     }
-    else
-        img = ir.read();
+    img = ir.read();
 
     NemoImageMetadata meta(id, format);
     if (meta.orientation() != NemoImageMetadata::TopLeft)
@@ -245,6 +269,7 @@
         (originalSize != requestedSize && originalSize.isValid())) {
         writeCacheFile(hashData, img);
     }
+
     TDEBUG() << Q_FUNC_INFO << "Wrote " << id << " to cache";
     return img;
 }
--- thumbnailer/nemothumbnailprovider.h
+++ thumbnailer/nemothumbnailprovider.h
@@ -43,6 +43,13 @@
     }
 
     QImage requestImage(const QString &id, QSize *size, const QSize 
&requestedSize);
+
+
+    static void setupCache();
+    static QByteArray cacheKey(const QString &fileName, const QSize 
&requestedSize);
+    static QImage loadThumbnail(const QString &fileName, const QByteArray 
&cacheKey);
+    static QImage generateThumbnail(const QString &fileName, const QByteArray 
&cacheKey, const QSize &requestedSize, bool crop = true);
+    static void writeCacheFile(const QByteArray &cacheKey, const QImage 
&thumbnail);
 };
 
 #endif // NEMOTHUMBNAILPROVIDER_H
--- thumbnailer/nemovideothumbnailer.cpp
+++ thumbnailer/nemovideothumbnailer.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2012 Jolla Ltd
+ * Contact: Andrew den Exter <[email protected]>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * "Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Nemo Mobile nor the names of its contributors
+ *     may be used to endorse or promote products derived from this
+ *     software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+ */
+
+#include "nemovideothumbnailer.h"
+#include "nemothumbnailprovider.h"
+
+#include <QLibrary>
+
+typedef QImage (*CreateThumbnailFunc)(const QString &fileName, const QSize 
&requestedSize, bool crop);
+
+namespace NemoVideoThumbnailer {
+
+QImage generateThumbnail(const QString &fileName, const QByteArray &cacheKey, 
const QSize &requestedSize, bool crop)
+{
+    QImage image;
+
+    static CreateThumbnailFunc createThumbnail = 
(CreateThumbnailFunc)QLibrary::resolve(
+                QLatin1String(NEMO_THUMBNAILER_DIR "/libvideothumbnailer.so"), 
"createThumbnail");
+
+    if (createThumbnail) {
+        image = createThumbnail(fileName, requestedSize, crop);
+
+        if (!image.isNull())
+            NemoThumbnailProvider::writeCacheFile(cacheKey, image);
+    } else {
+        qWarning("Cannot generate video thumbnail, thumbnailer function not 
available.");
+    }
+
+    return image;
+}
+
+}
--- thumbnailer/nemovideothumbnailer.h
+++ thumbnailer/nemovideothumbnailer.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2012 Jolla Ltd
+ * Contact: Andrew den Exter <[email protected]>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * "Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Nemo Mobile nor the names of its contributors
+ *     may be used to endorse or promote products derived from this
+ *     software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+ */
+
+#ifndef NEMOVIDEOTHUMBNAILER_H
+#define NEMOVIDEOTHUMBNAILER_H
+
+#include <QImage>
+
+namespace NemoVideoThumbnailer
+{
+    QImage generateThumbnail(const QString &fileName, const QByteArray 
&cacheKey, const QSize &requestedSize, bool crop);
+}
+
+#endif
--- thumbnailer/plugin.cpp
+++ thumbnailer/plugin.cpp
@@ -34,13 +34,9 @@
 #include <QDeclarativeEngine>
 #include <QDeclarativeExtensionPlugin>
 
+#include "nemothumbnailitem.h"
 #include "nemothumbnailprovider.h"
 
-// see registration below
-class DummyThumbnailerItem : public QDeclarativeItem
-{
-};
-
 class Q_DECL_EXPORT NemoThumbnailerPlugin : public QDeclarativeExtensionPlugin
 {
 public:
@@ -50,20 +46,20 @@
     {
         Q_ASSERT(uri == QLatin1String("org.nemomobile.thumbnailer"));
         engine->addImageProvider(QLatin1String("nemoThumbnail"), new 
NemoThumbnailProvider);
+
+        m_loader.start(QThread::IdlePriority);
+        qAddPostRoutine(NemoThumbnailLoader::shutdown);
     }
 
     void registerTypes(const char *uri)
     {
         Q_ASSERT(uri == QLatin1String("org.nemomobile.thumbnailer"));
 
-        // if we don't register at least one type, then
-        // QDeclarativeMetaType::isModule won't consider us a module. if that
-        // happens, the isModule check in QDeclarativeImportsPrivate::add will
-        // fail, and it won't consider us installed.
-        //
-        // +1 for ditzy hacks, huh?
-        qmlRegisterUncreatableType<DummyThumbnailerItem>(uri, 1, 0, 
"DummyNemoThumbnailType", "Dummy type to make QML consider this a module");
+        qmlRegisterType<NemoThumbnailItem>(uri, 1, 0, "Thumbnail");
     }
+
+private:
+    NemoThumbnailLoader m_loader;
 };
 
 Q_EXPORT_PLUGIN2(nemothumbnailer, NemoThumbnailerPlugin);
--- thumbnailer/plugin.pro
+++ thumbnailer/plugin.pro
@@ -0,0 +1,16 @@
+TARGET = nemothumbnailer
+PLUGIN_IMPORT_PATH = org/nemomobile/thumbnailer
+
+SOURCES += plugin.cpp \
+           nemothumbnailprovider.cpp \
+           nemoimagemetadata.cpp \
+           nemothumbnailitem.cpp    \
+           nemovideothumbnailer.cpp
+HEADERS += nemothumbnailprovider.h \
+           nemoimagemetadata.h \
+           nemothumbnailitem.h \
+           nemovideothumbnailer.h
+
+DEFINES += 
NEMO_THUMBNAILER_DIR=\\\"$$[QT_INSTALL_IMPORTS]/$$$$PLUGIN_IMPORT_PATH/thumbnailers\\\"
+
+include(../plugin.pri)
--- thumbnailer/thumbnailer.pro
+++ thumbnailer/thumbnailer.pro
@@ -1,10 +1,6 @@
-TARGET = nemothumbnailer
-PLUGIN_IMPORT_PATH = org/nemomobile/thumbnailer
+TEMPLATE = subdirs
 
-SOURCES += plugin.cpp \
-           nemothumbnailprovider.cpp \
-           nemoimagemetadata.cpp
-HEADERS += nemothumbnailprovider.h \
-           nemoimagemetadata.h
+SUBDIRS = plugin.pro
 
-include(../plugin.pri)
+packagesExist(gstreamer-0.10 gstreamer-app-0.10): SUBDIRS += 
gstvideothumbnailer
+else: warning("gstreamer packages not available, video thumbnailing disabled")

++++++ nemo-qml-plugins.yaml
--- nemo-qml-plugins.yaml
+++ nemo-qml-plugins.yaml
@@ -2,7 +2,7 @@
 Summary: Nemo QML plugins source package.
 Group: System/Libraries
 Description: Do not install this, install the subpackaged plugins.
-Version: 0.1.5
+Version: 0.1.6
 Release: 1
 Sources:
     - "%{name}-%{version}.tar.bz2"



Reply via email to