FolderListModel: remove widget and QDirModel use
authorMartin Petersson <Martin.Petersson@nokia.com>
Mon, 20 Feb 2012 13:56:12 +0000 (14:56 +0100)
committerQt by Nokia <qt-info@nokia.com>
Wed, 29 Feb 2012 08:20:00 +0000 (09:20 +0100)
FolderListModel used the obsolete QDirModel internally. Because of this
it needed widgets to work. I have made a threaded model instead that
use QDir internally.

Change-Id: Ibd1267a135ee3c6df7bcde420073866b7a76d0d1
Reviewed-by: Alan Alpert <alan.alpert@nokia.com>
src/imports/folderlistmodel/fileinfothread.cpp [new file with mode: 0644]
src/imports/folderlistmodel/fileinfothread_p.h [new file with mode: 0644]
src/imports/folderlistmodel/fileproperty_p.h [new file with mode: 0644]
src/imports/folderlistmodel/folderlistmodel.pro
src/imports/folderlistmodel/qdeclarativefolderlistmodel.cpp
src/imports/folderlistmodel/qdeclarativefolderlistmodel.h
tests/auto/declarative/qdeclarativefolderlistmodel/tst_qdeclarativefolderlistmodel.cpp

diff --git a/src/imports/folderlistmodel/fileinfothread.cpp b/src/imports/folderlistmodel/fileinfothread.cpp
new file mode 100644 (file)
index 0000000..3c4d60b
--- /dev/null
@@ -0,0 +1,280 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "fileinfothread_p.h"
+#include <qdiriterator.h>
+
+#include <QDebug>
+
+
+FileInfoThread::FileInfoThread(QObject *parent)
+    : QThread(parent),
+      abort(false),
+      watcher(0),
+      sortFlags(QDir::Name),
+      needUpdate(true),
+      folderUpdate(false),
+      sortUpdate(false),
+      showDirs(true),
+      showDirsFirst(false),
+      showDotDot(false),
+      showOnlyReadable(false)
+{
+    watcher = new QFileSystemWatcher(this);
+    connect(watcher, SIGNAL(directoryChanged(QString)), this, SLOT(dirChanged(QString)));
+    connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(updateFile(QString)));
+    start(LowPriority);
+}
+
+FileInfoThread::~FileInfoThread()
+{
+    QMutexLocker locker(&mutex);
+    abort = true;
+    condition.wakeOne();
+    locker.unlock();
+    wait();
+}
+
+void FileInfoThread::clear()
+{
+    QMutexLocker locker(&mutex);
+    watcher->removePaths(watcher->files());
+    watcher->removePaths(watcher->directories());
+}
+
+void FileInfoThread::removePath(const QString &path)
+{
+    QMutexLocker locker(&mutex);
+    watcher->removePath(path);
+    currentPath.clear();
+}
+
+void FileInfoThread::setPath(const QString &path)
+{
+    Q_ASSERT(!path.isEmpty());
+
+    QMutexLocker locker(&mutex);
+    watcher->addPath(path);
+    currentPath = path;
+    needUpdate = true;
+    condition.wakeAll();
+}
+
+void FileInfoThread::setRootPath(const QString &path)
+{
+    Q_ASSERT(!path.isEmpty());
+
+    QMutexLocker locker(&mutex);
+    rootPath = path;
+}
+
+void FileInfoThread::dirChanged(const QString &directoryPath)
+{
+    Q_UNUSED(directoryPath);
+    QMutexLocker locker(&mutex);
+    folderUpdate = true;
+    condition.wakeAll();
+}
+
+void FileInfoThread::setSortFlags(QDir::SortFlags flags)
+{
+    QMutexLocker locker(&mutex);
+    sortFlags = flags;
+    sortUpdate = true;
+    condition.wakeAll();
+}
+
+void FileInfoThread::setNameFilters(const QStringList & filters)
+{
+    QMutexLocker locker(&mutex);
+    nameFilters = filters;
+    folderUpdate = true;
+    condition.wakeAll();
+}
+
+void FileInfoThread::setShowDirs(bool showFolders)
+{
+    QMutexLocker locker(&mutex);
+    showDirs = showFolders;
+    folderUpdate = true;
+    condition.wakeAll();
+}
+
+void FileInfoThread::setShowDirsFirst(bool showDirsFirst)
+{
+    QMutexLocker locker(&mutex);
+    showDirsFirst = showDirsFirst;
+    folderUpdate = true;
+    condition.wakeAll();
+}
+
+void FileInfoThread::setShowDotDot(bool on)
+{
+    QMutexLocker locker(&mutex);
+    showDotDot = on;
+    folderUpdate = true;
+    condition.wakeAll();
+}
+
+void FileInfoThread::setShowOnlyReadable(bool on)
+{
+    QMutexLocker locker(&mutex);
+    showOnlyReadable = on;
+    folderUpdate = true;
+    condition.wakeAll();
+}
+
+void FileInfoThread::updateFile(const QString &path)
+{
+    Q_UNUSED(path);
+    QMutexLocker locker(&mutex);
+    folderUpdate = true;
+    condition.wakeAll();
+}
+
+void FileInfoThread::run()
+{
+    forever {
+        bool updateFiles = false;
+        QMutexLocker locker(&mutex);
+        if (abort) {
+            return;
+        }
+        if (currentPath.isEmpty() || !needUpdate)
+            condition.wait(&mutex);
+
+        if (abort) {
+            return;
+        }
+
+        if (!currentPath.isEmpty()) {
+            updateFiles = true;
+        }
+        if (updateFiles)
+            getFileInfos(currentPath);
+        locker.unlock();
+    }
+}
+
+
+void FileInfoThread::getFileInfos(const QString &path)
+{
+    QDir::Filters filter;
+    filter = QDir::Files | QDir::NoDot | QDir::CaseSensitive;
+    if (showDirs)
+        filter = filter | QDir::AllDirs | QDir::Drives;
+    if ((path == rootPath) || !showDotDot)
+        filter = filter | QDir::NoDotDot;
+    if (showOnlyReadable)
+        filter = filter | QDir::Readable;
+    if (showDirsFirst)
+        sortFlags = sortFlags | QDir::DirsFirst;
+
+    QDir currentDir(path, QString(), sortFlags);
+    QFileInfoList fileInfoList;
+    QList<FileProperty> filePropertyList;
+
+    fileInfoList = currentDir.entryInfoList(nameFilters, filter, sortFlags);
+
+    if (!fileInfoList.isEmpty()) {
+        foreach (QFileInfo info, fileInfoList) {
+            //qDebug() << "Adding file : " << info.fileName() << "to list ";
+            filePropertyList << FileProperty(info);
+        }
+        if (folderUpdate) {
+            int fromIndex = 0;
+            int toIndex = currentFileList.size()-1;
+            findChangeRange(filePropertyList, fromIndex, toIndex);
+            folderUpdate = false;
+            currentFileList = filePropertyList;
+            //qDebug() << "emit directoryUpdated : " << fromIndex << " " << toIndex;
+            emit directoryUpdated(path, filePropertyList, fromIndex, toIndex);
+        } else {
+            currentFileList = filePropertyList;
+            if (sortUpdate) {
+                emit sortFinished(filePropertyList);
+                sortUpdate = false;
+            } else
+                emit directoryChanged(path, filePropertyList);
+        }
+    } else {
+        // The directory is empty
+        if (folderUpdate) {
+            int fromIndex = 0;
+            int toIndex = currentFileList.size()-1;
+            folderUpdate = false;
+            currentFileList.clear();
+            emit directoryUpdated(path, filePropertyList, fromIndex, toIndex);
+        } else {
+            currentFileList.clear();
+            emit directoryChanged(path, filePropertyList);
+        }
+    }
+    needUpdate = false;
+}
+
+void FileInfoThread::findChangeRange(const QList<FileProperty> &list, int &fromIndex, int &toIndex)
+{
+    if (currentFileList.size() == 0) {
+        fromIndex = 0;
+        toIndex = list.size();
+        return;
+    }
+
+    int i;
+    int listSize = list.size() < currentFileList.size() ? list.size() : currentFileList.size();
+    bool changeFound = false;
+
+    for (i=0; i < listSize; i++) {
+        if (list.at(i) != currentFileList.at(i)) {
+            changeFound = true;
+            break;
+        }
+    }
+
+    if (changeFound)
+        fromIndex = i;
+    else
+        fromIndex = i-1;
+
+    // For now I let the rest of the list be updated..
+    toIndex = list.size() > currentFileList.size() ? list.size() - 1 : currentFileList.size() - 1;
+}
diff --git a/src/imports/folderlistmodel/fileinfothread_p.h b/src/imports/folderlistmodel/fileinfothread_p.h
new file mode 100644 (file)
index 0000000..a5be6e6
--- /dev/null
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef FILEINFOTHREAD_P_H
+#define FILEINFOTHREAD_P_H
+
+#include <QThread>
+#include <QMutex>
+#include <QWaitCondition>
+#include <QFileSystemWatcher>
+#include <QFileInfo>
+#include <QDir>
+
+#include "fileproperty_p.h"
+
+class FileInfoThread : public QThread
+{
+    Q_OBJECT
+
+Q_SIGNALS:
+    void directoryChanged(const QString &directory, const QList<FileProperty> &list) const;
+    void directoryUpdated(const QString &directory, const QList<FileProperty> &list, int fromIndex, int toIndex) const;
+    void sortFinished(const QList<FileProperty> &list) const;
+
+public:
+    FileInfoThread(QObject *parent = 0);
+    ~FileInfoThread();
+
+    void clear();
+    void removePath(const QString &path);
+    void setPath(const QString &path);
+    void setRootPath(const QString &path);
+    void setSortFlags(QDir::SortFlags flags);
+    void setNameFilters(const QStringList & nameFilters);
+    void setShowDirs(bool showFolders);
+    void setShowDirsFirst(bool showDirsFirst);
+    void setShowDotDot(bool on);
+    void setShowOnlyReadable(bool on);
+
+public Q_SLOTS:
+    void dirChanged(const QString &directoryPath);
+    void updateFile(const QString &path);
+
+protected:
+    void run();
+    void getFileInfos(const QString &path);
+    void findChangeRange(const QList<FileProperty> &list, int &fromIndex, int &toIndex);
+
+private:
+    QMutex mutex;
+    QWaitCondition condition;
+    volatile bool abort;
+
+    QFileSystemWatcher *watcher;
+    QList<FileProperty> currentFileList;
+    QDir::SortFlags sortFlags;
+    QString currentPath;
+    QString rootPath;
+    QStringList nameFilters;
+    bool needUpdate;
+    bool folderUpdate;
+    bool sortUpdate;
+    bool showDirs;
+    bool showDirsFirst;
+    bool showDotDot;
+    bool showOnlyReadable;
+};
+
+#endif // FILEINFOTHREAD_P_H
diff --git a/src/imports/folderlistmodel/fileproperty_p.h b/src/imports/folderlistmodel/fileproperty_p.h
new file mode 100644 (file)
index 0000000..690581a
--- /dev/null
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef FILEPROPERTY_P_H
+#define FILEPROPERTY_P_H
+
+#include <QFileInfo>
+#include <QDateTime>
+
+class FileProperty
+{
+public:
+    FileProperty(const QFileInfo &info)
+    {
+        mFileName = info.fileName();
+        mFilePath = info.filePath();
+        mBaseName = info.baseName();
+        mSize = info.size();
+        mSuffix = info.completeSuffix();
+        mIsDir = info.isDir();
+        mIsFile = info.isFile();
+        mLastModified = info.lastModified();
+        mLastRead = info.lastRead();
+    }
+    ~FileProperty()
+    {}
+
+    inline QString fileName() const { return mFileName; }
+    inline QString filePath() const { return mFilePath; }
+    inline QString baseName() const { return mBaseName; }
+    inline qint64 size() const { return mSize; }
+    inline QString suffix() const { return mSuffix; }
+    inline bool isDir() const { return mIsDir; }
+    inline bool isFile() const { return mIsFile; }
+    inline QDateTime lastModified() const { return mLastModified; }
+    inline QDateTime lastRead() const { return mLastRead; }
+
+    inline bool operator !=(const FileProperty &fileInfo) const {
+        return !operator==(fileInfo);
+    }
+    bool operator ==(const FileProperty &property) const {
+        return ((mFileName == property.mFileName) && (isDir() == property.isDir()));
+    }
+
+private:
+    QString mFileName;
+    QString mFilePath;
+    QString mBaseName;
+    QString mSuffix;
+    qint64 mSize;
+    bool mIsDir;
+    bool mIsFile;
+    QDateTime mLastModified;
+    QDateTime mLastRead;
+};
+#endif // FILEPROPERTY_P_H
index 26efc65..9727b51 100644 (file)
@@ -2,10 +2,13 @@ TARGET  = qmlfolderlistmodelplugin
 TARGETPATH = Qt/labs/folderlistmodel
 include(../qimportbase.pri)
 
-QT += widgets declarative
+QT += declarative
 
-SOURCES += qdeclarativefolderlistmodel.cpp plugin.cpp
-HEADERS += qdeclarativefolderlistmodel.h
+SOURCES += qdeclarativefolderlistmodel.cpp plugin.cpp \
+    fileinfothread.cpp
+HEADERS += qdeclarativefolderlistmodel.h \
+    fileproperty_p.h \
+    fileinfothread_p.h
 
 DESTDIR = $$QT.declarative.imports/$$TARGETPATH
 target.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH
index 870479a..fa1a181 100644 (file)
 
 //![code]
 #include "qdeclarativefolderlistmodel.h"
-#include <QDirModel>
+#include "fileinfothread_p.h"
+#include "fileproperty_p.h"
 #include <QDebug>
 #include <qdeclarativecontext.h>
 
-#ifndef QT_NO_DIRMODEL
-
 QT_BEGIN_NAMESPACE
 
 class QDeclarativeFolderListModelPrivate
 {
+    Q_DECLARE_PUBLIC(QDeclarativeFolderListModel)
+
 public:
-    QDeclarativeFolderListModelPrivate()
-        : sortField(QDeclarativeFolderListModel::Name), sortReversed(false), count(0), showDirs(true), showDots(false), showOnlyReadable(false), insideRefresh(false) {
+    QDeclarativeFolderListModelPrivate(QDeclarativeFolderListModel *q)
+        : q_ptr(q),
+          sortField(QDeclarativeFolderListModel::Name), sortReversed(false), showDirs(true), showDirsFirst(false), showDots(false), showOnlyReadable(false)
+    {
         nameFilters << QLatin1String("*");
     }
 
-    void updateSorting() {
-        QDir::SortFlags flags = 0;
-        switch(sortField) {
+
+    QDeclarativeFolderListModel *q_ptr;
+    QUrl currentDir;
+    QUrl rootDir;
+    FileInfoThread fileInfoThread;
+    QList<FileProperty> data;
+    QHash<int, QByteArray> roleNames;
+    QDeclarativeFolderListModel::SortField sortField;
+    QStringList nameFilters;
+    bool sortReversed;
+    bool showDirs;
+    bool showDirsFirst;
+    bool showDots;
+    bool showOnlyReadable;
+
+    ~QDeclarativeFolderListModelPrivate() {}
+    void init();
+    void updateSorting();
+
+    // private slots
+    void _q_directoryChanged(const QString &directory, const QList<FileProperty> &list);
+    void _q_directoryUpdated(const QString &directory, const QList<FileProperty> &list, int fromIndex, int toIndex);
+    void _q_sortFinished(const QList<FileProperty> &list);
+};
+
+
+void QDeclarativeFolderListModelPrivate::init()
+{
+    Q_Q(QDeclarativeFolderListModel);
+    qRegisterMetaType<QList<FileProperty> >("QList<FileProperty>");
+    q->connect(&fileInfoThread, SIGNAL(directoryChanged(QString, QList<FileProperty>)),
+               q, SLOT(_q_directoryChanged(QString, QList<FileProperty>)));
+    q->connect(&fileInfoThread, SIGNAL(directoryUpdated(QString, QList<FileProperty>, int, int)),
+               q, SLOT(_q_directoryUpdated(QString, QList<FileProperty>, int, int)));
+    q->connect(&fileInfoThread, SIGNAL(sortFinished(QList<FileProperty>)),
+               q, SLOT(_q_sortFinished(QList<FileProperty>)));
+}
+
+
+void QDeclarativeFolderListModelPrivate::updateSorting()
+{
+    Q_Q(QDeclarativeFolderListModel);
+
+    QDir::SortFlags flags = 0;
+
+    switch (sortField) {
         case QDeclarativeFolderListModel::Unsorted:
             flags |= QDir::Unsorted;
             break;
@@ -75,26 +121,80 @@ public:
         case QDeclarativeFolderListModel::Type:
             flags |= QDir::Type;
             break;
-        }
+        default:
+            break;
+    }
+
+    emit q->layoutAboutToBeChanged();
+
+    if (sortReversed)
+        flags |= QDir::Reversed;
+
+    fileInfoThread.setSortFlags(flags);
+}
+
+void QDeclarativeFolderListModelPrivate::_q_directoryChanged(const QString &directory, const QList<FileProperty> &list)
+{
+    Q_Q(QDeclarativeFolderListModel);
+    Q_UNUSED(directory);
+
+    data = list;
+    q->endResetModel();
+    emit q->rowCountChanged();
+    emit q->folderChanged();
+}
 
-        if (sortReversed)
-            flags |= QDir::Reversed;
 
-        model.setSorting(flags);
+void QDeclarativeFolderListModelPrivate::_q_directoryUpdated(const QString &directory, const QList<FileProperty> &list, int fromIndex, int toIndex)
+{
+    Q_Q(QDeclarativeFolderListModel);
+    Q_UNUSED(directory);
+
+    QModelIndex parent;
+    if (data.size() > list.size()) {
+        //File(s) removed. Since I do not know how many
+        //or where I need to update the whole list from the first item.
+        data = list;
+        q->beginRemoveRows(parent, fromIndex, toIndex);
+        q->endRemoveRows();
+        q->beginInsertRows(parent, fromIndex, list.size()-1);
+        q->endInsertRows();
+        emit q->rowCountChanged();
+    } else if (data.size() < list.size()) {
+        //qDebug() << "File added. FromIndex: " << fromIndex << " toIndex: " << toIndex << " list size: " << list.size();
+        //File(s) added. Calculate how many and insert
+        //from the first changed one.
+        toIndex = fromIndex + (list.size() - data.size()-1);
+        q->beginInsertRows(parent, fromIndex, toIndex);
+        q->endInsertRows();
+        data = list;
+        emit q->rowCountChanged();
+        QModelIndex modelIndexFrom = q->createIndex(fromIndex, 0);
+        QModelIndex modelIndexTo = q->createIndex(toIndex, 0);
+        emit q->dataChanged(modelIndexFrom, modelIndexTo);
+    } else {
+        //qDebug() << "File has been updated";
+        QModelIndex modelIndexFrom = q->createIndex(fromIndex, 0);
+        QModelIndex modelIndexTo = q->createIndex(toIndex, 0);
+        data = list;
+        emit q->dataChanged(modelIndexFrom, modelIndexTo);
     }
+}
+
+void QDeclarativeFolderListModelPrivate::_q_sortFinished(const QList<FileProperty> &list)
+{
+    Q_Q(QDeclarativeFolderListModel);
+
+    QModelIndex parent;
+    q->beginRemoveRows(parent, 0, data.size()-1);
+    data.clear();
+    q->endRemoveRows();
+
+    q->beginInsertRows(parent, 0, list.size()-1);
+    data = list;
+    q->endInsertRows();
+}
 
-    QDirModel model;
-    QUrl folder;
-    QStringList nameFilters;
-    QModelIndex folderIndex;
-    QDeclarativeFolderListModel::SortField sortField;
-    bool sortReversed;
-    int count;
-    bool showDirs;
-    bool showDots;
-    bool showOnlyReadable;
-    bool insideRefresh;
-};
 
 /*!
     \qmlclass FolderListModel QDeclarativeFolderListModel
@@ -115,8 +215,14 @@ public:
     Components access names and paths via the following roles:
 
     \list
-    \o fileName
-    \o filePath
+    \o \c fileName
+    \o \c filePath
+    \o \c fileBaseName
+    \o \c fileSuffix
+    \o \c fileSize
+    \o \c fileModified
+    \o \c fileAccessed
+    \o \c fileIsDir
     \endlist
 
     Additionally a file entry can be differentiated from a folder entry via the
@@ -157,39 +263,62 @@ public:
 */
 
 QDeclarativeFolderListModel::QDeclarativeFolderListModel(QObject *parent)
-    : QAbstractListModel(parent)
+    : QAbstractListModel(parent), d_ptr(new QDeclarativeFolderListModelPrivate(this))
 {
-    QHash<int, QByteArray> roles;
-    roles[FileNameRole] = "fileName";
-    roles[FilePathRole] = "filePath";
-    setRoleNames(roles);
-
-    d = new QDeclarativeFolderListModelPrivate;
-    d->model.setFilter(QDir::AllDirs | QDir::Files | QDir::Drives | QDir::NoDotAndDotDot);
-    connect(&d->model, SIGNAL(rowsInserted(const QModelIndex&,int,int))
-            , this, SLOT(inserted(const QModelIndex&,int,int)));
-    connect(&d->model, SIGNAL(rowsRemoved(const QModelIndex&,int,int))
-            , this, SLOT(removed(const QModelIndex&,int,int)));
-    connect(&d->model, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&))
-            , this, SLOT(handleDataChanged(const QModelIndex&,const QModelIndex&)));
-    connect(&d->model, SIGNAL(modelReset()), this, SLOT(refresh()));
-    connect(&d->model, SIGNAL(layoutChanged()), this, SLOT(refresh()));
+    Q_D(QDeclarativeFolderListModel);
+    d->roleNames[FileNameRole] = "fileName";
+    d->roleNames[FilePathRole] = "filePath";
+    d->roleNames[FileBaseNameRole] = "fileBaseName";
+    d->roleNames[FileSuffixRole] = "fileSuffix";
+    d->roleNames[FileSizeRole] = "fileSize";
+    d->roleNames[FileLastModifiedRole] = "fileModified";
+    d->roleNames[FileLastReadRole] = "fileAccessed";
+    d->roleNames[FileIsDirRole] = "fileIsDir";
+    setRoleNames(d->roleNames);
+
+    d->init();
 }
 
 QDeclarativeFolderListModel::~QDeclarativeFolderListModel()
 {
-    delete d;
 }
 
 QVariant QDeclarativeFolderListModel::data(const QModelIndex &index, int role) const
 {
+    Q_D(const QDeclarativeFolderListModel);
     QVariant rv;
-    QModelIndex modelIndex = d->model.index(index.row(), 0, d->folderIndex);
-    if (modelIndex.isValid()) {
-        if (role == FileNameRole)
-            rv = d->model.data(modelIndex, QDirModel::FileNameRole).toString();
-        else if (role == FilePathRole)
-            rv = QUrl::fromLocalFile(d->model.data(modelIndex, QDirModel::FilePathRole).toString());
+
+    if (index.row() >= d->data.size())
+        return rv;
+
+    switch (role)
+    {
+        case FileNameRole:
+            rv = d->data.at(index.row()).fileName();
+            break;
+        case FilePathRole:
+            rv = d->data.at(index.row()).filePath();
+            break;
+        case FileBaseNameRole:
+            rv = d->data.at(index.row()).baseName();
+            break;
+        case FileSuffixRole:
+            rv = d->data.at(index.row()).suffix();
+            break;
+        case FileSizeRole:
+            rv = d->data.at(index.row()).size();
+            break;
+        case FileLastModifiedRole:
+            rv = d->data.at(index.row()).lastModified().date().toString(Qt::ISODate) + " " + d->data.at(index.row()).lastModified().time().toString();
+            break;
+        case FileLastReadRole:
+            rv = d->data.at(index.row()).lastRead().date().toString(Qt::ISODate) + " " + d->data.at(index.row()).lastRead().time().toString();
+            break;
+        case FileIsDirRole:
+            rv = d->data.at(index.row()).isDir();
+            break;
+        default:
+            break;
     }
     return rv;
 }
@@ -202,8 +331,14 @@ QVariant QDeclarativeFolderListModel::data(const QModelIndex &index, int role) c
 */
 int QDeclarativeFolderListModel::rowCount(const QModelIndex &parent) const
 {
+    Q_D(const QDeclarativeFolderListModel);
     Q_UNUSED(parent);
-    return d->count;
+    return d->data.size();
+}
+
+QModelIndex QDeclarativeFolderListModel::index(int row, int , const QModelIndex &) const
+{
+    return createIndex(row, 0);
 }
 
 /*!
@@ -219,46 +354,70 @@ int QDeclarativeFolderListModel::rowCount(const QModelIndex &parent) const
 */
 QUrl QDeclarativeFolderListModel::folder() const
 {
-    return d->folder;
+    Q_D(const QDeclarativeFolderListModel);
+    return d->currentDir;
 }
 
 void QDeclarativeFolderListModel::setFolder(const QUrl &folder)
 {
-    if (folder == d->folder)
+    Q_D(QDeclarativeFolderListModel);
+
+    if (folder == d->currentDir)
         return;
 
-    QModelIndex index = d->model.index(folder.toLocalFile()); // This can modify the filtering rules.
-    if ((index.isValid() && d->model.isDir(index)) || folder.toLocalFile().isEmpty()) {
-        d->folder = folder;
-        QMetaObject::invokeMethod(this, "resetFiltering", Qt::QueuedConnection); // resetFiltering will invoke refresh().
-        emit folderChanged();
+    QString resolvedPath = QDir::cleanPath(folder.path());
+
+    beginResetModel();
+
+    //Remove the old path for the file system watcher
+    if (!d->currentDir.isEmpty())
+        d->fileInfoThread.removePath(d->currentDir.path());
+
+    d->currentDir = folder;
+
+    QFileInfo info(resolvedPath);
+    if (!info.exists() || !info.isDir()) {
+        d->data.clear();
+        endResetModel();
+        emit rowCountChanged();
+        return;
     }
+
+    d->fileInfoThread.setPath(resolvedPath);
+}
+
+
+/*!
+   \qmlproperty string QDeclarativeFolderListModel::rootFolder
+
+   When the rootFolder is set, then this folder will
+   be threated as the root in the file system, so that
+   you can only travers sub folders from this rootFolder.
+*/
+QUrl QDeclarativeFolderListModel::rootFolder() const
+{
+    Q_D(const QDeclarativeFolderListModel);
+    return d->rootDir;
 }
 
-void QDeclarativeFolderListModel::resetFiltering()
+void QDeclarativeFolderListModel::setRootFolder(const QUrl &path)
 {
-    // ensure that we reset the filtering rules, because the QDirModel::index()
-    // function isn't quite as const as it claims to be.
-    QDir::Filters filt = d->model.filter();
+    Q_D(QDeclarativeFolderListModel);
 
-    if (d->showDirs)
-        filt |= (QDir::AllDirs | QDir::Drives);
-    else
-        filt &= ~(QDir::AllDirs | QDir::Drives);
+    if (path.isEmpty())
+        return;
 
-    if (d->showDots)
-        filt &= ~QDir::NoDotAndDotDot;
-    else
-        filt |= QDir::NoDotAndDotDot;
+    QString resolvedPath = QDir::cleanPath(path.path());
 
-    if (d->showOnlyReadable)
-        filt |= QDir::Readable;
-    else
-        filt &= ~QDir::Readable;
+    QFileInfo info(resolvedPath);
+    if (!info.exists() || !info.isDir())
+        return;
 
-    d->model.setFilter(filt); // this causes a refresh().
+    d->fileInfoThread.setRootPath(resolvedPath);
+    d->rootDir = path;
 }
 
+
 /*!
     \qmlproperty url FolderListModel::parentFolder
 
@@ -266,7 +425,9 @@ void QDeclarativeFolderListModel::resetFiltering()
 */
 QUrl QDeclarativeFolderListModel::parentFolder() const
 {
-    QString localFile = d->folder.toLocalFile();
+    Q_D(const QDeclarativeFolderListModel);
+
+    QString localFile = d->currentDir.toLocalFile();
     if (!localFile.isEmpty()) {
         QDir dir(localFile);
 #if defined(Q_OS_WIN)
@@ -277,10 +438,10 @@ QUrl QDeclarativeFolderListModel::parentFolder() const
             dir.cdUp();
         localFile = dir.path();
     } else {
-        int pos = d->folder.path().lastIndexOf(QLatin1Char('/'));
+        int pos = d->currentDir.path().lastIndexOf(QLatin1Char('/'));
         if (pos == -1)
             return QUrl();
-        localFile = d->folder.path().left(pos);
+        localFile = d->currentDir.path().left(pos);
     }
     return QUrl::fromLocalFile(localFile);
 }
@@ -303,13 +464,15 @@ QUrl QDeclarativeFolderListModel::parentFolder() const
 */
 QStringList QDeclarativeFolderListModel::nameFilters() const
 {
+    Q_D(const QDeclarativeFolderListModel);
     return d->nameFilters;
 }
 
 void QDeclarativeFolderListModel::setNameFilters(const QStringList &filters)
 {
+    Q_D(QDeclarativeFolderListModel);
+    d->fileInfoThread.setNameFilters(filters);
     d->nameFilters = filters;
-    d->model.setNameFilters(d->nameFilters);
 }
 
 void QDeclarativeFolderListModel::classBegin()
@@ -318,11 +481,10 @@ void QDeclarativeFolderListModel::classBegin()
 
 void QDeclarativeFolderListModel::componentComplete()
 {
-    if (!d->folder.isValid() || d->folder.toLocalFile().isEmpty() || !QDir().exists(d->folder.toLocalFile()))
-        setFolder(QUrl(QLatin1String("file://")+QDir::currentPath()));
+    Q_D(QDeclarativeFolderListModel);
 
-    if (!d->folderIndex.isValid())
-        QMetaObject::invokeMethod(this, "refresh", Qt::QueuedConnection);
+    if (!d->currentDir.isValid() || d->currentDir.toLocalFile().isEmpty() || !QDir().exists(d->currentDir.toLocalFile()))
+        setFolder(QUrl(QLatin1String("file://")+QDir::currentPath()));
 }
 
 /*!
@@ -331,9 +493,9 @@ void QDeclarativeFolderListModel::componentComplete()
     The \a sortField property contains field to use for sorting.  sortField
     may be one of:
     \list
-    \o Unsorted - no sorting is applied.  The order is system default.
+    \o Unsorted - no sorting is applied.
     \o Name - sort by filename
-    \o Time - sort by time modified
+    \o LastModified - sort by time modified
     \o Size - sort by file size
     \o Type - sort by file type (extension)
     \endlist
@@ -342,17 +504,25 @@ void QDeclarativeFolderListModel::componentComplete()
 */
 QDeclarativeFolderListModel::SortField QDeclarativeFolderListModel::sortField() const
 {
+    Q_D(const QDeclarativeFolderListModel);
     return d->sortField;
 }
 
 void QDeclarativeFolderListModel::setSortField(SortField field)
 {
+    Q_D(QDeclarativeFolderListModel);
     if (field != d->sortField) {
         d->sortField = field;
         d->updateSorting();
     }
 }
 
+int QDeclarativeFolderListModel::roleFromString(const QString &roleName) const
+{
+    Q_D(const QDeclarativeFolderListModel);
+    return d->roleNames.key(roleName.toLatin1(), -1);
+}
+
 /*!
     \qmlproperty bool FolderListModel::sortReversed
 
@@ -362,11 +532,14 @@ void QDeclarativeFolderListModel::setSortField(SortField field)
 */
 bool QDeclarativeFolderListModel::sortReversed() const
 {
+    Q_D(const QDeclarativeFolderListModel);
     return d->sortReversed;
 }
 
 void QDeclarativeFolderListModel::setSortReversed(bool rev)
 {
+    Q_D(QDeclarativeFolderListModel);
+
     if (rev != d->sortReversed) {
         d->sortReversed = rev;
         d->updateSorting();
@@ -382,91 +555,66 @@ void QDeclarativeFolderListModel::setSortReversed(bool rev)
 bool QDeclarativeFolderListModel::isFolder(int index) const
 {
     if (index != -1) {
-        QModelIndex idx = d->model.index(index, 0, d->folderIndex);
-        if (idx.isValid())
-            return d->model.isDir(idx);
+        QModelIndex idx = createIndex(index, 0);
+        if (idx.isValid()) {
+            QVariant var = data(idx, FileIsDirRole);
+            if (var.isValid())
+                return var.toBool();
+        }
     }
     return false;
 }
 
-void QDeclarativeFolderListModel::refresh()
-{
-    if (d->insideRefresh)
-        return;
-    d->insideRefresh = true;
+/*!
+    \qmlproperty bool FolderListModel::showDirs
 
-    d->folderIndex = QModelIndex();
-    if (d->count) {
-        emit beginRemoveRows(QModelIndex(), 0, d->count-1);
-        d->count = 0;
-        emit endRemoveRows();
-    }
+    If true, directories are included in the model; otherwise only files
+    are included.
 
-    d->folderIndex = d->model.index(d->folder.toLocalFile());
-    int newcount = d->model.rowCount(d->folderIndex);
-    if (newcount) {
-        emit beginInsertRows(QModelIndex(), 0, newcount-1);
-        d->count = newcount;
-        emit endInsertRows();
-    }
+    By default, this property is true.
 
-    d->insideRefresh = false; // finished refreshing.
-}
+    Note that the nameFilters are not applied to directories.
 
-void QDeclarativeFolderListModel::inserted(const QModelIndex &index, int start, int end)
+    \sa showDotAndDotDot
+*/
+bool QDeclarativeFolderListModel::showDirs() const
 {
-    if (index == d->folderIndex) {
-        emit beginInsertRows(QModelIndex(), start, end);
-        d->count = d->model.rowCount(d->folderIndex);
-        emit endInsertRows();
-    }
+    Q_D(const QDeclarativeFolderListModel);
+    return d->showDirs;
 }
 
-void QDeclarativeFolderListModel::removed(const QModelIndex &index, int start, int end)
+void  QDeclarativeFolderListModel::setShowDirs(bool on)
 {
-    if (index == d->folderIndex) {
-        emit beginRemoveRows(QModelIndex(), start, end);
-        d->count = d->model.rowCount(d->folderIndex);
-        emit endRemoveRows();
-    }
-}
+    Q_D(QDeclarativeFolderListModel);
 
-void QDeclarativeFolderListModel::handleDataChanged(const QModelIndex &start, const QModelIndex &end)
-{
-    if (start.parent() == d->folderIndex)
-        emit dataChanged(index(start.row(),0), index(end.row(),0));
+    d->fileInfoThread.setShowDirs(on);
+    d->showDirs = on;
 }
 
 /*!
-    \qmlproperty bool FolderListModel::showDirs
+    \qmlproperty bool FolderListModel::showDirsFirst
 
-    If true, directories are included in the model; otherwise only files
-    are included.
+    If true, if directories are included in the model they will
+    always be shown first, then the files.
 
-    By default, this property is true.
-
-    Note that the nameFilters are not applied to directories.
+    By default, this property is false.
 
-    \sa showDotAndDotDot
 */
-bool QDeclarativeFolderListModel::showDirs() const
+bool QDeclarativeFolderListModel::showDirsFirst() const
 {
-    return d->model.filter() & QDir::AllDirs;
+    Q_D(const QDeclarativeFolderListModel);
+    return d->showDirsFirst;
 }
 
-void  QDeclarativeFolderListModel::setShowDirs(bool on)
+void  QDeclarativeFolderListModel::setShowDirsFirst(bool on)
 {
-    if (!(d->model.filter() & QDir::AllDirs) == !on)
-        return;
-    if (on) {
-        d->showDirs = true;
-        d->model.setFilter(d->model.filter() | QDir::AllDirs | QDir::Drives);
-    } else {
-        d->showDirs = false;
-        d->model.setFilter(d->model.filter() & ~(QDir::AllDirs | QDir::Drives));
-    }
+    Q_D(QDeclarativeFolderListModel);
+
+    d->fileInfoThread.setShowDirsFirst(on);
+    d->showDirsFirst = on;
 }
 
+
 /*!
     \qmlproperty bool FolderListModel::showDotAndDotDot
 
@@ -479,19 +627,16 @@ void  QDeclarativeFolderListModel::setShowDirs(bool on)
 */
 bool QDeclarativeFolderListModel::showDotAndDotDot() const
 {
-    return !(d->model.filter() & QDir::NoDotAndDotDot);
+    Q_D(const QDeclarativeFolderListModel);
+    return d->showDots;
 }
 
 void  QDeclarativeFolderListModel::setShowDotAndDotDot(bool on)
 {
-    if (!(d->model.filter() & QDir::NoDotAndDotDot) == on)
-        return;
-    if (on) {
-        d->showDots = true;
-        d->model.setFilter(d->model.filter() & ~QDir::NoDotAndDotDot);
-    } else {
-        d->showDots = false;
-        d->model.setFilter(d->model.filter() | QDir::NoDotAndDotDot);
+    Q_D(QDeclarativeFolderListModel);
+
+    if (on != d->showDots) {
+        d->fileInfoThread.setShowDotDot(on);
     }
 }
 
@@ -507,23 +652,46 @@ void  QDeclarativeFolderListModel::setShowDotAndDotDot(bool on)
 */
 bool QDeclarativeFolderListModel::showOnlyReadable() const
 {
-    return d->model.filter() & QDir::Readable;
+    Q_D(const QDeclarativeFolderListModel);
+    return d->showOnlyReadable;
 }
 
 void QDeclarativeFolderListModel::setShowOnlyReadable(bool on)
 {
-    if (!(d->model.filter() & QDir::Readable) == !on)
-        return;
-    if (on) {
-        d->showOnlyReadable = true;
-        d->model.setFilter(d->model.filter() | QDir::Readable);
-    } else {
-        d->showOnlyReadable = false;
-        d->model.setFilter(d->model.filter() & ~QDir::Readable);
+    Q_D(QDeclarativeFolderListModel);
+
+    if (on != d->showOnlyReadable) {
+        d->fileInfoThread.setShowOnlyReadable(on);
     }
 }
 
+/*!
+    \qmlmethod QVariant QDeclarativeFolderListModel::get(int idx, const QString &property) const
+
+    Get the folder property for the given index. The following properties
+    are available.
+
+    \list
+        \o \c fileName
+        \o \c filePath
+        \o \c fileBaseName
+        \o \c fileSuffix
+        \o \c fileSize
+        \o \c fileModified
+        \o \c fileAccessed
+        \o \c fileIsDir
+    \endlist
+*/
+QVariant QDeclarativeFolderListModel::get(int idx, const QString &property) const
+{
+    int role = roleFromString(property);
+    if (role >= 0 && idx >= 0)
+        return data(index(idx, 0), role);
+    else
+        return QVariant();
+}
+
+#include "moc_qdeclarativefolderlistmodel.cpp"
+
 //![code]
 QT_END_NAMESPACE
-
-#endif // QT_NO_DIRMODEL
index 5f9cb0e..27a7bc0 100644 (file)
@@ -47,8 +47,6 @@
 #include <QUrl>
 #include <QAbstractListModel>
 
-#ifndef QT_NO_DIRMODEL
-
 QT_BEGIN_HEADER
 
 QT_BEGIN_NAMESPACE
@@ -68,14 +66,16 @@ class QDeclarativeFolderListModel : public QAbstractListModel, public QDeclarati
 
 //![class props]
     Q_PROPERTY(QUrl folder READ folder WRITE setFolder NOTIFY folderChanged)
+    Q_PROPERTY(QUrl rootFolder READ rootFolder WRITE setRootFolder)
     Q_PROPERTY(QUrl parentFolder READ parentFolder NOTIFY folderChanged)
     Q_PROPERTY(QStringList nameFilters READ nameFilters WRITE setNameFilters)
     Q_PROPERTY(SortField sortField READ sortField WRITE setSortField)
     Q_PROPERTY(bool sortReversed READ sortReversed WRITE setSortReversed)
     Q_PROPERTY(bool showDirs READ showDirs WRITE setShowDirs)
+    Q_PROPERTY(bool showDirsFirst READ showDirsFirst WRITE setShowDirsFirst)
     Q_PROPERTY(bool showDotAndDotDot READ showDotAndDotDot WRITE setShowDotAndDotDot)
     Q_PROPERTY(bool showOnlyReadable READ showOnlyReadable WRITE setShowOnlyReadable)
-    Q_PROPERTY(int count READ count)
+    Q_PROPERTY(int count READ count NOTIFY rowCountChanged)
 //![class props]
 
 //![abslistmodel]
@@ -83,10 +83,20 @@ public:
     QDeclarativeFolderListModel(QObject *parent = 0);
     ~QDeclarativeFolderListModel();
 
-    enum Roles { FileNameRole = Qt::UserRole+1, FilePathRole = Qt::UserRole+2 };
-
-    int rowCount(const QModelIndex &parent) const;
-    QVariant data(const QModelIndex &index, int role) const;
+    enum Roles {
+        FileNameRole = Qt::UserRole + 1,
+        FilePathRole = Qt::UserRole + 2,
+        FileBaseNameRole = Qt::UserRole + 3,
+        FileSuffixRole = Qt::UserRole + 4,
+        FileSizeRole = Qt::UserRole + 5,
+        FileLastModifiedRole = Qt::UserRole + 6,
+        FileLastReadRole = Qt::UserRole +7,
+        FileIsDirRole = Qt::UserRole + 8
+    };
+
+    virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
+    virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
+    virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
 //![abslistmodel]
 
 //![count]
@@ -96,6 +106,8 @@ public:
 //![prop funcs]
     QUrl folder() const;
     void setFolder(const QUrl &folder);
+    QUrl rootFolder() const;
+    void setRootFolder(const QUrl &path);
 
     QUrl parentFolder() const;
 
@@ -111,49 +123,47 @@ public:
     void setSortReversed(bool rev);
 
     bool showDirs() const;
-    void  setShowDirs(bool);
+    void setShowDirs(bool showDirs);
+    bool showDirsFirst() const;
+    void setShowDirsFirst(bool showDirsFirst);
     bool showDotAndDotDot() const;
-    void  setShowDotAndDotDot(bool);
+    void setShowDotAndDotDot(bool on);
     bool showOnlyReadable() const;
-    void  setShowOnlyReadable(bool);
+    void setShowOnlyReadable(bool on);
 //![prop funcs]
 
-//![isfolder]
     Q_INVOKABLE bool isFolder(int index) const;
-//![isfolder]
+    Q_INVOKABLE QVariant get(int idx, const QString &property) const;
 
 //![parserstatus]
     virtual void classBegin();
     virtual void componentComplete();
 //![parserstatus]
 
+    int roleFromString(const QString &roleName) const;
+
 //![notifier]
 Q_SIGNALS:
     void folderChanged();
+    void rowCountChanged() const;
 //![notifier]
 
 //![class end]
-private Q_SLOTS:
-    void refresh();
-    void resetFiltering();
-    void inserted(const QModelIndex &index, int start, int end);
-    void removed(const QModelIndex &index, int start, int end);
-    void handleDataChanged(const QModelIndex &start, const QModelIndex &end);
+
 
 private:
     Q_DISABLE_COPY(QDeclarativeFolderListModel)
-    QDeclarativeFolderListModelPrivate *d;
+    Q_DECLARE_PRIVATE(QDeclarativeFolderListModel)
+    QScopedPointer<QDeclarativeFolderListModelPrivate> d_ptr;
+
+    Q_PRIVATE_SLOT(d_func(), void _q_directoryChanged(const QString &directory, const QList<FileProperty> &list))
+    Q_PRIVATE_SLOT(d_func(), void _q_directoryUpdated(const QString &directory, const QList<FileProperty> &list, int fromIndex, int toIndex))
+    Q_PRIVATE_SLOT(d_func(), void _q_sortFinished(const QList<FileProperty> &list))
 };
 //![class end]
 
 QT_END_NAMESPACE
 
-//![qml decl]
-QML_DECLARE_TYPE(QDeclarativeFolderListModel)
-//![qml decl]
-
 QT_END_HEADER
 
-#endif // QT_NO_DIRMODEL
-
 #endif // QDECLARATIVEFOLDERLISTMODEL_H
index 07eb6e8..708f3c9 100644 (file)
@@ -170,8 +170,8 @@ void tst_qdeclarativefolderlistmodel::refresh()
 
     flm->setProperty("sortReversed", true);
 
-    QCOMPARE(removeStart, 0);
-    QCOMPARE(removeEnd, count-1);
+    QTRY_COMPARE(removeStart, 0);
+    QTRY_COMPARE(removeEnd, count-1); // wait for refresh
 }
 
 QTEST_MAIN(tst_qdeclarativefolderlistmodel)