diff --git a/svgpart.h b/svgpart.h --- a/svgpart.h +++ b/svgpart.h @@ -21,6 +21,8 @@ // KF #include +// Qt +#include class QGraphicsScene; class QGraphicsSvgItem; @@ -38,21 +40,33 @@ protected: bool openFile() override; + bool doOpenStream(const QString& mimeType) override; + bool doWriteStream(const QByteArray& data) override; + bool doCloseStream() override; private Q_SLOTS: void zoomActualSize(); void zoomIn(); void zoomOut(); + void delayedRestoreViewStateOnReload(); + private: qreal zoom() const; void setZoom(qreal value); + void restoreViewStateOnReload(); private: QGraphicsScene* mScene; QGraphicsView* mView; QGraphicsSvgItem* mItem; QSvgRenderer* mRenderer; + + QUrl mPreviousUrl; + qreal mPreviousZoom; + QPoint mPreviousScrollPosition; + + QByteArray mStreamedData; }; #endif /* SVGPART_H */ diff --git a/svgpart.cpp b/svgpart.cpp --- a/svgpart.cpp +++ b/svgpart.cpp @@ -30,6 +30,9 @@ #include #include #include +#include +#include +#include static KAboutData createAboutData() @@ -75,12 +78,65 @@ mScene->addItem(mItem); // we reuse the scene, whose scenerect though is not properly resetable, so ensure up-to-date one mScene->setSceneRect(mItem->boundingRect()); + + restoreViewStateOnReload(); + + return true; +} + + +bool SvgPart::doOpenStream(const QString& mimeType) +{ + auto mime = QMimeDatabase().mimeTypeForName(mimeType); + if (!mime.inherits(QStringLiteral("image/svg+xml")) + && !mime.inherits(QStringLiteral("image/svg+xml-compressed"))) { + return false; + } + + mStreamedData.clear(); + + return true; +} + + +bool SvgPart::doWriteStream(const QByteArray& data) +{ + mStreamedData.append(data); + return true; +} + + +bool SvgPart::doCloseStream() +{ + // too bad QSvgRenderer supports QXmlStreamReader, but not its incremental parsing + if (!mRenderer->load(mStreamedData)) { + mStreamedData.clear(); + return false; + } + + mStreamedData.clear(); + mItem = new QGraphicsSvgItem(); + mItem->setSharedRenderer(mRenderer); + mScene->addItem(mItem); + // we reuse the scene, whose scenerect though is not properly resetable, so ensure up-to-date one + mScene->setSceneRect(mItem->boundingRect()); + + restoreViewStateOnReload(); + return true; } bool SvgPart::closeUrl() { + // protect against repeated call if already closed + const auto currentUrl = url(); + if (currentUrl.isValid()) { + mPreviousUrl = currentUrl; + mPreviousZoom = zoom(); + mPreviousScrollPosition = QPoint(mView->horizontalScrollBar()->value(), mView->verticalScrollBar()->value()); + } + mView->resetMatrix(); mView->resetTransform(); // cannot reset the rect completely, as a null QRectF is ignored @@ -94,6 +150,27 @@ } +void SvgPart::restoreViewStateOnReload() +{ + if (url() == mPreviousUrl) { + // ideally the scrollstate would be restored here, but at this point in time + // the view has not yet been updated to the scene and is a wrong size, + // so setting the scrollbars now will not have any effect + // TODO: this results in flickering, needs to find a better way to hook into + // updating of view state to new content before the first rendering is done + QTimer::singleShot(0, this, &SvgPart::delayedRestoreViewStateOnReload); + } +} + + +void SvgPart::delayedRestoreViewStateOnReload() +{ + setZoom(mPreviousZoom); + mView->horizontalScrollBar()->setValue(mPreviousScrollPosition.x()); + mView->verticalScrollBar()->setValue(mPreviousScrollPosition.y()); +} + + void SvgPart::zoomIn() { setZoom(zoom() * 2);