aboutsummaryrefslogtreecommitdiffstats
path: root/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/imports/folderlistmodel/qquickfolderlistmodel.cpp')
-rw-r--r--src/imports/folderlistmodel/qquickfolderlistmodel.cpp494
1 files changed, 331 insertions, 163 deletions
diff --git a/src/imports/folderlistmodel/qquickfolderlistmodel.cpp b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
index 5621622cca..d68d7af6d4 100644
--- a/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
+++ b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp
@@ -41,25 +41,71 @@
//![code]
#include "qquickfolderlistmodel.h"
-#include <QDirModel>
+#include "fileinfothread_p.h"
+#include "fileproperty_p.h"
#include <QDebug>
#include <qqmlcontext.h>
-#ifndef QT_NO_DIRMODEL
-
QT_BEGIN_NAMESPACE
class QQuickFolderListModelPrivate
{
+ Q_DECLARE_PUBLIC(QQuickFolderListModel)
+
public:
- QQuickFolderListModelPrivate()
- : sortField(QQuickFolderListModel::Name), sortReversed(false), count(0), showDirs(true), showDots(false), showOnlyReadable(false), insideRefresh(false) {
+ QQuickFolderListModelPrivate(QQuickFolderListModel *q)
+ : q_ptr(q),
+ sortField(QQuickFolderListModel::Name), sortReversed(false), showDirs(true), showDirsFirst(false), showDots(false), showOnlyReadable(false)
+ {
nameFilters << QLatin1String("*");
}
- void updateSorting() {
- QDir::SortFlags flags = 0;
- switch(sortField) {
+
+ QQuickFolderListModel *q_ptr;
+ QUrl currentDir;
+ QUrl rootDir;
+ FileInfoThread fileInfoThread;
+ QList<FileProperty> data;
+ QHash<int, QByteArray> roleNames;
+ QQuickFolderListModel::SortField sortField;
+ QStringList nameFilters;
+ bool sortReversed;
+ bool showDirs;
+ bool showDirsFirst;
+ bool showDots;
+ bool showOnlyReadable;
+
+ ~QQuickFolderListModelPrivate() {}
+ 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 QQuickFolderListModelPrivate::init()
+{
+ Q_Q(QQuickFolderListModel);
+ 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 QQuickFolderListModelPrivate::updateSorting()
+{
+ Q_Q(QQuickFolderListModel);
+
+ QDir::SortFlags flags = 0;
+
+ switch (sortField) {
case QQuickFolderListModel::Unsorted:
flags |= QDir::Unsorted;
break;
@@ -75,26 +121,80 @@ public:
case QQuickFolderListModel::Type:
flags |= QDir::Type;
break;
- }
+ default:
+ break;
+ }
+
+ emit q->layoutAboutToBeChanged();
+
+ if (sortReversed)
+ flags |= QDir::Reversed;
+
+ fileInfoThread.setSortFlags(flags);
+}
+
+void QQuickFolderListModelPrivate::_q_directoryChanged(const QString &directory, const QList<FileProperty> &list)
+{
+ Q_Q(QQuickFolderListModel);
+ Q_UNUSED(directory);
+
+ data = list;
+ q->endResetModel();
+ emit q->rowCountChanged();
+ emit q->folderChanged();
+}
- if (sortReversed)
- flags |= QDir::Reversed;
- model.setSorting(flags);
+void QQuickFolderListModelPrivate::_q_directoryUpdated(const QString &directory, const QList<FileProperty> &list, int fromIndex, int toIndex)
+{
+ Q_Q(QQuickFolderListModel);
+ 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 QQuickFolderListModelPrivate::_q_sortFinished(const QList<FileProperty> &list)
+{
+ Q_Q(QQuickFolderListModel);
+
+ 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;
- QQuickFolderListModel::SortField sortField;
- bool sortReversed;
- int count;
- bool showDirs;
- bool showDots;
- bool showOnlyReadable;
- bool insideRefresh;
-};
/*!
\qmlclass FolderListModel QQuickFolderListModel
@@ -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:
*/
QQuickFolderListModel::QQuickFolderListModel(QObject *parent)
- : QAbstractListModel(parent)
+ : QAbstractListModel(parent), d_ptr(new QQuickFolderListModelPrivate(this))
{
- QHash<int, QByteArray> roles;
- roles[FileNameRole] = "fileName";
- roles[FilePathRole] = "filePath";
- setRoleNames(roles);
-
- d = new QQuickFolderListModelPrivate;
- 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(QQuickFolderListModel);
+ 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();
}
QQuickFolderListModel::~QQuickFolderListModel()
{
- delete d;
}
QVariant QQuickFolderListModel::data(const QModelIndex &index, int role) const
{
+ Q_D(const QQuickFolderListModel);
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 QQuickFolderListModel::data(const QModelIndex &index, int role) const
*/
int QQuickFolderListModel::rowCount(const QModelIndex &parent) const
{
+ Q_D(const QQuickFolderListModel);
Q_UNUSED(parent);
- return d->count;
+ return d->data.size();
+}
+
+QModelIndex QQuickFolderListModel::index(int row, int , const QModelIndex &) const
+{
+ return createIndex(row, 0);
}
/*!
@@ -219,46 +354,70 @@ int QQuickFolderListModel::rowCount(const QModelIndex &parent) const
*/
QUrl QQuickFolderListModel::folder() const
{
- return d->folder;
+ Q_D(const QQuickFolderListModel);
+ return d->currentDir;
}
void QQuickFolderListModel::setFolder(const QUrl &folder)
{
- if (folder == d->folder)
+ Q_D(QQuickFolderListModel);
+
+ 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 QQuickFolderListModel::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 QQuickFolderListModel::rootFolder() const
+{
+ Q_D(const QQuickFolderListModel);
+ return d->rootDir;
}
-void QQuickFolderListModel::resetFiltering()
+void QQuickFolderListModel::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(QQuickFolderListModel);
- 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 QQuickFolderListModel::resetFiltering()
*/
QUrl QQuickFolderListModel::parentFolder() const
{
- QString localFile = d->folder.toLocalFile();
+ Q_D(const QQuickFolderListModel);
+
+ QString localFile = d->currentDir.toLocalFile();
if (!localFile.isEmpty()) {
QDir dir(localFile);
#if defined(Q_OS_WIN)
@@ -277,10 +438,10 @@ QUrl QQuickFolderListModel::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 QQuickFolderListModel::parentFolder() const
*/
QStringList QQuickFolderListModel::nameFilters() const
{
+ Q_D(const QQuickFolderListModel);
return d->nameFilters;
}
void QQuickFolderListModel::setNameFilters(const QStringList &filters)
{
+ Q_D(QQuickFolderListModel);
+ d->fileInfoThread.setNameFilters(filters);
d->nameFilters = filters;
- d->model.setNameFilters(d->nameFilters);
}
void QQuickFolderListModel::classBegin()
@@ -318,11 +481,10 @@ void QQuickFolderListModel::classBegin()
void QQuickFolderListModel::componentComplete()
{
- if (!d->folder.isValid() || d->folder.toLocalFile().isEmpty() || !QDir().exists(d->folder.toLocalFile()))
- setFolder(QUrl(QLatin1String("file://")+QDir::currentPath()));
+ Q_D(QQuickFolderListModel);
- 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 QQuickFolderListModel::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 QQuickFolderListModel::componentComplete()
*/
QQuickFolderListModel::SortField QQuickFolderListModel::sortField() const
{
+ Q_D(const QQuickFolderListModel);
return d->sortField;
}
void QQuickFolderListModel::setSortField(SortField field)
{
+ Q_D(QQuickFolderListModel);
if (field != d->sortField) {
d->sortField = field;
d->updateSorting();
}
}
+int QQuickFolderListModel::roleFromString(const QString &roleName) const
+{
+ Q_D(const QQuickFolderListModel);
+ return d->roleNames.key(roleName.toLatin1(), -1);
+}
+
/*!
\qmlproperty bool FolderListModel::sortReversed
@@ -362,11 +532,14 @@ void QQuickFolderListModel::setSortField(SortField field)
*/
bool QQuickFolderListModel::sortReversed() const
{
+ Q_D(const QQuickFolderListModel);
return d->sortReversed;
}
void QQuickFolderListModel::setSortReversed(bool rev)
{
+ Q_D(QQuickFolderListModel);
+
if (rev != d->sortReversed) {
d->sortReversed = rev;
d->updateSorting();
@@ -382,91 +555,66 @@ void QQuickFolderListModel::setSortReversed(bool rev)
bool QQuickFolderListModel::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 QQuickFolderListModel::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 QQuickFolderListModel::inserted(const QModelIndex &index, int start, int end)
+ \sa showDotAndDotDot
+*/
+bool QQuickFolderListModel::showDirs() const
{
- if (index == d->folderIndex) {
- emit beginInsertRows(QModelIndex(), start, end);
- d->count = d->model.rowCount(d->folderIndex);
- emit endInsertRows();
- }
+ Q_D(const QQuickFolderListModel);
+ return d->showDirs;
}
-void QQuickFolderListModel::removed(const QModelIndex &index, int start, int end)
+void QQuickFolderListModel::setShowDirs(bool on)
{
- if (index == d->folderIndex) {
- emit beginRemoveRows(QModelIndex(), start, end);
- d->count = d->model.rowCount(d->folderIndex);
- emit endRemoveRows();
- }
-}
+ Q_D(QQuickFolderListModel);
-void QQuickFolderListModel::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 QQuickFolderListModel::showDirs() const
+bool QQuickFolderListModel::showDirsFirst() const
{
- return d->model.filter() & QDir::AllDirs;
+ Q_D(const QQuickFolderListModel);
+ return d->showDirsFirst;
}
-void QQuickFolderListModel::setShowDirs(bool on)
+void QQuickFolderListModel::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(QQuickFolderListModel);
+
+ d->fileInfoThread.setShowDirsFirst(on);
+ d->showDirsFirst = on;
}
+
/*!
\qmlproperty bool FolderListModel::showDotAndDotDot
@@ -479,19 +627,16 @@ void QQuickFolderListModel::setShowDirs(bool on)
*/
bool QQuickFolderListModel::showDotAndDotDot() const
{
- return !(d->model.filter() & QDir::NoDotAndDotDot);
+ Q_D(const QQuickFolderListModel);
+ return d->showDots;
}
void QQuickFolderListModel::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(QQuickFolderListModel);
+
+ if (on != d->showDots) {
+ d->fileInfoThread.setShowDotDot(on);
}
}
@@ -507,23 +652,46 @@ void QQuickFolderListModel::setShowDotAndDotDot(bool on)
*/
bool QQuickFolderListModel::showOnlyReadable() const
{
- return d->model.filter() & QDir::Readable;
+ Q_D(const QQuickFolderListModel);
+ return d->showOnlyReadable;
}
void QQuickFolderListModel::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(QQuickFolderListModel);
+
+ if (on != d->showOnlyReadable) {
+ d->fileInfoThread.setShowOnlyReadable(on);
}
}
+/*!
+ \qmlmethod QVariant QQuickFolderListModel::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 QQuickFolderListModel::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_qquickfolderlistmodel.cpp"
+
//![code]
QT_END_NAMESPACE
-
-#endif // QT_NO_DIRMODEL