aboutsummaryrefslogtreecommitdiffstats
path: root/src/labs/folderlistmodel/fileinfothread.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/labs/folderlistmodel/fileinfothread.cpp')
-rw-r--r--src/labs/folderlistmodel/fileinfothread.cpp369
1 files changed, 369 insertions, 0 deletions
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;
+}