git repos / SagoImageBrowser

blame: src/imagemodel.cpp

normal view · raw

032aa1e1 Poul Sander 2026-02-19 18:55 1
#include "imagemodel.h"
cec3b5da Poul Sander 2026-02-19 19:17 2
#include "thumbnailworker.h"
032aa1e1 Poul Sander 2026-02-19 18:55 3
80a9926d Poul Sander 2026-05-19 20:28 4
#include <QFile>
032aa1e1 Poul Sander 2026-02-19 18:55 5
#include <QImageReader>
09130ab9 Poul Sander 2026-02-22 22:19 6
#include <QFileIconProvider>
032aa1e1 Poul Sander 2026-02-19 18:55 7
80a9926d Poul Sander 2026-05-19 20:28 8
#include <algorithm>
80a9926d Poul Sander 2026-05-19 20:28 9
#include <filesystem>
80a9926d Poul Sander 2026-05-19 20:28 10
#include <vector>
80a9926d Poul Sander 2026-05-19 20:28 11
032aa1e1 Poul Sander 2026-02-19 18:55 12
ImageModel::ImageModel(QObject *parent)
032aa1e1 Poul Sander 2026-02-19 18:55 13
    : QAbstractListModel(parent)
032aa1e1 Poul Sander 2026-02-19 18:55 14
{
459bad0f Poul Sander 2026-05-17 14:11 15
    // Limit 1 thread for thumbnail loading to avoid excessive disk I/O on harddrives. SSDs are so fast the extra threads don't help much anyway.
459bad0f Poul Sander 2026-05-17 14:11 16
    m_threadPool.setMaxThreadCount(1);  //QThread::idealThreadCount()
cec3b5da Poul Sander 2026-02-19 19:17 17
cec3b5da Poul Sander 2026-02-19 19:17 18
    m_placeholder = QPixmap(128, 128);
cec3b5da Poul Sander 2026-02-19 19:17 19
    m_placeholder.fill(Qt::lightGray);
09130ab9 Poul Sander 2026-02-22 22:19 20
09130ab9 Poul Sander 2026-02-22 22:19 21
    QFileIconProvider iconProvider;
09130ab9 Poul Sander 2026-02-22 22:19 22
    m_folderIcon = iconProvider.icon(QFileIconProvider::Folder);
cec3b5da Poul Sander 2026-02-19 19:17 23
}
cec3b5da Poul Sander 2026-02-19 19:17 24
cec3b5da Poul Sander 2026-02-19 19:17 25
ImageModel::~ImageModel()
cec3b5da Poul Sander 2026-02-19 19:17 26
{
6fcd6c90 Poul Sander 2026-02-19 21:12 27
    m_cancelFlag = true;
cec3b5da Poul Sander 2026-02-19 19:17 28
    m_threadPool.waitForDone();
032aa1e1 Poul Sander 2026-02-19 18:55 29
}
032aa1e1 Poul Sander 2026-02-19 18:55 30
459bad0f Poul Sander 2026-05-17 14:11 31
void ImageModel::setCacheMaxSize(int n)
459bad0f Poul Sander 2026-05-17 14:11 32
{
459bad0f Poul Sander 2026-05-17 14:11 33
    m_cacheMaxSize = std::max(0, n);
459bad0f Poul Sander 2026-05-17 14:11 34
    while (m_cacheOrder.size() > m_cacheMaxSize)
459bad0f Poul Sander 2026-05-17 14:11 35
        m_folderThumbnailCache.remove(m_cacheOrder.takeFirst());
459bad0f Poul Sander 2026-05-17 14:11 36
}
459bad0f Poul Sander 2026-05-17 14:11 37
ac476ca8 Poul Sander 2026-05-18 16:47 38
void ImageModel::setThumbnailSize(ThumbnailCache::Size size)
ac476ca8 Poul Sander 2026-05-18 16:47 39
{
ac476ca8 Poul Sander 2026-05-18 16:47 40
    if (size == m_thumbnailSize)
ac476ca8 Poul Sander 2026-05-18 16:47 41
        return;
ac476ca8 Poul Sander 2026-05-18 16:47 42
ac476ca8 Poul Sander 2026-05-18 16:47 43
    m_thumbnailSize = size;
ac476ca8 Poul Sander 2026-05-18 16:47 44
ac476ca8 Poul Sander 2026-05-18 16:47 45
    // Cancel any in-flight workers (they were started with the previous size).
ac476ca8 Poul Sander 2026-05-18 16:47 46
    m_cancelFlag = true;
ac476ca8 Poul Sander 2026-05-18 16:47 47
    m_threadPool.waitForDone();
ac476ca8 Poul Sander 2026-05-18 16:47 48
    m_cancelFlag = false;
ac476ca8 Poul Sander 2026-05-18 16:47 49
ac476ca8 Poul Sander 2026-05-18 16:47 50
    m_pendingRows.clear();
ac476ca8 Poul Sander 2026-05-18 16:47 51
ac476ca8 Poul Sander 2026-05-18 16:47 52
    // The folder cache is keyed by directory and size-agnostic; drop it so the
ac476ca8 Poul Sander 2026-05-18 16:47 53
    // user actually sees the new size.
ac476ca8 Poul Sander 2026-05-18 16:47 54
    m_folderThumbnailCache.clear();
ac476ca8 Poul Sander 2026-05-18 16:47 55
    m_cacheOrder.clear();
ac476ca8 Poul Sander 2026-05-18 16:47 56
ac476ca8 Poul Sander 2026-05-18 16:47 57
    // Mark existing image entries unloaded so they get re-fetched at the new size.
ac476ca8 Poul Sander 2026-05-18 16:47 58
    if (!m_items.isEmpty())
ac476ca8 Poul Sander 2026-05-18 16:47 59
    {
ac476ca8 Poul Sander 2026-05-18 16:47 60
        for (int row = 0; row < m_items.size(); ++row)
ac476ca8 Poul Sander 2026-05-18 16:47 61
        {
ac476ca8 Poul Sander 2026-05-18 16:47 62
            Item &item = m_items[row];
ac476ca8 Poul Sander 2026-05-18 16:47 63
            if (item.isFolder)
ac476ca8 Poul Sander 2026-05-18 16:47 64
                continue;
ac476ca8 Poul Sander 2026-05-18 16:47 65
            item.thumbnail = m_placeholder;
ac476ca8 Poul Sander 2026-05-18 16:47 66
            item.loaded = false;
ac476ca8 Poul Sander 2026-05-18 16:47 67
        }
ac476ca8 Poul Sander 2026-05-18 16:47 68
        emit dataChanged(index(0), index(m_items.size() - 1),
ac476ca8 Poul Sander 2026-05-18 16:47 69
                         {Qt::DecorationRole});
ac476ca8 Poul Sander 2026-05-18 16:47 70
    }
ac476ca8 Poul Sander 2026-05-18 16:47 71
}
ac476ca8 Poul Sander 2026-05-18 16:47 72
032aa1e1 Poul Sander 2026-02-19 18:55 73
void ImageModel::setDirectory(const QString &path)
032aa1e1 Poul Sander 2026-02-19 18:55 74
{
80a9926d Poul Sander 2026-05-19 20:28 75
    setDirectory(QFile::encodeName(path));
80a9926d Poul Sander 2026-05-19 20:28 76
}
80a9926d Poul Sander 2026-05-19 20:28 77
80a9926d Poul Sander 2026-05-19 20:28 78
void ImageModel::setDirectory(const QByteArray &path)
80a9926d Poul Sander 2026-05-19 20:28 79
{
6fcd6c90 Poul Sander 2026-02-19 21:12 80
    m_cancelFlag = true;
6fcd6c90 Poul Sander 2026-02-19 21:12 81
    m_threadPool.waitForDone();
6fcd6c90 Poul Sander 2026-02-19 21:12 82
    m_cancelFlag = false;
6fcd6c90 Poul Sander 2026-02-19 21:12 83
459bad0f Poul Sander 2026-05-17 14:11 84
    // Save current folder's thumbnails to cache before discarding them
459bad0f Poul Sander 2026-05-17 14:11 85
    if (!m_currentDir.isEmpty()) {
459bad0f Poul Sander 2026-05-17 14:11 86
        ThumbnailMap map;
459bad0f Poul Sander 2026-05-17 14:11 87
        for (const Item &item : m_items)
459bad0f Poul Sander 2026-05-17 14:11 88
            if (item.loaded && !item.isFolder)
459bad0f Poul Sander 2026-05-17 14:11 89
                map[item.path] = item.thumbnail;
459bad0f Poul Sander 2026-05-17 14:11 90
        if (!map.isEmpty()) {
459bad0f Poul Sander 2026-05-17 14:11 91
            if (!m_cacheOrder.contains(m_currentDir)) {
459bad0f Poul Sander 2026-05-17 14:11 92
                m_cacheOrder.append(m_currentDir);
459bad0f Poul Sander 2026-05-17 14:11 93
                if (m_cacheOrder.size() > m_cacheMaxSize)
459bad0f Poul Sander 2026-05-17 14:11 94
                    m_folderThumbnailCache.remove(m_cacheOrder.takeFirst());
459bad0f Poul Sander 2026-05-17 14:11 95
            }
459bad0f Poul Sander 2026-05-17 14:11 96
            m_folderThumbnailCache[m_currentDir] = std::move(map);
459bad0f Poul Sander 2026-05-17 14:11 97
        }
459bad0f Poul Sander 2026-05-17 14:11 98
    }
459bad0f Poul Sander 2026-05-17 14:11 99
032aa1e1 Poul Sander 2026-02-19 18:55 100
    beginResetModel();
032aa1e1 Poul Sander 2026-02-19 18:55 101
    m_items.clear();
6fcd6c90 Poul Sander 2026-02-19 21:12 102
    m_pendingRows.clear();
09130ab9 Poul Sander 2026-02-22 22:19 103
    m_currentDir = path;
032aa1e1 Poul Sander 2026-02-19 18:55 104
80a9926d Poul Sander 2026-05-19 20:28 105
    // Build set of supported image extensions (lower-case, without dot)
80a9926d Poul Sander 2026-05-19 20:28 106
    QSet<QByteArray> imageExts;
80a9926d Poul Sander 2026-05-19 20:28 107
    for (const QByteArray &fmt : QImageReader::supportedImageFormats())
80a9926d Poul Sander 2026-05-19 20:28 108
        imageExts.insert(fmt.toLower());
80a9926d Poul Sander 2026-05-19 20:28 109
80a9926d Poul Sander 2026-05-19 20:28 110
    // Use std::filesystem::directory_iterator so that directory entries with
80a9926d Poul Sander 2026-05-19 20:28 111
    // non-UTF-8 filenames (e.g. Latin-1 encoded names) are not silently
80a9926d Poul Sander 2026-05-19 20:28 112
    // skipped or mangled as they would be with QDir::entryInfoList().
80a9926d Poul Sander 2026-05-19 20:28 113
    namespace fs = std::filesystem;
80a9926d Poul Sander 2026-05-19 20:28 114
80a9926d Poul Sander 2026-05-19 20:28 115
    std::vector<std::string> dirs;
80a9926d Poul Sander 2026-05-19 20:28 116
    std::vector<std::string> imageFiles;
80a9926d Poul Sander 2026-05-19 20:28 117
80a9926d Poul Sander 2026-05-19 20:28 118
    try {
80a9926d Poul Sander 2026-05-19 20:28 119
        fs::path dirPath(path.toStdString());
80a9926d Poul Sander 2026-05-19 20:28 120
80a9926d Poul Sander 2026-05-19 20:28 121
        // Add ".." parent entry directly with the literal display name ".."
80a9926d Poul Sander 2026-05-19 20:28 122
        // (mirrors QDir::NoDot behaviour)
80a9926d Poul Sander 2026-05-19 20:28 123
        fs::path parentPath = dirPath.parent_path();
80a9926d Poul Sander 2026-05-19 20:28 124
        if (!parentPath.empty() && parentPath != dirPath) {
80a9926d Poul Sander 2026-05-19 20:28 125
            QPixmap folderPixmap = m_folderIcon.pixmap(128, 128);
80a9926d Poul Sander 2026-05-19 20:28 126
            m_items.append({QByteArray::fromStdString(parentPath.native()),
80a9926d Poul Sander 2026-05-19 20:28 127
                            QStringLiteral(".."), folderPixmap, true, true});
80a9926d Poul Sander 2026-05-19 20:28 128
        }
09130ab9 Poul Sander 2026-02-22 22:19 129
80a9926d Poul Sander 2026-05-19 20:28 130
        for (const fs::directory_entry &entry :
80a9926d Poul Sander 2026-05-19 20:28 131
             fs::directory_iterator(dirPath,
80a9926d Poul Sander 2026-05-19 20:28 132
                 fs::directory_options::skip_permission_denied))
80a9926d Poul Sander 2026-05-19 20:28 133
        {
80a9926d Poul Sander 2026-05-19 20:28 134
            std::error_code ec;
80a9926d Poul Sander 2026-05-19 20:28 135
            const std::string fname = entry.path().filename().native();
80a9926d Poul Sander 2026-05-19 20:28 136
            if (fname.empty() || fname[0] == '.')
80a9926d Poul Sander 2026-05-19 20:28 137
                continue;   // skip hidden entries
80a9926d Poul Sander 2026-05-19 20:28 138
80a9926d Poul Sander 2026-05-19 20:28 139
            if (entry.is_directory(ec)) {
80a9926d Poul Sander 2026-05-19 20:28 140
                dirs.push_back(entry.path().native());
80a9926d Poul Sander 2026-05-19 20:28 141
            } else if (entry.is_regular_file(ec)) {
80a9926d Poul Sander 2026-05-19 20:28 142
                // Filter by image extension
80a9926d Poul Sander 2026-05-19 20:28 143
                const std::string &nativeExt = entry.path().extension().native();
80a9926d Poul Sander 2026-05-19 20:28 144
                if (nativeExt.empty())
80a9926d Poul Sander 2026-05-19 20:28 145
                    continue;
80a9926d Poul Sander 2026-05-19 20:28 146
                // extension() includes the dot; strip it and lower-case
80a9926d Poul Sander 2026-05-19 20:28 147
                QByteArray ext = QByteArray(nativeExt.c_str() + 1,
80a9926d Poul Sander 2026-05-19 20:28 148
                                           static_cast<qsizetype>(nativeExt.size()) - 1).toLower();
80a9926d Poul Sander 2026-05-19 20:28 149
                if (imageExts.contains(ext))
80a9926d Poul Sander 2026-05-19 20:28 150
                    imageFiles.push_back(entry.path().native());
80a9926d Poul Sander 2026-05-19 20:28 151
            }
80a9926d Poul Sander 2026-05-19 20:28 152
        }
80a9926d Poul Sander 2026-05-19 20:28 153
    } catch (const fs::filesystem_error &) {
80a9926d Poul Sander 2026-05-19 20:28 154
        // Directory unreadable — show empty listing
09130ab9 Poul Sander 2026-02-22 22:19 155
    }
09130ab9 Poul Sander 2026-02-22 22:19 156
80a9926d Poul Sander 2026-05-19 20:28 157
    // Sort subdirectories by filename
80a9926d Poul Sander 2026-05-19 20:28 158
    std::sort(dirs.begin(), dirs.end(),
80a9926d Poul Sander 2026-05-19 20:28 159
              [](const auto &a, const auto &b) {
80a9926d Poul Sander 2026-05-19 20:28 160
                  return fs::path(a).filename() < fs::path(b).filename();
80a9926d Poul Sander 2026-05-19 20:28 161
              });
032aa1e1 Poul Sander 2026-02-19 18:55 162
80a9926d Poul Sander 2026-05-19 20:28 163
    std::sort(imageFiles.begin(), imageFiles.end(),
80a9926d Poul Sander 2026-05-19 20:28 164
              [](const auto &a, const auto &b) {
80a9926d Poul Sander 2026-05-19 20:28 165
                  return fs::path(a).filename() < fs::path(b).filename();
80a9926d Poul Sander 2026-05-19 20:28 166
              });
032aa1e1 Poul Sander 2026-02-19 18:55 167
80a9926d Poul Sander 2026-05-19 20:28 168
    QPixmap folderPixmap = m_folderIcon.pixmap(128, 128);
80a9926d Poul Sander 2026-05-19 20:28 169
    for (const std::string &nativePath : dirs)
80a9926d Poul Sander 2026-05-19 20:28 170
    {
80a9926d Poul Sander 2026-05-19 20:28 171
        QByteArray entryPath = QByteArray::fromStdString(nativePath);
80a9926d Poul Sander 2026-05-19 20:28 172
        std::string fname = fs::path(nativePath).filename().native();
80a9926d Poul Sander 2026-05-19 20:28 173
        QString displayName = QString::fromLocal8Bit(fname.c_str(),
80a9926d Poul Sander 2026-05-19 20:28 174
                                                     static_cast<qsizetype>(fname.size()));
80a9926d Poul Sander 2026-05-19 20:28 175
        m_items.append({entryPath, displayName, folderPixmap, true, true});
80a9926d Poul Sander 2026-05-19 20:28 176
    }
cec3b5da Poul Sander 2026-02-19 19:17 177
459bad0f Poul Sander 2026-05-17 14:11 178
    // Restore cached thumbnails for this folder if available
459bad0f Poul Sander 2026-05-17 14:11 179
    const ThumbnailMap *cached = m_folderThumbnailCache.contains(path)
459bad0f Poul Sander 2026-05-17 14:11 180
        ? &m_folderThumbnailCache[path]
459bad0f Poul Sander 2026-05-17 14:11 181
        : nullptr;
459bad0f Poul Sander 2026-05-17 14:11 182
80a9926d Poul Sander 2026-05-19 20:28 183
    for (const std::string &nativePath : imageFiles)
032aa1e1 Poul Sander 2026-02-19 18:55 184
    {
80a9926d Poul Sander 2026-05-19 20:28 185
        QByteArray entryPath = QByteArray::fromStdString(nativePath);
80a9926d Poul Sander 2026-05-19 20:28 186
        std::string fname = fs::path(nativePath).filename().native();
80a9926d Poul Sander 2026-05-19 20:28 187
        QString displayName = QString::fromLocal8Bit(fname.c_str(),
80a9926d Poul Sander 2026-05-19 20:28 188
                                                     static_cast<qsizetype>(fname.size()));
80a9926d Poul Sander 2026-05-19 20:28 189
459bad0f Poul Sander 2026-05-17 14:11 190
        QPixmap thumb = m_placeholder;
459bad0f Poul Sander 2026-05-17 14:11 191
        bool loaded = false;
459bad0f Poul Sander 2026-05-17 14:11 192
        if (cached) {
80a9926d Poul Sander 2026-05-19 20:28 193
            auto it = cached->find(entryPath);
459bad0f Poul Sander 2026-05-17 14:11 194
            if (it != cached->end()) {
459bad0f Poul Sander 2026-05-17 14:11 195
                thumb = it.value();
459bad0f Poul Sander 2026-05-17 14:11 196
                loaded = true;
459bad0f Poul Sander 2026-05-17 14:11 197
            }
459bad0f Poul Sander 2026-05-17 14:11 198
        }
80a9926d Poul Sander 2026-05-19 20:28 199
        m_items.append({entryPath, displayName, thumb, loaded, false});
6fcd6c90 Poul Sander 2026-02-19 21:12 200
    }
cec3b5da Poul Sander 2026-02-19 19:17 201
6fcd6c90 Poul Sander 2026-02-19 21:12 202
    endResetModel();
6fcd6c90 Poul Sander 2026-02-19 21:12 203
}
032aa1e1 Poul Sander 2026-02-19 18:55 204
6fcd6c90 Poul Sander 2026-02-19 21:12 205
void ImageModel::requestThumbnails(int firstRow, int lastRow)
6fcd6c90 Poul Sander 2026-02-19 21:12 206
{
6fcd6c90 Poul Sander 2026-02-19 21:12 207
    if (m_items.isEmpty())
6fcd6c90 Poul Sander 2026-02-19 21:12 208
        return;
032aa1e1 Poul Sander 2026-02-19 18:55 209
6fcd6c90 Poul Sander 2026-02-19 21:12 210
    firstRow = std::max(0, firstRow);
6fcd6c90 Poul Sander 2026-02-19 21:12 211
    lastRow = std::min(lastRow, static_cast<int>(m_items.size()) - 1);
cec3b5da Poul Sander 2026-02-19 19:17 212
6fcd6c90 Poul Sander 2026-02-19 21:12 213
    for (int row = firstRow; row <= lastRow; ++row)
6fcd6c90 Poul Sander 2026-02-19 21:12 214
    {
09130ab9 Poul Sander 2026-02-22 22:19 215
        if (!m_items[row].loaded && !m_items[row].isFolder)
6fcd6c90 Poul Sander 2026-02-19 21:12 216
            queueRow(row);
032aa1e1 Poul Sander 2026-02-19 18:55 217
    }
032aa1e1 Poul Sander 2026-02-19 18:55 218
6fcd6c90 Poul Sander 2026-02-19 21:12 219
    // Optional: preload nearby rows
6fcd6c90 Poul Sander 2026-02-19 21:12 220
    int buffer = 20;
6fcd6c90 Poul Sander 2026-02-19 21:12 221
    for (int row = firstRow - buffer; row < firstRow; ++row)
09130ab9 Poul Sander 2026-02-22 22:19 222
        if (row >= 0 && !m_items[row].loaded && !m_items[row].isFolder)
6fcd6c90 Poul Sander 2026-02-19 21:12 223
            queueRow(row);
6fcd6c90 Poul Sander 2026-02-19 21:12 224
6fcd6c90 Poul Sander 2026-02-19 21:12 225
    for (int row = lastRow + 1; row <= lastRow + buffer; ++row)
09130ab9 Poul Sander 2026-02-22 22:19 226
        if (row < m_items.size() && !m_items[row].loaded && !m_items[row].isFolder)
6fcd6c90 Poul Sander 2026-02-19 21:12 227
            queueRow(row);
6fcd6c90 Poul Sander 2026-02-19 21:12 228
}
6fcd6c90 Poul Sander 2026-02-19 21:12 229
6fcd6c90 Poul Sander 2026-02-19 21:12 230
void ImageModel::queueRow(int row)
6fcd6c90 Poul Sander 2026-02-19 21:12 231
{
6fcd6c90 Poul Sander 2026-02-19 21:12 232
    if (m_pendingRows.contains(row))
6fcd6c90 Poul Sander 2026-02-19 21:12 233
        return;
6fcd6c90 Poul Sander 2026-02-19 21:12 234
6fcd6c90 Poul Sander 2026-02-19 21:12 235
    m_pendingRows.insert(row);
6fcd6c90 Poul Sander 2026-02-19 21:12 236
6fcd6c90 Poul Sander 2026-02-19 21:12 237
    auto *worker = new ThumbnailWorker(
6fcd6c90 Poul Sander 2026-02-19 21:12 238
        m_items[row].path,
6fcd6c90 Poul Sander 2026-02-19 21:12 239
        row,
ac476ca8 Poul Sander 2026-05-18 16:47 240
        m_thumbnailSize,
6fcd6c90 Poul Sander 2026-02-19 21:12 241
        &m_cancelFlag);
6fcd6c90 Poul Sander 2026-02-19 21:12 242
6fcd6c90 Poul Sander 2026-02-19 21:12 243
    connect(worker, &ThumbnailWorker::finished,
6fcd6c90 Poul Sander 2026-02-19 21:12 244
            this, &ImageModel::thumbnailReady,
6fcd6c90 Poul Sander 2026-02-19 21:12 245
            Qt::QueuedConnection);
6fcd6c90 Poul Sander 2026-02-19 21:12 246
6fcd6c90 Poul Sander 2026-02-19 21:12 247
    m_threadPool.start(worker);
032aa1e1 Poul Sander 2026-02-19 18:55 248
}
032aa1e1 Poul Sander 2026-02-19 18:55 249
80a9926d Poul Sander 2026-05-19 20:28 250
QByteArray ImageModel::filePath(const QModelIndex &index) const
032aa1e1 Poul Sander 2026-02-19 18:55 251
{
032aa1e1 Poul Sander 2026-02-19 18:55 252
    if (!index.isValid())
032aa1e1 Poul Sander 2026-02-19 18:55 253
        return {};
032aa1e1 Poul Sander 2026-02-19 18:55 254
032aa1e1 Poul Sander 2026-02-19 18:55 255
    return m_items[index.row()].path;
032aa1e1 Poul Sander 2026-02-19 18:55 256
}
032aa1e1 Poul Sander 2026-02-19 18:55 257
09130ab9 Poul Sander 2026-02-22 22:19 258
bool ImageModel::isFolder(const QModelIndex &index) const
09130ab9 Poul Sander 2026-02-22 22:19 259
{
09130ab9 Poul Sander 2026-02-22 22:19 260
    if (!index.isValid() || index.row() >= m_items.size())
09130ab9 Poul Sander 2026-02-22 22:19 261
        return false;
09130ab9 Poul Sander 2026-02-22 22:19 262
    return m_items[index.row()].isFolder;
09130ab9 Poul Sander 2026-02-22 22:19 263
}
09130ab9 Poul Sander 2026-02-22 22:19 264
80a9926d Poul Sander 2026-05-19 20:28 265
QByteArray ImageModel::currentDirectory() const
09130ab9 Poul Sander 2026-02-22 22:19 266
{
09130ab9 Poul Sander 2026-02-22 22:19 267
    return m_currentDir;
09130ab9 Poul Sander 2026-02-22 22:19 268
}
09130ab9 Poul Sander 2026-02-22 22:19 269
032aa1e1 Poul Sander 2026-02-19 18:55 270
int ImageModel::rowCount(const QModelIndex &) const
032aa1e1 Poul Sander 2026-02-19 18:55 271
{
032aa1e1 Poul Sander 2026-02-19 18:55 272
    return m_items.size();
032aa1e1 Poul Sander 2026-02-19 18:55 273
}
032aa1e1 Poul Sander 2026-02-19 18:55 274
032aa1e1 Poul Sander 2026-02-19 18:55 275
QVariant ImageModel::data(const QModelIndex &index, int role) const
032aa1e1 Poul Sander 2026-02-19 18:55 276
{
032aa1e1 Poul Sander 2026-02-19 18:55 277
    if (!index.isValid())
032aa1e1 Poul Sander 2026-02-19 18:55 278
        return {};
032aa1e1 Poul Sander 2026-02-19 18:55 279
032aa1e1 Poul Sander 2026-02-19 18:55 280
    const Item &item = m_items[index.row()];
032aa1e1 Poul Sander 2026-02-19 18:55 281
032aa1e1 Poul Sander 2026-02-19 18:55 282
    if (role == Qt::DecorationRole)
032aa1e1 Poul Sander 2026-02-19 18:55 283
        return item.thumbnail;
032aa1e1 Poul Sander 2026-02-19 18:55 284
032aa1e1 Poul Sander 2026-02-19 18:55 285
    if (role == Qt::DisplayRole)
09130ab9 Poul Sander 2026-02-22 22:19 286
        return item.displayName;
032aa1e1 Poul Sander 2026-02-19 18:55 287
032aa1e1 Poul Sander 2026-02-19 18:55 288
    return {};
032aa1e1 Poul Sander 2026-02-19 18:55 289
}
cec3b5da Poul Sander 2026-02-19 19:17 290
6fcd6c90 Poul Sander 2026-02-19 21:12 291
void ImageModel::thumbnailReady(int row, const QImage &image)
cec3b5da Poul Sander 2026-02-19 19:17 292
{
6fcd6c90 Poul Sander 2026-02-19 21:12 293
    if (m_cancelFlag)
6fcd6c90 Poul Sander 2026-02-19 21:12 294
        return;
6fcd6c90 Poul Sander 2026-02-19 21:12 295
cec3b5da Poul Sander 2026-02-19 19:17 296
    if (row < 0 || row >= m_items.size())
cec3b5da Poul Sander 2026-02-19 19:17 297
        return;
cec3b5da Poul Sander 2026-02-19 19:17 298
6fcd6c90 Poul Sander 2026-02-19 21:12 299
    m_items[row].thumbnail = QPixmap::fromImage(image);
cec3b5da Poul Sander 2026-02-19 19:17 300
    m_items[row].loaded = true;
6fcd6c90 Poul Sander 2026-02-19 21:12 301
    m_pendingRows.remove(row);
cec3b5da Poul Sander 2026-02-19 19:17 302
cec3b5da Poul Sander 2026-02-19 19:17 303
    QModelIndex idx = index(row);
cec3b5da Poul Sander 2026-02-19 19:17 304
    emit dataChanged(idx, idx, {Qt::DecorationRole});
cec3b5da Poul Sander 2026-02-19 19:17 305
}
1970-01-01 00:00 306