File indexing completed on 2024-05-12 15:26:42

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