File indexing completed on 2024-05-12 03:47:29

0001 /*
0002     File                 : DatapickerPoint.cpp
0003     Project              : LabPlot
0004     Description          : Graphic Item for coordinate points of Datapicker
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2015 Ankit Wagadre <wagadre.ankit@gmail.com>
0007     SPDX-FileCopyrightText: 2015-2021 Alexander Semke <alexander.semke@web.de>
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "DatapickerPoint.h"
0012 #include "DatapickerPointPrivate.h"
0013 #include "backend/datapicker/DatapickerCurve.h"
0014 #include "backend/lib/XmlStreamReader.h"
0015 #include "backend/lib/commandtemplates.h"
0016 #include "backend/worksheet/Worksheet.h"
0017 #include "backend/worksheet/plots/cartesian/Symbol.h"
0018 
0019 #include <QGraphicsScene>
0020 #include <QGraphicsSceneMouseEvent>
0021 #include <QMenu>
0022 #include <QPainter>
0023 
0024 #include <KConfig>
0025 #include <KConfigGroup>
0026 #include <KLocalizedString>
0027 
0028 /**
0029  * \class ErrorBarItem
0030  * \brief A customizable error-bar for DatapickerPoint.
0031  */
0032 
0033 ErrorBarItem::ErrorBarItem(DatapickerPoint* parent, ErrorBarType type)
0034     : QGraphicsRectItem(parent->graphicsItem())
0035     , barLineItem(new QGraphicsLineItem(parent->graphicsItem()))
0036     , m_type(type)
0037     , m_parentItem(parent) {
0038     setFlag(QGraphicsItem::ItemIsMovable);
0039     setFlag(QGraphicsItem::ItemIsSelectable);
0040     setFlag(QGraphicsItem::ItemSendsGeometryChanges);
0041     initRect();
0042     setAcceptHoverEvents(true);
0043 }
0044 
0045 void ErrorBarItem::initRect() {
0046     QRectF xBarRect(-0.15, -0.5, 0.3, 1);
0047     QRectF yBarRect(-0.5, -0.15, 1, 0.3);
0048 
0049     if (m_type == ErrorBarType::PlusDeltaX || m_type == ErrorBarType::MinusDeltaX)
0050         m_rect = xBarRect;
0051     else
0052         m_rect = yBarRect;
0053 }
0054 
0055 void ErrorBarItem::setPosition(QPointF position) {
0056     setPos(position);
0057     barLineItem->setLine(0, 0, position.x(), position.y());
0058 }
0059 
0060 void ErrorBarItem::setRectSize(qreal size) {
0061     QTransform matrix;
0062     matrix.scale(size, size);
0063     setRect(matrix.mapRect(m_rect));
0064 }
0065 
0066 void ErrorBarItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) {
0067     if (m_type == ErrorBarType::PlusDeltaX)
0068         m_parentItem->setPlusDeltaXPos(pos());
0069     else if (m_type == ErrorBarType::MinusDeltaX)
0070         m_parentItem->setMinusDeltaXPos(pos());
0071     else if (m_type == ErrorBarType::PlusDeltaY)
0072         m_parentItem->setPlusDeltaYPos(pos());
0073     else if (m_type == ErrorBarType::MinusDeltaY)
0074         m_parentItem->setMinusDeltaYPos(pos());
0075 
0076     QGraphicsItem::mouseReleaseEvent(event);
0077 }
0078 
0079 void ErrorBarItem::hoverEnterEvent(QGraphicsSceneHoverEvent*) {
0080     if (m_type == ErrorBarType::PlusDeltaX || m_type == ErrorBarType::MinusDeltaX)
0081         setCursor(Qt::SizeHorCursor);
0082     else
0083         setCursor(Qt::SizeVerCursor);
0084 }
0085 
0086 QVariant ErrorBarItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant& value) {
0087     if (change == QGraphicsItem::ItemPositionChange) {
0088         QPointF newPos = value.toPointF();
0089         if (m_type == ErrorBarType::PlusDeltaX || m_type == ErrorBarType::MinusDeltaX) {
0090             newPos.setY(0);
0091             barLineItem->setLine(0, 0, newPos.x(), 0);
0092         } else {
0093             newPos.setX(0);
0094             barLineItem->setLine(0, 0, 0, newPos.y());
0095         }
0096         return QGraphicsRectItem::itemChange(change, newPos);
0097     }
0098 
0099     return QGraphicsRectItem::itemChange(change, value);
0100 }
0101 
0102 /**
0103  * \class Datapicker-Point
0104  * \brief A customizable symbol supports error-bars.
0105  *
0106  * The datapicker-Point is aligned relative to the specified position.
0107  * The position can be either specified by mouse events or by providing the
0108  * x- and y- coordinates in parent's coordinate system, or by specifying one
0109  * of the predefined position flags (\c HorizontalPosition, \c VerticalPosition).
0110  */
0111 
0112 DatapickerPoint::DatapickerPoint(const QString& name)
0113     : AbstractAspect(name, AspectType::DatapickerPoint)
0114     , d_ptr(new DatapickerPointPrivate(this)) {
0115     init();
0116 }
0117 
0118 DatapickerPoint::DatapickerPoint(const QString& name, DatapickerPointPrivate* dd)
0119     : AbstractAspect(name, AspectType::DatapickerPoint)
0120     , d_ptr(dd) {
0121     init();
0122 }
0123 
0124 // no need to delete the d-pointer here - it inherits from QGraphicsItem
0125 // and is deleted during the cleanup in QGraphicsScene
0126 DatapickerPoint::~DatapickerPoint() = default;
0127 
0128 void DatapickerPoint::init() {
0129     Q_D(DatapickerPoint);
0130 
0131     KConfig config;
0132     KConfigGroup group;
0133     group = config.group(QStringLiteral("DatapickerPoint"));
0134     d->position.setX(group.readEntry(QStringLiteral("PositionXValue"), Worksheet::convertToSceneUnits(1, Worksheet::Unit::Centimeter)));
0135     d->position.setY(group.readEntry(QStringLiteral("PositionYValue"), Worksheet::convertToSceneUnits(1, Worksheet::Unit::Centimeter)));
0136     d->plusDeltaXPos = group.readEntry(QStringLiteral("PlusDeltaXPos"), QPointF(30, 0));
0137     d->minusDeltaXPos = group.readEntry(QStringLiteral("MinusDeltaXPos"), QPointF(-30, 0));
0138     d->plusDeltaYPos = group.readEntry(QStringLiteral("PlusDeltaYPos"), QPointF(0, -30));
0139     d->minusDeltaYPos = group.readEntry(QStringLiteral("MinusDeltaYPos"), QPointF(0, 30));
0140 }
0141 
0142 void DatapickerPoint::initErrorBar(DatapickerCurve::Errors errors) {
0143     if (m_errorBarItemList.isEmpty() && errors.x == DatapickerCurve::ErrorType::NoError && errors.y == DatapickerCurve::ErrorType::NoError)
0144         return; // no need to update
0145     m_errorBarItemList.clear();
0146     if (errors.x != DatapickerCurve::ErrorType::NoError) {
0147         auto* plusDeltaXItem = new ErrorBarItem(this, ErrorBarItem::ErrorBarType::PlusDeltaX);
0148         plusDeltaXItem->setPosition(plusDeltaXPos());
0149         connect(this, &DatapickerPoint::plusDeltaXPosChanged, plusDeltaXItem, &ErrorBarItem::setPosition);
0150 
0151         auto* minusDeltaXItem = new ErrorBarItem(this, ErrorBarItem::ErrorBarType::MinusDeltaX);
0152         minusDeltaXItem->setPosition(minusDeltaXPos());
0153         connect(this, &DatapickerPoint::minusDeltaXPosChanged, minusDeltaXItem, &ErrorBarItem::setPosition);
0154 
0155         m_errorBarItemList << plusDeltaXItem << minusDeltaXItem;
0156     }
0157 
0158     if (errors.y != DatapickerCurve::ErrorType::NoError) {
0159         auto* plusDeltaYItem = new ErrorBarItem(this, ErrorBarItem::ErrorBarType::PlusDeltaY);
0160         plusDeltaYItem->setPosition(plusDeltaYPos());
0161         connect(this, &DatapickerPoint::plusDeltaYPosChanged, plusDeltaYItem, &ErrorBarItem::setPosition);
0162 
0163         auto* minusDeltaYItem = new ErrorBarItem(this, ErrorBarItem::ErrorBarType::MinusDeltaY);
0164         minusDeltaYItem->setPosition(minusDeltaYPos());
0165         connect(this, &DatapickerPoint::minusDeltaYPosChanged, minusDeltaYItem, &ErrorBarItem::setPosition);
0166 
0167         m_errorBarItemList << plusDeltaYItem << minusDeltaYItem;
0168     }
0169 
0170     retransform();
0171 }
0172 
0173 /*!
0174     Returns an icon to be used in the project explorer.
0175 */
0176 QIcon DatapickerPoint::icon() const {
0177     return QIcon::fromTheme(QStringLiteral("draw-cross"));
0178 }
0179 
0180 QMenu* DatapickerPoint::createContextMenu() {
0181     QMenu* menu = AbstractAspect::createContextMenu();
0182     return menu;
0183 }
0184 
0185 QGraphicsItem* DatapickerPoint::graphicsItem() const {
0186     return d_ptr;
0187 }
0188 
0189 void DatapickerPoint::setParentGraphicsItem(QGraphicsItem* item) {
0190     Q_D(DatapickerPoint);
0191     d->setParentItem(item);
0192 }
0193 
0194 void DatapickerPoint::retransform() {
0195     Q_D(DatapickerPoint);
0196     d->retransform();
0197 }
0198 
0199 /* ============================ getter methods ================= */
0200 // point
0201 BASIC_SHARED_D_READER_IMPL(DatapickerPoint, QPointF, position, position)
0202 // error-bar
0203 BASIC_SHARED_D_READER_IMPL(DatapickerPoint, QPointF, plusDeltaXPos, plusDeltaXPos)
0204 BASIC_SHARED_D_READER_IMPL(DatapickerPoint, QPointF, minusDeltaXPos, minusDeltaXPos)
0205 BASIC_SHARED_D_READER_IMPL(DatapickerPoint, QPointF, plusDeltaYPos, plusDeltaYPos)
0206 BASIC_SHARED_D_READER_IMPL(DatapickerPoint, QPointF, minusDeltaYPos, minusDeltaYPos)
0207 
0208 /* ============================ setter methods and undo commands ================= */
0209 STD_SETTER_CMD_IMPL_F_S(DatapickerPoint, SetPosition, QPointF, position, retransform)
0210 void DatapickerPoint::setPosition(QPointF pos) {
0211     Q_D(DatapickerPoint);
0212     if (pos != d->position)
0213         exec(new DatapickerPointSetPositionCmd(d, pos, ki18n("%1: set position")));
0214 }
0215 
0216 STD_SETTER_CMD_IMPL_F_S(DatapickerPoint, SetPlusDeltaXPos, QPointF, plusDeltaXPos, updatePoint)
0217 void DatapickerPoint::setPlusDeltaXPos(QPointF pos) {
0218     Q_D(DatapickerPoint);
0219     if (pos != d->plusDeltaXPos) {
0220         auto* curve = dynamic_cast<DatapickerCurve*>(parentAspect());
0221         if (!curve)
0222             return;
0223 
0224         beginMacro(i18n("%1: set +delta_X position", name()));
0225         if (curve->curveErrorTypes().x == DatapickerCurve::ErrorType::SymmetricError) {
0226             exec(new DatapickerPointSetPlusDeltaXPosCmd(d, pos, ki18n("%1: set +delta X position")));
0227             setMinusDeltaXPos(QPointF(-std::abs(pos.x()), pos.y()));
0228         } else
0229             exec(new DatapickerPointSetPlusDeltaXPosCmd(d, pos, ki18n("%1: set +delta X position")));
0230         endMacro();
0231     }
0232 }
0233 
0234 STD_SETTER_CMD_IMPL_F_S(DatapickerPoint, SetMinusDeltaXPos, QPointF, minusDeltaXPos, updatePoint)
0235 void DatapickerPoint::setMinusDeltaXPos(QPointF pos) {
0236     Q_D(DatapickerPoint);
0237     if (pos != d->minusDeltaXPos) {
0238         auto* curve = dynamic_cast<DatapickerCurve*>(parentAspect());
0239         if (!curve)
0240             return;
0241 
0242         beginMacro(i18n("%1: set -delta_X position", name()));
0243         if (curve->curveErrorTypes().x == DatapickerCurve::ErrorType::SymmetricError) {
0244             exec(new DatapickerPointSetMinusDeltaXPosCmd(d, pos, ki18n("%1: set -delta_X position")));
0245             setPlusDeltaXPos(QPointF(std::abs(pos.x()), pos.y()));
0246         } else
0247             exec(new DatapickerPointSetMinusDeltaXPosCmd(d, pos, ki18n("%1: set -delta_X position")));
0248         endMacro();
0249     }
0250 }
0251 
0252 STD_SETTER_CMD_IMPL_F_S(DatapickerPoint, SetPlusDeltaYPos, QPointF, plusDeltaYPos, updatePoint)
0253 void DatapickerPoint::setPlusDeltaYPos(QPointF pos) {
0254     Q_D(DatapickerPoint);
0255     if (pos != d->plusDeltaYPos) {
0256         auto* curve = dynamic_cast<DatapickerCurve*>(parentAspect());
0257         if (!curve)
0258             return;
0259 
0260         beginMacro(i18n("%1: set +delta_Y position", name()));
0261         if (curve->curveErrorTypes().y == DatapickerCurve::ErrorType::SymmetricError) {
0262             exec(new DatapickerPointSetPlusDeltaYPosCmd(d, pos, ki18n("%1: set +delta_Y position")));
0263             setMinusDeltaYPos(QPointF(pos.x(), std::abs(pos.y())));
0264         } else
0265             exec(new DatapickerPointSetPlusDeltaYPosCmd(d, pos, ki18n("%1: set +delta_Y position")));
0266         endMacro();
0267     }
0268 }
0269 
0270 STD_SETTER_CMD_IMPL_F_S(DatapickerPoint, SetMinusDeltaYPos, QPointF, minusDeltaYPos, updatePoint)
0271 void DatapickerPoint::setMinusDeltaYPos(QPointF pos) {
0272     Q_D(DatapickerPoint);
0273     if (pos != d->minusDeltaYPos) {
0274         auto* curve = dynamic_cast<DatapickerCurve*>(parentAspect());
0275         if (!curve)
0276             return;
0277 
0278         beginMacro(i18n("%1: set -delta_Y position", name()));
0279         if (curve->curveErrorTypes().y == DatapickerCurve::ErrorType::SymmetricError) {
0280             exec(new DatapickerPointSetMinusDeltaYPosCmd(d, pos, ki18n("%1: set -delta_Y position")));
0281             setPlusDeltaYPos(QPointF(pos.x(), -std::abs(pos.y())));
0282         } else
0283             exec(new DatapickerPointSetMinusDeltaYPosCmd(d, pos, ki18n("%1: set -delta_Y position")));
0284         endMacro();
0285     }
0286 }
0287 
0288 void DatapickerPoint::setPrinting(bool on) {
0289     Q_D(DatapickerPoint);
0290     d->m_printing = on;
0291 }
0292 
0293 void DatapickerPoint::setIsReferencePoint(bool value) {
0294     Q_D(DatapickerPoint);
0295     d->isReferencePoint = value;
0296 }
0297 
0298 bool DatapickerPoint::isReferencePoint() const {
0299     Q_D(const DatapickerPoint);
0300     return d->isReferencePoint;
0301 }
0302 
0303 // ##############################################################################
0304 // ####################### Private implementation ###############################
0305 // ##############################################################################
0306 DatapickerPointPrivate::DatapickerPointPrivate(DatapickerPoint* owner)
0307     : q(owner) {
0308     setFlag(QGraphicsItem::ItemIsMovable);
0309     setFlag(QGraphicsItem::ItemSendsGeometryChanges);
0310     setFlag(QGraphicsItem::ItemIsSelectable);
0311     setAcceptHoverEvents(true);
0312 }
0313 
0314 QString DatapickerPointPrivate::name() const {
0315     return q->name();
0316 }
0317 
0318 /*!
0319     calculates the position and the bounding box of the item/point. Called on geometry or properties changes.
0320  */
0321 void DatapickerPointPrivate::retransform() {
0322     if (q->isLoading())
0323         return;
0324 
0325     setPos(position);
0326     updatePoint();
0327 
0328     updatePropeties();
0329 
0330     QPainterPath path = Symbol::stylePath(pointStyle);
0331     boundingRectangle = path.boundingRect();
0332     recalcShapeAndBoundingRect();
0333     retransformErrorBar();
0334 }
0335 
0336 /*!
0337   update color and size of all error-bar.
0338 */
0339 void DatapickerPointPrivate::retransformErrorBar() {
0340     for (auto* item : q->m_errorBarItemList) {
0341         if (item) {
0342             item->setBrush(errorBarBrush);
0343             item->setPen(errorBarPen);
0344             item->setRectSize(errorBarSize);
0345         }
0346     }
0347 }
0348 
0349 /*!
0350   update datasheet on any change in position of Datapicker-Point or it's error-bar.
0351 */
0352 void DatapickerPointPrivate::updatePoint() {
0353     auto* curve = dynamic_cast<DatapickerCurve*>(q->parentAspect());
0354     if (curve)
0355         curve->updatePoint(q);
0356 }
0357 
0358 void DatapickerPointPrivate::updatePropeties() {
0359     auto* curve = dynamic_cast<DatapickerCurve*>(q->parentAspect());
0360     auto* image = dynamic_cast<DatapickerImage*>(q->parentAspect());
0361     if (image) {
0362         rotationAngle = image->symbol()->rotationAngle();
0363         pointStyle = image->symbol()->style();
0364         brush = image->symbol()->brush();
0365         pen = image->symbol()->pen();
0366         opacity = image->symbol()->opacity();
0367         size = image->symbol()->size();
0368         setVisible(image->pointVisibility());
0369     } else if (curve) {
0370         rotationAngle = curve->symbol()->rotationAngle();
0371         pointStyle = curve->symbol()->style();
0372         brush = curve->symbol()->brush();
0373         pen = curve->symbol()->pen();
0374         opacity = curve->symbol()->opacity();
0375         size = curve->symbol()->size();
0376         errorBarBrush = curve->pointErrorBarBrush();
0377         errorBarPen = curve->pointErrorBarPen();
0378         errorBarSize = curve->pointErrorBarSize();
0379         setVisible(curve->pointVisibility());
0380     }
0381 }
0382 
0383 /*!
0384     Returns the outer bounds of the item as a rectangle.
0385  */
0386 QRectF DatapickerPointPrivate::boundingRect() const {
0387     return transformedBoundingRectangle;
0388 }
0389 
0390 /*!
0391     Returns the shape of this item as a QPainterPath in local coordinates.
0392 */
0393 QPainterPath DatapickerPointPrivate::shape() const {
0394     return itemShape;
0395 }
0396 
0397 /*!
0398   recalculates the outer bounds and the shape of the item.
0399 */
0400 void DatapickerPointPrivate::recalcShapeAndBoundingRect() {
0401     prepareGeometryChange();
0402 
0403     QTransform matrix;
0404     matrix.scale(size, size);
0405     matrix.rotate(-rotationAngle);
0406     transformedBoundingRectangle = matrix.mapRect(boundingRectangle);
0407     itemShape = QPainterPath();
0408     itemShape.addRect(transformedBoundingRectangle);
0409     itemShape = WorksheetElement::shapeFromPath(itemShape, pen);
0410 }
0411 
0412 void DatapickerPointPrivate::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) {
0413     q->setPosition(pos());
0414     QGraphicsItem::mouseReleaseEvent(event);
0415 }
0416 
0417 void DatapickerPointPrivate::hoverEnterEvent(QGraphicsSceneHoverEvent*) {
0418     setCursor(Qt::ArrowCursor);
0419 }
0420 
0421 void DatapickerPointPrivate::hoverLeaveEvent(QGraphicsSceneHoverEvent*) {
0422     setCursor(Qt::CrossCursor);
0423 }
0424 
0425 QVariant DatapickerPointPrivate::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant& value) {
0426     if (change == QGraphicsItem::GraphicsItemChange::ItemSelectedHasChanged && value.toBool())
0427         Q_EMIT q->pointSelected(q);
0428     else if (change == QGraphicsItem::GraphicsItemChange::ItemPositionChange)
0429         Q_EMIT q->positionChanged(value.toPointF());
0430     return QGraphicsItem::itemChange(change, value);
0431 }
0432 
0433 void DatapickerPointPrivate::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget*) {
0434     QPainterPath path = Symbol::stylePath(pointStyle);
0435     QTransform trafo;
0436     trafo.scale(size, size);
0437     path = trafo.map(path);
0438     trafo.reset();
0439     if (rotationAngle != 0) {
0440         trafo.rotate(-rotationAngle);
0441         path = trafo.map(path);
0442     }
0443     painter->save();
0444     painter->setPen(pen);
0445     painter->setBrush(brush);
0446     painter->setOpacity(opacity);
0447     painter->drawPath(path);
0448     painter->restore();
0449 
0450     if (isSelected() && !m_printing) {
0451         // TODO: move the initialization of QPen to a parent class later so we don't
0452         // need to create it in every paint() call.
0453         painter->setPen(QPen(QApplication::palette().color(QPalette::Highlight), 1, Qt::SolidLine));
0454         painter->drawPath(itemShape);
0455     }
0456 }
0457 
0458 void DatapickerPointPrivate::contextMenuEvent(QGraphicsSceneContextMenuEvent* event) {
0459     q->createContextMenu()->exec(event->screenPos());
0460 }
0461 
0462 // ##############################################################################
0463 // ##################  Serialization/Deserialization  ###########################
0464 // ##############################################################################
0465 //! Save as XML
0466 void DatapickerPoint::save(QXmlStreamWriter* writer) const {
0467     Q_D(const DatapickerPoint);
0468 
0469     writer->writeStartElement(QStringLiteral("datapickerPoint"));
0470     writeBasicAttributes(writer);
0471 
0472     // geometry
0473     writer->writeStartElement(QStringLiteral("geometry"));
0474     writer->writeAttribute(QStringLiteral("x"), QString::number(d->position.x()));
0475     writer->writeAttribute(QStringLiteral("y"), QString::number(d->position.y()));
0476     writer->writeEndElement();
0477 
0478     auto* curve = dynamic_cast<DatapickerCurve*>(parentAspect());
0479     if (curve && (curve->curveErrorTypes().x != DatapickerCurve::ErrorType::NoError || curve->curveErrorTypes().y != DatapickerCurve::ErrorType::NoError)) {
0480         writer->writeStartElement(QStringLiteral("errorBar"));
0481         writer->writeAttribute(QStringLiteral("plusDeltaXPos_x"), QString::number(d->plusDeltaXPos.x()));
0482         writer->writeAttribute(QStringLiteral("plusDeltaXPos_y"), QString::number(d->plusDeltaXPos.y()));
0483         writer->writeAttribute(QStringLiteral("minusDeltaXPos_x"), QString::number(d->minusDeltaXPos.x()));
0484         writer->writeAttribute(QStringLiteral("minusDeltaXPos_y"), QString::number(d->minusDeltaXPos.y()));
0485         writer->writeAttribute(QStringLiteral("plusDeltaYPos_x"), QString::number(d->plusDeltaYPos.x()));
0486         writer->writeAttribute(QStringLiteral("plusDeltaYPos_y"), QString::number(d->plusDeltaYPos.y()));
0487         writer->writeAttribute(QStringLiteral("minusDeltaYPos_x"), QString::number(d->minusDeltaYPos.x()));
0488         writer->writeAttribute(QStringLiteral("minusDeltaYPos_y"), QString::number(d->minusDeltaYPos.y()));
0489         writer->writeEndElement();
0490     }
0491 
0492     writer->writeEndElement(); // close "DatapickerPoint" section
0493 }
0494 
0495 //! Load from XML
0496 bool DatapickerPoint::load(XmlStreamReader* reader, bool preview) {
0497     Q_D(DatapickerPoint);
0498 
0499     if (!readBasicAttributes(reader))
0500         return false;
0501 
0502     QXmlStreamAttributes attribs;
0503     QString str;
0504 
0505     while (!reader->atEnd()) {
0506         reader->readNext();
0507         if (reader->isEndElement() && reader->name() == QStringLiteral("datapickerPoint"))
0508             break;
0509 
0510         if (!reader->isStartElement())
0511             continue;
0512 
0513         if (!preview && reader->name() == QStringLiteral("geometry")) {
0514             attribs = reader->attributes();
0515 
0516             str = attribs.value(QStringLiteral("x")).toString();
0517             if (str.isEmpty())
0518                 reader->raiseMissingAttributeWarning(QStringLiteral("x"));
0519             else
0520                 d->position.setX(str.toDouble());
0521 
0522             str = attribs.value(QStringLiteral("y")).toString();
0523             if (str.isEmpty())
0524                 reader->raiseMissingAttributeWarning(QStringLiteral("y"));
0525             else
0526                 d->position.setY(str.toDouble());
0527         } else if (!preview && reader->name() == QStringLiteral("errorBar")) {
0528             attribs = reader->attributes();
0529 
0530             str = attribs.value(QStringLiteral("plusDeltaXPos_x")).toString();
0531             if (str.isEmpty())
0532                 reader->raiseMissingAttributeWarning(QStringLiteral("plusDeltaXPos_x"));
0533             else
0534                 d->plusDeltaXPos.setX(str.toDouble());
0535 
0536             str = attribs.value(QStringLiteral("plusDeltaXPos_y")).toString();
0537             if (str.isEmpty())
0538                 reader->raiseMissingAttributeWarning(QStringLiteral("plusDeltaXPos_y"));
0539             else
0540                 d->plusDeltaXPos.setY(str.toDouble());
0541 
0542             str = attribs.value(QStringLiteral("minusDeltaXPos_x")).toString();
0543             if (str.isEmpty())
0544                 reader->raiseMissingAttributeWarning(QStringLiteral("minusDeltaXPos_x"));
0545             else
0546                 d->minusDeltaXPos.setX(str.toDouble());
0547 
0548             str = attribs.value(QStringLiteral("minusDeltaXPos_y")).toString();
0549             if (str.isEmpty())
0550                 reader->raiseMissingAttributeWarning(QStringLiteral("minusDeltaXPos_y"));
0551             else
0552                 d->minusDeltaXPos.setY(str.toDouble());
0553 
0554             str = attribs.value(QStringLiteral("plusDeltaYPos_x")).toString();
0555             if (str.isEmpty())
0556                 reader->raiseMissingAttributeWarning(QStringLiteral("plusDeltaYPos_x"));
0557             else
0558                 d->plusDeltaYPos.setX(str.toDouble());
0559 
0560             str = attribs.value(QStringLiteral("plusDeltaYPos_y")).toString();
0561             if (str.isEmpty())
0562                 reader->raiseMissingAttributeWarning(QStringLiteral("plusDeltaYPos_y"));
0563             else
0564                 d->plusDeltaYPos.setY(str.toDouble());
0565 
0566             str = attribs.value(QStringLiteral("minusDeltaYPos_x")).toString();
0567             if (str.isEmpty())
0568                 reader->raiseMissingAttributeWarning(QStringLiteral("minusDeltaYPos_x"));
0569             else
0570                 d->minusDeltaYPos.setX(str.toDouble());
0571 
0572             str = attribs.value(QStringLiteral("minusDeltaYPos_y")).toString();
0573             if (str.isEmpty())
0574                 reader->raiseMissingAttributeWarning(QStringLiteral("minusDeltaYPos_y"));
0575             else
0576                 d->minusDeltaYPos.setY(str.toDouble());
0577         } else { // unknown element
0578             reader->raiseUnknownElementWarning();
0579             if (!reader->skipToEndElement())
0580                 return false;
0581         }
0582     }
0583 
0584     retransform();
0585     return true;
0586 }