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"