diff options
author | Maximilian Goldstein <max.goldstein@qt.io> | 2021-01-20 17:23:23 +0100 |
---|---|---|
committer | Maximilian Goldstein <max.goldstein@qt.io> | 2021-01-21 10:35:52 +0100 |
commit | eb5bb9e7f547a7e222b5dbb848774639ab11f243 (patch) | |
tree | 7c4377e7b272025a4240e5707365a50b49898cc9 /src/labs | |
parent | 3fadfb2c3fa7d4b22d0d0269c645c1086fa56619 (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.txt | 3 | ||||
-rw-r--r-- | src/labs/folderlistmodel/CMakeLists.txt | 24 | ||||
-rw-r--r-- | src/labs/folderlistmodel/fileinfothread.cpp | 369 | ||||
-rw-r--r-- | src/labs/folderlistmodel/fileinfothread_p.h | 133 | ||||
-rw-r--r-- | src/labs/folderlistmodel/fileproperty_p.h | 103 | ||||
-rw-r--r-- | src/labs/folderlistmodel/qquickfolderlistmodel.cpp | 927 | ||||
-rw-r--r-- | src/labs/folderlistmodel/qquickfolderlistmodel.h | 191 | ||||
-rw-r--r-- | src/labs/folderlistmodel/qquickfolderlistmodelglobal_p.h | 73 |
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 |