| 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 |
|