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/6595

Thank You,
Robin Burchell

[This message was auto-generated]

---

Request # 6595:

Messages from BOSS:

State: review at 2012-09-03T12:28:04 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: home:w00t:branches:CE:MW:Shared / nemo-qml-plugins -> CE:MW:Shared / 
nemo-qml-plugins
  
changes files:
--------------
--- nemo-qml-plugins.changes
+++ nemo-qml-plugins.changes
@@ -0,0 +1,8 @@
+* Mon Sep 3 2012 Robin Burchell <[email protected]> - 0.0.6
+- Fixes NEMO#394: Import contacts dialog shows always "Imported 0 contacts" 
(by Robin)
+- Fixes NEMO#396: Contact export always adds empty contact to the export (by 
Robin)
+- Fixes NEMO#150: Thumbnailing should use EXIF data on orientation (by Hannu 
Mallat)
+- Performance improvements in contact deletion (from Robin)
+- Fix performance in contact list sorting (from Robin)
+- Drop 0001-fix-defaults-for-variables.patch, applied upstream
+

old:
----
  0001-fix-defaults-for-variables.patch
  nemo-qml-plugins-0.0.5.tar.bz2

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

spec files:
-----------
--- nemo-qml-plugins.spec
+++ nemo-qml-plugins.spec
@@ -9,14 +9,13 @@
 # << macros
 
 Summary:    Nemo QML plugins source package.
-Version:    0.0.5
+Version:    0.0.6
 Release:    1
 Group:      System/Libraries
 License:    BSD
 URL:        https://github.com/nemomobile/nemo-qml-plugins
 Source0:    %{name}-%{version}.tar.bz2
 Source100:  nemo-qml-plugins.yaml
-Patch0:     0001-fix-defaults-for-variables.patch
 BuildRequires:  pkgconfig(QtCore) >= 4.7.0
 BuildRequires:  pkgconfig(QtDeclarative)
 BuildRequires:  pkgconfig(QtGui)
@@ -57,8 +56,6 @@
 %prep
 %setup -q -n %{name}
 
-# 0001-fix-defaults-for-variables.patch
-%patch0 -p1
 # >> setup
 # << setup
 

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

++++++ nemo-qml-plugins-0.0.5.tar.bz2 -> nemo-qml-plugins-0.0.6.tar.bz2
--- contacts/seasidepeoplemodel.cpp
+++ contacts/seasidepeoplemodel.cpp
@@ -155,7 +155,7 @@
 void SeasidePeopleModel::removePerson(SeasidePerson *person)
 {
     qDebug() << Q_FUNC_INFO << "Removing " << person;
-    // TODO: fake remove the contact, so it appears to happen faster
+
     QContactRemoveRequest *removeRequest = new QContactRemoveRequest(this);
     removeRequest->setManager(priv->manager);
     connect(removeRequest,
@@ -168,6 +168,9 @@
         qWarning() << Q_FUNC_INFO << "Remove request failed";
         delete removeRequest;
     }
+
+    // fake removal for slow managers
+    priv->contactsRemoved(QList<QContactLocalId>() << person->id());
 }
 
 QVariant SeasidePeopleModel::data(const QModelIndex& index, int role) const
@@ -194,13 +197,13 @@
 
 #include <QDir>
 
-void SeasidePeopleModel::importContacts(const QString &path)
+int SeasidePeopleModel::importContacts(const QString &path)
 {
     qDebug() << QDir::currentPath();
     QFile vcf(path);
     if (!vcf.open(QIODevice::ReadOnly)) {
         qWarning() << Q_FUNC_INFO << "Cannot open " << path;
-        return;
+        return 0;
     }
 
     // TODO: thread
@@ -218,6 +221,7 @@
 
     priv->savePendingContacts();
     qDebug() << Q_FUNC_INFO << "Imported " << newContacts.size() << " contacts 
" << " from " << path;
+    return newContacts.size();
 }
 
 QString SeasidePeopleModel::exportContacts() const
@@ -229,6 +233,10 @@
 
     foreach (const QContactLocalId &contactId, priv->contactIds) {
         SeasidePerson *p = personById(contactId);
+
+        if (p->id() == manager()->selfContactId())
+            continue;
+
         contacts.append(p->contact());
     }
 
--- contacts/seasidepeoplemodel.h
+++ contacts/seasidepeoplemodel.h
@@ -71,7 +71,7 @@
     Q_INVOKABLE SeasidePerson *personById(int id) const;
     Q_INVOKABLE SeasidePerson *personByPhoneNumber(const QString &msisdn) 
const;
     Q_INVOKABLE void removePerson(SeasidePerson *person);
-    Q_INVOKABLE void importContacts(const QString &path);
+    Q_INVOKABLE int importContacts(const QString &path);
     Q_INVOKABLE QString exportContacts() const;
 
     QContactManager *manager() const;
--- contacts/seasidepeoplemodel_p.cpp
+++ contacts/seasidepeoplemodel_p.cpp
@@ -195,9 +195,8 @@
         return;
 
     qDebug() << Q_FUNC_INFO << "Removed" << removeRequest->contactIds();
-    // TODO: where is our actual removal?
-
     removeRequest->deleteLater();
+    // actual removal done on contactsRemoved signal
 }
 
 // helper function to check validity of sender and stuff.
@@ -301,7 +300,12 @@
     foreach (const QContact &changedContact, changedContactsList) {
         qDebug() << Q_FUNC_INFO << "Fetched changed contact " << 
changedContact.id();
         QContactLocalId id = changedContact.localId();
-        int index =idToIndex.value(changedContact.localId());
+
+        QMap<QContactLocalId, int>::ConstIterator it = 
idToIndex.find(changedContact.localId());
+        if (it == idToIndex.constEnd())
+            continue;
+
+        int index = *it;
 
         if (index < min)
             min = index;
@@ -309,8 +313,6 @@
         if (index > max)
             max = index;
 
-        // FIXME: this looks like it may be wrong,
-        // could lead to multiple entries
         idToContact[id]->setContact(changedContact);
 
         // TODO: use normalized number from qtcontacts-tracker/mobility
@@ -349,14 +351,18 @@
 void SeasidePeopleModelPriv::contactsRemoved(const QList<QContactLocalId>& 
contactIds)
 {
     qDebug() << Q_FUNC_INFO << "contacts removed:" << contactIds;
-    // FIXME: the fact that we're only notified after removal may mean that we 
must
-    //   store the full contact in the model, because the data could be invalid
-    //   when the view goes to access it
 
     QList<int> removed;
-    foreach (const QContactLocalId& id, contactIds)
-        removed.push_front(idToIndex.value(id));
-    qSort(removed);
+    removed.reserve(contactIds.size());
+
+    foreach (const QContactLocalId& id, contactIds) {
+        QMap<QContactLocalId, int>::ConstIterator it = idToIndex.find(id);
+        if (it == idToIndex.end())
+            continue;
+
+        removed.push_front(*it);
+    }
+    std::sort(removed.begin(), removed.end());
 
     // NOTE: this could check for adjacent rows being removed and send fewer 
signals
     int size = removed.size();
@@ -366,12 +372,16 @@
         q->beginRemoveRows(QModelIndex(), index, index);
         QContactLocalId id = this->contactIds.takeAt(index);
 
-        delete idToContact.take(id);
+        // don't use delete here, otherwise it'll break the fake removal of
+        // contacts in the case of the memory manager (remove request -> 
instant
+        // non-queued contactsRemoved -> gets us back here again, so we delete
+        // the contact before we've had a chance to fake the removal)
+        idToContact.take(id)->deleteLater();
         idToIndex.remove(id);
 
         foreach(const QString &phoneNumber, phoneNumbersToContactIds.keys()) {
             QContactLocalId cId = phoneNumbersToContactIds.value(phoneNumber);
-            if(cId = id) phoneNumbersToContactIds.remove(phoneNumber);
+            if(cId == id) phoneNumbersToContactIds.remove(phoneNumber);
         }
 
         q->endRemoveRows();
--- contacts/seasidepeoplemodel_p.h
+++ contacts/seasidepeoplemodel_p.h
@@ -52,6 +52,7 @@
 public slots:
     void dataReset();
     void savePendingContacts();
+    void contactsRemoved(const QList<QContactLocalId>& contactIds);
 
 private slots:
     void onSaveStateChanged(QContactAbstractRequest::State requestState);
@@ -62,9 +63,6 @@
 
     void contactsAdded(const QList<QContactLocalId>& contactIds);
     void contactsChanged(const QList<QContactLocalId>& contactIds);
-    void contactsRemoved(const QList<QContactLocalId>& contactIds);
-
-
 
 private:
     Q_DISABLE_COPY(SeasidePeopleModelPriv);
--- contacts/seasideproxymodel.h
+++ contacts/seasideproxymodel.h
@@ -68,10 +68,10 @@
         SeasidePeopleModel *model = static_cast<SeasidePeopleModel 
*>(sourceModel());
         model->removePerson(person);
     }
-    Q_INVOKABLE void importContacts(const QString &path)
+    Q_INVOKABLE int importContacts(const QString &path)
     {
         SeasidePeopleModel *model = static_cast<SeasidePeopleModel 
*>(sourceModel());
-        model->importContacts(path);
+        return model->importContacts(path);
     }
     Q_INVOKABLE QString exportContacts()
     {
--- folderlistmodel/dirmodel.cpp
+++ folderlistmodel/dirmodel.cpp
@@ -88,7 +88,10 @@
     QString mPathName;
 };
 
-DirModel::DirModel(QObject *parent) : QAbstractListModel(parent)
+DirModel::DirModel(QObject *parent)
+    : QAbstractListModel(parent)
+    , mAwaitingResults(false)
+    , mShowDirectories(true)
 {
     mNameFilters = QStringList() << "*";
 
--- thumbnailer/nemoimagemetadata.cpp
+++ thumbnailer/nemoimagemetadata.cpp
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2012 Hannu Mallat <[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 "nemoimagemetadata.h"
+
+#include <QFile>
+#include <QString>
+#include <QtEndian>
+
+#define EXIF_TIFF_LSB_MAGIC "Exif\x00\x00II\x2a\x00"
+#define EXIF_TIFF_MSB_MAGIC "Exif\x00\x00MM\x00\x2a"
+#define EXIF_TIFF_MAGIC_LEN 10
+
+#define TIFF_HEADER_LEN 8
+#define TIFF_IFD_ENTRY_LEN 12
+
+#define EXIF_IDENTIFIER_LEN 6
+
+#define EXIF_TYPE_SHORT 3
+
+#define EXIF_TAG_ORIENTATION 0x112
+
+/* Standalone markers without length information */
+#define JPEG_MARKER_TEM  0x01
+#define JPEG_MARKER_RST0 0xd0
+#define JPEG_MARKER_RST1 0xd1
+#define JPEG_MARKER_RST2 0xd2
+#define JPEG_MARKER_RST3 0xd3
+#define JPEG_MARKER_RST4 0xd4
+#define JPEG_MARKER_RST5 0xd5
+#define JPEG_MARKER_RST6 0xd6
+#define JPEG_MARKER_RST7 0xd7
+#define JPEG_MARKER_SOI  0xd8
+#define JPEG_MARKER_EOI  0xd9
+
+#define JPEG_MARKER_APP1 0xe1
+
+#define JPEG_MARKER_PREFIX 0xff
+
+static uchar getMarker(QFile &f)
+{
+    /* CCITT T.81 Annex B: "All markers are assigned two-byte
+       codes: an XFF byte followed by a byte which is not equal
+       to 0 or XFF (see Table B.1). Any marker may optionally be
+       preceded by any number of fill bytes, which are bytes
+       assigned code XFF." */
+
+    uchar c;
+
+    if (!f.getChar(reinterpret_cast<char*>(&c)) || c != JPEG_MARKER_PREFIX)
+        return 0;
+
+    while (c == JPEG_MARKER_PREFIX)
+        if (f.getChar(reinterpret_cast<char*>(&c)) == false)
+            return 0;
+
+    if (c == 0) /* Not a marker */
+        return 0;
+
+    return c;
+}
+
+static quint16 getMarkerLength(QFile &f)
+{
+    char buf[2];
+
+    if (f.read(buf, 2) != 2)
+        return 0;
+    return qFromBigEndian<quint16>(reinterpret_cast<uchar *>(buf));
+}
+
+static bool getExifData(QFile &f, QByteArray &data)
+{
+    uchar marker;
+    quint16 len;
+    qint64 skip;
+
+    f.seek(0);
+
+    marker = getMarker(f);
+    if (marker != JPEG_MARKER_SOI)
+        return false;
+    while (true) {
+        marker = getMarker(f);
+        if (marker == 0)
+            return false;
+
+        switch (marker) {
+
+            case JPEG_MARKER_SOI: /* shouldn't see this anymore */
+            case JPEG_MARKER_EOI: /* end of the line, no EXIF in sight */
+                return false;
+
+            case JPEG_MARKER_TEM:
+            case JPEG_MARKER_RST0:
+            case JPEG_MARKER_RST1:
+            case JPEG_MARKER_RST2:
+            case JPEG_MARKER_RST3:
+            case JPEG_MARKER_RST4:
+            case JPEG_MARKER_RST5:
+            case JPEG_MARKER_RST6:
+            case JPEG_MARKER_RST7:
+                /* Standalones, just skip */
+                break;
+
+            case JPEG_MARKER_APP1:
+                /* CCITT T.81 Annex B:
+                   The first parameter in a marker segment is the
+                   two-byte length parameter. This length parameter
+                   encodes the number of bytes in the marker segment,
+                   including the length parameter and excluding the
+                   two-byte marker. */
+                len = getMarkerLength(f);
+                if (len < 2)
+                    return false;
+                data.resize(len - 2);
+                if (f.read(data.data(), len - 2) != len - 2)
+                    return false;
+                return true;
+
+            default:
+                /* Marker segment, just skip. */
+                len = getMarkerLength(f);
+                if (len < 2)
+                    return false;
+                skip = f.pos() + static_cast<qint64>(len) - 2;
+                f.seek(skip);
+                if (f.pos() != skip)
+                    return false;
+                break;
+        }
+    }
+}
+
+static
+NemoImageMetadata::Orientation exifOrientationFromJpeg(const QString &fname)
+{
+    QByteArray data;
+    const uchar *ptr;
+    quint32 len;
+    quint32 pos;
+    bool msbFirst;
+    quint32 ifdOff;
+    quint16 fieldCount;
+    quint16 o;
+
+    QFile f(fname);
+    if (f.open(QIODevice::ReadOnly) == false || getExifData(f, data) == false)
+        goto exit;
+
+    ptr = reinterpret_cast<const uchar *>(data.constData());
+    len = data.length();
+    pos = 0;
+
+    /* 6 bytes for Exif identifier, 8 bytes for TIFF header */
+    if (len < EXIF_IDENTIFIER_LEN + TIFF_HEADER_LEN)
+        goto exit;
+
+    if (memcmp(ptr + pos, EXIF_TIFF_LSB_MAGIC, EXIF_TIFF_MAGIC_LEN) == 0)
+        msbFirst = false;
+    else if (memcmp(ptr + pos, EXIF_TIFF_MSB_MAGIC, EXIF_TIFF_MAGIC_LEN) == 0)
+        msbFirst = true;
+    else
+        goto exit;
+
+    ifdOff = msbFirst
+        ? qFromBigEndian<quint32>(ptr + pos + EXIF_TIFF_MAGIC_LEN)
+        : qFromLittleEndian<quint32>(ptr + pos + EXIF_TIFF_MAGIC_LEN);
+
+    /* IFD offset is measured from TIFF header and can't go backwards */
+    if (ifdOff < TIFF_HEADER_LEN)
+        goto exit;
+
+    pos = EXIF_IDENTIFIER_LEN + ifdOff;
+
+    if (len < pos + 2)
+        goto exit;
+    fieldCount = msbFirst
+        ? qFromBigEndian<quint16>(ptr + pos)
+        : qFromLittleEndian<quint16>(ptr + pos);
+    pos += 2;
+    if (len < pos + TIFF_IFD_ENTRY_LEN*static_cast<quint32>(fieldCount))
+        goto exit;
+
+    for (quint16 f = 0; f < fieldCount; f++) {
+        quint16 tag = msbFirst
+            ? qFromBigEndian<quint16>(ptr + pos)
+            : qFromLittleEndian<quint16>(ptr + pos);
+        quint16 type = msbFirst
+            ? qFromBigEndian<quint16>(ptr + pos + 2)
+            : qFromLittleEndian<quint16>(ptr + pos + 2);
+        quint32 num = msbFirst
+            ? qFromBigEndian<quint32>(ptr + pos + 4)
+            : qFromLittleEndian<quint32>(ptr + pos + 4);
+        if (tag == EXIF_TAG_ORIENTATION &&
+            type == EXIF_TYPE_SHORT &&
+            num == 1) {
+            o = msbFirst
+                ? qFromBigEndian<quint16>(ptr + pos + 8)
+                : qFromLittleEndian<quint16>(ptr + pos + 8);
+            goto exit;
+        } else {
+            pos += TIFF_IFD_ENTRY_LEN;
+        }
+    }
+
+    /* We're only interested in the 0th IFD, so quit when at its end */
+
+exit:
+    f.close();
+
+    if (o < static_cast<quint16>(NemoImageMetadata::TopLeft) || 
+        o > static_cast<quint16>(NemoImageMetadata::LeftBottom))
+        return NemoImageMetadata::TopLeft;
+
+    return static_cast<NemoImageMetadata::Orientation>(o);
+}
+
+NemoImageMetadata::NemoImageMetadata()
+    : m_orientation(NemoImageMetadata::TopLeft)
+{
+}
+
+NemoImageMetadata::NemoImageMetadata(const QString &filename,
+                                     const QByteArray &format)
+    : m_orientation(NemoImageMetadata::TopLeft)
+{
+    if (format == "jpeg")
+        m_orientation = exifOrientationFromJpeg(filename);
+}
+
+NemoImageMetadata::NemoImageMetadata(const NemoImageMetadata &other)
+    : m_orientation(other.m_orientation)
+{
+}
+
+NemoImageMetadata &NemoImageMetadata::operator=(const NemoImageMetadata &other)
+{
+    if (&other == this)
+        return *this;
+
+    m_orientation = other.m_orientation;
+    return *this;
+}
+
+NemoImageMetadata::~NemoImageMetadata()
+{
+}
--- thumbnailer/nemoimagemetadata.h
+++ thumbnailer/nemoimagemetadata.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2012 Hannu Mallat <[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 NEMOIMAGEMETADATA_H
+#define NEMOIMAGEMETADATA_H
+
+class QString;
+class QByteArray;
+
+#include <QMetaType>
+
+class NemoImageMetadata
+{
+public:
+
+    enum Orientation {
+        TopLeft = 1,
+        TopRight,
+        BottomRight,
+        BottomLeft,
+        LeftTop,
+        RightTop,
+        RightBottom,
+        LeftBottom
+    };
+
+    NemoImageMetadata();
+
+    NemoImageMetadata(const QString &filename, const QByteArray &format);
+
+    NemoImageMetadata(const NemoImageMetadata &other);
+
+    ~NemoImageMetadata();
+
+    NemoImageMetadata &operator=(const NemoImageMetadata &other);
+
+    Orientation orientation(void) const {
+        return m_orientation;
+    }
+
+private:
+
+    Orientation m_orientation;
+
+};
+
+Q_DECLARE_METATYPE(NemoImageMetadata)
+
+Q_DECLARE_METATYPE(NemoImageMetadata::Orientation)
+
+#endif // NEMOIMAGEMETADATA_H
--- thumbnailer/nemothumbnailprovider.cpp
+++ thumbnailer/nemothumbnailprovider.cpp
@@ -36,6 +36,7 @@
 #include <QDir>
 #include <QImageReader>
 #include <QDateTime>
+#include <QtEndian>
 
 #undef THUMBNAILER_DEBUG
 
@@ -45,6 +46,7 @@
 #define TDEBUG if(false)qDebug
 #endif
 
+#include "nemoimagemetadata.h"
 #include "nemothumbnailprovider.h"
 
 static inline QString cachePath()
@@ -106,6 +108,60 @@
     fi.close();
 }
 
+static QImage rotate(const QImage &src,
+                     NemoImageMetadata::Orientation orientation)
+{
+    QTransform trans;
+    QImage dst, tmp;
+
+    /* For square images 90-degree rotations of the pixel could be
+       done in-place, and flips could be done in-place for any image
+       instead of using the QImage routines which make copies of the
+       data. */
+
+    switch (orientation) {
+        case NemoImageMetadata::TopRight:
+            /* horizontal flip */
+            dst = src.mirrored(true, false);
+            break;
+        case NemoImageMetadata::BottomRight:
+            /* horizontal flip, vertical flip */
+            dst = src.mirrored(true, true);
+            break;
+        case NemoImageMetadata::BottomLeft:
+            /* vertical flip */
+            dst = src.mirrored(false, true);
+            break;
+        case NemoImageMetadata::LeftTop:
+            /* rotate 90 deg clockwise and flip horizontally */
+            trans.rotate(90.0);
+            tmp = src.transformed(trans);
+            dst = tmp.mirrored(true, false);
+            break;
+        case NemoImageMetadata::RightTop:
+            /* rotate 90 deg anticlockwise */
+            trans.rotate(90.0);
+            dst = src.transformed(trans);
+            break;
+        case NemoImageMetadata::RightBottom:
+            /* rotate 90 deg anticlockwise and flip horizontally */
+            trans.rotate(-90.0);
+            tmp = src.transformed(trans);
+            dst = tmp.mirrored(true, false);
+            break;
+        case NemoImageMetadata::LeftBottom:
+            /* rotate 90 deg clockwise */
+            trans.rotate(-90.0);
+            dst = src.transformed(trans);
+            break;
+        default:
+            dst = src;
+            break;
+    }
+
+    return dst;
+}
+
 QImage NemoThumbnailProvider::requestImage(const QString &id, QSize *size, 
const QSize &requestedSize)
 {
     setupCache();
@@ -137,6 +193,7 @@
     // image was not in cache thus we read it
     QImageReader ir(id);
     QSize originalSize = ir.size();
+    QByteArray 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
@@ -158,10 +215,17 @@
         img = ir.read();
     }
     else
-        return ir.read();
+        img = ir.read();
+
+    NemoImageMetadata meta(id, format);
+    if (meta.orientation() != NemoImageMetadata::TopLeft)
+        img = rotate(img, meta.orientation());
 
     // write the scaled image to cache
-    writeCacheFile(hashData, img);
+    if (meta.orientation() != NemoImageMetadata::TopLeft ||
+        (originalSize != requestedSize && originalSize.isValid())) {
+        writeCacheFile(hashData, img);
+    }
     TDEBUG() << Q_FUNC_INFO << "Wrote " << id << " to cache";
     return img;
 }
--- thumbnailer/thumbnailer.pro
+++ thumbnailer/thumbnailer.pro
@@ -2,8 +2,10 @@
 PLUGIN_IMPORT_PATH = org/nemomobile/thumbnailer
 
 SOURCES += plugin.cpp \
-           nemothumbnailprovider.cpp
-HEADERS += nemothumbnailprovider.h
+           nemothumbnailprovider.cpp \
+           nemoimagemetadata.cpp
+HEADERS += nemothumbnailprovider.h \
+           nemoimagemetadata.h
 
 # do not edit below here, move this to a shared .pri?
 TEMPLATE = lib

++++++ nemo-qml-plugins.yaml
--- nemo-qml-plugins.yaml
+++ nemo-qml-plugins.yaml
@@ -2,12 +2,10 @@
 Summary: Nemo QML plugins source package.
 Group: System/Libraries
 Description: Do not install this, install the subpackaged plugins.
-Version: 0.0.5
+Version: 0.0.6
 Release: 1
 Sources:
     - "%{name}-%{version}.tar.bz2"
-Patches:
-    - 0001-fix-defaults-for-variables.patch
 License: BSD
 URL: https://github.com/nemomobile/nemo-qml-plugins
 Configure: none

++++++ deleted files:
--- 0001-fix-defaults-for-variables.patch



Reply via email to