kdelibs/kio/kfile/kimagefilepreview.cpp

315 lines
8.7 KiB
C++
Raw Normal View History

2014-11-13 01:04:59 +02:00
/*
* This file is part of the KDE project
* Copyright (C) 2001 Martin R. Jones <mjones@kde.org>
* 2001 Carsten Pfeiffer <pfeiffer@kde.org>
* 2008 Rafael Fernández López <ereslibre@kde.org>
*
* You can Freely distribute this program under the GNU Library General Public
* License. See the file "COPYING" for the exact licensing terms.
*/
#include "kimagefilepreview.h"
#include <QtGui/QLayout>
#include <QtGui/QLabel>
#include <QtGui/QPainter>
#include <QtGui/QComboBox>
#include <QtGui/QCheckBox>
#include <QtGui/qevent.h>
2014-11-13 01:04:59 +02:00
#include <QtCore/QTimer>
#include <QtCore/QTimeLine>
#include <kglobalsettings.h>
#include <kconfig.h>
#include <kiconloader.h>
#include <kdebug.h>
#include <klocale.h>
#include <kfileitem.h>
#include <kpixmapsequenceoverlaypainter.h>
2014-11-13 01:04:59 +02:00
#include <kio/previewjob.h>
#include <kconfiggroup.h>
#include <config-kfile.h>
/**** KImageFilePreview ****/
class KImageFilePreview::KImageFilePreviewPrivate
{
public:
KImageFilePreviewPrivate()
: m_job(nullptr),
clear(true),
imageLabel(nullptr),
busyPainter(nullptr)
2014-11-13 01:04:59 +02:00
{
m_timeLine = new QTimeLine(150);
m_timeLine->setCurveShape(QTimeLine::EaseInCurve);
m_timeLine->setDirection(QTimeLine::Forward);
m_timeLine->setFrameRange(0, 100);
}
~KImageFilePreviewPrivate()
{
delete m_timeLine;
}
void _k_slotResult(KJob*);
void _k_slotFailed(const KFileItem&);
void _k_slotStepAnimation(int frame);
void _k_slotFinished();
void _k_slotActuallyClear();
2014-11-13 01:04:59 +02:00
KUrl currentURL;
KUrl lastShownURL;
QLabel *imageLabel;
KPixmapSequenceOverlayPainter *busyPainter;
2014-11-13 01:04:59 +02:00
KIO::PreviewJob *m_job;
QTimeLine *m_timeLine;
QPixmap m_pmCurrent;
QPixmap m_pmTransition;
float m_pmCurrentOpacity;
float m_pmTransitionOpacity;
bool clear;
};
KImageFilePreview::KImageFilePreview(QWidget *parent)
: KPreviewWidgetBase(parent),
d(new KImageFilePreviewPrivate())
2014-11-13 01:04:59 +02:00
{
QVBoxLayout *vb = new QVBoxLayout(this);
vb->setMargin(0);
2014-11-13 01:04:59 +02:00
d->imageLabel = new QLabel(this);
d->imageLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
d->imageLabel->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
vb->addWidget(d->imageLabel);
d->busyPainter = new KPixmapSequenceOverlayPainter(this);
d->busyPainter->setWidget(d->imageLabel);
2014-11-13 01:04:59 +02:00
setSupportedMimeTypes(KIO::PreviewJob::supportedMimeTypes());
setMinimumWidth(50);
connect(
d->m_timeLine, SIGNAL(frameChanged(int)),
this, SLOT(_k_slotStepAnimation(int))
);
connect(
d->m_timeLine, SIGNAL(finished()),
this, SLOT(_k_slotFinished())
);
2014-11-13 01:04:59 +02:00
}
KImageFilePreview::~KImageFilePreview()
{
if (d->m_job) {
d->m_job->kill();
}
delete d;
}
void KImageFilePreview::showPreview()
{
// Pass a copy since clearPreview() will clear currentURL
KUrl url = d->currentURL;
showPreview(url, true);
2014-11-13 01:04:59 +02:00
}
// called via KPreviewWidgetBase interface
void KImageFilePreview::showPreview(const KUrl& url)
2014-11-13 01:04:59 +02:00
{
showPreview(url, false);
2014-11-13 01:04:59 +02:00
}
void KImageFilePreview::showPreview(const KUrl &url, bool force)
2014-11-13 01:04:59 +02:00
{
if (!url.isValid() ||
(d->lastShownURL.isValid() &&
url.equals(d->lastShownURL, KUrl::CompareWithoutTrailingSlash) &&
d->currentURL.isValid())) {
2014-11-13 01:04:59 +02:00
return;
}
2014-11-13 01:04:59 +02:00
d->clear = false;
d->currentURL = url;
d->lastShownURL = url;
d->busyPainter->start();
2014-11-13 01:04:59 +02:00
int w = d->imageLabel->contentsRect().width() - 4;
int h = d->imageLabel->contentsRect().height() - 4;
if (d->m_job) {
disconnect(
d->m_job, SIGNAL(result(KJob*)),
this, SLOT(_k_slotResult(KJob*))
);
disconnect(
d->m_job, SIGNAL(gotPreview(const KFileItem&, const QPixmap& )),
this, SLOT(gotPreview(KFileItem,QPixmap))
);
disconnect(
d->m_job, SIGNAL(failed(KFileItem)),
this, SLOT(_k_slotFailed(KFileItem))
);
2014-11-13 01:04:59 +02:00
d->m_job->kill();
}
d->m_job = createJob(url, w, h);
if (force) { // explicitly requested previews shall always be generated!
2014-11-13 01:04:59 +02:00
d->m_job->setIgnoreMaximumSize(true);
}
2014-11-13 01:04:59 +02:00
connect(
d->m_job, SIGNAL(result(KJob*)),
this, SLOT(_k_slotResult(KJob*))
);
connect(
d->m_job, SIGNAL(gotPreview(const KFileItem&,const QPixmap&)),
this, SLOT(gotPreview(KFileItem,QPixmap))
);
connect(
d->m_job, SIGNAL(failed(KFileItem)),
this, SLOT(_k_slotFailed(KFileItem))
);
2014-11-13 01:04:59 +02:00
}
void KImageFilePreview::resizeEvent(QResizeEvent *)
2014-11-13 01:04:59 +02:00
{
clearPreview();
d->currentURL = KUrl(); // force this to actually happen
showPreview( d->lastShownURL );
}
QSize KImageFilePreview::sizeHint() const
{
return QSize(100, 200);
2014-11-13 01:04:59 +02:00
}
KIO::PreviewJob * KImageFilePreview::createJob(const KUrl& url, int w, int h)
2014-11-13 01:04:59 +02:00
{
if (url.isValid()) {
KFileItemList items;
items.append(KFileItem(KFileItem::Unknown, KFileItem::Unknown, url, true));
QStringList plugins = KIO::PreviewJob::availablePlugins();
KIO::PreviewJob *previewJob = KIO::filePreview(items, QSize(w, h), &plugins);
previewJob->setOverlayIconAlpha(0);
previewJob->setScaleType(KIO::PreviewJob::Scaled);
return previewJob;
} else {
return 0;
}
}
void KImageFilePreview::gotPreview(const KFileItem& item, const QPixmap& pm)
2014-11-13 01:04:59 +02:00
{
d->busyPainter->stop();
2014-11-13 01:04:59 +02:00
if (item.url() == d->currentURL) { // should always be the case
if (KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects) {
if (d->m_timeLine->state() == QTimeLine::Running) {
d->m_timeLine->setCurrentTime(0);
}
d->m_pmTransition = pm;
d->m_pmTransitionOpacity = 0;
d->m_pmCurrentOpacity = 1;
d->m_timeLine->setDirection(QTimeLine::Forward);
d->m_timeLine->start();
} else {
2014-11-13 01:04:59 +02:00
d->imageLabel->setPixmap(pm);
}
}
}
void KImageFilePreview::KImageFilePreviewPrivate::_k_slotFailed(const KFileItem& item)
2014-11-13 01:04:59 +02:00
{
if (item.isDir()) {
2014-11-13 01:04:59 +02:00
imageLabel->clear();
} else if (item.url() == currentURL) { // should always be the case
imageLabel->setPixmap(
SmallIcon("image-missing", KIconLoader::SizeLarge, KIconLoader::DisabledState)
);
}
2014-11-13 01:04:59 +02:00
}
void KImageFilePreview::KImageFilePreviewPrivate::_k_slotResult(KJob *job)
2014-11-13 01:04:59 +02:00
{
if (job == m_job) {
m_job = nullptr;
2014-11-13 01:04:59 +02:00
}
}
void KImageFilePreview::KImageFilePreviewPrivate::_k_slotStepAnimation(int frame)
2014-11-13 01:04:59 +02:00
{
Q_UNUSED(frame)
QPixmap pm(QSize(qMax(m_pmCurrent.size().width(), m_pmTransition.size().width()),
qMax(m_pmCurrent.size().height(), m_pmTransition.size().height())));
pm.fill(Qt::transparent);
QPainter p(&pm);
p.setOpacity(m_pmCurrentOpacity);
//If we have a current pixmap
if (!m_pmCurrent.isNull())
p.drawPixmap(QPoint(((float) pm.size().width() - m_pmCurrent.size().width()) / 2.0,
((float) pm.size().height() - m_pmCurrent.size().height()) / 2.0), m_pmCurrent);
if (!m_pmTransition.isNull()) {
p.setOpacity(m_pmTransitionOpacity);
p.drawPixmap(QPoint(((float) pm.size().width() - m_pmTransition.size().width()) / 2.0,
((float) pm.size().height() - m_pmTransition.size().height()) / 2.0), m_pmTransition);
}
p.end();
imageLabel->setPixmap(pm);
m_pmCurrentOpacity = qMax(m_pmCurrentOpacity - 0.4, 0.0); // krazy:exclude=qminmax
m_pmTransitionOpacity = qMin(m_pmTransitionOpacity + 0.4, 1.0); //krazy:exclude=qminmax
}
void KImageFilePreview::KImageFilePreviewPrivate::_k_slotFinished()
{
m_pmCurrent = m_pmTransition;
m_pmTransitionOpacity = 0;
m_pmCurrentOpacity = 1;
m_pmTransition = QPixmap();
// The animation might have lost some frames. Be sure that if the last one
// was dropped, the last image shown is the opaque one.
imageLabel->setPixmap(m_pmCurrent);
clear = false;
}
void KImageFilePreview::clearPreview()
{
if (d->m_job) {
d->m_job->kill();
d->m_job = nullptr;
2014-11-13 01:04:59 +02:00
}
if (d->clear || d->m_timeLine->state() == QTimeLine::Running) {
return;
}
if (KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects) {
d->m_pmTransition = QPixmap();
//If we add a previous preview then we run the animation
if (!d->m_pmCurrent.isNull()) {
d->m_timeLine->setCurrentTime(0);
d->m_timeLine->setDirection(QTimeLine::Backward);
d->m_timeLine->start();
}
d->currentURL = KUrl();
d->clear = true;
} else {
2014-11-13 01:04:59 +02:00
d->imageLabel->clear();
}
}
#include "moc_kimagefilepreview.cpp"