1
by Alf Gaida
Adding upstream version 0.10.0+20151214. |
1 |
/*
|
2 |
* Copyright (C) 2012 - 2015 Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
|
|
3 |
*
|
|
4 |
* This library is free software; you can redistribute it and/or
|
|
5 |
* modify it under the terms of the GNU Lesser General Public
|
|
6 |
* License as published by the Free Software Foundation; either
|
|
7 |
* version 2.1 of the License, or (at your option) any later version.
|
|
8 |
*
|
|
9 |
* This library is distributed in the hope that it will be useful,
|
|
10 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
12 |
* Lesser General Public License for more details.
|
|
13 |
*
|
|
14 |
* You should have received a copy of the GNU Lesser General Public
|
|
15 |
* License along with this library; if not, write to the Free Software
|
|
16 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
17 |
*
|
|
18 |
*/
|
|
19 |
||
20 |
||
21 |
#include "foldermodel.h" |
|
22 |
#include "icontheme.h" |
|
23 |
#include <iostream> |
|
24 |
#include <QtAlgorithms> |
|
25 |
#include <QVector> |
|
26 |
#include <qmimedata.h> |
|
27 |
#include <QMimeData> |
|
28 |
#include <QByteArray> |
|
29 |
#include <QPixmap> |
|
30 |
#include <QPainter> |
|
31 |
#include "utilities.h" |
|
32 |
#include "fileoperation.h" |
|
33 |
#include "thumbnailloader.h" |
|
34 |
||
35 |
namespace Fm { |
|
36 |
||
37 |
FolderModel::FolderModel() : |
|
38 |
folder_(nullptr) { |
|
39 |
/*
|
|
40 |
ColumnIcon,
|
|
41 |
ColumnName,
|
|
42 |
ColumnFileType,
|
|
43 |
ColumnMTime,
|
|
44 |
NumOfColumns
|
|
45 |
*/
|
|
46 |
thumbnailRefCounts.reserve(4); |
|
47 |
||
48 |
// reload all icons when the icon theme is changed
|
|
49 |
connect(IconTheme::instance(), &IconTheme::changed, this, &FolderModel::updateIcons); |
|
50 |
}
|
|
51 |
||
52 |
FolderModel::~FolderModel() { |
|
53 |
qDebug("delete FolderModel"); |
|
54 |
||
55 |
if(folder_) |
|
56 |
setFolder(nullptr); |
|
57 |
||
58 |
// if the thumbnail requests list is not empty, cancel them
|
|
59 |
if(!thumbnailResults.empty()) { |
|
60 |
Q_FOREACH(FmThumbnailLoader* res, thumbnailResults) { |
|
61 |
ThumbnailLoader::cancel(res); |
|
62 |
}
|
|
63 |
}
|
|
64 |
}
|
|
65 |
||
66 |
void FolderModel::setFolder(FmFolder* new_folder) { |
|
67 |
if(folder_) { |
|
68 |
removeAll(); // remove old items |
|
69 |
g_signal_handlers_disconnect_by_func(folder_, gpointer(onStartLoading), this); |
|
70 |
g_signal_handlers_disconnect_by_func(folder_, gpointer(onFinishLoading), this); |
|
71 |
g_signal_handlers_disconnect_by_func(folder_, gpointer(onFilesAdded), this); |
|
72 |
g_signal_handlers_disconnect_by_func(folder_, gpointer(onFilesChanged), this); |
|
73 |
g_signal_handlers_disconnect_by_func(folder_, gpointer(onFilesRemoved), this); |
|
74 |
g_object_unref(folder_); |
|
75 |
}
|
|
76 |
if(new_folder) { |
|
77 |
folder_ = FM_FOLDER(g_object_ref(new_folder)); |
|
78 |
g_signal_connect(folder_, "start-loading", G_CALLBACK(onStartLoading), this); |
|
79 |
g_signal_connect(folder_, "finish-loading", G_CALLBACK(onFinishLoading), this); |
|
80 |
g_signal_connect(folder_, "files-added", G_CALLBACK(onFilesAdded), this); |
|
81 |
g_signal_connect(folder_, "files-changed", G_CALLBACK(onFilesChanged), this); |
|
82 |
g_signal_connect(folder_, "files-removed", G_CALLBACK(onFilesRemoved), this); |
|
83 |
// handle the case if the folder is already loaded
|
|
84 |
if(fm_folder_is_loaded(folder_)) |
|
85 |
insertFiles(0, fm_folder_get_files(folder_)); |
|
86 |
}
|
|
87 |
else
|
|
88 |
folder_ = nullptr; |
|
89 |
}
|
|
90 |
||
91 |
void FolderModel::onStartLoading(FmFolder* folder, gpointer user_data) { |
|
92 |
FolderModel* model = static_cast<FolderModel*>(user_data); |
|
93 |
// remove all items
|
|
94 |
model->removeAll(); |
|
95 |
}
|
|
96 |
||
97 |
void FolderModel::onFinishLoading(FmFolder* folder, gpointer user_data) { |
|
98 |
Q_UNUSED(folder) |
|
99 |
Q_UNUSED(user_data) |
|
100 |
}
|
|
101 |
||
102 |
void FolderModel::onFilesAdded(FmFolder* folder, GSList* files, gpointer user_data) { |
|
103 |
FolderModel* model = static_cast<FolderModel*>(user_data); |
|
104 |
int n_files = g_slist_length(files); |
|
105 |
model->beginInsertRows(QModelIndex(), model->items.count(), model->items.count() + n_files - 1); |
|
106 |
for(GSList* l = files; l; l = l->next) { |
|
107 |
FmFileInfo* info = FM_FILE_INFO(l->data); |
|
108 |
FolderModelItem item(info); |
|
109 |
/*
|
|
110 |
if(fm_file_info_is_hidden(info)) {
|
|
111 |
model->hiddenItems.append(item);
|
|
112 |
continue;
|
|
113 |
}
|
|
114 |
*/
|
|
115 |
model->items.append(item); |
|
116 |
}
|
|
117 |
model->endInsertRows(); |
|
118 |
}
|
|
119 |
||
120 |
//static
|
|
121 |
void FolderModel::onFilesChanged(FmFolder* folder, GSList* files, gpointer user_data) { |
|
122 |
FolderModel* model = static_cast<FolderModel*>(user_data); |
|
123 |
for(GSList* l = files; l; l = l->next) { |
|
124 |
FmFileInfo* info = FM_FILE_INFO(l->data); |
|
125 |
int row; |
|
126 |
QList<FolderModelItem>::iterator it = model->findItemByFileInfo(info, &row); |
|
127 |
if(it != model->items.end()) { |
|
128 |
FolderModelItem& item = *it; |
|
129 |
// try to update the item
|
|
130 |
item.displayName = QString::fromUtf8(fm_file_info_get_disp_name(info)); |
|
131 |
item.updateIcon(); |
|
132 |
item.thumbnails.clear(); |
|
133 |
QModelIndex index = model->createIndex(row, 0, &item); |
|
134 |
Q_EMIT model->dataChanged(index, index); |
|
135 |
}
|
|
136 |
}
|
|
137 |
}
|
|
138 |
||
139 |
//static
|
|
140 |
void FolderModel::onFilesRemoved(FmFolder* folder, GSList* files, gpointer user_data) { |
|
141 |
FolderModel* model = static_cast<FolderModel*>(user_data); |
|
142 |
for(GSList* l = files; l; l = l->next) { |
|
143 |
FmFileInfo* info = FM_FILE_INFO(l->data); |
|
144 |
const char* name = fm_file_info_get_name(info); |
|
145 |
int row; |
|
146 |
QList<FolderModelItem>::iterator it = model->findItemByName(name, &row); |
|
147 |
if(it != model->items.end()) { |
|
148 |
model->beginRemoveRows(QModelIndex(), row, row); |
|
149 |
model->items.erase(it); |
|
150 |
model->endRemoveRows(); |
|
151 |
}
|
|
152 |
}
|
|
153 |
}
|
|
154 |
||
155 |
void FolderModel::insertFiles(int row, FmFileInfoList* files) { |
|
156 |
int n_files = fm_file_info_list_get_length(files); |
|
157 |
beginInsertRows(QModelIndex(), row, row + n_files - 1); |
|
158 |
for(GList* l = fm_file_info_list_peek_head_link(files); l; l = l->next) { |
|
159 |
FolderModelItem item(FM_FILE_INFO(l->data)); |
|
160 |
items.append(item); |
|
161 |
}
|
|
162 |
endInsertRows(); |
|
163 |
}
|
|
164 |
||
165 |
void FolderModel::removeAll() { |
|
166 |
if(items.empty()) |
|
167 |
return; |
|
168 |
beginRemoveRows(QModelIndex(), 0, items.size() - 1); |
|
169 |
items.clear(); |
|
170 |
endRemoveRows(); |
|
171 |
}
|
|
172 |
||
173 |
int FolderModel::rowCount(const QModelIndex & parent) const { |
|
174 |
if(parent.isValid()) |
|
175 |
return 0; |
|
176 |
return items.size(); |
|
177 |
}
|
|
178 |
||
179 |
int FolderModel::columnCount (const QModelIndex & parent = QModelIndex()) const { |
|
180 |
if(parent.isValid()) |
|
181 |
return 0; |
|
182 |
return NumOfColumns; |
|
183 |
}
|
|
184 |
||
185 |
FolderModelItem* FolderModel::itemFromIndex(const QModelIndex& index) const { |
|
186 |
return reinterpret_cast<FolderModelItem*>(index.internalPointer()); |
|
187 |
}
|
|
188 |
||
189 |
FmFileInfo* FolderModel::fileInfoFromIndex(const QModelIndex& index) const { |
|
190 |
FolderModelItem* item = itemFromIndex(index); |
|
191 |
return item ? item->info : nullptr; |
|
192 |
}
|
|
193 |
||
194 |
QVariant FolderModel::data(const QModelIndex & index, int role/* = Qt::DisplayRole*/) const { |
|
195 |
if(!index.isValid() || index.row() > items.size() || index.column() >= NumOfColumns) { |
|
196 |
return QVariant(); |
|
197 |
}
|
|
198 |
FolderModelItem* item = itemFromIndex(index); |
|
199 |
FmFileInfo* info = item->info; |
|
200 |
||
201 |
switch(role) { |
|
202 |
case Qt::ToolTipRole: |
|
203 |
return QVariant(item->displayName); |
|
204 |
case Qt::DisplayRole: { |
|
205 |
switch(index.column()) { |
|
206 |
case ColumnFileName: { |
|
207 |
return QVariant(item->displayName); |
|
208 |
}
|
|
209 |
case ColumnFileType: { |
|
210 |
FmMimeType* mime = fm_file_info_get_mime_type(info); |
|
211 |
const char* desc = fm_mime_type_get_desc(mime); |
|
212 |
return QString::fromUtf8(desc); |
|
213 |
}
|
|
214 |
case ColumnFileMTime: { |
|
215 |
const char* name = fm_file_info_get_disp_mtime(info); |
|
216 |
return QString::fromUtf8(name); |
|
217 |
}
|
|
218 |
case ColumnFileSize: { |
|
219 |
const char* name = fm_file_info_get_disp_size(info); |
|
220 |
return QString::fromUtf8(name); |
|
221 |
}
|
|
222 |
case ColumnFileOwner: { |
|
223 |
const char* name = fm_file_info_get_disp_owner(info); |
|
224 |
return QString::fromUtf8(name); |
|
225 |
}
|
|
226 |
}
|
|
227 |
}
|
|
228 |
case Qt::DecorationRole: { |
|
229 |
if(index.column() == 0) { |
|
230 |
// QPixmap pix = IconTheme::loadIcon(fm_file_info_get_icon(info), iconSize_);
|
|
231 |
return QVariant(item->icon); |
|
232 |
// return QVariant(pix);
|
|
233 |
}
|
|
234 |
break; |
|
235 |
}
|
|
236 |
case FileInfoRole: |
|
237 |
return qVariantFromValue((void*)info); |
|
238 |
}
|
|
239 |
return QVariant(); |
|
240 |
}
|
|
241 |
||
242 |
QVariant FolderModel::headerData(int section, Qt::Orientation orientation, int role/* = Qt::DisplayRole*/) const { |
|
243 |
if(role == Qt::DisplayRole) { |
|
244 |
if(orientation == Qt::Horizontal) { |
|
245 |
QString title; |
|
246 |
switch(section) { |
|
247 |
case ColumnFileName: |
|
248 |
title = tr("Name"); |
|
249 |
break; |
|
250 |
case ColumnFileType: |
|
251 |
title = tr("Type"); |
|
252 |
break; |
|
253 |
case ColumnFileSize: |
|
254 |
title = tr("Size"); |
|
255 |
break; |
|
256 |
case ColumnFileMTime: |
|
257 |
title = tr("Modified"); |
|
258 |
break; |
|
259 |
case ColumnFileOwner: |
|
260 |
title = tr("Owner"); |
|
261 |
break; |
|
262 |
}
|
|
263 |
return QVariant(title); |
|
264 |
}
|
|
265 |
}
|
|
266 |
return QVariant(); |
|
267 |
}
|
|
268 |
||
269 |
QModelIndex FolderModel::index(int row, int column, const QModelIndex & parent) const { |
|
270 |
if(row <0 || row >= items.size() || column < 0 || column >= NumOfColumns) |
|
271 |
return QModelIndex(); |
|
272 |
const FolderModelItem& item = items.at(row); |
|
273 |
return createIndex(row, column, (void*)&item); |
|
274 |
}
|
|
275 |
||
276 |
QModelIndex FolderModel::parent(const QModelIndex & index) const { |
|
277 |
return QModelIndex(); |
|
278 |
}
|
|
279 |
||
280 |
Qt::ItemFlags FolderModel::flags(const QModelIndex& index) const { |
|
281 |
// FIXME: should not return same flags unconditionally for all columns
|
|
282 |
Qt::ItemFlags flags; |
|
283 |
if(index.isValid()) { |
|
284 |
flags = Qt::ItemIsEnabled|Qt::ItemIsSelectable; |
|
285 |
if(index.column() == ColumnFileName) |
|
286 |
flags |= (Qt::ItemIsDragEnabled|Qt::ItemIsDropEnabled); |
|
287 |
}
|
|
288 |
else { |
|
289 |
flags = Qt::ItemIsDropEnabled; |
|
290 |
}
|
|
291 |
return flags; |
|
292 |
}
|
|
293 |
||
294 |
// FIXME: this is very inefficient and should be replaced with a
|
|
295 |
// more reasonable implementation later.
|
|
296 |
QList<FolderModelItem>::iterator FolderModel::findItemByPath(FmPath* path, int* row) { |
|
297 |
QList<FolderModelItem>::iterator it = items.begin(); |
|
298 |
int i = 0; |
|
299 |
while(it != items.end()) { |
|
300 |
FolderModelItem& item = *it; |
|
301 |
FmPath* item_path = fm_file_info_get_path(item.info); |
|
302 |
if(fm_path_equal(item_path, path)) { |
|
303 |
*row = i; |
|
304 |
return it; |
|
305 |
}
|
|
306 |
++it; |
|
307 |
++i; |
|
308 |
}
|
|
309 |
return items.end(); |
|
310 |
}
|
|
311 |
||
312 |
// FIXME: this is very inefficient and should be replaced with a
|
|
313 |
// more reasonable implementation later.
|
|
314 |
QList<FolderModelItem>::iterator FolderModel::findItemByName(const char* name, int* row) { |
|
315 |
QList<FolderModelItem>::iterator it = items.begin(); |
|
316 |
int i = 0; |
|
317 |
while(it != items.end()) { |
|
318 |
FolderModelItem& item = *it; |
|
319 |
const char* item_name = fm_file_info_get_name(item.info); |
|
320 |
if(strcmp(name, item_name) == 0) { |
|
321 |
*row = i; |
|
322 |
return it; |
|
323 |
}
|
|
324 |
++it; |
|
325 |
++i; |
|
326 |
}
|
|
327 |
return items.end(); |
|
328 |
}
|
|
329 |
||
330 |
QList< FolderModelItem >::iterator FolderModel::findItemByFileInfo(FmFileInfo* info, int* row) { |
|
331 |
QList<FolderModelItem>::iterator it = items.begin(); |
|
332 |
int i = 0; |
|
333 |
while(it != items.end()) { |
|
334 |
FolderModelItem& item = *it; |
|
335 |
if(item.info == info) { |
|
336 |
*row = i; |
|
337 |
return it; |
|
338 |
}
|
|
339 |
++it; |
|
340 |
++i; |
|
341 |
}
|
|
342 |
return items.end(); |
|
343 |
}
|
|
344 |
||
345 |
QStringList FolderModel::mimeTypes() const { |
|
346 |
qDebug("FolderModel::mimeTypes"); |
|
347 |
QStringList types = QAbstractItemModel::mimeTypes(); |
|
348 |
// now types contains "application/x-qabstractitemmodeldatalist"
|
|
349 |
types << "text/uri-list"; |
|
350 |
// types << "x-special/gnome-copied-files";
|
|
351 |
return types; |
|
352 |
}
|
|
353 |
||
354 |
QMimeData* FolderModel::mimeData(const QModelIndexList& indexes) const { |
|
355 |
QMimeData* data = QAbstractItemModel::mimeData(indexes); |
|
356 |
qDebug("FolderModel::mimeData"); |
|
357 |
// build a uri list
|
|
358 |
QByteArray urilist; |
|
359 |
urilist.reserve(4096); |
|
360 |
||
361 |
for(const auto &index : indexes) { |
|
362 |
FolderModelItem* item = itemFromIndex(index); |
|
363 |
if(item) { |
|
364 |
FmPath* path = fm_file_info_get_path(item->info); |
|
365 |
char* uri = fm_path_to_uri(path); |
|
366 |
urilist.append(uri); |
|
367 |
urilist.append('\n'); |
|
368 |
g_free(uri); |
|
369 |
}
|
|
370 |
}
|
|
371 |
data->setData("text/uri-list", urilist); |
|
372 |
||
373 |
return data; |
|
374 |
}
|
|
375 |
||
376 |
bool FolderModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) { |
|
377 |
qDebug("FolderModel::dropMimeData"); |
|
378 |
if(!folder_) |
|
379 |
return false; |
|
380 |
FmPath* destPath; |
|
381 |
if(parent.isValid()) { // drop on an item |
|
382 |
FmFileInfo* info; |
|
383 |
if(row == -1 && column == -1) |
|
384 |
info = fileInfoFromIndex(parent); |
|
385 |
else { |
|
386 |
QModelIndex itemIndex = parent.child(row, column); |
|
387 |
info = fileInfoFromIndex(itemIndex); |
|
388 |
}
|
|
389 |
if(info) |
|
390 |
destPath = fm_file_info_get_path(info); |
|
391 |
else
|
|
392 |
return false; |
|
393 |
}
|
|
394 |
else { // drop on blank area of the folder |
|
395 |
destPath = path(); |
|
396 |
}
|
|
397 |
||
398 |
// FIXME: should we put this in dropEvent handler of FolderView instead?
|
|
399 |
if(data->hasUrls()) { |
|
400 |
qDebug("drop action: %d", action); |
|
401 |
FmPathList* srcPaths = pathListFromQUrls(data->urls()); |
|
402 |
switch(action) { |
|
403 |
case Qt::CopyAction: |
|
404 |
FileOperation::copyFiles(srcPaths, destPath); |
|
405 |
break; |
|
406 |
case Qt::MoveAction: |
|
407 |
FileOperation::moveFiles(srcPaths, destPath); |
|
408 |
break; |
|
409 |
case Qt::LinkAction: |
|
410 |
FileOperation::symlinkFiles(srcPaths, destPath); |
|
411 |
default: |
|
412 |
fm_path_list_unref(srcPaths); |
|
413 |
return false; |
|
414 |
}
|
|
415 |
fm_path_list_unref(srcPaths); |
|
416 |
return true; |
|
417 |
}
|
|
418 |
else if(data->hasFormat("application/x-qabstractitemmodeldatalist")) { |
|
419 |
return true; |
|
420 |
}
|
|
421 |
return QAbstractListModel::dropMimeData(data, action, row, column, parent); |
|
422 |
}
|
|
423 |
||
424 |
Qt::DropActions FolderModel::supportedDropActions() const { |
|
425 |
qDebug("FolderModel::supportedDropActions"); |
|
426 |
return Qt::CopyAction|Qt::MoveAction|Qt::LinkAction; |
|
427 |
}
|
|
428 |
||
429 |
// ask the model to load thumbnails of the specified size
|
|
430 |
void FolderModel::cacheThumbnails(const int size) { |
|
431 |
QVector<QPair<int, int>>::iterator it = thumbnailRefCounts.begin(); |
|
432 |
while (it != thumbnailRefCounts.end()) { |
|
433 |
if (it->first == size) { |
|
434 |
++it->second; |
|
435 |
return; |
|
436 |
} else ++it; |
|
437 |
}
|
|
438 |
thumbnailRefCounts.append(QPair<int, int>(size, 1)); |
|
439 |
}
|
|
440 |
||
441 |
// ask the model to free cached thumbnails of the specified size
|
|
442 |
void FolderModel::releaseThumbnails(int size) { |
|
443 |
QVector<QPair<int, int> >::iterator it; |
|
444 |
for(it = thumbnailRefCounts.begin(); it != thumbnailRefCounts.end(); ++it) { |
|
445 |
if(it->first == size) { |
|
446 |
break; |
|
447 |
}
|
|
448 |
}
|
|
449 |
if(it != thumbnailRefCounts.end()) { |
|
450 |
--it->second; |
|
451 |
if(it->second == 0) { |
|
452 |
thumbnailRefCounts.erase(it); |
|
453 |
||
454 |
// remove thumbnails that ara queued for loading from thumbnailResults
|
|
455 |
QLinkedList<FmThumbnailLoader*>::iterator it; |
|
456 |
for(it = thumbnailResults.begin(); it != thumbnailResults.end();) { |
|
457 |
QLinkedList<FmThumbnailLoader*>::iterator next = it + 1; |
|
458 |
FmThumbnailLoader* res = *it; |
|
459 |
if(ThumbnailLoader::size(res) == size) { |
|
460 |
ThumbnailLoader::cancel(res); |
|
461 |
thumbnailResults.erase(it); |
|
462 |
}
|
|
463 |
it = next; |
|
464 |
}
|
|
465 |
||
466 |
// remove all cached thumbnails of the specified size
|
|
467 |
QList<FolderModelItem>::iterator itemIt; |
|
468 |
for(itemIt = items.begin(); itemIt != items.end(); ++itemIt) { |
|
469 |
FolderModelItem& item = *itemIt; |
|
470 |
item.removeThumbnail(size); |
|
471 |
}
|
|
472 |
}
|
|
473 |
}
|
|
474 |
}
|
|
475 |
||
476 |
void FolderModel::onThumbnailLoaded(FmThumbnailLoader* res, gpointer user_data) { |
|
477 |
FolderModel* pThis = reinterpret_cast<FolderModel*>(user_data); |
|
478 |
QLinkedList<FmThumbnailLoader*>::iterator it; |
|
479 |
for(it = pThis->thumbnailResults.begin(); it != pThis->thumbnailResults.end(); ++it) { |
|
480 |
if(*it == res) { // the thumbnail result is in our list |
|
481 |
pThis->thumbnailResults.erase(it); // remove it from the list |
|
482 |
FmFileInfo* info = ThumbnailLoader::fileInfo(res); |
|
483 |
int row = -1; |
|
484 |
// find the model item this thumbnail belongs to
|
|
485 |
QList<FolderModelItem>::iterator it = pThis->findItemByFileInfo(info, &row); |
|
486 |
if(it != pThis->items.end()) { |
|
487 |
// the file is found in our model
|
|
488 |
FolderModelItem& item = *it; |
|
489 |
QModelIndex index = pThis->createIndex(row, 0, (void*)&item); |
|
490 |
// store the image in the folder model item.
|
|
491 |
int size = ThumbnailLoader::size(res); |
|
492 |
QImage image = ThumbnailLoader::image(res); |
|
493 |
FolderModelItem::Thumbnail* thumbnail = item.findThumbnail(size); |
|
494 |
thumbnail->image = image; |
|
495 |
// qDebug("thumbnail loaded for: %s, size: %d", item.displayName.toUtf8().constData(), size);
|
|
496 |
if(image.isNull()) |
|
497 |
thumbnail->status = FolderModelItem::ThumbnailFailed; |
|
498 |
else { |
|
499 |
thumbnail->status = FolderModelItem::ThumbnailLoaded; |
|
500 |
// FIXME: due to bugs in Qt's QStyledItemDelegate, if the image width and height
|
|
501 |
// are not the same, painting errors will happen. It's quite unfortunate.
|
|
502 |
// Let's do some padding to make its width and height equals.
|
|
503 |
// This greatly decrease performance :-(
|
|
504 |
// Later if we can re-implement our own item delegate, this can be avoided.
|
|
505 |
QPixmap pixmap = QPixmap(size, size); |
|
506 |
pixmap.fill(QColor(0, 0, 0, 0)); // fill the pixmap with transparent color (alpha:0) |
|
507 |
QPainter painter(&pixmap); |
|
508 |
int x = (size - image.width()) / 2; |
|
509 |
int y = (size - image.height()) / 2; |
|
510 |
painter.drawImage(QPoint(x, y), image); // draw the image to the pixmap at center. |
|
511 |
// FIXME: should we cache QPixmap instead for performance reason?
|
|
512 |
thumbnail->image = pixmap.toImage(); // convert it back to image |
|
513 |
||
514 |
// tell the world that we have the thumbnail loaded
|
|
515 |
Q_EMIT pThis->thumbnailLoaded(index, size); |
|
516 |
}
|
|
517 |
}
|
|
518 |
break; |
|
519 |
}
|
|
520 |
}
|
|
521 |
}
|
|
522 |
||
523 |
// get a thumbnail of size at the index
|
|
524 |
// if a thumbnail is not yet loaded, this will initiate loading of the thumbnail.
|
|
525 |
QImage FolderModel::thumbnailFromIndex(const QModelIndex& index, int size) { |
|
526 |
FolderModelItem* item = itemFromIndex(index); |
|
527 |
if(item) { |
|
528 |
FolderModelItem::Thumbnail* thumbnail = item->findThumbnail(size); |
|
529 |
// qDebug("FolderModel::thumbnailFromIndex: %d, %s", thumbnail->status, item->displayName.toUtf8().data());
|
|
530 |
switch(thumbnail->status) { |
|
531 |
case FolderModelItem::ThumbnailNotChecked: { |
|
532 |
// load the thumbnail
|
|
533 |
FmThumbnailLoader* res = ThumbnailLoader::load(item->info, size, onThumbnailLoaded, this); |
|
534 |
thumbnailResults.push_back(res); |
|
535 |
thumbnail->status = FolderModelItem::ThumbnailLoading; |
|
536 |
break; |
|
537 |
}
|
|
538 |
case FolderModelItem::ThumbnailLoaded: |
|
539 |
return thumbnail->image; |
|
540 |
default:; |
|
541 |
}
|
|
542 |
}
|
|
543 |
return QImage(); |
|
544 |
}
|
|
545 |
||
546 |
void FolderModel::updateIcons() { |
|
547 |
QList<FolderModelItem>::iterator it = items.begin(); |
|
548 |
for(;it != items.end(); ++it) { |
|
549 |
(*it).updateIcon(); |
|
550 |
}
|
|
551 |
}
|
|
552 |
||
553 |
||
554 |
} // namespace Fm |