summaryrefslogtreecommitdiff
path: root/plugin/src/Caelestia/filesystemmodel.hpp
blob: 978497e895868716a37ad54494dc1d1d43eab4f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#pragma once

#include <QAbstractListModel>
#include <QDir>
#include <QFileInfo>
#include <QFileSystemWatcher>
#include <QFuture>
#include <QImageReader>
#include <QObject>
#include <qqmlintegration.h>

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)
    Q_PROPERTY(bool isDir READ isDir CONSTANT)
    Q_PROPERTY(bool isImage READ isImage 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(); };
    bool isDir() const { return m_fileInfo.isDir(); };

    bool isImage() {
        if (!m_isImageInitialised) {
            QImageReader reader(m_path);
            m_isImage = reader.canRead();
            m_isImageInitialised = true;
        }
        return m_isImage;
    }

private:
    const QFileInfo m_fileInfo;

    const QString m_path;
    const QString m_relativePath;

    bool m_isImage;
    bool m_isImageInitialised;
};

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*> entries READ entries NOTIFY entriesChanged)

public:
    enum Filter {
        NoFilter,
        Images,
        Files
    };
    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::updateEntriesForDir);
    }

    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*> entries() const;

signals:
    void pathChanged();
    void recursiveChanged();
    void filterChanged();
    void entriesChanged();

    void added(const FileSystemEntry* entry);
    void removed(const QString& path);

private:
    QDir m_dir;
    QFileSystemWatcher m_watcher;
    QList<FileSystemEntry*> m_entries;
    QHash<QString, QFuture<QPair<QSet<QString>, QSet<QString>>>> m_futures;

    QString m_path;
    bool m_recursive;
    Filter m_filter;

    void watchDirIfRecursive(const QString& path);
    void update();
    void updateWatcher();
    void updateEntries();
    void updateEntriesForDir(const QString& dir);
};