File indexing completed on 2024-05-12 04:19:40

0001 // vim: set tabstop=4 shiftwidth=4 expandtab:
0002 /*
0003 Gwenview: an image viewer
0004 Copyright 2011 Aurélien Gâteau <agateau@kde.org>
0005 
0006 This program is free software; you can redistribute it and/or
0007 modify it under the terms of the GNU General Public License
0008 as published by the Free Software Foundation; either version 2
0009 of the License, or (at your option) any later version.
0010 
0011 This program is distributed in the hope that it will be useful,
0012 but WITHOUT ANY WARRANTY; without even the implied warranty of
0013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014 GNU General Public License for more details.
0015 
0016 You should have received a copy of the GNU General Public License
0017 along with this program; if not, write to the Free Software
0018 Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA.
0019 
0020 */
0021 // Self
0022 #include "rasterimageview.h"
0023 
0024 // Local
0025 #include "alphabackgrounditem.h"
0026 #include "gwenview_lib_debug.h"
0027 #include "rasterimageitem.h"
0028 #include <lib/cms/cmsprofile.h>
0029 #include <lib/documentview/abstractrasterimageviewtool.h>
0030 #include <lib/gvdebug.h>
0031 #include <lib/paintutils.h>
0032 
0033 // KF
0034 
0035 // Qt
0036 #include <QGraphicsSceneMouseEvent>
0037 #include <QPainter>
0038 #include <QPointer>
0039 
0040 #include <QCryptographicHash>
0041 
0042 namespace Gwenview
0043 {
0044 /*
0045  * We need the tools to be painted on top of the image. However, since we are
0046  * using RasterImageItem as a child of this item, the image gets painted on
0047  * top of this item. To fix that, this custom item is stacked after the image
0048  * item and will paint the tools, which will draw it on top of the image.
0049  */
0050 class ToolPainter : public QGraphicsItem
0051 {
0052 public:
0053     ToolPainter(AbstractRasterImageViewTool *tool, QGraphicsItem *parent = nullptr)
0054         : QGraphicsItem(parent)
0055         , mTool(tool)
0056     {
0057     }
0058 
0059     void paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/) override
0060     {
0061         if (mTool) {
0062             mTool->paint(painter);
0063         }
0064     }
0065 
0066     QRectF boundingRect() const override
0067     {
0068         return parentItem()->boundingRect();
0069     }
0070 
0071     QPointer<AbstractRasterImageViewTool> mTool;
0072 };
0073 
0074 struct RasterImageViewPrivate {
0075     RasterImageViewPrivate(RasterImageView *qq)
0076         : q(qq)
0077     {
0078     }
0079 
0080     RasterImageView *q = nullptr;
0081 
0082     RasterImageItem *mImageItem = nullptr;
0083     ToolPainter *mToolItem = nullptr;
0084 
0085     QPointer<AbstractRasterImageViewTool> mTool;
0086 
0087     void startAnimationIfNecessary()
0088     {
0089         if (q->document() && q->isVisible()) {
0090             q->document()->startAnimation();
0091         }
0092     }
0093 
0094     void adjustItemPosition()
0095     {
0096         mImageItem->setPos((q->imageOffset() - q->scrollPos()).toPoint());
0097         q->update();
0098     }
0099 };
0100 
0101 RasterImageView::RasterImageView(QGraphicsItem *parent)
0102     : AbstractImageView(parent)
0103     , d(new RasterImageViewPrivate{this})
0104 {
0105     d->mImageItem = new RasterImageItem{this};
0106 
0107     // Clip this item so we only render the visible part of the image when
0108     // zoomed or when viewing a large image.
0109     setFlag(QGraphicsItem::ItemClipsChildrenToShape);
0110 }
0111 
0112 RasterImageView::~RasterImageView()
0113 {
0114     if (d->mTool) {
0115         d->mTool.data()->toolDeactivated();
0116     }
0117 
0118     delete d;
0119 }
0120 
0121 void RasterImageView::setRenderingIntent(const RenderingIntent::Enum &renderingIntent)
0122 {
0123     d->mImageItem->setRenderingIntent(renderingIntent);
0124 }
0125 
0126 void RasterImageView::resetMonitorICC()
0127 {
0128     update();
0129 }
0130 
0131 void RasterImageView::loadFromDocument()
0132 {
0133     Document::Ptr doc = document();
0134     if (!doc) {
0135         return;
0136     }
0137 
0138     connect(doc.data(), &Document::metaInfoLoaded, this, &RasterImageView::slotDocumentMetaInfoLoaded);
0139     connect(doc.data(), &Document::isAnimatedUpdated, this, &RasterImageView::slotDocumentIsAnimatedUpdated);
0140     connect(doc.data(), &Document::imageRectUpdated, this, [this]() {
0141         d->mImageItem->updateCache();
0142     });
0143 
0144     const Document::LoadingState state = doc->loadingState();
0145     if (state == Document::MetaInfoLoaded || state == Document::Loaded) {
0146         slotDocumentMetaInfoLoaded();
0147     }
0148 }
0149 
0150 void RasterImageView::slotDocumentMetaInfoLoaded()
0151 {
0152     if (document()->size().isValid() && document()->image().format() != QImage::Format_Invalid) {
0153         QMetaObject::invokeMethod(this, &RasterImageView::finishSetDocument, Qt::QueuedConnection);
0154     } else {
0155         // Could not retrieve image size from meta info, we need to load the
0156         // full image now.
0157         connect(document().data(), &Document::loaded, this, &RasterImageView::finishSetDocument);
0158         document()->startLoadingFullImage();
0159     }
0160 }
0161 
0162 void RasterImageView::finishSetDocument()
0163 {
0164     GV_RETURN_IF_FAIL(document()->size().isValid());
0165 
0166     if (zoomToFit()) {
0167         // Force the update otherwise if computeZoomToFit() returns 1, setZoom()
0168         // will think zoom has not changed and won't update the image
0169         setZoom(computeZoomToFit(), QPointF(-1, -1), ForceUpdate);
0170     } else if (zoomToFill()) {
0171         setZoom(computeZoomToFill(), QPointF(-1, -1), ForceUpdate);
0172     } else {
0173         onZoomChanged();
0174     }
0175 
0176     applyPendingScrollPos();
0177     d->startAnimationIfNecessary();
0178     update();
0179 
0180     d->mImageItem->updateCache();
0181 
0182     backgroundItem()->setVisible(true);
0183 
0184     Q_EMIT completed();
0185 }
0186 
0187 void RasterImageView::slotDocumentIsAnimatedUpdated()
0188 {
0189     d->startAnimationIfNecessary();
0190 }
0191 
0192 void RasterImageView::onZoomChanged()
0193 {
0194     d->adjustItemPosition();
0195 }
0196 
0197 void RasterImageView::onImageOffsetChanged()
0198 {
0199     d->adjustItemPosition();
0200 }
0201 
0202 void RasterImageView::onScrollPosChanged(const QPointF &oldPos)
0203 {
0204     Q_UNUSED(oldPos);
0205     d->adjustItemPosition();
0206 }
0207 
0208 void RasterImageView::setCurrentTool(AbstractRasterImageViewTool *tool)
0209 {
0210     if (d->mTool) {
0211         d->mTool.data()->toolDeactivated();
0212         d->mTool.data()->deleteLater();
0213         delete d->mToolItem;
0214     }
0215 
0216     // Go back to default cursor when tool is deactivated. We need to call this here and
0217     // not further below in case toolActivated wants to set its own new cursor afterwards.
0218     updateCursor();
0219 
0220     d->mTool = tool;
0221     if (d->mTool) {
0222         d->mTool.data()->toolActivated();
0223         d->mToolItem = new ToolPainter{d->mTool, this};
0224     }
0225     Q_EMIT currentToolChanged(tool);
0226     update();
0227 }
0228 
0229 AbstractRasterImageViewTool *RasterImageView::currentTool() const
0230 {
0231     return d->mTool.data();
0232 }
0233 
0234 void RasterImageView::mousePressEvent(QGraphicsSceneMouseEvent *event)
0235 {
0236     if (d->mTool) {
0237         d->mTool.data()->mousePressEvent(event);
0238         if (event->isAccepted()) {
0239             return;
0240         }
0241     }
0242     AbstractImageView::mousePressEvent(event);
0243 }
0244 
0245 void RasterImageView::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
0246 {
0247     if (d->mTool) {
0248         d->mTool.data()->mouseDoubleClickEvent(event);
0249         if (event->isAccepted()) {
0250             return;
0251         }
0252     }
0253     AbstractImageView::mouseDoubleClickEvent(event);
0254 }
0255 
0256 void RasterImageView::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
0257 {
0258     if (d->mTool) {
0259         d->mTool.data()->mouseMoveEvent(event);
0260         if (event->isAccepted()) {
0261             return;
0262         }
0263     }
0264     AbstractImageView::mouseMoveEvent(event);
0265 }
0266 
0267 void RasterImageView::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
0268 {
0269     if (d->mTool) {
0270         d->mTool.data()->mouseReleaseEvent(event);
0271         if (event->isAccepted()) {
0272             return;
0273         }
0274     }
0275     AbstractImageView::mouseReleaseEvent(event);
0276 }
0277 
0278 void RasterImageView::wheelEvent(QGraphicsSceneWheelEvent *event)
0279 {
0280     if (d->mTool) {
0281         d->mTool.data()->wheelEvent(event);
0282         if (event->isAccepted()) {
0283             return;
0284         }
0285     }
0286     AbstractImageView::wheelEvent(event);
0287 }
0288 
0289 void RasterImageView::keyPressEvent(QKeyEvent *event)
0290 {
0291     if (d->mTool) {
0292         d->mTool.data()->keyPressEvent(event);
0293         if (event->isAccepted()) {
0294             return;
0295         }
0296     }
0297     AbstractImageView::keyPressEvent(event);
0298 }
0299 
0300 void RasterImageView::keyReleaseEvent(QKeyEvent *event)
0301 {
0302     if (d->mTool) {
0303         d->mTool.data()->keyReleaseEvent(event);
0304         if (event->isAccepted()) {
0305             return;
0306         }
0307     }
0308     AbstractImageView::keyReleaseEvent(event);
0309 }
0310 
0311 void RasterImageView::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
0312 {
0313     if (d->mTool) {
0314         d->mTool.data()->hoverMoveEvent(event);
0315         if (event->isAccepted()) {
0316             return;
0317         }
0318     }
0319     AbstractImageView::hoverMoveEvent(event);
0320 }
0321 
0322 } // namespace
0323 
0324 #include "moc_rasterimageview.cpp"