diff options
Diffstat (limited to 'plugin/src/Caelestia')
| -rw-r--r-- | plugin/src/Caelestia/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | plugin/src/Caelestia/filesystemmodel.cpp | 171 | ||||
| -rw-r--r-- | plugin/src/Caelestia/filesystemmodel.hpp | 104 |
3 files changed, 276 insertions, 0 deletions
diff --git a/plugin/src/Caelestia/CMakeLists.txt b/plugin/src/Caelestia/CMakeLists.txt index dfc7f78..a56074e 100644 --- a/plugin/src/Caelestia/CMakeLists.txt +++ b/plugin/src/Caelestia/CMakeLists.txt @@ -4,6 +4,7 @@ qt_add_qml_module(caelestia SOURCES cutils.hpp cutils.cpp cachingimagemanager.hpp cachingimagemanager.cpp + filesystemmodel.hpp filesystemmodel.cpp ) qt_query_qml_module(caelestia diff --git a/plugin/src/Caelestia/filesystemmodel.cpp b/plugin/src/Caelestia/filesystemmodel.cpp new file mode 100644 index 0000000..052b065 --- /dev/null +++ b/plugin/src/Caelestia/filesystemmodel.cpp @@ -0,0 +1,171 @@ +#include "filesystemmodel.hpp" + +#include <QObject> +#include <qqmlintegration.h> +#include <QAbstractListModel> +#include <QFileInfo> +#include <QDir> +#include <QDirIterator> +#include <QImageReader> + +int FileSystemModel::rowCount(const QModelIndex& parent) const { + Q_UNUSED(parent); + return m_files.size(); +} + +QVariant FileSystemModel::data(const QModelIndex& index, int role) const { + if (!index.isValid() || index.row() >= m_files.size()) { + return QVariant(); + } + + const FileSystemEntry* file = m_files.at(index.row()); + switch (role) { + case FilePathRole: + return file->path(); + case RelativeFilePathRole: + return file->relativePath(); + case FileNameRole: + return file->name(); + case ParentDirRole: + return file->parentDir(); + case FileSizeRole: + return file->size(); + default: + return QVariant(); + } +} + +QHash<int, QByteArray> FileSystemModel::roleNames() const { + QHash<int, QByteArray> roles; + roles[FilePathRole] = "filePath"; + roles[RelativeFilePathRole] = "relativeFilePath"; + roles[FileNameRole] = "fileName"; + roles[ParentDirRole] = "parentDir"; + roles[FileSizeRole] = "fileSize"; + return roles; +} + +QString FileSystemModel::path() const { + return m_path; +} + +void FileSystemModel::setPath(const QString& path) { + if (m_path == path) { + return; + } + + m_path = path; + emit pathChanged(); + + m_dir.setPath(m_path); + update(); +} + +bool FileSystemModel::recursive() const { + return m_recursive; +} + +void FileSystemModel::setRecursive(bool recursive) { + if (m_recursive == recursive) { + return; + } + + m_recursive = recursive; + emit recursiveChanged(); + + update(); +} + +FileSystemModel::Filter FileSystemModel::filter() const { + return m_filter; +} + +void FileSystemModel::setFilter(Filter filter) { + if (m_filter == filter) { + return; + } + + m_filter = filter; + emit filterChanged(); + + update(); +} + +QList<FileSystemEntry*> FileSystemModel::files() const { + return m_files; +} + +void FileSystemModel::watchDirIfRecursive(const QString& path) { + if (m_recursive) { + QDirIterator iter(path, QDir::Dirs | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); + while (iter.hasNext()) { + m_watcher.addPath(iter.next()); + } + } +} + +void FileSystemModel::update() { + updateWatcher(); + updateFiles(); +} + +void FileSystemModel::updateWatcher() { + if (!m_watcher.directories().isEmpty()) { + m_watcher.removePaths(m_watcher.directories()); + } + + if (m_path.isEmpty()) { + return; + } + + m_watcher.addPath(m_path); + watchDirIfRecursive(m_path); +} + +void FileSystemModel::updateFiles() { + if (m_path.isEmpty()) { + beginResetModel(); + qDeleteAll(m_files); + m_files.clear(); + emit filesChanged(); + endResetModel(); + + return; + } + + beginResetModel(); + qDeleteAll(m_files); + m_files.clear(); + + const auto flags = m_recursive ? QDirIterator::Subdirectories : QDirIterator::NoIteratorFlags; + + std::optional<QDirIterator> iter; + + if (m_filter == ImagesOnly) { + QStringList filters; + for (const auto& format : QImageReader::supportedImageFormats()) { + filters << "*." + format; + } + + iter.emplace(m_path, filters, QDir::Files, flags); + } else { + iter.emplace(m_path, QDir::Files, flags); + } + + while (iter.value().hasNext()) { + QString file = iter.value().next(); + + if (m_filter == ImagesOnly) { + QImageReader reader(file); + if (reader.canRead()) { + m_files << new FileSystemEntry(file, m_dir.relativeFilePath(file), this); + } + } else { + m_files << new FileSystemEntry(file, m_dir.relativeFilePath(file), this); + } + } + + emit filesChanged(); + + endResetModel(); +} diff --git a/plugin/src/Caelestia/filesystemmodel.hpp b/plugin/src/Caelestia/filesystemmodel.hpp new file mode 100644 index 0000000..8584e87 --- /dev/null +++ b/plugin/src/Caelestia/filesystemmodel.hpp @@ -0,0 +1,104 @@ +#pragma once + +#include <QObject> +#include <qqmlintegration.h> +#include <QAbstractListModel> +#include <QFileSystemWatcher> +#include <QFileInfo> +#include <QDir> + +class FileSystemEntry : public QObject { + Q_OBJECT + QML_ELEMENT; + QML_UNCREATABLE("FileSystemEntry instances can only be retrieved from a FileSystemModel"); + + Q_PROPERTY(QString path READ path CONSTANT); + Q_PROPERTY(QString relativePath READ relativePath CONSTANT); + Q_PROPERTY(QString name READ name CONSTANT); + Q_PROPERTY(QString parentDir READ parentDir CONSTANT); + Q_PROPERTY(qint64 size READ size CONSTANT); + +public: + explicit FileSystemEntry(const QString& path, const QString& relativePath, QObject* parent = nullptr) + : QObject(parent), m_fileInfo(QFileInfo(path)), m_path(path), m_relativePath(relativePath) {} + + QString path() const { return m_path; }; + QString relativePath() const { return m_relativePath; }; + + QString name() const { return m_fileInfo.fileName(); }; + QString parentDir() const { return m_fileInfo.absolutePath(); }; + qint64 size() const { return m_fileInfo.size(); }; + +private: + const QFileInfo m_fileInfo; + + const QString m_path; + const QString m_relativePath; +}; + +class FileSystemModel : public QAbstractListModel { + Q_OBJECT; + QML_ELEMENT; + + Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged); + Q_PROPERTY(bool recursive READ recursive WRITE setRecursive NOTIFY recursiveChanged); + Q_PROPERTY(Filter filter READ filter WRITE setFilter NOTIFY filterChanged); + + Q_PROPERTY(QList<FileSystemEntry*> files READ files NOTIFY filesChanged); + +public: + enum Roles { + FilePathRole = Qt::UserRole + 1, + RelativeFilePathRole, + FileNameRole, + ParentDirRole, + FileSizeRole + }; + + enum Filter { + NoFilter, + ImagesOnly + }; + Q_ENUM(Filter) + + explicit FileSystemModel(QObject* parent = nullptr) + : QAbstractListModel(parent), m_recursive(true), m_filter(NoFilter) { + connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, &FileSystemModel::watchDirIfRecursive); + connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, &FileSystemModel::updateFiles); + } + + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + QHash<int, QByteArray> roleNames() const override; + + QString path() const; + void setPath(const QString& path); + + bool recursive() const; + void setRecursive(bool recursive); + + Filter filter() const; + void setFilter(Filter filter); + + QList<FileSystemEntry*> files() const; + +signals: + void pathChanged(); + void recursiveChanged(); + void filterChanged(); + void filesChanged(); + +private: + QDir m_dir; + QFileSystemWatcher m_watcher; + QList<FileSystemEntry*> m_files; + + QString m_path; + bool m_recursive; + Filter m_filter; + + void watchDirIfRecursive(const QString& path); + void update(); + void updateWatcher(); + void updateFiles(); +}; |