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