File indexing completed on 2024-05-12 03:47:28
0001 /* 0002 File : DatapickerCurve.cpp 0003 Project : LabPlot 0004 Description : container for Curve-Point and Datasheet/Spreadsheet 0005 of datapicker 0006 -------------------------------------------------------------------- 0007 SPDX-FileCopyrightText: 2015 Ankit Wagadre <wagadre.ankit@gmail.com> 0008 SPDX-FileCopyrightText: 2015-2022 Alexander Semke <alexander.semke@web.de> 0009 SPDX-License-Identifier: GPL-2.0-or-later 0010 */ 0011 0012 #include "DatapickerCurve.h" 0013 #include "backend/datapicker/Datapicker.h" 0014 #include "backend/datapicker/DatapickerCurvePrivate.h" 0015 #include "backend/datapicker/DatapickerPoint.h" 0016 #include "backend/lib/XmlStreamReader.h" 0017 #include "backend/lib/commandtemplates.h" 0018 #include "backend/spreadsheet/Spreadsheet.h" 0019 #include "backend/worksheet/Worksheet.h" 0020 #include "backend/worksheet/plots/cartesian/Symbol.h" 0021 0022 #include <QIcon> 0023 #include <QVector3D> 0024 0025 #include <KConfig> 0026 #include <KConfigGroup> 0027 #include <KLocalizedString> 0028 0029 /** 0030 * \class DatapickerCurve 0031 * \brief Top-level container for Curve-Point and Datasheet/Spreadsheet of datapicker. 0032 * \ingroup backend 0033 */ 0034 0035 DatapickerCurve::DatapickerCurve(const QString& name) 0036 : AbstractAspect(name, AspectType::DatapickerCurve) 0037 , d_ptr(new DatapickerCurvePrivate(this)) { 0038 init(); 0039 } 0040 0041 DatapickerCurve::DatapickerCurve(const QString& name, DatapickerCurvePrivate* dd) 0042 : AbstractAspect(name, AspectType::DatapickerCurve) 0043 , d_ptr(dd) { 0044 init(); 0045 } 0046 0047 DatapickerCurve::~DatapickerCurve() { 0048 delete d_ptr; 0049 } 0050 0051 void DatapickerCurve::init() { 0052 Q_D(DatapickerCurve); 0053 0054 KConfig config; 0055 KConfigGroup group; 0056 group = config.group(QStringLiteral("DatapickerCurve")); 0057 d->pointVisibility = group.readEntry(QStringLiteral("PointVisibility"), true); 0058 0059 // error bars 0060 d->curveErrorTypes.x = (ErrorType)group.readEntry(QStringLiteral("CurveErrorType_X"), static_cast<int>(ErrorType::NoError)); 0061 d->curveErrorTypes.y = (ErrorType)group.readEntry(QStringLiteral("CurveErrorType_Y"), static_cast<int>(ErrorType::NoError)); 0062 d->pointErrorBarSize = group.readEntry(QStringLiteral("ErrorBarSize"), Worksheet::convertToSceneUnits(8, Worksheet::Unit::Point)); 0063 d->pointErrorBarBrush.setStyle((Qt::BrushStyle)group.readEntry(QStringLiteral("ErrorBarFillingStyle"), (int)Qt::NoBrush)); 0064 d->pointErrorBarBrush.setColor(group.readEntry(QStringLiteral("ErrorBarFillingColor"), QColor(Qt::black))); 0065 d->pointErrorBarPen.setStyle((Qt::PenStyle)group.readEntry(QStringLiteral("ErrorBarBorderStyle"), (int)Qt::SolidLine)); 0066 d->pointErrorBarPen.setColor(group.readEntry(QStringLiteral("ErrorBarBorderColor"), QColor(Qt::black))); 0067 d->pointErrorBarPen.setWidthF(group.readEntry(QStringLiteral("ErrorBarBorderWidth"), Worksheet::convertToSceneUnits(1, Worksheet::Unit::Point))); 0068 0069 // initialize the symbol 0070 d->symbol = new Symbol(QString()); 0071 addChild(d->symbol); 0072 d->symbol->setHidden(true); 0073 connect(d->symbol, &Symbol::updateRequested, [=] { 0074 d->retransform(); 0075 }); 0076 connect(d->symbol, &Symbol::updatePixmapRequested, [=] { 0077 d->retransform(); 0078 }); 0079 d->symbol->init(group); 0080 0081 connect(this, &AbstractAspect::childAspectAdded, this, &DatapickerCurve::childAdded); 0082 connect(this, &AbstractAspect::childAspectAboutToBeRemoved, this, &DatapickerCurve::childRemoved); 0083 } 0084 0085 void DatapickerCurve::childAdded(const AbstractAspect* child) { 0086 if (m_supressResizeDatasheet) 0087 return; 0088 const auto* p = dynamic_cast<const DatapickerPoint*>(child); 0089 if (!p) 0090 return; 0091 m_datasheet->setRowCount(m_datasheet->rowCount() + 1); 0092 } 0093 0094 void DatapickerCurve::childRemoved(const AbstractAspect* child) { 0095 Q_UNUSED(child); 0096 const auto* point = dynamic_cast<const DatapickerPoint*>(child); 0097 if (!point) 0098 return; 0099 0100 int row = indexOfChild<DatapickerPoint>(point, ChildIndexFlag::IncludeHidden); 0101 m_datasheet->removeRows(row, 1); 0102 } 0103 0104 /*! 0105 Returns an icon to be used in the project explorer. 0106 */ 0107 QIcon DatapickerCurve::icon() const { 0108 return QIcon::fromTheme(QStringLiteral("labplot-xy-curve")); 0109 } 0110 0111 Column* DatapickerCurve::appendColumn(const QString& name) { 0112 auto* col = new Column(name); 0113 col->insertRows(0, m_datasheet->rowCount()); 0114 col->setFixed(true); 0115 col->setUndoAware(false); 0116 m_datasheet->addChild(col); 0117 0118 return col; 0119 } 0120 0121 // ############################################################################## 0122 // ########################## getter methods ################################## 0123 // ############################################################################## 0124 Symbol* DatapickerCurve::symbol() const { 0125 Q_D(const DatapickerCurve); 0126 return d->symbol; 0127 } 0128 0129 BASIC_SHARED_D_READER_IMPL(DatapickerCurve, DatapickerCurve::Errors, curveErrorTypes, curveErrorTypes) 0130 BASIC_SHARED_D_READER_IMPL(DatapickerCurve, qreal, pointErrorBarSize, pointErrorBarSize) 0131 BASIC_SHARED_D_READER_IMPL(DatapickerCurve, QBrush, pointErrorBarBrush, pointErrorBarBrush) 0132 BASIC_SHARED_D_READER_IMPL(DatapickerCurve, QPen, pointErrorBarPen, pointErrorBarPen) 0133 BASIC_SHARED_D_READER_IMPL(DatapickerCurve, bool, pointVisibility, pointVisibility) 0134 0135 BASIC_SHARED_D_READER_IMPL(DatapickerCurve, AbstractColumn*, posXColumn, posXColumn) 0136 QString& DatapickerCurve::posXColumnPath() const { 0137 return d_ptr->posXColumnPath; 0138 } 0139 0140 BASIC_SHARED_D_READER_IMPL(DatapickerCurve, AbstractColumn*, posYColumn, posYColumn) 0141 QString& DatapickerCurve::posYColumnPath() const { 0142 return d_ptr->posYColumnPath; 0143 } 0144 0145 BASIC_SHARED_D_READER_IMPL(DatapickerCurve, AbstractColumn*, posZColumn, posZColumn) 0146 QString& DatapickerCurve::posZColumnPath() const { 0147 return d_ptr->posZColumnPath; 0148 } 0149 0150 BASIC_SHARED_D_READER_IMPL(DatapickerCurve, AbstractColumn*, plusDeltaXColumn, plusDeltaXColumn) 0151 QString& DatapickerCurve::plusDeltaXColumnPath() const { 0152 return d_ptr->plusDeltaXColumnPath; 0153 } 0154 0155 BASIC_SHARED_D_READER_IMPL(DatapickerCurve, AbstractColumn*, minusDeltaXColumn, minusDeltaXColumn) 0156 QString& DatapickerCurve::minusDeltaXColumnPath() const { 0157 return d_ptr->minusDeltaXColumnPath; 0158 } 0159 0160 BASIC_SHARED_D_READER_IMPL(DatapickerCurve, AbstractColumn*, plusDeltaYColumn, plusDeltaYColumn) 0161 QString& DatapickerCurve::plusDeltaYColumnPath() const { 0162 return d_ptr->plusDeltaYColumnPath; 0163 } 0164 0165 BASIC_SHARED_D_READER_IMPL(DatapickerCurve, AbstractColumn*, minusDeltaYColumn, minusDeltaYColumn) 0166 QString& DatapickerCurve::minusDeltaYColumnPath() const { 0167 return d_ptr->minusDeltaYColumnPath; 0168 } 0169 0170 // ############################################################################## 0171 // ######################### setter methods ################################### 0172 // ############################################################################## 0173 void DatapickerCurve::addDatasheet(DatapickerImage::GraphType type) { 0174 Q_D(DatapickerCurve); 0175 0176 m_datasheet = new Spreadsheet(i18n("Data")); 0177 m_datasheet->setFixed(true); 0178 m_datasheet->setRowCount(0); 0179 addChild(m_datasheet); 0180 0181 QString xLabel; 0182 QString yLabel; 0183 0184 switch (type) { 0185 case DatapickerImage::GraphType::Linear: { 0186 xLabel = QLatin1Char('x'); 0187 yLabel = QLatin1Char('y'); 0188 break; 0189 } 0190 case DatapickerImage::GraphType::PolarInDegree: { 0191 xLabel = QLatin1String("r"); 0192 yLabel = QLatin1String("y(deg)"); 0193 break; 0194 } 0195 case DatapickerImage::GraphType::PolarInRadians: { 0196 xLabel = QLatin1String("r"); 0197 yLabel = QLatin1String("y(rad)"); 0198 break; 0199 } 0200 case DatapickerImage::GraphType::LnXY: { 0201 xLabel = QLatin1String("ln(x)"); 0202 yLabel = QLatin1String("ln(y)"); 0203 break; 0204 } 0205 case DatapickerImage::GraphType::LnX: { 0206 xLabel = QLatin1String("ln(x)"); 0207 yLabel = QLatin1String("y"); 0208 break; 0209 } 0210 case DatapickerImage::GraphType::LnY: { 0211 xLabel = QLatin1String("x"); 0212 yLabel = QLatin1String("ln(y)"); 0213 break; 0214 } 0215 case DatapickerImage::GraphType::Log10XY: { 0216 xLabel = QLatin1String("log(x)"); 0217 yLabel = QLatin1String("log(y)"); 0218 break; 0219 } 0220 case DatapickerImage::GraphType::Log10X: { 0221 xLabel = QLatin1String("log(x)"); 0222 yLabel = QLatin1String("y"); 0223 break; 0224 } 0225 case DatapickerImage::GraphType::Log10Y: { 0226 xLabel = QLatin1String("x"); 0227 yLabel = QLatin1String("log(y)"); 0228 break; 0229 } 0230 case DatapickerImage::GraphType::Ternary: { 0231 xLabel = QLatin1Char('a'); 0232 yLabel = QLatin1Char('b'); 0233 break; 0234 } 0235 } 0236 0237 // the default spreadsheet can have arbitrary number of colums as per user's default template. 0238 // make sure we have the columns for x and y only 0239 if (m_datasheet->columnCount() < 1) 0240 appendColumn(xLabel); 0241 if (m_datasheet->columnCount() < 2) 0242 appendColumn(yLabel); 0243 if (m_datasheet->columnCount() > 2) 0244 m_datasheet->setColumnCount(2); 0245 0246 // add the third column for Ternary 0247 if (type == DatapickerImage::GraphType::Ternary) 0248 d->posZColumn = appendColumn(QLatin1String("c")); 0249 0250 d->posXColumn = m_datasheet->column(0); 0251 d->posXColumn->setName(xLabel); 0252 d->posXColumn->setPlotDesignation(AbstractColumn::PlotDesignation::X); 0253 d->posXColumn->setFixed(true); 0254 d->posXColumn->setUndoAware(false); 0255 0256 d->posYColumn = m_datasheet->column(1); 0257 d->posYColumn->setName(yLabel); 0258 d->posYColumn->setPlotDesignation(AbstractColumn::PlotDesignation::Y); 0259 d->posYColumn->setFixed(true); 0260 d->posYColumn->setUndoAware(false); 0261 } 0262 0263 STD_SETTER_CMD_IMPL_S(DatapickerCurve, SetCurveErrorTypes, DatapickerCurve::Errors, curveErrorTypes) 0264 void DatapickerCurve::setCurveErrorTypes(const DatapickerCurve::Errors errors) { 0265 Q_D(DatapickerCurve); 0266 if (d->curveErrorTypes.x != errors.x || d->curveErrorTypes.y != errors.y) { 0267 beginMacro(i18n("%1: set xy-error type", name())); 0268 exec(new DatapickerCurveSetCurveErrorTypesCmd(d, errors, ki18n("%1: set xy-error type"))); 0269 0270 if (errors.x != ErrorType::NoError && !d->plusDeltaXColumn) 0271 setPlusDeltaXColumn(appendColumn(QLatin1String("+delta_x"))); 0272 else if (d->plusDeltaXColumn && errors.x == ErrorType::NoError) { 0273 d->plusDeltaXColumn->remove(); 0274 d->plusDeltaXColumn = nullptr; 0275 } 0276 0277 if (errors.x == ErrorType::AsymmetricError && !d->minusDeltaXColumn) 0278 setMinusDeltaXColumn(appendColumn(QLatin1String("-delta_x"))); 0279 else if (d->minusDeltaXColumn && errors.x != ErrorType::AsymmetricError) { 0280 d->minusDeltaXColumn->remove(); 0281 d->minusDeltaXColumn = nullptr; 0282 } 0283 0284 if (errors.y != ErrorType::NoError && !d->plusDeltaYColumn) 0285 setPlusDeltaYColumn(appendColumn(QLatin1String("+delta_y"))); 0286 else if (d->plusDeltaYColumn && errors.y == ErrorType::NoError) { 0287 d->plusDeltaYColumn->remove(); 0288 d->plusDeltaYColumn = nullptr; 0289 } 0290 0291 if (errors.y == ErrorType::AsymmetricError && !d->minusDeltaYColumn) 0292 setMinusDeltaYColumn(appendColumn(QLatin1String("-delta_y"))); 0293 else if (d->minusDeltaYColumn && errors.y != ErrorType::AsymmetricError) { 0294 d->minusDeltaYColumn->remove(); 0295 d->minusDeltaYColumn = nullptr; 0296 } 0297 0298 endMacro(); 0299 } 0300 } 0301 0302 STD_SETTER_CMD_IMPL_S(DatapickerCurve, SetPosXColumn, AbstractColumn*, posXColumn) 0303 void DatapickerCurve::setPosXColumn(AbstractColumn* column) { 0304 Q_D(DatapickerCurve); 0305 if (d->posXColumn != column) 0306 exec(new DatapickerCurveSetPosXColumnCmd(d, column, ki18n("%1: set position X column"))); 0307 } 0308 0309 STD_SETTER_CMD_IMPL_S(DatapickerCurve, SetPosYColumn, AbstractColumn*, posYColumn) 0310 void DatapickerCurve::setPosYColumn(AbstractColumn* column) { 0311 Q_D(DatapickerCurve); 0312 if (d->posYColumn != column) 0313 exec(new DatapickerCurveSetPosYColumnCmd(d, column, ki18n("%1: set position Y column"))); 0314 } 0315 0316 STD_SETTER_CMD_IMPL_S(DatapickerCurve, SetPosZColumn, AbstractColumn*, posZColumn) 0317 void DatapickerCurve::setPosZColumn(AbstractColumn* column) { 0318 Q_D(DatapickerCurve); 0319 if (d->posZColumn != column) 0320 exec(new DatapickerCurveSetPosZColumnCmd(d, column, ki18n("%1: set position Z column"))); 0321 } 0322 0323 STD_SETTER_CMD_IMPL_S(DatapickerCurve, SetPlusDeltaXColumn, AbstractColumn*, plusDeltaXColumn) 0324 void DatapickerCurve::setPlusDeltaXColumn(AbstractColumn* column) { 0325 Q_D(DatapickerCurve); 0326 if (d->plusDeltaXColumn != column) 0327 exec(new DatapickerCurveSetPlusDeltaXColumnCmd(d, column, ki18n("%1: set +delta_X column"))); 0328 } 0329 0330 STD_SETTER_CMD_IMPL_S(DatapickerCurve, SetMinusDeltaXColumn, AbstractColumn*, minusDeltaXColumn) 0331 void DatapickerCurve::setMinusDeltaXColumn(AbstractColumn* column) { 0332 Q_D(DatapickerCurve); 0333 if (d->minusDeltaXColumn != column) 0334 exec(new DatapickerCurveSetMinusDeltaXColumnCmd(d, column, ki18n("%1: set -delta_X column"))); 0335 } 0336 0337 STD_SETTER_CMD_IMPL_S(DatapickerCurve, SetPlusDeltaYColumn, AbstractColumn*, plusDeltaYColumn) 0338 void DatapickerCurve::setPlusDeltaYColumn(AbstractColumn* column) { 0339 Q_D(DatapickerCurve); 0340 if (d->plusDeltaYColumn != column) 0341 exec(new DatapickerCurveSetPlusDeltaYColumnCmd(d, column, ki18n("%1: set +delta_Y column"))); 0342 } 0343 0344 STD_SETTER_CMD_IMPL_S(DatapickerCurve, SetMinusDeltaYColumn, AbstractColumn*, minusDeltaYColumn) 0345 void DatapickerCurve::setMinusDeltaYColumn(AbstractColumn* column) { 0346 Q_D(DatapickerCurve); 0347 if (d->minusDeltaYColumn != column) 0348 exec(new DatapickerCurveSetMinusDeltaYColumnCmd(d, column, ki18n("%1: set -delta_Y column"))); 0349 } 0350 0351 STD_SETTER_CMD_IMPL_F_S(DatapickerCurve, SetPointErrorBarSize, qreal, pointErrorBarSize, retransform) 0352 void DatapickerCurve::setPointErrorBarSize(qreal size) { 0353 Q_D(DatapickerCurve); 0354 if (size != d->pointErrorBarSize) 0355 exec(new DatapickerCurveSetPointErrorBarSizeCmd(d, size, ki18n("%1: set error bar size"))); 0356 } 0357 0358 STD_SETTER_CMD_IMPL_F_S(DatapickerCurve, SetPointErrorBarBrush, QBrush, pointErrorBarBrush, retransform) 0359 void DatapickerCurve::setPointErrorBarBrush(const QBrush& brush) { 0360 Q_D(DatapickerCurve); 0361 if (brush != d->pointErrorBarBrush) 0362 exec(new DatapickerCurveSetPointErrorBarBrushCmd(d, brush, ki18n("%1: set error bar filling"))); 0363 } 0364 0365 STD_SETTER_CMD_IMPL_F_S(DatapickerCurve, SetPointErrorBarPen, QPen, pointErrorBarPen, retransform) 0366 void DatapickerCurve::setPointErrorBarPen(const QPen& pen) { 0367 Q_D(DatapickerCurve); 0368 if (pen != d->pointErrorBarPen) 0369 exec(new DatapickerCurveSetPointErrorBarPenCmd(d, pen, ki18n("%1: set error bar outline style"))); 0370 } 0371 0372 STD_SETTER_CMD_IMPL_F_S(DatapickerCurve, SetPointVisibility, bool, pointVisibility, retransform) 0373 void DatapickerCurve::setPointVisibility(bool on) { 0374 Q_D(DatapickerCurve); 0375 if (on != d->pointVisibility) 0376 exec(new DatapickerCurveSetPointVisibilityCmd(d, on, on ? ki18n("%1: set visible") : ki18n("%1: set invisible"))); 0377 } 0378 0379 void DatapickerCurve::setPrinting(bool on) { 0380 for (auto* point : children<DatapickerPoint>(AbstractAspect::ChildIndexFlag::IncludeHidden)) 0381 point->setPrinting(on); 0382 } 0383 0384 /*! 0385 Selects or deselects the Datapicker/Curve in the project explorer. 0386 This function is called in \c DatapickerImageView. 0387 */ 0388 void DatapickerCurve::setSelectedInView(bool b) { 0389 if (b) 0390 Q_EMIT childAspectSelectedInView(this); 0391 else 0392 Q_EMIT childAspectDeselectedInView(this); 0393 } 0394 0395 // ############################################################################## 0396 // ###### SLOTs for changes triggered via QActions in the context menu ######## 0397 // ############################################################################## 0398 void DatapickerCurve::suppressUpdatePoint(bool suppress) { 0399 m_supressResizeDatasheet = suppress; 0400 0401 if (!suppress) { 0402 // update points 0403 auto points = children<DatapickerPoint>(ChildIndexFlag::IncludeHidden); 0404 m_datasheet->setRowCount(points.count()); 0405 updatePoints(); 0406 } 0407 } 0408 0409 void DatapickerCurve::updatePoints() { 0410 for (auto* point : children<DatapickerPoint>(ChildIndexFlag::IncludeHidden)) 0411 updatePoint(point); 0412 } 0413 0414 /*! 0415 Update datasheet for corresponding curve-point, 0416 it is called every time whenever there is any change in position 0417 of curve-point or its error-bar so keep it undo unaware 0418 no need to create extra entry in undo stack 0419 */ 0420 void DatapickerCurve::updatePoint(const DatapickerPoint* point) { 0421 Q_D(DatapickerCurve); 0422 0423 if (m_supressResizeDatasheet) 0424 return; 0425 0426 // TODO: this check shouldn't be required. 0427 // redesign the retransform()-call in load() to avoid it. 0428 if (!parentAspect()) 0429 return; 0430 0431 auto* datapicker = static_cast<Datapicker*>(parentAspect()); 0432 int row = indexOfChild<DatapickerPoint>(point, ChildIndexFlag::IncludeHidden); 0433 0434 const auto xDateTime = datapicker->xDateTime(); 0435 if ((m_datetime && !xDateTime) || (!m_datetime && xDateTime)) 0436 updateColumns(xDateTime); 0437 0438 Vector3D data = datapicker->mapSceneToLogical(point->position()); 0439 0440 if (d->posXColumn) { 0441 if (xDateTime) { 0442 auto dt = QDateTime::fromMSecsSinceEpoch(data.x()); 0443 dt.setTimeSpec(Qt::TimeSpec::UTC); 0444 d->posXColumn->setDateTimeAt(row, dt); 0445 } else 0446 d->posXColumn->setValueAt(row, data.x()); 0447 } 0448 0449 if (d->posYColumn) 0450 d->posYColumn->setValueAt(row, data.y()); 0451 0452 if (d->posZColumn) 0453 d->posZColumn->setValueAt(row, data.y()); 0454 0455 if (d->plusDeltaXColumn) { 0456 data = datapicker->mapSceneLengthToLogical(QPointF(point->plusDeltaXPos().x(), 0)); 0457 d->plusDeltaXColumn->setValueAt(row, std::abs(data.x())); 0458 } 0459 0460 if (d->minusDeltaXColumn) { 0461 data = datapicker->mapSceneLengthToLogical(QPointF(point->minusDeltaXPos().x(), 0)); 0462 d->minusDeltaXColumn->setValueAt(row, std::abs(data.x())); 0463 } 0464 0465 if (d->plusDeltaYColumn) { 0466 data = datapicker->mapSceneLengthToLogical(QPointF(0, point->plusDeltaYPos().y())); 0467 d->plusDeltaYColumn->setValueAt(row, std::abs(data.y())); 0468 } 0469 0470 if (d->minusDeltaYColumn) { 0471 data = datapicker->mapSceneLengthToLogical(QPointF(0, point->minusDeltaYPos().y())); 0472 d->minusDeltaYColumn->setValueAt(row, std::abs(data.y())); 0473 } 0474 } 0475 0476 void DatapickerCurve::updateColumns(bool datetime) { 0477 m_datetime = datetime; 0478 Q_D(DatapickerCurve); 0479 if (datetime) 0480 d->posXColumn->setColumnMode(AbstractColumn::ColumnMode::DateTime); 0481 else 0482 d->posXColumn->setColumnMode(AbstractColumn::ColumnMode::Double); 0483 } 0484 0485 // ############################################################################## 0486 // ####################### Private implementation ############################### 0487 // ############################################################################## 0488 DatapickerCurvePrivate::DatapickerCurvePrivate(DatapickerCurve* curve) 0489 : q(curve) { 0490 } 0491 0492 QString DatapickerCurvePrivate::name() const { 0493 return q->name(); 0494 } 0495 0496 void DatapickerCurvePrivate::retransform() { 0497 if (q->isLoading()) 0498 return; 0499 const auto& points = q->children<DatapickerPoint>(AbstractAspect::ChildIndexFlag::IncludeHidden); 0500 for (auto* point : points) 0501 point->retransform(); 0502 } 0503 0504 // ############################################################################## 0505 // ################## Serialization/Deserialization ########################### 0506 // ############################################################################## 0507 //! Save as XML 0508 void DatapickerCurve::save(QXmlStreamWriter* writer) const { 0509 Q_D(const DatapickerCurve); 0510 0511 writer->writeStartElement(QStringLiteral("datapickerCurve")); 0512 writeBasicAttributes(writer); 0513 writeCommentElement(writer); 0514 0515 // general 0516 writer->writeStartElement(QStringLiteral("general")); 0517 WRITE_COLUMN(d->posXColumn, posXColumn); 0518 WRITE_COLUMN(d->posYColumn, posYColumn); 0519 WRITE_COLUMN(d->posZColumn, posZColumn); 0520 WRITE_COLUMN(d->plusDeltaXColumn, plusDeltaXColumn); 0521 WRITE_COLUMN(d->minusDeltaXColumn, minusDeltaXColumn); 0522 WRITE_COLUMN(d->plusDeltaYColumn, plusDeltaYColumn); 0523 WRITE_COLUMN(d->minusDeltaYColumn, minusDeltaYColumn); 0524 writer->writeAttribute(QStringLiteral("curveErrorType_X"), QString::number(static_cast<int>(d->curveErrorTypes.x))); 0525 writer->writeAttribute(QStringLiteral("curveErrorType_Y"), QString::number(static_cast<int>(d->curveErrorTypes.y))); 0526 writer->writeAttribute(QStringLiteral("vibible"), QString::number(d->pointVisibility)); 0527 writer->writeEndElement(); 0528 0529 // Symbols 0530 d->symbol->save(writer); 0531 0532 // error bar properties 0533 writer->writeStartElement(QStringLiteral("errorBarProperties")); 0534 writer->writeAttribute(QStringLiteral("pointErrorBarSize"), QString::number(d->pointErrorBarSize)); 0535 WRITE_QBRUSH(d->pointErrorBarBrush); 0536 WRITE_QPEN(d->pointErrorBarPen); 0537 writer->writeEndElement(); 0538 0539 // serialize all children 0540 for (auto* child : children<AbstractAspect>(ChildIndexFlag::IncludeHidden)) 0541 child->save(writer); 0542 0543 writer->writeEndElement(); // close section 0544 } 0545 0546 //! Load from XML 0547 bool DatapickerCurve::load(XmlStreamReader* reader, bool preview) { 0548 Q_D(DatapickerCurve); 0549 0550 if (!readBasicAttributes(reader)) 0551 return false; 0552 0553 QXmlStreamAttributes attribs; 0554 QString str; 0555 0556 while (!reader->atEnd()) { 0557 reader->readNext(); 0558 if (reader->isEndElement() && reader->name() == QLatin1String("datapickerCurve")) 0559 break; 0560 0561 if (!reader->isStartElement()) 0562 continue; 0563 0564 if (reader->name() == QLatin1String("comment")) { 0565 if (!readCommentElement(reader)) 0566 return false; 0567 } else if (!preview && reader->name() == QLatin1String("general")) { 0568 attribs = reader->attributes(); 0569 0570 READ_INT_VALUE("visible", pointVisibility, bool); 0571 READ_INT_VALUE("curveErrorType_X", curveErrorTypes.x, ErrorType); 0572 READ_INT_VALUE("curveErrorType_Y", curveErrorTypes.y, ErrorType); 0573 0574 READ_COLUMN(posXColumn); 0575 READ_COLUMN(posYColumn); 0576 READ_COLUMN(posZColumn); 0577 READ_COLUMN(plusDeltaXColumn); 0578 READ_COLUMN(minusDeltaXColumn); 0579 READ_COLUMN(plusDeltaYColumn); 0580 READ_COLUMN(minusDeltaYColumn); 0581 } else if (!preview && reader->name() == QLatin1String("symbolProperties")) { 0582 // old serialization that was used before the switch to Symbol::load(). 0583 // in the old serialization the symbol properties and "point visibility" where saved 0584 // under "symbolProperties". 0585 attribs = reader->attributes(); 0586 0587 str = attribs.value(QStringLiteral("pointRotationAngle")).toString(); 0588 if (str.isEmpty()) 0589 reader->raiseMissingAttributeWarning(QStringLiteral("pointRotationAngle")); 0590 else 0591 d->symbol->setRotationAngle(str.toDouble()); 0592 0593 str = attribs.value(QStringLiteral("pointOpacity")).toString(); 0594 if (str.isEmpty()) 0595 reader->raiseMissingAttributeWarning(QStringLiteral("pointOpacity")); 0596 else 0597 d->symbol->setOpacity(str.toDouble()); 0598 0599 str = attribs.value(QStringLiteral("pointSize")).toString(); 0600 if (str.isEmpty()) 0601 reader->raiseMissingAttributeWarning(QStringLiteral("pointSize")); 0602 else 0603 d->symbol->setSize(str.toDouble()); 0604 0605 str = attribs.value(QStringLiteral("pointStyle")).toString(); 0606 if (str.isEmpty()) 0607 reader->raiseMissingAttributeWarning(QStringLiteral("pointStyle")); 0608 else 0609 d->symbol->setStyle(static_cast<Symbol::Style>(str.toInt())); 0610 0611 // brush 0612 QBrush brush; 0613 str = attribs.value(QStringLiteral("brush_style")).toString(); 0614 if (str.isEmpty()) 0615 reader->raiseMissingAttributeWarning(QStringLiteral("brush_style")); 0616 else 0617 brush.setStyle(static_cast<Qt::BrushStyle>(str.toInt())); 0618 0619 QColor color; 0620 str = attribs.value(QStringLiteral("brush_color_r")).toString(); 0621 if (str.isEmpty()) 0622 reader->raiseMissingAttributeWarning(QStringLiteral("brush_color_r")); 0623 else 0624 color.setRed(str.toInt()); 0625 0626 str = attribs.value(QStringLiteral("brush_color_g")).toString(); 0627 if (str.isEmpty()) 0628 reader->raiseMissingAttributeWarning(QStringLiteral("brush_color_g")); 0629 else 0630 color.setGreen(str.toInt()); 0631 0632 str = attribs.value(QStringLiteral("brush_color_b")).toString(); 0633 if (str.isEmpty()) 0634 reader->raiseMissingAttributeWarning(QStringLiteral("brush_color_b")); 0635 else 0636 color.setBlue(str.toInt()); 0637 0638 brush.setColor(color); 0639 d->symbol->setBrush(brush); 0640 0641 // pen 0642 QPen pen; 0643 str = attribs.value(QStringLiteral("style")).toString(); 0644 if (str.isEmpty()) 0645 reader->raiseMissingAttributeWarning(QStringLiteral("style")); 0646 else 0647 pen.setStyle(static_cast<Qt::PenStyle>(str.toInt())); 0648 0649 str = attribs.value(QStringLiteral("color_r")).toString(); 0650 if (str.isEmpty()) 0651 reader->raiseMissingAttributeWarning(QStringLiteral("color_r")); 0652 else 0653 color.setRed(str.toInt()); 0654 0655 str = attribs.value(QStringLiteral("color_g")).toString(); 0656 if (str.isEmpty()) 0657 reader->raiseMissingAttributeWarning(QStringLiteral("color_g")); 0658 else 0659 color.setGreen(str.toInt()); 0660 0661 str = attribs.value(QStringLiteral("color_b")).toString(); 0662 if (str.isEmpty()) 0663 reader->raiseMissingAttributeWarning(QStringLiteral("color_b")); 0664 else 0665 color.setBlue(str.toInt()); 0666 0667 pen.setColor(color); 0668 0669 str = attribs.value(QStringLiteral("width")).toString(); 0670 if (str.isEmpty()) 0671 reader->raiseMissingAttributeWarning(QStringLiteral("width")); 0672 else 0673 pen.setWidthF(str.toDouble()); 0674 0675 d->symbol->setPen(pen); 0676 0677 READ_INT_VALUE("pointVisibility", pointVisibility, bool); 0678 } else if (!preview && reader->name() == QLatin1String("symbols")) { 0679 d->symbol->load(reader, preview); 0680 } else if (!preview && reader->name() == QLatin1String("errorBarProperties")) { 0681 attribs = reader->attributes(); 0682 0683 READ_DOUBLE_VALUE("pointErrorBarSize", pointErrorBarSize); 0684 READ_QBRUSH(d->pointErrorBarBrush); 0685 READ_QPEN(d->pointErrorBarPen); 0686 } else if (reader->name() == QLatin1String("datapickerPoint")) { 0687 auto* curvePoint = new DatapickerPoint(QString()); 0688 curvePoint->setHidden(true); 0689 if (!curvePoint->load(reader, preview)) { 0690 delete curvePoint; 0691 return false; 0692 } else { 0693 addChild(curvePoint); 0694 curvePoint->initErrorBar(curveErrorTypes()); 0695 } 0696 } else if (reader->name() == QLatin1String("spreadsheet")) { 0697 auto* datasheet = new Spreadsheet(QStringLiteral("spreadsheet"), true); 0698 if (!datasheet->load(reader, preview)) { 0699 delete datasheet; 0700 return false; 0701 } else { 0702 addChild(datasheet); 0703 datasheet->setFixed(true); 0704 const auto& columns = datasheet->children<Column>(); 0705 for (auto* col : columns) 0706 col->setFixed(true); 0707 m_datasheet = datasheet; 0708 } 0709 } else { // unknown element 0710 reader->raiseUnknownElementWarning(); 0711 if (!reader->skipToEndElement()) 0712 return false; 0713 } 0714 } 0715 0716 d->retransform(); 0717 return true; 0718 }