aboutsummaryrefslogtreecommitdiffstats
path: root/src/labs
diff options
context:
space:
mode:
authorMaximilian Goldstein <max.goldstein@qt.io>2021-01-20 17:23:23 +0100
committerMaximilian Goldstein <max.goldstein@qt.io>2021-01-21 10:35:52 +0100
commiteb5bb9e7f547a7e222b5dbb848774639ab11f243 (patch)
tree7c4377e7b272025a4240e5707365a50b49898cc9 /src/labs
parent3fadfb2c3fa7d4b22d0d0269c645c1086fa56619 (diff)
Qt.labs.folderlistmodel: Make plugin optional
This moves the folderlistmodel types into a new library and is meant to make them availabe to the QML compiler at some point in the future. Task-number: QTBUG-90487 Change-Id: Iee84a4804a241aa1dee5f896a02ccc9f0ecc0d8d Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/labs')
-rw-r--r--src/labs/CMakeLists.txt3
-rw-r--r--src/labs/folderlistmodel/CMakeLists.txt24
-rw-r--r--src/labs/folderlistmodel/fileinfothread.cpp369
-rw-r--r--src/labs/folderlistmodel/fileinfothread_p.h133
-rw-r--r--src/labs/folderlistmodel/fileproperty_p.h103
-rw-r--r--src/labs/folderlistmodel/qquickfolderlistmodel.cpp927
-rw-r--r--src/labs/folderlistmodel/qquickfolderlistmodel.h191
-rw-r--r--src/labs/folderlistmodel/qquickfolderlistmodelglobal_p.h73
8 files changed, 1823 insertions, 0 deletions
diff --git a/src/labs/CMakeLists.txt b/src/labs/CMakeLists.txt
index b1f8c7c142..5dc715db60 100644
--- a/src/labs/CMakeLists.txt
+++ b/src/labs/CMakeLists.txt
@@ -1 +1,4 @@
add_subdirectory(settings)
+if(QT_FEATURE_qml_itemmodel)
+ add_subdirectory(folderlistmodel)
+endif()
diff --git a/src/labs/folderlistmodel/CMakeLists.txt b/src/labs/folderlistmodel/CMakeLists.txt
new file mode 100644
index 0000000000..bcee01629b
--- /dev/null
+++ b/src/labs/folderlistmodel/CMakeLists.txt
@@ -0,0 +1,24 @@
+qt_internal_add_module(LabsFolderListModel
+ GENERATE_METATYPES
+ SOURCES
+ fileinfothread.cpp fileinfothread_p.h
+ fileproperty_p.h
+ qquickfolderlistmodel.cpp qquickfolderlistmodel.h
+ qquickfolderlistmodelglobal_p.h
+ DEFINES
+ QT_BUILD_LABSFOLDERMODEL_LIB
+ PUBLIC_LIBRARIES
+ Qt::CorePrivate
+ Qt::QmlPrivate
+)
+
+set_target_properties(LabsFolderListModel PROPERTIES
+ QT_QML_MODULE_INSTALL_QMLTYPES TRUE
+ QT_QML_MODULE_VERSION ${CMAKE_PROJECT_VERSION}
+ QT_QML_MODULE_URI Qt.labs.folderlistmodel
+ QT_QMLTYPES_FILENAME plugins.qmltypes
+ QT_QML_MODULE_INSTALL_DIR "${INSTALL_QMLDIR}/Qt/labs/folderlistmodel"
+)
+
+
+qt6_qml_type_registration(LabsFolderListModel)
diff --git a/src/labs/folderlistmodel/fileinfothread.cpp b/src/labs/folderlistmodel/fileinfothread.cpp
new file mode 100644
index 0000000000..a93edd3b1b
--- /dev/null
+++ b/src/labs/folderlistmodel/fileinfothread.cpp
@@ -0,0 +1,369 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "fileinfothread_p.h"
+#include <qdiriterator.h>
+#include <qpointer.h>
+#include <qtimer.h>
+
+#include <QDebug>
+
+
+FileInfoThread::FileInfoThread(QObject *parent)
+ : QThread(parent),
+ abort(false),
+ scanPending(false),
+#if QT_CONFIG(filesystemwatcher)
+ watcher(nullptr),
+#endif
+ sortFlags(QDir::Name),
+ needUpdate(true),
+ folderUpdate(false),
+ sortUpdate(false),
+ showFiles(true),
+ showDirs(true),
+ showDirsFirst(false),
+ showDotAndDotDot(false),
+ showHidden(false),
+ showOnlyReadable(false),
+ caseSensitive(true)
+{
+#if QT_CONFIG(filesystemwatcher)
+ watcher = new QFileSystemWatcher(this);
+ connect(watcher, SIGNAL(directoryChanged(QString)), this, SLOT(dirChanged(QString)));
+ connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(updateFile(QString)));
+#endif // filesystemwatcher
+}
+
+FileInfoThread::~FileInfoThread()
+{
+ QMutexLocker locker(&mutex);
+ abort = true;
+ condition.wakeOne();
+ locker.unlock();
+ wait();
+}
+
+void FileInfoThread::clear()
+{
+ QMutexLocker locker(&mutex);
+#if QT_CONFIG(filesystemwatcher)
+ watcher->removePaths(watcher->files());
+ watcher->removePaths(watcher->directories());
+#endif
+}
+
+void FileInfoThread::removePath(const QString &path)
+{
+ QMutexLocker locker(&mutex);
+#if QT_CONFIG(filesystemwatcher)
+ if (!path.startsWith(QLatin1Char(':')))
+ watcher->removePath(path);
+#else
+ Q_UNUSED(path);
+#endif
+ currentPath.clear();
+}
+
+void FileInfoThread::setPath(const QString &path)
+{
+ Q_ASSERT(!path.isEmpty());
+
+ QMutexLocker locker(&mutex);
+#if QT_CONFIG(filesystemwatcher)
+ if (!path.startsWith(QLatin1Char(':')))
+ watcher->addPath(path);
+#endif
+ currentPath = path;
+ needUpdate = true;
+ initiateScan();
+}
+
+void FileInfoThread::setRootPath(const QString &path)
+{
+ Q_ASSERT(!path.isEmpty());
+
+ QMutexLocker locker(&mutex);
+ rootPath = path;
+}
+
+#if QT_CONFIG(filesystemwatcher)
+void FileInfoThread::dirChanged(const QString &directoryPath)
+{
+ Q_UNUSED(directoryPath);
+ QMutexLocker locker(&mutex);
+ folderUpdate = true;
+ initiateScan();
+}
+#endif
+
+void FileInfoThread::setSortFlags(QDir::SortFlags flags)
+{
+ QMutexLocker locker(&mutex);
+ sortFlags = flags;
+ sortUpdate = true;
+ needUpdate = true;
+ initiateScan();
+}
+
+void FileInfoThread::setNameFilters(const QStringList & filters)
+{
+ QMutexLocker locker(&mutex);
+ nameFilters = filters;
+ folderUpdate = true;
+ initiateScan();
+}
+
+void FileInfoThread::setShowFiles(bool show)
+{
+ QMutexLocker locker(&mutex);
+ showFiles = show;
+ folderUpdate = true;
+ initiateScan();
+}
+
+void FileInfoThread::setShowDirs(bool showFolders)
+{
+ QMutexLocker locker(&mutex);
+ showDirs = showFolders;
+ folderUpdate = true;
+ initiateScan();
+}
+
+void FileInfoThread::setShowDirsFirst(bool show)
+{
+ QMutexLocker locker(&mutex);
+ showDirsFirst = show;
+ folderUpdate = true;
+ initiateScan();
+}
+
+void FileInfoThread::setShowDotAndDotDot(bool on)
+{
+ QMutexLocker locker(&mutex);
+ showDotAndDotDot = on;
+ folderUpdate = true;
+ needUpdate = true;
+ initiateScan();
+}
+
+void FileInfoThread::setShowHidden(bool on)
+{
+ QMutexLocker locker(&mutex);
+ showHidden = on;
+ folderUpdate = true;
+ needUpdate = true;
+ initiateScan();
+}
+
+void FileInfoThread::setShowOnlyReadable(bool on)
+{
+ QMutexLocker locker(&mutex);
+ showOnlyReadable = on;
+ folderUpdate = true;
+ initiateScan();
+}
+
+void FileInfoThread::setCaseSensitive(bool on)
+{
+ QMutexLocker locker(&mutex);
+ caseSensitive = on;
+ folderUpdate = true;
+ initiateScan();
+}
+
+#if QT_CONFIG(filesystemwatcher)
+void FileInfoThread::updateFile(const QString &path)
+{
+ Q_UNUSED(path);
+ QMutexLocker locker(&mutex);
+ folderUpdate = true;
+ initiateScan();
+}
+#endif
+
+void FileInfoThread::run()
+{
+ forever {
+ bool updateFiles = false;
+ QMutexLocker locker(&mutex);
+ if (abort) {
+ return;
+ }
+ if (currentPath.isEmpty() || !needUpdate) {
+ emit statusChanged(currentPath.isEmpty() ? QQuickFolderListModel::Null : QQuickFolderListModel::Ready);
+ condition.wait(&mutex);
+ }
+
+ if (abort) {
+ return;
+ }
+
+ if (!currentPath.isEmpty()) {
+ updateFiles = true;
+ emit statusChanged(QQuickFolderListModel::Loading);
+ }
+ if (updateFiles)
+ getFileInfos(currentPath);
+ locker.unlock();
+ }
+}
+
+void FileInfoThread::runOnce()
+{
+ if (scanPending)
+ return;
+ scanPending = true;
+ QPointer<FileInfoThread> guardedThis(this);
+
+ auto getFileInfosAsync = [guardedThis](){
+ if (!guardedThis)
+ return;
+ guardedThis->scanPending = false;
+ if (guardedThis->currentPath.isEmpty()) {
+ emit guardedThis->statusChanged(QQuickFolderListModel::Null);
+ return;
+ }
+ emit guardedThis->statusChanged(QQuickFolderListModel::Loading);
+ guardedThis->getFileInfos(guardedThis->currentPath);
+ emit guardedThis->statusChanged(QQuickFolderListModel::Ready);
+ };
+
+ QTimer::singleShot(0, getFileInfosAsync);
+}
+
+void FileInfoThread::initiateScan()
+{
+#if QT_CONFIG(thread)
+ condition.wakeAll();
+#else
+ runOnce();
+#endif
+}
+
+void FileInfoThread::getFileInfos(const QString &path)
+{
+ QDir::Filters filter;
+ if (caseSensitive)
+ filter = QDir::CaseSensitive;
+ if (showFiles)
+ filter = filter | QDir::Files;
+ if (showDirs)
+ filter = filter | QDir::AllDirs | QDir::Drives;
+ if (!showDotAndDotDot)
+ filter = filter | QDir::NoDot | QDir::NoDotDot;
+ else if (path == rootPath)
+ filter = filter | QDir::NoDotDot;
+ if (showHidden)
+ filter = filter | QDir::Hidden;
+ if (showOnlyReadable)
+ filter = filter | QDir::Readable;
+ if (showDirsFirst)
+ sortFlags = sortFlags | QDir::DirsFirst;
+
+ QDir currentDir(path, QString(), sortFlags);
+ QList<FileProperty> filePropertyList;
+
+ const QFileInfoList fileInfoList = currentDir.entryInfoList(nameFilters, filter, sortFlags);
+
+ if (!fileInfoList.isEmpty()) {
+ filePropertyList.reserve(fileInfoList.count());
+ for (const 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/labs/folderlistmodel/fileinfothread_p.h b/src/labs/folderlistmodel/fileinfothread_p.h
new file mode 100644
index 0000000000..923cb29e03
--- /dev/null
+++ b/src/labs/folderlistmodel/fileinfothread_p.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef FILEINFOTHREAD_P_H
+#define FILEINFOTHREAD_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QThread>
+#include <QMutex>
+#include <QWaitCondition>
+#if QT_CONFIG(filesystemwatcher)
+#include <QFileSystemWatcher>
+#endif
+#include <QFileInfo>
+#include <QDir>
+
+#include "fileproperty_p.h"
+#include "qquickfolderlistmodel.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;
+ void statusChanged(QQuickFolderListModel::Status status) 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 setShowFiles(bool show);
+ void setShowDirs(bool showFolders);
+ void setShowDirsFirst(bool show);
+ void setShowDotAndDotDot(bool on);
+ void setShowHidden(bool on);
+ void setShowOnlyReadable(bool on);
+ void setCaseSensitive(bool on);
+
+public Q_SLOTS:
+#if QT_CONFIG(filesystemwatcher)
+ void dirChanged(const QString &directoryPath);
+ void updateFile(const QString &path);
+#endif
+
+protected:
+ void run() override;
+ void runOnce();
+ void initiateScan();
+ void getFileInfos(const QString &path);
+ void findChangeRange(const QList<FileProperty> &list, int &fromIndex, int &toIndex);
+
+private:
+ QMutex mutex;
+ QWaitCondition condition;
+ volatile bool abort;
+ bool scanPending;
+
+#if QT_CONFIG(filesystemwatcher)
+ QFileSystemWatcher *watcher;
+#endif
+ QList<FileProperty> currentFileList;
+ QDir::SortFlags sortFlags;
+ QString currentPath;
+ QString rootPath;
+ QStringList nameFilters;
+ bool needUpdate;
+ bool folderUpdate;
+ bool sortUpdate;
+ bool showFiles;
+ bool showDirs;
+ bool showDirsFirst;
+ bool showDotAndDotDot;
+ bool showHidden;
+ bool showOnlyReadable;
+ bool caseSensitive;
+};
+
+#endif // FILEINFOTHREAD_P_H
diff --git a/src/labs/folderlistmodel/fileproperty_p.h b/src/labs/folderlistmodel/fileproperty_p.h
new file mode 100644
index 0000000000..48be4a3d85
--- /dev/null
+++ b/src/labs/folderlistmodel/fileproperty_p.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef FILEPROPERTY_P_H
+#define FILEPROPERTY_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QFileInfo>
+#include <QDateTime>
+
+class FileProperty
+{
+public:
+ FileProperty(const QFileInfo &info) :
+ mFileName(info.fileName()),
+ mFilePath(info.filePath()),
+ mBaseName(info.baseName()),
+ mSuffix(info.completeSuffix()),
+ mSize(info.size()),
+ 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
diff --git a/src/labs/folderlistmodel/qquickfolderlistmodel.cpp b/src/labs/folderlistmodel/qquickfolderlistmodel.cpp
new file mode 100644
index 0000000000..ef21471c0c
--- /dev/null
+++ b/src/labs/folderlistmodel/qquickfolderlistmodel.cpp
@@ -0,0 +1,927 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//![code]
+#include "qquickfolderlistmodel.h"
+#include "fileinfothread_p.h"
+#include "fileproperty_p.h"
+#include <qqmlcontext.h>
+#include <qqmlfile.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickFolderListModelPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickFolderListModel)
+
+public:
+ QQuickFolderListModelPrivate(QQuickFolderListModel *q) : q_ptr(q) { }
+
+ QQuickFolderListModel *q_ptr;
+ QUrl currentDir;
+ QUrl rootDir;
+ FileInfoThread fileInfoThread;
+ QList<FileProperty> data;
+ QHash<int, QByteArray> roleNames;
+ QQuickFolderListModel::SortField sortField = QQuickFolderListModel::Name;
+ QStringList nameFilters = { QLatin1String("*") };
+ QQuickFolderListModel::Status status = QQuickFolderListModel::Null;
+ bool sortReversed = false;
+ bool showFiles = true;
+ bool showDirs = true;
+ bool showDirsFirst = false;
+ bool showDotAndDotDot = false;
+ bool showOnlyReadable = false;
+ bool showHidden = false;
+ bool caseSensitive = true;
+ bool sortCaseSensitive = true;
+
+ ~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 _q_statusChanged(QQuickFolderListModel::Status s);
+
+ static QString resolvePath(const QUrl &path);
+};
+
+
+void QQuickFolderListModelPrivate::init()
+{
+ Q_Q(QQuickFolderListModel);
+ qRegisterMetaType<QList<FileProperty> >("QList<FileProperty>");
+ qRegisterMetaType<QQuickFolderListModel::Status>("QQuickFolderListModel::Status");
+ 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>)));
+ q->connect(&fileInfoThread, SIGNAL(statusChanged(QQuickFolderListModel::Status)),
+ q, SLOT(_q_statusChanged(QQuickFolderListModel::Status)));
+ q->connect(q, SIGNAL(rowCountChanged()), q, SIGNAL(countChanged()));
+}
+
+
+void QQuickFolderListModelPrivate::updateSorting()
+{
+ Q_Q(QQuickFolderListModel);
+
+ QDir::SortFlags flags;
+
+ switch (sortField) {
+ case QQuickFolderListModel::Unsorted:
+ flags |= QDir::Unsorted;
+ break;
+ case QQuickFolderListModel::Name:
+ flags |= QDir::Name;
+ break;
+ case QQuickFolderListModel::Time:
+ flags |= QDir::Time;
+ break;
+ case QQuickFolderListModel::Size:
+ flags |= QDir::Size;
+ break;
+ case QQuickFolderListModel::Type:
+ flags |= QDir::Type;
+ break;
+ }
+
+ emit q->layoutAboutToBeChanged();
+
+ if (sortReversed)
+ flags |= QDir::Reversed;
+ if (!sortCaseSensitive)
+ flags |= QDir::IgnoreCase;
+
+ 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();
+}
+
+
+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()) {
+ QModelIndex modelIndexFrom = q->createIndex(fromIndex, 0);
+ QModelIndex modelIndexTo = q->createIndex(toIndex, 0);
+ data = list;
+ emit q->dataChanged(modelIndexFrom, modelIndexTo);
+ } else {
+ // File(s) inserted or removed. Since I do not know how many
+ // or where, I need to update the whole list from the first item.
+ // This is a little pessimistic, but optimizing it would require
+ // more information in the signal from FileInfoThread.
+ if (data.size() > 0) {
+ q->beginRemoveRows(parent, 0, data.size() - 1);
+ q->endRemoveRows();
+ }
+ data = list;
+ if (list.size() > 0) {
+ if (toIndex > list.size() - 1)
+ toIndex = list.size() - 1;
+ q->beginInsertRows(parent, 0, data.size() - 1);
+ q->endInsertRows();
+ }
+ emit q->rowCountChanged();
+ }
+}
+
+void QQuickFolderListModelPrivate::_q_sortFinished(const QList<FileProperty> &list)
+{
+ Q_Q(QQuickFolderListModel);
+
+ QModelIndex parent;
+ if (data.size() > 0) {
+ q->beginRemoveRows(parent, 0, data.size()-1);
+ data.clear();
+ q->endRemoveRows();
+ }
+
+ q->beginInsertRows(parent, 0, list.size()-1);
+ data = list;
+ q->endInsertRows();
+}
+
+void QQuickFolderListModelPrivate::_q_statusChanged(QQuickFolderListModel::Status s)
+{
+ Q_Q(QQuickFolderListModel);
+
+ if (status != s) {
+ status = s;
+ emit q->statusChanged();
+ }
+}
+
+QString QQuickFolderListModelPrivate::resolvePath(const QUrl &path)
+{
+ QString localPath = QQmlFile::urlToLocalFileOrQrc(path);
+ QUrl localUrl = QUrl(localPath);
+ QString fullPath = localUrl.path();
+ if (localUrl.scheme().length())
+ fullPath = localUrl.scheme() + QLatin1Char(':') + fullPath;
+ return QDir::cleanPath(fullPath);
+}
+
+/*!
+ \qmlmodule Qt.labs.folderlistmodel 2.\QtMinorVersion
+ \title Qt Labs FolderListModel QML Types
+ \ingroup qmlmodules
+ \brief The FolderListModel provides a model of the contents of a file system folder.
+
+ To use this module, import the module with the following line:
+
+ \qml
+ import Qt.labs.folderlistmodel
+ \endqml
+*/
+
+/*!
+ \qmltype FolderListModel
+ \inqmlmodule Qt.labs.folderlistmodel
+ \instantiates QQuickFolderListModel
+ \ingroup qtquick-models
+ \brief The FolderListModel provides a model of the contents of a file system folder.
+
+ FolderListModel provides access to information about the contents of a folder
+ in the local file system, exposing a list of files to views and other data components.
+
+ \note This type is made available by importing the \c Qt.labs.folderlistmodel module.
+ \e{Elements in the Qt.labs module are not guaranteed to remain compatible
+ in future versions.}
+
+ \qml
+ import Qt.labs.folderlistmodel
+ \endqml
+
+ The \l folder property specifies the folder to access. Information about the
+ files and directories in the folder is supplied via the model's interface.
+ Components access names and paths via the following roles:
+
+ \list
+ \li \c fileName
+ \li \c filePath
+ \li \c fileURL (since Qt 5.2; deprecated since Qt 5.15)
+ \li \c fileUrl (since Qt 5.15)
+ \li \c fileBaseName
+ \li \c fileSuffix
+ \li \c fileSize
+ \li \c fileModified
+ \li \c fileAccessed
+ \li \c fileIsDir
+ \endlist
+
+ Additionally a file entry can be differentiated from a folder entry via the
+ isFolder() method.
+
+ \section1 Filtering
+
+ Various properties can be set to filter the number of files and directories
+ exposed by the model.
+
+ The \l nameFilters property can be set to contain a list of wildcard filters
+ that are applied to names of files and directories, causing only those that
+ match the filters to be exposed.
+
+ Directories can be included or excluded using the \l showDirs property,
+ navigation directories can also be excluded by setting the \l showDotAndDotDot
+ property to false, hidden files can be included or excluded using the
+ \l showHidden property.
+
+ It is sometimes useful to limit the files and directories exposed to those
+ that the user can access. The \l showOnlyReadable property can be set to
+ enable this feature.
+
+ \section1 Example Usage
+
+ The following example shows a FolderListModel being used to provide a list
+ of QML files in a \l ListView:
+
+ \qml
+ import QtQuick
+ import Qt.labs.folderlistmodel
+
+ ListView {
+ width: 200; height: 400
+
+ FolderListModel {
+ id: folderModel
+ nameFilters: ["*.qml"]
+ }
+
+ Component {
+ id: fileDelegate
+ Text { text: fileName }
+ }
+
+ model: folderModel
+ delegate: fileDelegate
+ }
+ \endqml
+
+ \section1 Path Separators
+
+ Qt uses "/" as a universal directory separator in the same way that "/" is
+ used as a path separator in URLs. If you always use "/" as a directory
+ separator, Qt will translate your paths to conform to the underlying
+ operating system.
+
+ \sa {QML Data Models}
+*/
+
+QQuickFolderListModel::QQuickFolderListModel(QObject *parent)
+ : QAbstractListModel(parent), d_ptr(new QQuickFolderListModelPrivate(this))
+{
+ 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";
+ d->roleNames[FileUrlRole] = "fileUrl";
+ d->roleNames[FileURLRole] = "fileURL";
+ d->init();
+}
+
+QQuickFolderListModel::~QQuickFolderListModel()
+{
+}
+
+QVariant QQuickFolderListModel::data(const QModelIndex &index, int role) const
+{
+ Q_D(const QQuickFolderListModel);
+ QVariant rv;
+
+ 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();
+ break;
+ case FileLastReadRole:
+ rv = d->data.at(index.row()).lastRead();
+ break;
+ case FileIsDirRole:
+ rv = d->data.at(index.row()).isDir();
+ break;
+ case FileUrlRole:
+ case FileURLRole:
+ rv = QUrl::fromLocalFile(d->data.at(index.row()).filePath());
+ break;
+ default:
+ break;
+ }
+ return rv;
+}
+
+QHash<int, QByteArray> QQuickFolderListModel::roleNames() const
+{
+ Q_D(const QQuickFolderListModel);
+ return d->roleNames;
+}
+
+/*!
+ \qmlproperty int FolderListModel::count
+
+ Returns the number of items in the current folder that match the
+ filter criteria.
+*/
+int QQuickFolderListModel::rowCount(const QModelIndex &parent) const
+{
+ Q_D(const QQuickFolderListModel);
+ Q_UNUSED(parent);
+ return d->data.size();
+}
+
+QModelIndex QQuickFolderListModel::index(int row, int , const QModelIndex &) const
+{
+ return createIndex(row, 0);
+}
+
+/*!
+ \qmlproperty url FolderListModel::folder
+
+ The \a folder property holds a URL for the folder that the model
+ currently provides.
+
+ The value must be a \c file: or \c qrc: URL, or a relative URL.
+
+ The default value is an invalid URL.
+*/
+QUrl QQuickFolderListModel::folder() const
+{
+ Q_D(const QQuickFolderListModel);
+ return d->currentDir;
+}
+
+void QQuickFolderListModel::setFolder(const QUrl &folder)
+{
+ Q_D(QQuickFolderListModel);
+
+ if (folder == d->currentDir)
+ return;
+
+ QString resolvedPath = QQuickFolderListModelPrivate::resolvePath(folder);
+
+ 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();
+ if (d->status != QQuickFolderListModel::Null) {
+ d->status = QQuickFolderListModel::Null;
+ emit statusChanged();
+ }
+ return;
+ }
+
+ d->fileInfoThread.setPath(resolvedPath);
+}
+
+
+/*!
+ \qmlproperty url FolderListModel::rootFolder
+
+ When this property is set, the given folder will
+ be treated as the root in the file system, so that
+ you can only traverse subfolders within it.
+*/
+QUrl QQuickFolderListModel::rootFolder() const
+{
+ Q_D(const QQuickFolderListModel);
+ return d->rootDir;
+}
+
+void QQuickFolderListModel::setRootFolder(const QUrl &path)
+{
+ Q_D(QQuickFolderListModel);
+
+ if (path.isEmpty())
+ return;
+
+ QString resolvedPath = QQuickFolderListModelPrivate::resolvePath(path);
+
+ QFileInfo info(resolvedPath);
+ if (!info.exists() || !info.isDir())
+ return;
+
+ d->fileInfoThread.setRootPath(resolvedPath);
+ d->rootDir = path;
+}
+
+
+/*!
+ \qmlproperty url FolderListModel::parentFolder
+
+ Returns the URL of the parent of the current \l folder.
+*/
+QUrl QQuickFolderListModel::parentFolder() const
+{
+ Q_D(const QQuickFolderListModel);
+
+ QString localFile = d->currentDir.toLocalFile();
+ if (!localFile.isEmpty()) {
+ QDir dir(localFile);
+ if (dir.isRoot() || !dir.cdUp())
+ return QUrl();
+ localFile = dir.path();
+ } else {
+ const QString path = d->currentDir.path();
+ const int pos = path.lastIndexOf(QLatin1Char('/'));
+ if (pos <= 0)
+ return QUrl();
+ localFile = path.left(pos);
+ }
+ return QUrl::fromLocalFile(localFile);
+}
+
+/*!
+ \qmlproperty list<string> FolderListModel::nameFilters
+
+ The \a nameFilters property contains a list of file name filters.
+ The filters may include the ? and * wildcards.
+
+ The example below filters on PNG and JPEG files:
+
+ \qml
+ FolderListModel {
+ nameFilters: [ "*.png", "*.jpg" ]
+ }
+ \endqml
+
+ \note Directories are not excluded by filters.
+*/
+QStringList QQuickFolderListModel::nameFilters() const
+{
+ Q_D(const QQuickFolderListModel);
+ return d->nameFilters;
+}
+
+void QQuickFolderListModel::setNameFilters(const QStringList &filters)
+{
+ Q_D(QQuickFolderListModel);
+ if (d->nameFilters == filters)
+ return;
+ d->fileInfoThread.setNameFilters(filters);
+ d->nameFilters = filters;
+}
+
+void QQuickFolderListModel::classBegin()
+{
+}
+
+void QQuickFolderListModel::componentComplete()
+{
+ Q_D(QQuickFolderListModel);
+ QString localPath = QQmlFile::urlToLocalFileOrQrc(d->currentDir);
+ if (localPath.isEmpty() || !QDir(localPath).exists())
+ setFolder(QUrl::fromLocalFile(QDir::currentPath()));
+ d->fileInfoThread.start(QThread::LowPriority);
+}
+
+/*!
+ \qmlproperty enumeration FolderListModel::sortField
+
+ The \a sortField property contains field to use for sorting. sortField
+ may be one of:
+ \list
+ \li Unsorted - no sorting is applied.
+ \li Name - sort by filename
+ \li Time - sort by time modified
+ \li Size - sort by file size
+ \li Type - sort by file type (extension)
+ \endlist
+
+ \sa sortReversed
+*/
+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
+
+ If set to true, reverses the sort order. The default is false.
+
+ \sa sortField
+*/
+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();
+ }
+}
+
+/*!
+ \qmlmethod bool FolderListModel::isFolder(int index)
+
+ Returns true if the entry \a index is a folder; otherwise
+ returns false.
+*/
+bool QQuickFolderListModel::isFolder(int index) const
+{
+ if (index != -1) {
+ QModelIndex idx = createIndex(index, 0);
+ if (idx.isValid()) {
+ QVariant var = data(idx, FileIsDirRole);
+ if (var.isValid())
+ return var.toBool();
+ }
+ }
+ return false;
+}
+
+/*!
+ \qmlproperty bool FolderListModel::showFiles
+ \since 5.2
+
+ If true, files are included in the model; otherwise only directories
+ are included.
+
+ By default, this property is true.
+
+ \sa showDirs
+*/
+bool QQuickFolderListModel::showFiles() const
+{
+ Q_D(const QQuickFolderListModel);
+ return d->showFiles;
+}
+
+void QQuickFolderListModel::setShowFiles(bool on)
+{
+ Q_D(QQuickFolderListModel);
+
+ d->fileInfoThread.setShowFiles(on);
+ d->showFiles = on;
+}
+
+/*!
+ \qmlproperty bool FolderListModel::showDirs
+
+ If true, directories are included in the model; otherwise only files
+ are included.
+
+ By default, this property is true.
+
+ Note that the nameFilters are not applied to directories.
+
+ \sa showDotAndDotDot
+*/
+bool QQuickFolderListModel::showDirs() const
+{
+ Q_D(const QQuickFolderListModel);
+ return d->showDirs;
+}
+
+void QQuickFolderListModel::setShowDirs(bool on)
+{
+ Q_D(QQuickFolderListModel);
+
+ d->fileInfoThread.setShowDirs(on);
+ d->showDirs = on;
+}
+
+/*!
+ \qmlproperty bool FolderListModel::showDirsFirst
+
+ If true, if directories are included in the model they will
+ always be shown first, then the files.
+
+ By default, this property is false.
+
+*/
+bool QQuickFolderListModel::showDirsFirst() const
+{
+ Q_D(const QQuickFolderListModel);
+ return d->showDirsFirst;
+}
+
+void QQuickFolderListModel::setShowDirsFirst(bool on)
+{
+ Q_D(QQuickFolderListModel);
+
+ d->fileInfoThread.setShowDirsFirst(on);
+ d->showDirsFirst = on;
+}
+
+
+/*!
+ \qmlproperty bool FolderListModel::showDotAndDotDot
+
+ If true, the "." and ".." directories are included in the model; otherwise
+ they are excluded.
+
+ By default, this property is false.
+
+ \sa showDirs
+*/
+bool QQuickFolderListModel::showDotAndDotDot() const
+{
+ Q_D(const QQuickFolderListModel);
+ return d->showDotAndDotDot;
+}
+
+void QQuickFolderListModel::setShowDotAndDotDot(bool on)
+{
+ Q_D(QQuickFolderListModel);
+
+ if (on != d->showDotAndDotDot) {
+ d->fileInfoThread.setShowDotAndDotDot(on);
+ d->showDotAndDotDot = on;
+ }
+}
+
+
+/*!
+ \qmlproperty bool FolderListModel::showHidden
+ \since 5.2
+
+ If true, hidden files and directories are included in the model; otherwise
+ they are excluded.
+
+ By default, this property is false.
+*/
+bool QQuickFolderListModel::showHidden() const
+{
+ Q_D(const QQuickFolderListModel);
+ return d->showHidden;
+}
+
+void QQuickFolderListModel::setShowHidden(bool on)
+{
+ Q_D(QQuickFolderListModel);
+
+ if (on != d->showHidden) {
+ d->fileInfoThread.setShowHidden(on);
+ d->showHidden = on;
+ }
+}
+
+/*!
+ \qmlproperty bool FolderListModel::showOnlyReadable
+
+ If true, only readable files and directories are shown; otherwise all files
+ and directories are shown.
+
+ By default, this property is false.
+
+ \sa showDirs
+*/
+bool QQuickFolderListModel::showOnlyReadable() const
+{
+ Q_D(const QQuickFolderListModel);
+ return d->showOnlyReadable;
+}
+
+void QQuickFolderListModel::setShowOnlyReadable(bool on)
+{
+ Q_D(QQuickFolderListModel);
+
+ if (on != d->showOnlyReadable) {
+ d->fileInfoThread.setShowOnlyReadable(on);
+ d->showOnlyReadable = on;
+ }
+}
+
+/*!
+ * \qmlproperty bool FolderListModel::caseSensitive
+ * \since 5.7
+ *
+ * Use case sensitive pattern matching.
+ *
+ * By default, this property is true.
+ *
+ */
+bool QQuickFolderListModel::caseSensitive() const
+{
+ Q_D(const QQuickFolderListModel);
+ return d->caseSensitive;
+}
+
+void QQuickFolderListModel::setCaseSensitive(bool on)
+{
+ Q_D(QQuickFolderListModel);
+
+ if (on != d->caseSensitive) {
+ d->fileInfoThread.setCaseSensitive(on);
+ d->caseSensitive = on;
+ }
+}
+
+/*!
+ \qmlproperty enumeration FolderListModel::status
+ \since 5.11
+
+ This property holds the status of folder reading. It can be one of:
+ \list
+ \li FolderListModel.Null - no \a folder has been set
+ \li FolderListModel.Ready - the folder has been loaded
+ \li FolderListModel.Loading - the folder is currently being loaded
+ \endlist
+
+ Use this status to provide an update or respond to the status change in some way.
+ For example, you could:
+
+ \list
+ \li Trigger a state change:
+ \qml
+ State { name: 'loaded'; when: folderModel.status == FolderListModel.Ready }
+ \endqml
+
+ \li Implement an \c onStatusChanged signal handler:
+ \qml
+ FolderListModel {
+ id: folderModel
+ onStatusChanged: if (folderModel.status == FolderListModel.Ready) console.log('Loaded')
+ }
+ \endqml
+
+ \li Bind to the status value:
+ \qml
+ Text { text: folderModel.status == FolderListModel.Ready ? 'Loaded' : 'Not loaded' }
+ \endqml
+ \endlist
+*/
+QQuickFolderListModel::Status QQuickFolderListModel::status() const
+{
+ Q_D(const QQuickFolderListModel);
+ return d->status;
+}
+
+/*!
+ \qmlproperty bool FolderListModel::sortCaseSensitive
+ \since 5.12
+
+ If set to \c true, the sort is case sensitive. This property is \c true by default.
+*/
+
+bool QQuickFolderListModel::sortCaseSensitive() const
+{
+ Q_D(const QQuickFolderListModel);
+ return d->sortCaseSensitive;
+}
+
+void QQuickFolderListModel::setSortCaseSensitive(bool on)
+{
+ Q_D(QQuickFolderListModel);
+
+ if (on != d->sortCaseSensitive) {
+ d->sortCaseSensitive = on;
+ d->updateSorting();
+ }
+}
+
+/*!
+ \qmlmethod var FolderListModel::get(int index, string property)
+
+ Returns the folder \a property for the given \a index. The following properties
+ are available:
+
+ \list
+ \li \c fileName
+ \li \c filePath
+ \li \c fileURL (since Qt 5.2; deprecated since Qt 5.15)
+ \li \c fileUrl (since Qt 5.15)
+ \li \c fileBaseName
+ \li \c fileSuffix
+ \li \c fileSize
+ \li \c fileModified
+ \li \c fileAccessed
+ \li \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();
+}
+
+/*!
+ \qmlmethod int FolderListModel::indexOf(url file)
+ \since 5.6
+
+ Returns the index of the given \a file URL if the model contains it,
+ or -1 if not.
+*/
+int QQuickFolderListModel::indexOf(const QUrl &file) const
+{
+ Q_D(const QQuickFolderListModel);
+ FileProperty toFind(QFileInfo(file.toLocalFile()));
+ return d->data.indexOf(toFind);
+}
+
+#include "moc_qquickfolderlistmodel.cpp"
+
+//![code]
+QT_END_NAMESPACE
diff --git a/src/labs/folderlistmodel/qquickfolderlistmodel.h b/src/labs/folderlistmodel/qquickfolderlistmodel.h
new file mode 100644
index 0000000000..ba55ad2b92
--- /dev/null
+++ b/src/labs/folderlistmodel/qquickfolderlistmodel.h
@@ -0,0 +1,191 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKFOLDERLISTMODEL_H
+#define QQUICKFOLDERLISTMODEL_H
+
+#include "qquickfolderlistmodelglobal_p.h"
+
+#include <qqml.h>
+#include <QStringList>
+#include <QUrl>
+#include <QAbstractListModel>
+
+QT_BEGIN_NAMESPACE
+
+
+class QQmlContext;
+class QModelIndex;
+
+class QQuickFolderListModelPrivate;
+
+//![class begin]
+class Q_LABSFOLDERMODEL_PRIVATE_EXPORT QQuickFolderListModel : public QAbstractListModel, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+//![class begin]
+
+//![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 showFiles READ showFiles WRITE setShowFiles REVISION(2, 1))
+ 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 showHidden READ showHidden WRITE setShowHidden REVISION(2, 1))
+ Q_PROPERTY(bool showOnlyReadable READ showOnlyReadable WRITE setShowOnlyReadable)
+ Q_PROPERTY(bool caseSensitive READ caseSensitive WRITE setCaseSensitive REVISION(2, 2))
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged REVISION(2, 11))
+ Q_PROPERTY(bool sortCaseSensitive READ sortCaseSensitive WRITE setSortCaseSensitive REVISION(2, 12))
+//![class props]
+
+ QML_NAMED_ELEMENT(FolderListModel)
+ QML_ADDED_IN_VERSION(2, 0)
+//![abslistmodel]
+public:
+ QQuickFolderListModel(QObject *parent = nullptr);
+ ~QQuickFolderListModel();
+
+ 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,
+ FileUrlRole = Qt::UserRole + 9,
+ FileURLRole = Qt::UserRole + 10
+ };
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ QHash<int, QByteArray> roleNames() const override;
+//![abslistmodel]
+
+//![count]
+ int count() const { return rowCount(QModelIndex()); }
+//![count]
+
+//![prop funcs]
+ QUrl folder() const;
+ void setFolder(const QUrl &folder);
+ QUrl rootFolder() const;
+ void setRootFolder(const QUrl &path);
+
+ QUrl parentFolder() const;
+
+ QStringList nameFilters() const;
+ void setNameFilters(const QStringList &filters);
+
+ enum SortField { Unsorted, Name, Time, Size, Type };
+ Q_ENUM(SortField)
+ SortField sortField() const;
+ void setSortField(SortField field);
+
+ bool sortReversed() const;
+ void setSortReversed(bool rev);
+
+ bool showFiles() const;
+ void setShowFiles(bool showFiles);
+ bool showDirs() const;
+ void setShowDirs(bool showDirs);
+ bool showDirsFirst() const;
+ void setShowDirsFirst(bool showDirsFirst);
+ bool showDotAndDotDot() const;
+ void setShowDotAndDotDot(bool on);
+ bool showHidden() const;
+ void setShowHidden(bool on);
+ bool showOnlyReadable() const;
+ void setShowOnlyReadable(bool on);
+ bool caseSensitive() const;
+ void setCaseSensitive(bool on);
+
+ enum Status { Null, Ready, Loading };
+ Q_ENUM(Status)
+ Status status() const;
+ bool sortCaseSensitive() const;
+ void setSortCaseSensitive(bool on);
+//![prop funcs]
+
+ Q_INVOKABLE bool isFolder(int index) const;
+ Q_INVOKABLE QVariant get(int idx, const QString &property) const;
+ Q_INVOKABLE int indexOf(const QUrl &file) const;
+
+//![parserstatus]
+ void classBegin() override;
+ void componentComplete() override;
+//![parserstatus]
+
+ int roleFromString(const QString &roleName) const;
+
+//![notifier]
+Q_SIGNALS:
+ void folderChanged();
+ void rowCountChanged() const;
+ Q_REVISION(2, 1) void countChanged() const;
+ Q_REVISION(2, 11) void statusChanged();
+//![notifier]
+
+//![class end]
+
+
+private:
+ Q_DISABLE_COPY(QQuickFolderListModel)
+ Q_DECLARE_PRIVATE(QQuickFolderListModel)
+ QScopedPointer<QQuickFolderListModelPrivate> 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))
+ Q_PRIVATE_SLOT(d_func(), void _q_statusChanged(QQuickFolderListModel::Status s))
+};
+//![class end]
+
+QT_END_NAMESPACE
+
+#endif // QQUICKFOLDERLISTMODEL_H
diff --git a/src/labs/folderlistmodel/qquickfolderlistmodelglobal_p.h b/src/labs/folderlistmodel/qquickfolderlistmodelglobal_p.h
new file mode 100644
index 0000000000..c8df4e9ff7
--- /dev/null
+++ b/src/labs/folderlistmodel/qquickfolderlistmodelglobal_p.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTLABSFOLDERLISTMODELGLOBAL_P_H
+#define QTLABSFOLDERLISTMODELGLOBAL_P_H
+
+#include <QtCore/qglobal.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+#if !defined(QT_STATIC)
+# if defined(QT_BUILD_LABSFOLDERMODEL_LIB)
+# define Q_LABSFOLDERMODEL_EXPORT Q_DECL_EXPORT
+# else
+# define Q_LABSFOLDERMODEL_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define Q_LABSFOLDERMODEL_EXPORT
+#endif
+#define Q_LABSFOLDERMODEL_PRIVATE_EXPORT Q_LABSFOLDERMODEL_EXPORT
+
+QT_END_NAMESPACE
+
+void Q_LABSFOLDERMODEL_PRIVATE_EXPORT qml_register_types_Qt_labs_folderlistmodel();
+
+#endif // QTLABSFOLDERLISTMODELGLOBAL_P_H