]> cloud.milkyroute.net Git - dolphin.git/blob - src/panels/information/pixmapviewer.cpp
Detect animated format using mimeType instead of file path
[dolphin.git] / src / panels / information / pixmapviewer.cpp
1 /***************************************************************************
2 * Copyright (C) 2006 by Peter Penz <peter.penz19@gmail.com> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program 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 *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
18 ***************************************************************************/
19
20 #include "pixmapviewer.h"
21
22 #include <KIconLoader>
23
24 #include <QImageReader>
25 #include <QMovie>
26 #include <QPainter>
27 #include <QStyle>
28
29 PixmapViewer::PixmapViewer(QWidget* parent, Transition transition) :
30 QWidget(parent),
31 m_animatedImage(nullptr),
32 m_transition(transition),
33 m_animationStep(0),
34 m_sizeHint(),
35 m_hasAnimatedImage(false)
36 {
37 setMinimumWidth(KIconLoader::SizeEnormous);
38 setMinimumHeight(KIconLoader::SizeEnormous);
39
40 m_animation.setDuration(150);
41 m_animation.setCurveShape(QTimeLine::LinearCurve);
42
43 if (m_transition != NoTransition) {
44 connect(&m_animation, &QTimeLine::valueChanged, this, QOverload<>::of(&PixmapViewer::update));
45 connect(&m_animation, &QTimeLine::finished, this, &PixmapViewer::checkPendingPixmaps);
46 }
47 }
48
49 PixmapViewer::~PixmapViewer()
50 {
51 }
52
53 void PixmapViewer::setPixmap(const QPixmap& pixmap)
54 {
55 if (pixmap.isNull()) {
56 return;
57 }
58
59 // Avoid flicker with static pixmap if an animated image is running
60 if (m_animatedImage && m_animatedImage->state() == QMovie::Running) {
61 return;
62 }
63
64 if ((m_transition != NoTransition) && (m_animation.state() == QTimeLine::Running)) {
65 m_pendingPixmaps.enqueue(pixmap);
66 if (m_pendingPixmaps.count() > 5) {
67 // don't queue more than 5 pixmaps
68 m_pendingPixmaps.takeFirst();
69 }
70 return;
71 }
72
73 m_oldPixmap = m_pixmap.isNull() ? pixmap : m_pixmap;
74 m_pixmap = pixmap;
75 update();
76
77 const bool animateTransition = (m_transition != NoTransition) &&
78 (m_pixmap.size() != m_oldPixmap.size());
79 if (animateTransition) {
80 m_animation.start();
81 } else if (m_hasAnimatedImage) {
82 // If there is no transition animation but an animatedImage
83 // and it is not already running, start animating now
84 if (m_animatedImage->state() != QMovie::Running) {
85 m_animatedImage->setScaledSize(m_pixmap.size());
86 m_animatedImage->start();
87 }
88 }
89 }
90
91 void PixmapViewer::setSizeHint(const QSize& size)
92 {
93 if (m_animatedImage && size != m_sizeHint) {
94 m_animatedImage->stop();
95 }
96
97 m_sizeHint = size;
98 updateGeometry();
99 }
100
101 QSize PixmapViewer::sizeHint() const
102 {
103 return m_sizeHint;
104 }
105
106 void PixmapViewer::setAnimatedImageFileName(const QString &fileName)
107 {
108 if (!m_animatedImage) {
109 m_animatedImage = new QMovie(this);
110 connect(m_animatedImage, &QMovie::frameChanged, this, &PixmapViewer::updateAnimatedImageFrame);
111 }
112
113 if (m_animatedImage->fileName() != fileName) {
114 m_animatedImage->stop();
115 m_animatedImage->setFileName(fileName);
116 }
117
118 m_hasAnimatedImage = m_animatedImage->isValid() && (m_animatedImage->frameCount() > 1);
119 }
120
121
122 QString PixmapViewer::animatedImageFileName() const
123 {
124 if (!m_hasAnimatedImage) {
125 return QString();
126 }
127 return m_animatedImage->fileName();
128 }
129
130 void PixmapViewer::paintEvent(QPaintEvent* event)
131 {
132 QWidget::paintEvent(event);
133
134 QPainter painter(this);
135
136 if (m_transition != NoTransition || (m_hasAnimatedImage && m_animatedImage->state() != QMovie::Running)) {
137 const float value = m_animation.currentValue();
138 const int scaledWidth = static_cast<int>((m_oldPixmap.width() * (1.0 - value)) + (m_pixmap.width() * value));
139 const int scaledHeight = static_cast<int>((m_oldPixmap.height() * (1.0 - value)) + (m_pixmap.height() * value));
140
141 const bool useOldPixmap = (m_transition == SizeTransition) &&
142 (m_oldPixmap.width() > m_pixmap.width());
143 const QPixmap& largePixmap = useOldPixmap ? m_oldPixmap : m_pixmap;
144 if (!largePixmap.isNull()) {
145 const QPixmap scaledPixmap = largePixmap.scaled(scaledWidth,
146 scaledHeight,
147 Qt::IgnoreAspectRatio,
148 Qt::FastTransformation);
149
150 style()->drawItemPixmap(&painter, rect(), Qt::AlignCenter, scaledPixmap);
151 }
152 } else {
153 style()->drawItemPixmap(&painter, rect(), Qt::AlignCenter, m_pixmap);
154 }
155 }
156
157 void PixmapViewer::checkPendingPixmaps()
158 {
159 if (!m_pendingPixmaps.isEmpty()) {
160 QPixmap pixmap = m_pendingPixmaps.dequeue();
161 m_oldPixmap = m_pixmap.isNull() ? pixmap : m_pixmap;
162 m_pixmap = pixmap;
163 update();
164 m_animation.start();
165 } else if (m_hasAnimatedImage) {
166 m_animatedImage->setScaledSize(m_pixmap.size());
167 m_animatedImage->start();
168 } else {
169 m_oldPixmap = m_pixmap;
170 }
171 }
172
173 void PixmapViewer::updateAnimatedImageFrame()
174 {
175 Q_ASSERT (m_animatedImage);
176
177 m_pixmap = m_animatedImage->currentPixmap();
178 update();
179 }
180
181 void PixmapViewer::stopAnimatedImage()
182 {
183 if (m_hasAnimatedImage) {
184 m_animatedImage->stop();
185 m_hasAnimatedImage = false;
186 }
187 }
188
189 bool PixmapViewer::isAnimatedMimeType(const QString &mimeType)
190 {
191 const QList<QByteArray> imageFormats = QImageReader::imageFormatsForMimeType(mimeType.toUtf8());
192 return std::any_of(imageFormats.begin(), imageFormats.end(),
193 [](const QByteArray &format){ return QMovie::supportedFormats().contains(format); });
194 }