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

Thank You,
Robin Burchell

[This message was auto-generated]

---

Request # 5594:

Messages from BOSS:

State: review at 2012-08-12T21:15:00 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 @@
+* Sun Aug 12 2012 Robin Burchell <[email protected]> - 0.0.5
+- folderlistmodel: New plugin from qmlfilemuncher code (by Robin)
+- folderlistmodel: Add properties for permissions to folderlistmodel (by Petri 
Gerdt)
+- folderlistmodel: API to customise display of folderlistmodel (by Robin)
+- folderlistmodel: Ignore repeated path change requests in folderlistmodel (by 
Robin)
+- contacts: Added lookup for Person by phone number (by Tom Swindell)
+- contacts: Provide basic import/export functionality
+

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

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

spec files:
-----------
--- nemo-qml-plugins.spec
+++ nemo-qml-plugins.spec
@@ -9,13 +9,14 @@
 # << macros
 
 Summary:    Nemo QML plugins source package.
-Version:    0.0.4
+Version:    0.0.5
 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)
@@ -45,10 +46,19 @@
 %description qrencode
 A QML QR encoder plugin
 
+%package folderlistmodel
+Summary:    Folder list model for QML applications
+Group:      System/Libraries
+
+%description folderlistmodel
+A model providing a view of the filesystem for QML applications
+
 
 %prep
 %setup -q -n %{name}
 
+# 0001-fix-defaults-for-variables.patch
+%patch0 -p1
 # >> setup
 # << setup
 
@@ -90,3 +100,9 @@
 %{_libdir}/qt4/imports/org/nemomobile/qrencode/*
 # >> files qrencode
 # << files qrencode
+
+%files folderlistmodel
+%defattr(-,root,root,-)
+%{_libdir}/qt4/imports/org/nemomobile/folderlistmodel/*
+# >> files folderlistmodel
+# << files folderlistmodel

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

++++++ 0001-fix-defaults-for-variables.patch (new)
--- 0001-fix-defaults-for-variables.patch
+++ 0001-fix-defaults-for-variables.patch
@@ -0,0 +1,28 @@
+From e10ee2fb051146ec7e2256352eac4f1814f970d7 Mon Sep 17 00:00:00 2001
+From: Robin Burchell <[email protected]>
+Date: Sun, 12 Aug 2012 22:08:40 +0200
+Subject: [PATCH] fix defaults for variables
+
+---
+ folderlistmodel/dirmodel.cpp | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/folderlistmodel/dirmodel.cpp b/folderlistmodel/dirmodel.cpp
+index e1b3542..afefa89 100644
+--- a/folderlistmodel/dirmodel.cpp
++++ b/folderlistmodel/dirmodel.cpp
+@@ -88,7 +88,10 @@ private:
+     QString mPathName;
+ };
+ 
+-DirModel::DirModel(QObject *parent) : QAbstractListModel(parent)
++DirModel::DirModel(QObject *parent)
++    : QAbstractListModel(parent)
++    , mAwaitingResults(false)
++    , mShowDirectories(true)
+ {
+     mNameFilters = QStringList() << "*";
+ 
+-- 
+1.7.11.2
+

++++++ nemo-qml-plugins-0.0.4.tar.bz2 -> nemo-qml-plugins-0.0.5.tar.bz2
--- README
+++ README
@@ -15,3 +15,6 @@
 - contacts: offers an API similar to QtMobility.contacts, except without the
   fail
 
+- qrencode: QR encoder API, using qrencode library.
+
+- folderlistmodel: threaded (and faster) version of Qt.labs.folderlistmodel
--- contacts/seasidepeoplemodel.cpp
+++ contacts/seasidepeoplemodel.cpp
@@ -33,6 +33,8 @@
 #include <QFile>
 #include <QVector>
 
+#include <QDesktopServices>
+
 #include <QContactAddress>
 #include <QContactAvatar>
 #include <QContactThumbnail>
@@ -55,7 +57,9 @@
 #include <QContactManagerEngine>
 
 #include <QVersitReader>
+#include <QVersitWriter>
 #include <QVersitContactImporter>
+#include <QVersitContactExporter>
 
 #include "seasideperson.h"
 #include "seasidepeoplemodel.h"
@@ -138,6 +142,16 @@
     return person;
 }
 
+SeasidePerson *SeasidePeopleModel::personByPhoneNumber(const QString &msisdn) 
const
+{
+    QString normalizedNumber = 
SeasidePeopleModelPriv::normalizePhoneNumber(msisdn);
+
+    if(normalizedNumber.isEmpty() || 
!priv->phoneNumbersToContactIds.contains(normalizedNumber)) return NULL;
+
+    QContactLocalId localId = 
priv->phoneNumbersToContactIds.value(normalizedNumber);
+    return priv->idToContact.value(localId);
+}
+
 void SeasidePeopleModel::removePerson(SeasidePerson *person)
 {
     qDebug() << Q_FUNC_INFO << "Removing " << person;
@@ -189,6 +203,7 @@
         return;
     }
 
+    // TODO: thread
     QVersitReader reader(&vcf);
     reader.startReading();
     reader.waitForFinished();
@@ -205,6 +220,45 @@
     qDebug() << Q_FUNC_INFO << "Imported " << newContacts.size() << " contacts 
" << " from " << path;
 }
 
+QString SeasidePeopleModel::exportContacts() const
+{
+    QVersitContactExporter exporter;
+
+    QList<QContact> contacts;
+    contacts.reserve(priv->contactIds.size());
+
+    foreach (const QContactLocalId &contactId, priv->contactIds) {
+        SeasidePerson *p = personById(contactId);
+        contacts.append(p->contact());
+    }
+
+    if (!exporter.exportContacts(contacts)) {
+        qWarning() << Q_FUNC_INFO << "Failed to export contacts: " << 
exporter.errorMap();
+        return QString();
+    }
+
+    QFile
+        
vcard(QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation)
+              + QDir::separator()
+              + QDateTime::currentDateTime().toString("ss_mm_hh_dd_mm_yyyy")
+              + ".vcf");
+
+    if (!vcard.open(QIODevice::WriteOnly)) {
+        qWarning() << "Cannot open " << vcard.fileName();
+        return QString();
+    }
+
+    QVersitWriter writer(&vcard);
+    if (!writer.startWriting(exporter.documents())) {
+        qWarning() << Q_FUNC_INFO << "Can't start writing vcards " << 
writer.error();
+        return QString();
+    }
+
+    // TODO: thread
+    writer.waitForFinished();
+    return vcard.fileName();
+}
+
 QContactManager *SeasidePeopleModel::manager() const
 {
     return priv->manager;
--- contacts/seasidepeoplemodel.h
+++ contacts/seasidepeoplemodel.h
@@ -69,8 +69,10 @@
     Q_INVOKABLE bool savePerson(SeasidePerson *person);
     Q_INVOKABLE SeasidePerson *personByRow(int row) const;
     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 QString exportContacts() const;
 
     QContactManager *manager() const;
 
--- contacts/seasidepeoplemodel_p.cpp
+++ contacts/seasidepeoplemodel_p.cpp
@@ -67,9 +67,18 @@
     dataReset();
 }
 
+QString SeasidePeopleModelPriv::normalizePhoneNumber(const QString &msisdn)
+{
+    // TODO:Possibly be more efficient here.
+    QString normalized = msisdn;
+    normalized.replace(QRegExp("[^0-9]"), "");
+    return normalized.right(7);
+}
+
 void SeasidePeopleModelPriv::addContacts(const QList<QContact> contactsList, 
int size)
 {
     foreach (const QContact &contact, contactsList) {
+        SeasidePerson *person = new SeasidePerson(contact);
         //qDebug() << Q_FUNC_INFO << "Adding contact " << contact.id() << " 
local " << contact.localId();
         QContactLocalId id = contact.localId();
 
@@ -78,7 +87,15 @@
           contactIds.push_back(id);
           idToIndex.insert(id, size++);
         }
-        idToContact.insert(id, new SeasidePerson(contact));
+        idToContact.insert(id, person);
+
+        // Create normalized numbers -> contact id map.
+        foreach(const QString &sourcePhoneNumber, person->phoneNumbers()) {
+            QString normalizedPhoneNumber = 
SeasidePeopleModelPriv::normalizePhoneNumber(sourcePhoneNumber);
+            if(phoneNumbersToContactIds.contains(normalizedPhoneNumber)) 
continue; // Ignore duplicates, first-come-first-serve.
+
+            phoneNumbersToContactIds.insert(normalizedPhoneNumber, 
contact.localId());
+        }
     }
 }
 
@@ -283,6 +300,7 @@
 
     foreach (const QContact &changedContact, changedContactsList) {
         qDebug() << Q_FUNC_INFO << "Fetched changed contact " << 
changedContact.id();
+        QContactLocalId id = changedContact.localId();
         int index =idToIndex.value(changedContact.localId());
 
         if (index < min)
@@ -293,7 +311,31 @@
 
         // FIXME: this looks like it may be wrong,
         // could lead to multiple entries
-       idToContact[changedContact.localId()]->setContact(changedContact);
+        idToContact[id]->setContact(changedContact);
+
+        // TODO: use normalized number from qtcontacts-tracker/mobility
+        SeasidePerson *person = idToContact[id];
+        foreach(const QString &msisdn, person->phoneNumbers()) {
+            QString normalizedPhoneNumber = 
SeasidePeopleModelPriv::normalizePhoneNumber(msisdn);
+
+            if(!phoneNumbersToContactIds.contains(normalizedPhoneNumber)) {
+                phoneNumbersToContactIds.insert(normalizedPhoneNumber, id);
+            }
+        }
+
+        foreach(const QString &phoneNumber, phoneNumbersToContactIds.keys()) {
+           bool remove = true;
+           foreach(const QString &msisdn, person->phoneNumbers()) {
+               QString normalizedPhoneNumber = 
SeasidePeopleModelPriv::normalizePhoneNumber(msisdn);
+               if(phoneNumber == normalizedPhoneNumber) {
+                   remove = false;
+                   break;
+               }
+           }
+           if(remove) {
+               phoneNumbersToContactIds.remove(phoneNumber);
+           }
+        }
     }
 
     // FIXME: unfortunate that we can't easily identify what changed
@@ -326,6 +368,12 @@
 
         delete idToContact.take(id);
         idToIndex.remove(id);
+
+        foreach(const QString &phoneNumber, phoneNumbersToContactIds.keys()) {
+            QContactLocalId cId = phoneNumbersToContactIds.value(phoneNumber);
+            if(cId = id) phoneNumbersToContactIds.remove(phoneNumber);
+        }
+
         q->endRemoveRows();
     }
     fixIndexMap();
@@ -364,6 +412,7 @@
     qDeleteAll(idToContact);
     idToContact.clear();
     idToIndex.clear();
+    phoneNumbersToContactIds.clear();
 
     addContacts(contactsList, size);
 
--- contacts/seasidepeoplemodel_p.h
+++ contacts/seasidepeoplemodel_p.h
@@ -37,12 +37,14 @@
     QList<QContactLocalId> contactIds;
     QMap<QContactLocalId, int> idToIndex;
     QMap<QContactLocalId, SeasidePerson *> idToContact;
+    QMap<QString, QContactLocalId> phoneNumbersToContactIds;
     QVector<QStringList> data;
     QStringList headers;
     LocaleUtils *localeHelper;
     QContactGuid currentGuid;
     QList<QContact> contactsPendingSave;
 
+    static QString normalizePhoneNumber(const QString &msisdn);
 
     void addContacts(const QList<QContact> contactsList, int size);
     void fixIndexMap();
--- contacts/seasideproxymodel.h
+++ contacts/seasideproxymodel.h
@@ -58,6 +58,11 @@
         SeasidePeopleModel *model = static_cast<SeasidePeopleModel 
*>(sourceModel());
         return model->personById(id);
     }
+    Q_INVOKABLE SeasidePerson *personByPhoneNumber(const QString &msisdn) const
+    {
+        SeasidePeopleModel *model = 
static_cast<SeasidePeopleModel*>(sourceModel());
+        return model->personByPhoneNumber(msisdn);
+    }
     Q_INVOKABLE void removePerson(SeasidePerson *person)
     {
         SeasidePeopleModel *model = static_cast<SeasidePeopleModel 
*>(sourceModel());
@@ -68,6 +73,11 @@
         SeasidePeopleModel *model = static_cast<SeasidePeopleModel 
*>(sourceModel());
         model->importContacts(path);
     }
+    Q_INVOKABLE QString exportContacts()
+    {
+        SeasidePeopleModel *model = static_cast<SeasidePeopleModel 
*>(sourceModel());
+        return model->exportContacts();
+    }
 
 signals:
     void countChanged();
--- folderlistmodel
+++ folderlistmodel
+(directory)
--- folderlistmodel/dirmodel.cpp
+++ folderlistmodel/dirmodel.cpp
@@ -0,0 +1,382 @@
+/*
+ * Copyright (C) 2012 Robin Burchell <[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 <QDirIterator>
+#include <QDir>
+#include <QDebug>
+#include <QDateTime>
+#include <QUrl>
+
+#include <errno.h>
+#include <string.h>
+
+#include "dirmodel.h"
+#include "ioworkerthread.h"
+
+Q_GLOBAL_STATIC(IOWorkerThread, ioWorkerThread);
+
+class DirListWorker : public IORequest
+{
+    Q_OBJECT
+public:
+    DirListWorker(const QString &pathName)
+        : mPathName(pathName)
+    { }
+
+    void run()
+    {
+        qDebug() << Q_FUNC_INFO << "Running on: " << 
QThread::currentThreadId();
+
+        QDir tmpDir = QDir(mPathName);
+        QDirIterator it(tmpDir);
+        QVector<QFileInfo> directoryContents;
+
+        while (it.hasNext()) {
+            it.next();
+
+            // skip hidden files
+            if (it.fileName()[0] == QLatin1Char('.'))
+                continue;
+
+            directoryContents.append(it.fileInfo());
+            if (directoryContents.count() >= 50) {
+                emit itemsAdded(directoryContents);
+
+                // clear() would force a deallocation, micro-optimisation
+                directoryContents.erase(directoryContents.begin(), 
directoryContents.end());
+            }
+        }
+
+        // last batch
+        emit itemsAdded(directoryContents);
+
+        //std::sort(directoryContents.begin(), directoryContents.end(), 
DirModel::fileCompare);
+    }
+
+signals:
+    void itemsAdded(const QVector<QFileInfo> &files);
+
+private:
+    QString mPathName;
+};
+
+DirModel::DirModel(QObject *parent) : QAbstractListModel(parent)
+{
+    mNameFilters = QStringList() << "*";
+
+    QHash<int, QByteArray> roles = roleNames();
+    roles.insert(FileNameRole, QByteArray("fileName"));
+    roles.insert(CreationDateRole, QByteArray("creationDate"));
+    roles.insert(ModifiedDateRole, QByteArray("modifiedDate"));
+    roles.insert(FileSizeRole, QByteArray("fileSize"));
+    roles.insert(IconSourceRole, QByteArray("iconSource"));
+    roles.insert(FilePathRole, QByteArray("filePath"));
+    roles.insert(IsDirRole, QByteArray("isDir"));
+    roles.insert(IsFileRole, QByteArray("isFile"));
+    roles.insert(IsReadableRole, QByteArray("isReadable"));
+    roles.insert(IsWritableRole, QByteArray("isWritable"));
+    roles.insert(IsExecutableRole, QByteArray("isExecutable"));
+    setRoleNames(roles);
+
+    // populate reverse mapping
+    QHash<int, QByteArray>::ConstIterator it = roles.constBegin();
+    for (;it != roles.constEnd(); ++it)
+        mRoleMapping.insert(it.value(), it.key());
+
+    // make sure we cover all roles
+//    Q_ASSERT(roles.count() == IsFileRole - FileNameRole);
+}
+
+QVariant DirModel::data(int row, const QByteArray &stringRole) const
+{
+    QHash<QByteArray, int>::ConstIterator it = 
mRoleMapping.constFind(stringRole);
+
+    if (it == mRoleMapping.constEnd())
+        return QVariant();
+
+    return data(index(row, 0), *it);
+}
+
+QVariant DirModel::data(const QModelIndex &index, int role) const
+{
+    if (role < FileNameRole || role > IsExecutableRole) {
+        qWarning() << Q_FUNC_INFO << "Got an out of range role: " << role;
+        return QVariant();
+    }
+
+    if (index.row() < 0 || index.row() >= mDirectoryContents.count()) {
+        qWarning() << "Attempted to access out of range row: " << index.row();
+        return QVariant();
+    }
+
+    if (index.column() != 0)
+        return QVariant();
+
+    const QFileInfo &fi = mDirectoryContents.at(index.row());
+
+    switch (role) {
+        case FileNameRole:
+            return fi.fileName();
+        case CreationDateRole:
+            return fi.created();
+        case ModifiedDateRole:
+            return fi.lastModified();
+        case FileSizeRole: {
+            qint64 kb = fi.size() / 1024;
+            if (kb < 1)
+                return QString::number(fi.size()) + " bytes";
+            else if (kb < 1024)
+                return QString::number(kb) + " kb";
+
+            kb /= 1024;
+            return QString::number(kb) + "mb";
+        }
+        case IconSourceRole: {
+            const QString &fileName = fi.fileName();
+
+            if (fi.isDir())
+                return "image://theme/icon-m-common-directory";
+
+            if (fileName.endsWith(".jpg", Qt::CaseInsensitive) ||
+                fileName.endsWith(".png", Qt::CaseInsensitive)) {
+                return "image://nemoThumbnail/" + fi.filePath();
+            }
+
+            return "image://theme/icon-m-content-document";
+        }
+        case FilePathRole:
+            return fi.filePath();
+        case IsDirRole:
+            return fi.isDir();
+        case IsFileRole:
+            return !fi.isDir();
+        case IsReadableRole:
+            return fi.isReadable();
+        case IsWritableRole:
+            return fi.isWritable();
+        case IsExecutableRole:
+            return fi.isExecutable();
+        default:
+            // this should not happen, ever
+            Q_ASSERT(false);
+            qWarning() << Q_FUNC_INFO << "Got an unknown role: " << role;
+            return QVariant();
+    }
+}
+
+void DirModel::setPath(const QString &pathName)
+{
+    if (pathName.isEmpty())
+        return;
+
+    if (mAwaitingResults) {
+        // TODO: handle the case where pathName != our current path, cancel old
+        // request, start a new one
+        qDebug() << Q_FUNC_INFO << "Ignoring path change request, request 
already running";
+        return;
+    }
+
+    mAwaitingResults = true;
+    emit awaitingResultsChanged();
+    qDebug() << Q_FUNC_INFO << "Changing to " << pathName << " on " << 
QThread::currentThreadId();
+
+    beginResetModel();
+    mDirectoryContents.clear();
+    endResetModel();
+
+    // TODO: we need to set a spinner active before we start getting results 
from DirListWorker
+    DirListWorker *dlw = new DirListWorker(pathName);
+    connect(dlw, SIGNAL(itemsAdded(QVector<QFileInfo>)), 
SLOT(onItemsAdded(QVector<QFileInfo>)));
+    ioWorkerThread()->addRequest(dlw);
+
+    mCurrentDir = pathName;
+    emit pathChanged();
+}
+
+static bool fileCompare(const QFileInfo &a, const QFileInfo &b)
+{
+    if (a.isDir() && !b.isDir())
+        return true;
+
+    if (b.isDir() && !a.isDir())
+        return false;
+
+    return QString::localeAwareCompare(a.fileName(), b.fileName()) < 0;
+}
+
+void DirModel::onItemsAdded(const QVector<QFileInfo> &newFiles)
+{
+    qDebug() << Q_FUNC_INFO << "Got new files: " << newFiles.count();
+
+    if (mAwaitingResults) {
+        qDebug() << Q_FUNC_INFO << "No longer awaiting results";
+        mAwaitingResults = false;
+        emit awaitingResultsChanged();
+    }
+
+    foreach (const QFileInfo &fi, newFiles) {
+        if (!mShowDirectories && fi.isDir())
+            continue;
+
+        bool doAdd = true;
+        foreach (const QString &nameFilter, mNameFilters) {
+            // TODO: using QRegExp for wildcard matching is slow
+            QRegExp re(nameFilter, Qt::CaseInsensitive, QRegExp::Wildcard);
+            if (!re.exactMatch(fi.fileName())) {
+                doAdd = false;
+                break;
+            }
+        }
+
+        if (!doAdd)
+            continue;
+
+        QVector<QFileInfo>::Iterator it = 
qLowerBound(mDirectoryContents.begin(),
+                                                      mDirectoryContents.end(),
+                                                      fi,
+                                                      fileCompare);
+
+        if (it == mDirectoryContents.end()) {
+            beginInsertRows(QModelIndex(), mDirectoryContents.count(), 
mDirectoryContents.count());
+            mDirectoryContents.append(fi);
+            endInsertRows();
+        } else {
+            int idx = it - mDirectoryContents.begin();
+            beginInsertRows(QModelIndex(), idx, idx);
+            mDirectoryContents.insert(it, fi);
+            endInsertRows();
+        }
+    }
+}
+
+void DirModel::rm(const QStringList &paths)
+{
+    // TODO: handle directory deletions?
+    bool error = false;
+
+    foreach (const QString &path, paths) {
+        error |= QFile::remove(path);
+
+        if (error) {
+            qWarning() << Q_FUNC_INFO << "Failed to remove " << path;
+            error = false;
+        }
+    }
+
+    // TODO: just remove removed items; don't reload the entire model
+    refresh();
+}
+
+bool DirModel::rename(int row, const QString &newName)
+{
+    qDebug() << Q_FUNC_INFO << "Renaming " << row << " to " << newName;
+    Q_ASSERT(row >= 0 && row < mDirectoryContents.count());
+    if (row < 0 || row >= mDirectoryContents.count()) {
+        qWarning() << Q_FUNC_INFO << "Out of bounds access";
+        return false;
+    }
+
+    const QFileInfo &fi = mDirectoryContents.at(row);
+
+    if (!fi.isDir()) {
+        QFile f(fi.absoluteFilePath());
+        bool retval = f.rename(fi.absolutePath() + QDir::separator() + 
newName);
+
+        if (!retval)
+            qDebug() << Q_FUNC_INFO << "Rename returned error code: " << 
f.error() << f.errorString();
+        else
+            refresh();
+        // TODO: just change the affected item... ^^
+
+        return retval;
+    } else {
+        QDir d(fi.absoluteFilePath());
+        bool retval = d.rename(fi.absoluteFilePath(), fi.absolutePath() + 
QDir::separator() + newName);
+
+        // QDir has no way to detect what went wrong. woohoo!
+
+        // TODO: just change the affected item...
+        refresh();
+
+        return retval;
+    }
+
+    // unreachable (we hope)
+    Q_ASSERT(false);
+    return false;
+}
+
+void DirModel::mkdir(const QString &newDir)
+{
+    qDebug() << Q_FUNC_INFO << "Creating new folder " << newDir << " to " << 
mCurrentDir;
+
+    QDir dir(mCurrentDir);
+    bool retval = dir.mkdir(newDir);
+    if (!retval) {
+        const char *errorStr = strerror(errno);
+        qDebug() << Q_FUNC_INFO << "Error creating new directory: " << errno 
<< " (" << errorStr << ")";
+        emit error("Error creating new folder", errorStr);
+    } else {
+        refresh();
+    }
+}
+
+bool DirModel::showDirectories() const
+{
+    return mShowDirectories;
+}
+
+void DirModel::setShowDirectories(bool showDirectories)
+{
+    mShowDirectories = showDirectories;
+    refresh();
+    emit showDirectoriesChanged();
+}
+
+QStringList DirModel::nameFilters() const
+{
+    return mNameFilters;
+}
+
+void DirModel::setNameFilters(const QStringList &nameFilters)
+{
+    mNameFilters = nameFilters;
+    refresh();
+    emit nameFiltersChanged();
+}
+
+bool DirModel::awaitingResults() const
+{
+    return mAwaitingResults;
+}
+
+// for dirlistworker
+#include "dirmodel.moc"
--- folderlistmodel/dirmodel.h
+++ folderlistmodel/dirmodel.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2012 Robin Burchell <[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 DIRMODEL_H
+#define DIRMODEL_H
+
+#include <QAbstractListModel>
+#include <QFileInfo>
+#include <QVector>
+#include <QStringList>
+
+#include "iorequest.h"
+
+class DirModel : public QAbstractListModel
+{
+    Q_OBJECT
+
+    enum Roles {
+        FileNameRole = Qt::UserRole,
+        CreationDateRole,
+        ModifiedDateRole,
+        FileSizeRole,
+        IconSourceRole,
+        FilePathRole,
+        IsDirRole,
+        IsFileRole,
+        IsReadableRole,
+        IsWritableRole,
+        IsExecutableRole
+    };
+
+public:
+    DirModel(QObject *parent = 0);
+
+    int rowCount(const QModelIndex &index) const
+    {
+        if (index.parent() != QModelIndex())
+            return 0;
+
+        return mDirectoryContents.count();
+    }
+
+    // TODO: this won't be safe if the model can change under the holder of 
the row
+    Q_INVOKABLE QVariant data(int row, const QByteArray &stringRole) const;
+
+    QVariant data(const QModelIndex &index, int role) const;
+
+    Q_INVOKABLE void refresh()
+    {
+        // just some syntactical sugar really
+        setPath(path());
+    }
+
+    Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged);
+    inline QString path() const { return mCurrentDir; }
+
+    Q_PROPERTY(bool awaitingResults READ awaitingResults NOTIFY 
awaitingResultsChanged);
+    bool awaitingResults() const;
+
+    void setPath(const QString &pathName);
+
+    Q_INVOKABLE void rm(const QStringList &paths);
+
+    Q_INVOKABLE bool rename(int row, const QString &newName);
+
+    Q_INVOKABLE void mkdir(const QString &newdir);
+
+    Q_PROPERTY(bool showDirectories READ showDirectories WRITE 
setShowDirectories NOTIFY showDirectoriesChanged)
+    bool showDirectories() const;
+    void setShowDirectories(bool showDirectories);
+
+    Q_PROPERTY(QStringList nameFilters READ nameFilters WRITE setNameFilters 
NOTIFY nameFiltersChanged)
+    QStringList nameFilters() const;
+    void setNameFilters(const QStringList &nameFilters);
+
+public slots:
+    void onItemsAdded(const QVector<QFileInfo> &newFiles);
+
+signals:
+    void awaitingResultsChanged();
+    void nameFiltersChanged();
+    void showDirectoriesChanged();
+    void pathChanged();
+    void error(const QString &errorTitle, const QString &errorMessage);
+
+private:
+    QStringList mNameFilters;
+    bool mShowDirectories;
+    bool mAwaitingResults;
+    QString mCurrentDir;
+    QVector<QFileInfo> mDirectoryContents;
+    QHash<QByteArray, int> mRoleMapping;
+};
+
+
+#endif // DIRMODEL_H
--- folderlistmodel/folderlistmodel.pro
+++ folderlistmodel/folderlistmodel.pro
@@ -0,0 +1,25 @@
+TARGET = nemofolderlistmodel
+PLUGIN_IMPORT_PATH = org/nemomobile/folderlistmodel
+
+SOURCES += plugin.cpp \
+           dirmodel.cpp \
+           iorequest.cpp \
+           iorequestworker.cpp \
+           ioworkerthread.cpp
+
+HEADERS += dirmodel.h \
+           iorequest.h \
+           iorequestworker.h \
+           ioworkerthread.h
+
+# do not edit below here, move this to a shared .pri?
+TEMPLATE = lib
+CONFIG += qt plugin hide_symbols
+QT += declarative
+
+target.path = $$[QT_INSTALL_IMPORTS]/$$PLUGIN_IMPORT_PATH
+INSTALLS += target
+
+qmldir.files += $$PWD/qmldir
+qmldir.path +=  $$[QT_INSTALL_IMPORTS]/$$$$PLUGIN_IMPORT_PATH
+INSTALLS += qmldir
--- folderlistmodel/iorequest.cpp
+++ folderlistmodel/iorequest.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2012 Robin Burchell <[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 "iorequest.h"
+
+IORequest::IORequest() : QObject()
+{
+}
--- folderlistmodel/iorequest.h
+++ folderlistmodel/iorequest.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2012 Robin Burchell <[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 IOREQUEST_H
+#define IOREQUEST_H
+
+#include <QObject>
+
+class IORequest : public QObject
+{
+    Q_OBJECT
+public:
+    explicit IORequest();
+    
+public:
+    virtual void run() = 0;
+    
+private:
+    // hide this because IORequest should *NOT* be parented directly
+    using QObject::setParent;
+};
+
+#endif // IOREQUEST_H
--- folderlistmodel/iorequestworker.cpp
+++ folderlistmodel/iorequestworker.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2012 Robin Burchell <[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 <QMutexLocker>
+#include <QDebug>
+
+#include "iorequestworker.h"
+#include "iorequest.h"
+
+/*!
+  Lives on an IOWorkerThread.
+
+  Responsible for running IORequest jobs on the thread instance, and
+  disposing of their resources once they are done.
+ */
+IORequestWorker::IORequestWorker()
+    : QThread()
+    , mTimeToQuit(false)
+{
+}
+
+void IORequestWorker::addRequest(IORequest *request)
+{
+    request->moveToThread(this);
+
+    // TODO: queue requests so we run the most important one first
+    QMutexLocker lock(&mMutex);
+    mRequests.append(request);
+
+    // wake run()
+    mWaitCondition.wakeOne();
+}
+
+void IORequestWorker::run()
+{
+    forever {
+        QMutexLocker lock(&mMutex);
+
+        if (mTimeToQuit)
+            return;
+
+        if (mRequests.empty())
+            mWaitCondition.wait(&mMutex);
+
+        while (!mRequests.isEmpty()) {
+            IORequest *request = mRequests.takeFirst();
+
+            lock.unlock();
+
+            request->run();
+            request->deleteLater();
+
+            lock.relock();
+        }
+    }
+}
+
+void IORequestWorker::exit()
+{
+    qDebug() << Q_FUNC_INFO << "Quitting";
+    QMutexLocker lock(&mMutex);
+    mTimeToQuit = true;
+    mWaitCondition.wakeOne();
+}
--- folderlistmodel/iorequestworker.h
+++ folderlistmodel/iorequestworker.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2012 Robin Burchell <[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 IOREQUESTWORKER_H
+#define IOREQUESTWORKER_H
+
+#include <QObject>
+#include <QThread>
+#include <QMutex>
+#include <QWaitCondition>
+
+#include "iorequest.h"
+
+class IORequestWorker : public QThread
+{
+    Q_OBJECT
+public:
+    explicit IORequestWorker();
+
+    void addRequest(IORequest *request);
+
+    void run();
+
+    void exit();
+
+private:
+    QMutex mMutex;
+    QWaitCondition mWaitCondition;
+    QList<IORequest *> mRequests;
+    bool mTimeToQuit;
+};
+
+#endif // IOREQUESTWORKER_H
--- folderlistmodel/ioworkerthread.cpp
+++ folderlistmodel/ioworkerthread.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2012 Robin Burchell <[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 "ioworkerthread.h"
+
+
+/*!
+  Hosts a thread, lives on the main thread.
+
+  Responsible for relaying interaction between the main thread and an 
IOWorkerThread.
+ */
+IOWorkerThread::IOWorkerThread(QObject *parent) :
+    QObject(parent)
+{
+    mWorker.start(QThread::IdlePriority);
+}
+
+/*!
+  Destroys an IOWorkerThread instance.
+ */
+IOWorkerThread::~IOWorkerThread()
+{
+    mWorker.exit();
+    mWorker.wait();
+}
+
+/*!
+  Attempts an asynchronous attempt to start a \a request.
+
+  If the request may be run, it is queued, and true is returned, otherwise, 
false.
+ */
+bool IOWorkerThread::addRequest(IORequest *request)
+{
+    mWorker.addRequest(request);
+    return true;
+}
--- folderlistmodel/ioworkerthread.h
+++ folderlistmodel/ioworkerthread.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2012 Robin Burchell <[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 IOWORKERTHREAD_H
+#define IOWORKERTHREAD_H
+
+#include <QObject>
+#include <QThread>
+
+#include "iorequestworker.h"
+
+class IOWorkerThread : public QObject
+{
+    Q_OBJECT
+public:
+    explicit IOWorkerThread(QObject *parent = 0);
+    virtual ~IOWorkerThread();
+    bool addRequest(IORequest *request);
+
+private:
+    IORequestWorker mWorker;
+};
+
+#endif // IOWORKERTHREAD_H
--- folderlistmodel/plugin.cpp
+++ folderlistmodel/plugin.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2012 Robin Burchell <[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 <QtGlobal>
+#include <QtDeclarative>
+#include <QDeclarativeEngine>
+#include <QDeclarativeExtensionPlugin>
+
+#include "dirmodel.h"
+
+Q_DECLARE_METATYPE(QVector<QFileInfo>)
+
+class Q_DECL_EXPORT NemoFolderListModelPlugin : public 
QDeclarativeExtensionPlugin
+{
+public:
+    virtual ~NemoFolderListModelPlugin() { }
+
+    void initializeEngine(QDeclarativeEngine *engine, const char *uri)
+    {
+        Q_ASSERT(uri == QLatin1String("org.nemomobile.folderlistmodel"));
+    }
+
+    void registerTypes(const char *uri)
+    {
+        Q_ASSERT(uri == QLatin1String("org.nemomobile.folderlistmodel"));
+        qRegisterMetaType<QVector<QFileInfo> >();
+        qmlRegisterType<DirModel>(uri, 1, 0, "FolderListModel");
+    }
+};
+
+Q_EXPORT_PLUGIN2(nemofolderlistmodel, NemoFolderListModelPlugin);
+
--- folderlistmodel/qmldir
+++ folderlistmodel/qmldir
@@ -0,0 +1 @@
+plugin nemofolderlistmodel
--- nemo-qml-plugins.pro
+++ nemo-qml-plugins.pro
@@ -1,2 +1,5 @@
 TEMPLATE = subdirs
-SUBDIRS += thumbnailer contacts qrencoder
+SUBDIRS += thumbnailer \
+           contacts \
+           qrencoder \
+           folderlistmodel

++++++ nemo-qml-plugins.yaml
--- nemo-qml-plugins.yaml
+++ nemo-qml-plugins.yaml
@@ -2,10 +2,12 @@
 Summary: Nemo QML plugins source package.
 Group: System/Libraries
 Description: Do not install this, install the subpackaged plugins.
-Version: 0.0.4
+Version: 0.0.5
 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
@@ -39,4 +41,10 @@
       Files:
           - "%{_libdir}/qt4/imports/org/nemomobile/qrencode/*"
 
+    - Name: folderlistmodel
+      Summary: Folder list model for QML applications
+      Group: System/Libraries
+      Description: A model providing a view of the filesystem for QML 
applications
+      Files:
+          - "%{_libdir}/qt4/imports/org/nemomobile/folderlistmodel/*"
 



Reply via email to