git repos / SagoImageBrowser

blame: 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 <QDir>
032aa1e1 Poul Sander 2026-02-19 18:55 5
#include <QImageReader>
032aa1e1 Poul Sander 2026-02-19 18:55 6
#include <QFileInfo>
032aa1e1 Poul Sander 2026-02-19 18:55 7
032aa1e1 Poul Sander 2026-02-19 18:55 8
ImageModel::ImageModel(QObject *parent)
032aa1e1 Poul Sander 2026-02-19 18:55 9
    : QAbstractListModel(parent)
032aa1e1 Poul Sander 2026-02-19 18:55 10
{
cec3b5da Poul Sander 2026-02-19 19:17 11
    m_threadPool.setMaxThreadCount(QThread::idealThreadCount());
cec3b5da Poul Sander 2026-02-19 19:17 12
cec3b5da Poul Sander 2026-02-19 19:17 13
    m_placeholder = QPixmap(128, 128);
cec3b5da Poul Sander 2026-02-19 19:17 14
    m_placeholder.fill(Qt::lightGray);
cec3b5da Poul Sander 2026-02-19 19:17 15
}
cec3b5da Poul Sander 2026-02-19 19:17 16
cec3b5da Poul Sander 2026-02-19 19:17 17
ImageModel::~ImageModel()
cec3b5da Poul Sander 2026-02-19 19:17 18
{
6fcd6c90 Poul Sander 2026-02-19 21:12 19
    m_cancelFlag = true;
cec3b5da Poul Sander 2026-02-19 19:17 20
    m_threadPool.waitForDone();
032aa1e1 Poul Sander 2026-02-19 18:55 21
}
032aa1e1 Poul Sander 2026-02-19 18:55 22
032aa1e1 Poul Sander 2026-02-19 18:55 23
void ImageModel::setDirectory(const QString &path)
032aa1e1 Poul Sander 2026-02-19 18:55 24
{
6fcd6c90 Poul Sander 2026-02-19 21:12 25
    m_cancelFlag = true;
6fcd6c90 Poul Sander 2026-02-19 21:12 26
    m_threadPool.waitForDone();
6fcd6c90 Poul Sander 2026-02-19 21:12 27
    m_cancelFlag = false;
6fcd6c90 Poul Sander 2026-02-19 21:12 28
032aa1e1 Poul Sander 2026-02-19 18:55 29
    beginResetModel();
032aa1e1 Poul Sander 2026-02-19 18:55 30
    m_items.clear();
6fcd6c90 Poul Sander 2026-02-19 21:12 31
    m_pendingRows.clear();
032aa1e1 Poul Sander 2026-02-19 18:55 32
032aa1e1 Poul Sander 2026-02-19 18:55 33
    QDir dir(path);
032aa1e1 Poul Sander 2026-02-19 18:55 34
    QStringList filters;
032aa1e1 Poul Sander 2026-02-19 18:55 35
032aa1e1 Poul Sander 2026-02-19 18:55 36
    const auto formats = QImageReader::supportedImageFormats();
032aa1e1 Poul Sander 2026-02-19 18:55 37
    for (const QByteArray &fmt : formats)
032aa1e1 Poul Sander 2026-02-19 18:55 38
        filters << "*." + fmt;
032aa1e1 Poul Sander 2026-02-19 18:55 39
032aa1e1 Poul Sander 2026-02-19 18:55 40
    dir.setNameFilters(filters);
032aa1e1 Poul Sander 2026-02-19 18:55 41
    dir.setFilter(QDir::Files);
032aa1e1 Poul Sander 2026-02-19 18:55 42
cec3b5da Poul Sander 2026-02-19 19:17 43
    const auto files = dir.entryInfoList();
cec3b5da Poul Sander 2026-02-19 19:17 44
cec3b5da Poul Sander 2026-02-19 19:17 45
    for (const QFileInfo &file : files)
032aa1e1 Poul Sander 2026-02-19 18:55 46
    {
cec3b5da Poul Sander 2026-02-19 19:17 47
        m_items.append({file.absoluteFilePath(), m_placeholder, false});
6fcd6c90 Poul Sander 2026-02-19 21:12 48
    }
cec3b5da Poul Sander 2026-02-19 19:17 49
6fcd6c90 Poul Sander 2026-02-19 21:12 50
    endResetModel();
6fcd6c90 Poul Sander 2026-02-19 21:12 51
}
032aa1e1 Poul Sander 2026-02-19 18:55 52
6fcd6c90 Poul Sander 2026-02-19 21:12 53
void ImageModel::requestThumbnails(int firstRow, int lastRow)
6fcd6c90 Poul Sander 2026-02-19 21:12 54
{
6fcd6c90 Poul Sander 2026-02-19 21:12 55
    if (m_items.isEmpty())
6fcd6c90 Poul Sander 2026-02-19 21:12 56
        return;
032aa1e1 Poul Sander 2026-02-19 18:55 57
6fcd6c90 Poul Sander 2026-02-19 21:12 58
    firstRow = std::max(0, firstRow);
6fcd6c90 Poul Sander 2026-02-19 21:12 59
    lastRow = std::min(lastRow, static_cast<int>(m_items.size()) - 1);
cec3b5da Poul Sander 2026-02-19 19:17 60
6fcd6c90 Poul Sander 2026-02-19 21:12 61
    for (int row = firstRow; row <= lastRow; ++row)
6fcd6c90 Poul Sander 2026-02-19 21:12 62
    {
6fcd6c90 Poul Sander 2026-02-19 21:12 63
        if (!m_items[row].loaded)
6fcd6c90 Poul Sander 2026-02-19 21:12 64
            queueRow(row);
032aa1e1 Poul Sander 2026-02-19 18:55 65
    }
032aa1e1 Poul Sander 2026-02-19 18:55 66
6fcd6c90 Poul Sander 2026-02-19 21:12 67
    // Optional: preload nearby rows
6fcd6c90 Poul Sander 2026-02-19 21:12 68
    int buffer = 20;
6fcd6c90 Poul Sander 2026-02-19 21:12 69
    for (int row = firstRow - buffer; row < firstRow; ++row)
6fcd6c90 Poul Sander 2026-02-19 21:12 70
        if (row >= 0 && !m_items[row].loaded)
6fcd6c90 Poul Sander 2026-02-19 21:12 71
            queueRow(row);
6fcd6c90 Poul Sander 2026-02-19 21:12 72
6fcd6c90 Poul Sander 2026-02-19 21:12 73
    for (int row = lastRow + 1; row <= lastRow + buffer; ++row)
6fcd6c90 Poul Sander 2026-02-19 21:12 74
        if (row < m_items.size() && !m_items[row].loaded)
6fcd6c90 Poul Sander 2026-02-19 21:12 75
            queueRow(row);
6fcd6c90 Poul Sander 2026-02-19 21:12 76
}
6fcd6c90 Poul Sander 2026-02-19 21:12 77
6fcd6c90 Poul Sander 2026-02-19 21:12 78
void ImageModel::queueRow(int row)
6fcd6c90 Poul Sander 2026-02-19 21:12 79
{
6fcd6c90 Poul Sander 2026-02-19 21:12 80
    if (m_pendingRows.contains(row))
6fcd6c90 Poul Sander 2026-02-19 21:12 81
        return;
6fcd6c90 Poul Sander 2026-02-19 21:12 82
6fcd6c90 Poul Sander 2026-02-19 21:12 83
    m_pendingRows.insert(row);
6fcd6c90 Poul Sander 2026-02-19 21:12 84
6fcd6c90 Poul Sander 2026-02-19 21:12 85
    auto *worker = new ThumbnailWorker(
6fcd6c90 Poul Sander 2026-02-19 21:12 86
        m_items[row].path,
6fcd6c90 Poul Sander 2026-02-19 21:12 87
        row,
6fcd6c90 Poul Sander 2026-02-19 21:12 88
        &m_cancelFlag);
6fcd6c90 Poul Sander 2026-02-19 21:12 89
6fcd6c90 Poul Sander 2026-02-19 21:12 90
    connect(worker, &ThumbnailWorker::finished,
6fcd6c90 Poul Sander 2026-02-19 21:12 91
            this, &ImageModel::thumbnailReady,
6fcd6c90 Poul Sander 2026-02-19 21:12 92
            Qt::QueuedConnection);
6fcd6c90 Poul Sander 2026-02-19 21:12 93
6fcd6c90 Poul Sander 2026-02-19 21:12 94
    m_threadPool.start(worker);
032aa1e1 Poul Sander 2026-02-19 18:55 95
}
032aa1e1 Poul Sander 2026-02-19 18:55 96
032aa1e1 Poul Sander 2026-02-19 18:55 97
QString ImageModel::filePath(const QModelIndex &index) const
032aa1e1 Poul Sander 2026-02-19 18:55 98
{
032aa1e1 Poul Sander 2026-02-19 18:55 99
    if (!index.isValid())
032aa1e1 Poul Sander 2026-02-19 18:55 100
        return {};
032aa1e1 Poul Sander 2026-02-19 18:55 101
032aa1e1 Poul Sander 2026-02-19 18:55 102
    return m_items[index.row()].path;
032aa1e1 Poul Sander 2026-02-19 18:55 103
}
032aa1e1 Poul Sander 2026-02-19 18:55 104
032aa1e1 Poul Sander 2026-02-19 18:55 105
int ImageModel::rowCount(const QModelIndex &) const
032aa1e1 Poul Sander 2026-02-19 18:55 106
{
032aa1e1 Poul Sander 2026-02-19 18:55 107
    return m_items.size();
032aa1e1 Poul Sander 2026-02-19 18:55 108
}
032aa1e1 Poul Sander 2026-02-19 18:55 109
032aa1e1 Poul Sander 2026-02-19 18:55 110
QVariant ImageModel::data(const QModelIndex &index, int role) const
032aa1e1 Poul Sander 2026-02-19 18:55 111
{
032aa1e1 Poul Sander 2026-02-19 18:55 112
    if (!index.isValid())
032aa1e1 Poul Sander 2026-02-19 18:55 113
        return {};
032aa1e1 Poul Sander 2026-02-19 18:55 114
032aa1e1 Poul Sander 2026-02-19 18:55 115
    const Item &item = m_items[index.row()];
032aa1e1 Poul Sander 2026-02-19 18:55 116
032aa1e1 Poul Sander 2026-02-19 18:55 117
    if (role == Qt::DecorationRole)
032aa1e1 Poul Sander 2026-02-19 18:55 118
        return item.thumbnail;
032aa1e1 Poul Sander 2026-02-19 18:55 119
032aa1e1 Poul Sander 2026-02-19 18:55 120
    if (role == Qt::DisplayRole)
032aa1e1 Poul Sander 2026-02-19 18:55 121
        return QFileInfo(item.path).fileName();
032aa1e1 Poul Sander 2026-02-19 18:55 122
032aa1e1 Poul Sander 2026-02-19 18:55 123
    return {};
032aa1e1 Poul Sander 2026-02-19 18:55 124
}
cec3b5da Poul Sander 2026-02-19 19:17 125
6fcd6c90 Poul Sander 2026-02-19 21:12 126
void ImageModel::thumbnailReady(int row, const QImage &image)
cec3b5da Poul Sander 2026-02-19 19:17 127
{
6fcd6c90 Poul Sander 2026-02-19 21:12 128
    if (m_cancelFlag)
6fcd6c90 Poul Sander 2026-02-19 21:12 129
        return;
6fcd6c90 Poul Sander 2026-02-19 21:12 130
cec3b5da Poul Sander 2026-02-19 19:17 131
    if (row < 0 || row >= m_items.size())
cec3b5da Poul Sander 2026-02-19 19:17 132
        return;
cec3b5da Poul Sander 2026-02-19 19:17 133
6fcd6c90 Poul Sander 2026-02-19 21:12 134
    m_items[row].thumbnail = QPixmap::fromImage(image);
cec3b5da Poul Sander 2026-02-19 19:17 135
    m_items[row].loaded = true;
6fcd6c90 Poul Sander 2026-02-19 21:12 136
    m_pendingRows.remove(row);
cec3b5da Poul Sander 2026-02-19 19:17 137
cec3b5da Poul Sander 2026-02-19 19:17 138
    QModelIndex idx = index(row);
cec3b5da Poul Sander 2026-02-19 19:17 139
    emit dataChanged(idx, idx, {Qt::DecorationRole});
cec3b5da Poul Sander 2026-02-19 19:17 140
}
1970-01-01 00:00 141