00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "kfilepreviewgenerator.h"
00021
00022 #include "../kio/kio/defaultviewadapter_p.h"
00023 #include "../kio/kio/imagefilter_p.h"
00024 #include <kfileitem.h>
00025 #include <kiconeffect.h>
00026 #include <kio/previewjob.h>
00027 #include <kdirlister.h>
00028 #include <kdirmodel.h>
00029 #include <kmimetyperesolver.h>
00030
00031 #include <QApplication>
00032 #include <QAbstractItemView>
00033 #include <QAbstractProxyModel>
00034 #include <QClipboard>
00035 #include <QColor>
00036 #include <QList>
00037 #include <QListView>
00038 #include <QPainter>
00039 #include <QPixmap>
00040 #include <QScrollBar>
00041 #include <QIcon>
00042
00043 #ifdef Q_WS_X11
00044 # include <QX11Info>
00045 # include <X11/Xlib.h>
00046 # include <X11/extensions/Xrender.h>
00047 #endif
00048
00069 class LayoutBlocker {
00070 public:
00071 LayoutBlocker(QAbstractItemView* view) :
00072 m_uniformSizes(false),
00073 m_view(qobject_cast<QListView*>(view))
00074 {
00075 if (m_view != 0) {
00076 m_uniformSizes = m_view->uniformItemSizes();
00077 m_view->setUniformItemSizes(true);
00078 }
00079 }
00080
00081 ~LayoutBlocker()
00082 {
00083 if (m_view != 0) {
00084 m_view->setUniformItemSizes(m_uniformSizes);
00085 }
00086 }
00087
00088 private:
00089 bool m_uniformSizes;
00090 QListView* m_view;
00091 };
00092
00094 class TileSet
00095 {
00096 public:
00097 enum Tile { TopLeftCorner = 0, TopSide, TopRightCorner, LeftSide, Center,
00098 RightSide, BottomLeftCorner, BottomSide, BottomRightCorner,
00099 NumTiles };
00100
00101 TileSet()
00102 {
00103 QImage image(8 * 3, 8 * 3, QImage::Format_ARGB32_Premultiplied);
00104
00105 QPainter p(&image);
00106 p.setCompositionMode(QPainter::CompositionMode_Source);
00107 p.fillRect(image.rect(), Qt::transparent);
00108 p.fillRect(image.rect().adjusted(3, 3, -3, -3), Qt::black);
00109 p.end();
00110
00111 KIO::ImageFilter::shadowBlur(image, 3, Qt::black);
00112
00113 QPixmap pixmap = QPixmap::fromImage(image);
00114 m_tiles[TopLeftCorner] = pixmap.copy(0, 0, 8, 8);
00115 m_tiles[TopSide] = pixmap.copy(8, 0, 8, 8);
00116 m_tiles[TopRightCorner] = pixmap.copy(16, 0, 8, 8);
00117 m_tiles[LeftSide] = pixmap.copy(0, 8, 8, 8);
00118 m_tiles[Center] = pixmap.copy(8, 8, 8, 8);
00119 m_tiles[RightSide] = pixmap.copy(16, 8, 8, 8);
00120 m_tiles[BottomLeftCorner] = pixmap.copy(0, 16, 8, 8);
00121 m_tiles[BottomSide] = pixmap.copy(8, 16, 8, 8);
00122 m_tiles[BottomRightCorner] = pixmap.copy(16, 16, 8, 8);
00123 }
00124
00125 void paint(QPainter* p, const QRect& r)
00126 {
00127 p->drawPixmap(r.topLeft(), m_tiles[TopLeftCorner]);
00128 if (r.width() - 16 > 0) {
00129 p->drawTiledPixmap(r.x() + 8, r.y(), r.width() - 16, 8, m_tiles[TopSide]);
00130 }
00131 p->drawPixmap(r.right() - 8 + 1, r.y(), m_tiles[TopRightCorner]);
00132 if (r.height() - 16 > 0) {
00133 p->drawTiledPixmap(r.x(), r.y() + 8, 8, r.height() - 16, m_tiles[LeftSide]);
00134 if (r.width() - 16 > 0) {
00135 p->drawTiledPixmap(r.x() + 8, r.y() + 8, r.width() - 16, r.height() - 16, m_tiles[Center]);
00136 }
00137 p->drawTiledPixmap(r.right() - 8 + 1, r.y() + 8, 8, r.height() - 16, m_tiles[RightSide]);
00138 }
00139 p->drawPixmap(r.x(), r.bottom() - 8 + 1, m_tiles[BottomLeftCorner]);
00140 if (r.width() - 16 > 0) {
00141 p->drawTiledPixmap(r.x() + 8, r.bottom() - 8 + 1, r.width() - 16, 8, m_tiles[BottomSide]);
00142 }
00143 p->drawPixmap(r.right() - 8 + 1, r.bottom() - 8 + 1, m_tiles[BottomRightCorner]);
00144 }
00145
00146 private:
00147 QPixmap m_tiles[NumTiles];
00148 };
00149
00150 class KFilePreviewGenerator::Private
00151 {
00152 public:
00153 Private(KFilePreviewGenerator* parent,
00154 KAbstractViewAdapter* viewAdapter,
00155 QAbstractItemModel* model);
00156 ~Private();
00157
00161 void generatePreviews(const KFileItemList& items);
00162
00167 void generatePreviews(const QModelIndex& topLeft, const QModelIndex& bottomRight);
00168
00174 void addToPreviewQueue(const KFileItem& item, const QPixmap& pixmap);
00175
00180 void slotPreviewJobFinished(KJob* job);
00181
00183 void updateCutItems();
00184
00189 void dispatchPreviewQueue();
00190
00196 void pausePreviews();
00197
00203 void resumePreviews();
00204
00209 bool isCutItem(const KFileItem& item) const;
00210
00212 void applyCutItemEffect();
00213
00218 bool applyImageFrame(QPixmap& icon);
00219
00225 void limitToSize(QPixmap& icon, const QSize& maxSize);
00226
00231 void startPreviewJob(const KFileItemList& items);
00232
00234 void killPreviewJobs();
00235
00242 void orderItems(KFileItemList& items);
00243
00248 bool decodeIsCutSelection(const QMimeData* mimeData);
00249
00251 struct ItemInfo
00252 {
00253 KUrl url;
00254 QPixmap pixmap;
00255 };
00256
00261 class DataChangeObtainer
00262 {
00263 public:
00264 DataChangeObtainer(KFilePreviewGenerator::Private* generator) :
00265 m_gen(generator) { ++m_gen->m_internalDataChange; }
00266 ~DataChangeObtainer() { --m_gen->m_internalDataChange; }
00267 private:
00268 KFilePreviewGenerator::Private* m_gen;
00269 };
00270
00271 bool m_previewShown;
00272
00277 bool m_clearItemQueues;
00278
00282 bool m_hasCutSelection;
00283
00289 int m_internalDataChange;
00290
00291 int m_pendingVisiblePreviews;
00292
00293 KAbstractViewAdapter* m_viewAdapter;
00294 QAbstractItemView* m_itemView;
00295 QTimer* m_previewTimer;
00296 QTimer* m_scrollAreaTimer;
00297 QList<KJob*> m_previewJobs;
00298 KDirModel* m_dirModel;
00299 QAbstractProxyModel* m_proxyModel;
00300
00301 KMimeTypeResolver* m_mimeTypeResolver;
00302
00303 QList<ItemInfo> m_cutItemsCache;
00304 QList<ItemInfo> m_previews;
00305
00310 KFileItemList m_pendingItems;
00311
00316 KFileItemList m_dispatchedItems;
00317
00318 QStringList m_enabledPlugins;
00319
00320 TileSet* m_tileSet;
00321
00322 private:
00323 KFilePreviewGenerator* const q;
00324
00325 };
00326
00327 KFilePreviewGenerator::Private::Private(KFilePreviewGenerator* parent,
00328 KAbstractViewAdapter* viewAdapter,
00329 QAbstractItemModel* model) :
00330 m_previewShown(true),
00331 m_clearItemQueues(true),
00332 m_hasCutSelection(false),
00333 m_internalDataChange(0),
00334 m_pendingVisiblePreviews(0),
00335 m_viewAdapter(viewAdapter),
00336 m_itemView(0),
00337 m_previewTimer(0),
00338 m_scrollAreaTimer(0),
00339 m_previewJobs(),
00340 m_dirModel(0),
00341 m_proxyModel(0),
00342 m_mimeTypeResolver(0),
00343 m_cutItemsCache(),
00344 m_previews(),
00345 m_pendingItems(),
00346 m_dispatchedItems(),
00347 m_tileSet(0),
00348 q(parent)
00349 {
00350 if (!m_viewAdapter->iconSize().isValid()) {
00351 m_previewShown = false;
00352 }
00353
00354 m_proxyModel = qobject_cast<QAbstractProxyModel*>(model);
00355 m_dirModel = (m_proxyModel == 0) ?
00356 qobject_cast<KDirModel*>(model) :
00357 qobject_cast<KDirModel*>(m_proxyModel->sourceModel());
00358 if (m_dirModel == 0) {
00359
00360 m_previewShown = false;
00361 } else {
00362 connect(m_dirModel->dirLister(), SIGNAL(newItems(const KFileItemList&)),
00363 q, SLOT(generatePreviews(const KFileItemList&)));
00364 connect(m_dirModel, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
00365 q, SLOT(generatePreviews(const QModelIndex&, const QModelIndex&)));
00366 }
00367
00368 QClipboard* clipboard = QApplication::clipboard();
00369 connect(clipboard, SIGNAL(dataChanged()),
00370 q, SLOT(updateCutItems()));
00371
00372 m_previewTimer = new QTimer(q);
00373 m_previewTimer->setSingleShot(true);
00374 connect(m_previewTimer, SIGNAL(timeout()), q, SLOT(dispatchPreviewQueue()));
00375
00376
00377
00378
00379
00380 m_scrollAreaTimer = new QTimer(q);
00381 m_scrollAreaTimer->setSingleShot(true);
00382 m_scrollAreaTimer->setInterval(200);
00383 connect(m_scrollAreaTimer, SIGNAL(timeout()),
00384 q, SLOT(resumePreviews()));
00385 m_viewAdapter->connect(KAbstractViewAdapter::ScrollBarValueChanged,
00386 q, SLOT(pausePreviews()));
00387 }
00388
00389 KFilePreviewGenerator::Private::~Private()
00390 {
00391 killPreviewJobs();
00392 m_pendingItems.clear();
00393 m_dispatchedItems.clear();
00394 if (m_mimeTypeResolver != 0) {
00395 m_mimeTypeResolver->deleteLater();
00396 m_mimeTypeResolver = 0;
00397 }
00398 delete m_tileSet;
00399 }
00400
00401 void KFilePreviewGenerator::Private::generatePreviews(const KFileItemList& items)
00402 {
00403 applyCutItemEffect();
00404
00405 if (!m_previewShown) {
00406 return;
00407 }
00408
00409 KFileItemList orderedItems = items;
00410 orderItems(orderedItems);
00411
00412 foreach (const KFileItem& item, orderedItems) {
00413 m_pendingItems.append(item);
00414 }
00415
00416 startPreviewJob(orderedItems);
00417 }
00418
00419 void KFilePreviewGenerator::Private::generatePreviews(const QModelIndex& topLeft,
00420 const QModelIndex& bottomRight)
00421 {
00422 if (m_internalDataChange > 0) {
00423
00424
00425
00426 return;
00427 }
00428
00429 KFileItemList itemList;
00430 for (int row = topLeft.row(); row <= bottomRight.row(); ++row) {
00431 const QModelIndex index = m_dirModel->index(row, 0);
00432 const KFileItem item = m_dirModel->itemForIndex(index);
00433 itemList.append(item);
00434 }
00435 generatePreviews(itemList);
00436 }
00437
00438 void KFilePreviewGenerator::Private::addToPreviewQueue(const KFileItem& item, const QPixmap& pixmap)
00439 {
00440 if (!m_previewShown) {
00441
00442 return;
00443 }
00444 const KUrl url = item.url();
00445
00446
00447
00448 KDirLister* dirLister = m_dirModel->dirLister();
00449 bool isOldPreview = true;
00450 const KUrl::List dirs = dirLister->directories();
00451 const QString itemDir = url.directory();
00452 foreach (const KUrl& url, dirs) {
00453 if (url.path() == itemDir) {
00454 isOldPreview = false;
00455 break;
00456 }
00457 }
00458 if (isOldPreview) {
00459 return;
00460 }
00461
00462 QPixmap icon = pixmap;
00463
00464 const QString mimeType = item.mimetype();
00465 const QString mimeTypeGroup = mimeType.left(mimeType.indexOf('/'));
00466 if ((mimeTypeGroup != "image") || !applyImageFrame(icon)) {
00467 limitToSize(icon, m_viewAdapter->iconSize());
00468 }
00469
00470 if (m_hasCutSelection && isCutItem(item)) {
00471
00472
00473
00474 QList<ItemInfo>::iterator begin = m_cutItemsCache.begin();
00475 QList<ItemInfo>::iterator end = m_cutItemsCache.end();
00476 for (QList<ItemInfo>::iterator it = begin; it != end; ++it) {
00477 if ((*it).url == item.url()) {
00478 (*it).pixmap = icon;
00479 break;
00480 }
00481 }
00482
00483
00484
00485 KIconEffect iconEffect;
00486 icon = iconEffect.apply(icon, KIconLoader::Desktop, KIconLoader::DisabledState);
00487 }
00488
00489
00490
00491 ItemInfo preview;
00492 preview.url = url;
00493 preview.pixmap = icon;
00494 m_previews.append(preview);
00495
00496 m_dispatchedItems.append(item);
00497 }
00498
00499 void KFilePreviewGenerator::Private::slotPreviewJobFinished(KJob* job)
00500 {
00501 const int index = m_previewJobs.indexOf(job);
00502 m_previewJobs.removeAt(index);
00503
00504 if ((m_previewJobs.count() == 0) && m_clearItemQueues) {
00505 m_pendingItems.clear();
00506 m_dispatchedItems.clear();
00507 m_pendingVisiblePreviews = 0;
00508 QMetaObject::invokeMethod(q, "dispatchPreviewQueue", Qt::QueuedConnection);
00509 }
00510 }
00511
00512 void KFilePreviewGenerator::Private::updateCutItems()
00513 {
00514 DataChangeObtainer obt(this);
00515
00516
00517
00518 foreach (const ItemInfo& cutItem, m_cutItemsCache) {
00519 const QModelIndex index = m_dirModel->indexForUrl(cutItem.url);
00520 if (index.isValid()) {
00521 m_dirModel->setData(index, QIcon(cutItem.pixmap), Qt::DecorationRole);
00522 }
00523 }
00524 m_cutItemsCache.clear();
00525
00526
00527 applyCutItemEffect();
00528 }
00529
00530 void KFilePreviewGenerator::Private::dispatchPreviewQueue()
00531 {
00532 const int previewsCount = m_previews.count();
00533 if (previewsCount > 0) {
00534
00535
00536
00537
00538 LayoutBlocker blocker(m_itemView);
00539 DataChangeObtainer obt(this);
00540 for (int i = 0; i < previewsCount; ++i) {
00541 const ItemInfo& preview = m_previews.first();
00542
00543 const QModelIndex idx = m_dirModel->indexForUrl(preview.url);
00544 if (idx.isValid() && (idx.column() == 0)) {
00545 m_dirModel->setData(idx, QIcon(preview.pixmap), Qt::DecorationRole);
00546 }
00547
00548 m_previews.pop_front();
00549 if (m_pendingVisiblePreviews > 0) {
00550 --m_pendingVisiblePreviews;
00551 }
00552 }
00553 }
00554
00555 if (m_pendingVisiblePreviews > 0) {
00556
00557
00558
00559 m_previewTimer->start(200);
00560 }
00561 }
00562
00563 void KFilePreviewGenerator::Private::pausePreviews()
00564 {
00565 foreach (KJob* job, m_previewJobs) {
00566 Q_ASSERT(job != 0);
00567 job->suspend();
00568 }
00569 m_scrollAreaTimer->start();
00570 }
00571
00572 void KFilePreviewGenerator::Private::resumePreviews()
00573 {
00574
00575
00576
00577
00578
00579
00580 foreach (const KFileItem& item, m_dispatchedItems) {
00581 KFileItemList::iterator begin = m_pendingItems.begin();
00582 KFileItemList::iterator end = m_pendingItems.end();
00583 for (KFileItemList::iterator it = begin; it != end; ++it) {
00584 if ((*it).url() == item.url()) {
00585 m_pendingItems.erase(it);
00586 break;
00587 }
00588 }
00589 }
00590 m_dispatchedItems.clear();
00591
00592 m_pendingVisiblePreviews = 0;
00593 dispatchPreviewQueue();
00594
00595 KFileItemList orderedItems = m_pendingItems;
00596 orderItems(orderedItems);
00597
00598
00599
00600
00601
00602 m_clearItemQueues = false;
00603 killPreviewJobs();
00604 m_clearItemQueues = true;
00605
00606 startPreviewJob(orderedItems);
00607 }
00608
00609 bool KFilePreviewGenerator::Private::isCutItem(const KFileItem& item) const
00610 {
00611 const QMimeData* mimeData = QApplication::clipboard()->mimeData();
00612 const KUrl::List cutUrls = KUrl::List::fromMimeData(mimeData);
00613
00614 const KUrl itemUrl = item.url();
00615 foreach (const KUrl& url, cutUrls) {
00616 if (url == itemUrl) {
00617 return true;
00618 }
00619 }
00620
00621 return false;
00622 }
00623
00624 void KFilePreviewGenerator::Private::applyCutItemEffect()
00625 {
00626 const QMimeData* mimeData = QApplication::clipboard()->mimeData();
00627 m_hasCutSelection = decodeIsCutSelection(mimeData);
00628 if (!m_hasCutSelection) {
00629 return;
00630 }
00631
00632 KFileItemList items;
00633 KDirLister* dirLister = m_dirModel->dirLister();
00634 const KUrl::List dirs = dirLister->directories();
00635 foreach (const KUrl& url, dirs) {
00636 items << dirLister->itemsForDir(url);
00637 }
00638
00639 DataChangeObtainer obt(this);
00640 foreach (const KFileItem& item, items) {
00641 if (isCutItem(item)) {
00642 const QModelIndex index = m_dirModel->indexForItem(item);
00643 const QVariant value = m_dirModel->data(index, Qt::DecorationRole);
00644 if (value.type() == QVariant::Icon) {
00645 const QIcon icon(qvariant_cast<QIcon>(value));
00646 const QSize actualSize = icon.actualSize(m_viewAdapter->iconSize());
00647 QPixmap pixmap = icon.pixmap(actualSize);
00648
00649
00650
00651 ItemInfo cutItem;
00652 cutItem.url = item.url();
00653 cutItem.pixmap = pixmap;
00654 m_cutItemsCache.append(cutItem);
00655
00656
00657 KIconEffect iconEffect;
00658 pixmap = iconEffect.apply(pixmap, KIconLoader::Desktop, KIconLoader::DisabledState);
00659 m_dirModel->setData(index, QIcon(pixmap), Qt::DecorationRole);
00660 }
00661 }
00662 }
00663 }
00664
00665 bool KFilePreviewGenerator::Private::applyImageFrame(QPixmap& icon)
00666 {
00667 const QSize maxSize = m_viewAdapter->iconSize();
00668 const bool applyFrame = (maxSize.width() > KIconLoader::SizeSmallMedium) &&
00669 (maxSize.height() > KIconLoader::SizeSmallMedium) &&
00670 ((icon.width() > KIconLoader::SizeLarge) ||
00671 (icon.height() > KIconLoader::SizeLarge));
00672 if (!applyFrame) {
00673
00674 return false;
00675 }
00676
00677 const int tloffset = 2;
00678 const int broffset = 4;
00679 const int doubleFrame = tloffset + broffset;
00680
00681
00682 limitToSize(icon, QSize(maxSize.width() - doubleFrame, maxSize.height() - doubleFrame));
00683
00684 if (!m_tileSet) {
00685 m_tileSet = new TileSet;
00686 }
00687
00688 QPixmap framedIcon(icon.size().width() + doubleFrame, icon.size().height() + doubleFrame);
00689 framedIcon.fill(Qt::transparent);
00690
00691 QPainter painter;
00692 painter.begin(&framedIcon);
00693 painter.setCompositionMode(QPainter::CompositionMode_Source);
00694 m_tileSet->paint(&painter, framedIcon.rect());
00695 painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
00696 painter.drawPixmap(tloffset, tloffset, icon);
00697 painter.end();
00698
00699 icon = framedIcon;
00700 return true;
00701 }
00702
00703 void KFilePreviewGenerator::Private::limitToSize(QPixmap& icon, const QSize& maxSize)
00704 {
00705 if ((icon.width() > maxSize.width()) || (icon.height() > maxSize.height())) {
00706 #ifdef Q_WS_X11
00707
00708 if ((icon.width() <= 2048) && (icon.height() <= 2048) && icon.x11PictureHandle()) {
00709 QSize size = icon.size();
00710 size.scale(maxSize, Qt::KeepAspectRatio);
00711
00712 const qreal factor = size.width() / qreal(icon.width());
00713
00714 XTransform xform = {{
00715 { XDoubleToFixed(1 / factor), 0, 0 },
00716 { 0, XDoubleToFixed(1 / factor), 0 },
00717 { 0, 0, XDoubleToFixed(1) }
00718 }};
00719
00720 QPixmap pixmap(size);
00721 pixmap.fill(Qt::transparent);
00722
00723 Display* dpy = QX11Info::display();
00724 XRenderSetPictureFilter(dpy, icon.x11PictureHandle(), FilterBilinear, 0, 0);
00725 XRenderSetPictureTransform(dpy, icon.x11PictureHandle(), &xform);
00726 XRenderComposite(dpy, PictOpOver, icon.x11PictureHandle(), None, pixmap.x11PictureHandle(),
00727 0, 0, 0, 0, 0, 0, pixmap.width(), pixmap.height());
00728 icon = pixmap;
00729 } else {
00730 icon = icon.scaled(maxSize, Qt::KeepAspectRatio, Qt::FastTransformation);
00731 }
00732 #else
00733 icon = icon.scaled(maxSize, Qt::KeepAspectRatio, Qt::FastTransformation);
00734 #endif
00735 }
00736 }
00737
00738 void KFilePreviewGenerator::Private::startPreviewJob(const KFileItemList& items)
00739 {
00740 if (items.count() == 0) {
00741 return;
00742 }
00743
00744 const QMimeData* mimeData = QApplication::clipboard()->mimeData();
00745 m_hasCutSelection = decodeIsCutSelection(mimeData);
00746
00747 const QSize size = m_viewAdapter->iconSize();
00748
00749
00750
00751
00752
00753
00754 const int cacheSize = (size.width() > 128) || (size.height() > 128) ? 256 : 128;
00755 KIO::PreviewJob* job = KIO::filePreview(items, cacheSize, cacheSize, 0, 70, true, true, &m_enabledPlugins);
00756 connect(job, SIGNAL(gotPreview(const KFileItem&, const QPixmap&)),
00757 q, SLOT(addToPreviewQueue(const KFileItem&, const QPixmap&)));
00758 connect(job, SIGNAL(finished(KJob*)),
00759 q, SLOT(slotPreviewJobFinished(KJob*)));
00760
00761 m_previewJobs.append(job);
00762 m_previewTimer->start(200);
00763 }
00764
00765 void KFilePreviewGenerator::Private::killPreviewJobs()
00766 {
00767 foreach (KJob* job, m_previewJobs) {
00768 Q_ASSERT(job != 0);
00769 job->kill();
00770 }
00771 m_previewJobs.clear();
00772 }
00773
00774 void KFilePreviewGenerator::Private::orderItems(KFileItemList& items)
00775 {
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786 const bool hasProxy = (m_proxyModel != 0);
00787 const int itemCount = items.count();
00788 const int rowCount = hasProxy ? m_proxyModel->rowCount() : m_dirModel->rowCount();
00789 const QRect visibleArea = m_viewAdapter->visibleArea();
00790
00791 QModelIndex dirIndex;
00792 QRect itemRect;
00793 int insertPos = 0;
00794 if (itemCount * 10 > rowCount) {
00795
00796
00797 for (int row = 0; row < rowCount; ++row) {
00798 if (hasProxy) {
00799 const QModelIndex proxyIndex = m_proxyModel->index(row, 0);
00800 itemRect = m_viewAdapter->visualRect(proxyIndex);
00801 dirIndex = m_proxyModel->mapToSource(proxyIndex);
00802 } else {
00803 dirIndex = m_dirModel->index(row, 0);
00804 itemRect = m_viewAdapter->visualRect(dirIndex);
00805 }
00806
00807 KFileItem item = m_dirModel->itemForIndex(dirIndex);
00808 const KUrl url = item.url();
00809
00810
00811 int index = -1;
00812 for (int i = 0; i < itemCount; ++i) {
00813 if (items.at(i).url() == url) {
00814 index = i;
00815 break;
00816 }
00817 }
00818
00819 if ((index > 0) && itemRect.intersects(visibleArea)) {
00820
00821
00822
00823 items.removeAt(index);
00824 items.insert(insertPos, item);
00825 ++insertPos;
00826 ++m_pendingVisiblePreviews;
00827 }
00828 }
00829 } else {
00830
00831
00832 for (int i = 0; i < itemCount; ++i) {
00833 dirIndex = m_dirModel->indexForItem(items.at(i));
00834 if (hasProxy) {
00835 const QModelIndex proxyIndex = m_proxyModel->mapFromSource(dirIndex);
00836 itemRect = m_viewAdapter->visualRect(proxyIndex);
00837 } else {
00838 itemRect = m_viewAdapter->visualRect(dirIndex);
00839 }
00840
00841 if (itemRect.intersects(visibleArea)) {
00842
00843
00844
00845 items.insert(insertPos, items.at(i));
00846 items.removeAt(i + 1);
00847 ++insertPos;
00848 ++m_pendingVisiblePreviews;
00849 }
00850 }
00851 }
00852 }
00853
00854 bool KFilePreviewGenerator::Private::decodeIsCutSelection(const QMimeData* mimeData)
00855 {
00856 const QByteArray data = mimeData->data("application/x-kde-cutselection");
00857 if (data.isEmpty()) {
00858 return false;
00859 } else {
00860 return data.at(0) == '1';
00861 }
00862 }
00863
00864 KFilePreviewGenerator::KFilePreviewGenerator(QAbstractItemView* parent) :
00865 QObject(parent),
00866 d(new Private(this, new KIO::DefaultViewAdapter(parent, this), parent->model()))
00867 {
00868 d->m_itemView = parent;
00869 }
00870
00871 KFilePreviewGenerator::KFilePreviewGenerator(KAbstractViewAdapter* parent, QAbstractProxyModel* model) :
00872 QObject(parent),
00873 d(new Private(this, parent, model))
00874 {
00875 }
00876
00877 KFilePreviewGenerator::~KFilePreviewGenerator()
00878 {
00879 delete d;
00880 }
00881
00882 void KFilePreviewGenerator::setPreviewShown(bool show)
00883 {
00884 if (show && (!d->m_viewAdapter->iconSize().isValid() || (d->m_dirModel == 0))) {
00885
00886
00887 return;
00888 }
00889
00890 if (d->m_previewShown != show) {
00891 d->m_previewShown = show;
00892 d->m_cutItemsCache.clear();
00893 d->updateCutItems();
00894 if (show) {
00895 updatePreviews();
00896 }
00897 }
00898
00899 if (show && (d->m_mimeTypeResolver != 0)) {
00900
00901 d->m_mimeTypeResolver->deleteLater();
00902 d->m_mimeTypeResolver = 0;
00903 } else if (!show && (d->m_mimeTypeResolver == 0)) {
00904
00905
00906 d->m_mimeTypeResolver = new KMimeTypeResolver(d->m_viewAdapter);
00907 }
00908 }
00909
00910 bool KFilePreviewGenerator::isPreviewShown() const
00911 {
00912 return d->m_previewShown;
00913 }
00914
00915 void KFilePreviewGenerator::updatePreviews()
00916 {
00917 if (!d->m_previewShown) {
00918 return;
00919 }
00920
00921 d->killPreviewJobs();
00922 d->m_cutItemsCache.clear();
00923 d->m_pendingItems.clear();
00924 d->m_dispatchedItems.clear();
00925
00926 KFileItemList itemList;
00927 const int rowCount = d->m_dirModel->rowCount();
00928 for (int row = 0; row < rowCount; ++row) {
00929 const QModelIndex index = d->m_dirModel->index(row, 0);
00930 KFileItem item = d->m_dirModel->itemForIndex(index);
00931 itemList.append(item);
00932 }
00933
00934 d->generatePreviews(itemList);
00935 d->updateCutItems();
00936 }
00937
00938 void KFilePreviewGenerator::cancelPreviews()
00939 {
00940 d->killPreviewJobs();
00941 d->m_cutItemsCache.clear();
00942 d->m_pendingItems.clear();
00943 d->m_dispatchedItems.clear();
00944 }
00945
00946 void KFilePreviewGenerator::setEnabledPlugins(const QStringList& plugins)
00947 {
00948 d->m_enabledPlugins = plugins;
00949 }
00950
00951 QStringList KFilePreviewGenerator::enabledPlugins() const
00952 {
00953 return d->m_enabledPlugins;
00954 }
00955
00956 #include "kfilepreviewgenerator.moc"