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