File indexing completed on 2025-01-26 03:34:10
0001 /* 0002 File : ErrorBar.cpp 0003 Project : LabPlot 0004 Description : ErrorBar 0005 -------------------------------------------------------------------- 0006 SPDX-FileCopyrightText: 2024 Alexander Semke <alexander.semke@web.de> 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 /*! 0011 \class ErrorBar 0012 \brief This class contains the background properties of worksheet elements like worksheet background, 0013 plot background, the area filling in ErrorBar, ErrorBar, etc. 0014 0015 \ingroup worksheet 0016 */ 0017 0018 #include "ErrorBar.h" 0019 #include "ErrorBarPrivate.h" 0020 #include "backend/core/AbstractColumn.h" 0021 #include "backend/core/Project.h" 0022 #include "backend/lib/XmlStreamReader.h" 0023 #include "backend/lib/commandtemplates.h" 0024 #include "backend/lib/macrosCurve.h" 0025 0026 #include <KConfigGroup> 0027 #include <KLocalizedString> 0028 0029 CURVE_COLUMN_CONNECT(ErrorBar, Plus, plus, update) 0030 CURVE_COLUMN_CONNECT(ErrorBar, Minus, minus, update) 0031 0032 ErrorBar::ErrorBar(const QString& name) 0033 : AbstractAspect(name, AspectType::AbstractAspect) 0034 , d_ptr(new ErrorBarPrivate(this)) { 0035 } 0036 0037 ErrorBar::~ErrorBar() { 0038 delete d_ptr; 0039 } 0040 0041 void ErrorBar::setPrefix(const QString& prefix) { 0042 Q_D(ErrorBar); 0043 d->prefix = prefix; 0044 } 0045 0046 const QString& ErrorBar::prefix() const { 0047 Q_D(const ErrorBar); 0048 return d->prefix; 0049 } 0050 0051 void ErrorBar::init(const KConfigGroup& group) { 0052 Q_D(ErrorBar); 0053 d->type = (Type)group.readEntry(d->prefix + QStringLiteral("ErrorType"), static_cast<int>(Type::NoError)); 0054 } 0055 0056 void ErrorBar::update() { 0057 Q_D(ErrorBar); 0058 d->update(); 0059 } 0060 0061 // ############################################################################## 0062 // ########################## getter methods ################################## 0063 // ############################################################################## 0064 BASIC_SHARED_D_READER_IMPL(ErrorBar, ErrorBar::Type, type, type) 0065 BASIC_SHARED_D_READER_IMPL(ErrorBar, const AbstractColumn*, plusColumn, plusColumn) 0066 BASIC_SHARED_D_READER_IMPL(ErrorBar, const AbstractColumn*, minusColumn, minusColumn) 0067 BASIC_SHARED_D_READER_IMPL(ErrorBar, QString, plusColumnPath, plusColumnPath) 0068 BASIC_SHARED_D_READER_IMPL(ErrorBar, QString, minusColumnPath, minusColumnPath) 0069 0070 // ############################################################################## 0071 // ################# setter methods and undo commands ########################## 0072 // ############################################################################## 0073 STD_SETTER_CMD_IMPL_F_S(ErrorBar, SetType, ErrorBar::Type, type, update) 0074 void ErrorBar::setType(Type type) { 0075 Q_D(ErrorBar); 0076 if (type != d->type) 0077 exec(new ErrorBarSetTypeCmd(d, type, ki18n("%1: error type changed"))); 0078 } 0079 0080 CURVE_COLUMN_SETTER_CMD_IMPL_F_S(ErrorBar, Plus, plus, update) 0081 void ErrorBar::setPlusColumn(const AbstractColumn* column) { 0082 Q_D(ErrorBar); 0083 if (column != d->plusColumn) 0084 exec(new ErrorBarSetPlusColumnCmd(d, column, ki18n("%1: set error column"))); 0085 } 0086 0087 void ErrorBar::setPlusColumnPath(const QString& path) { 0088 Q_D(ErrorBar); 0089 d->plusColumnPath = path; 0090 } 0091 0092 CURVE_COLUMN_SETTER_CMD_IMPL_F_S(ErrorBar, Minus, minus, update) 0093 void ErrorBar::setMinusColumn(const AbstractColumn* column) { 0094 Q_D(ErrorBar); 0095 if (column != d->minusColumn) 0096 exec(new ErrorBarSetMinusColumnCmd(d, column, ki18n("%1: set error column"))); 0097 } 0098 0099 void ErrorBar::setMinusColumnPath(const QString& path) { 0100 Q_D(ErrorBar); 0101 d->minusColumnPath = path; 0102 } 0103 0104 void ErrorBar::plusColumnAboutToBeRemoved(const AbstractAspect* aspect) { 0105 Q_D(ErrorBar); 0106 if (aspect == d->plusColumn) { 0107 d->plusColumn = nullptr; 0108 d->update(); 0109 } 0110 } 0111 0112 void ErrorBar::minusColumnAboutToBeRemoved(const AbstractAspect* aspect) { 0113 Q_D(ErrorBar); 0114 if (aspect == d->minusColumn) { 0115 d->minusColumn = nullptr; 0116 d->update(); 0117 } 0118 } 0119 0120 // ############################################################################## 0121 // ####################### Private implementation ############################### 0122 // ############################################################################## 0123 ErrorBarPrivate::ErrorBarPrivate(ErrorBar* owner) 0124 : q(owner) { 0125 } 0126 0127 QString ErrorBarPrivate::name() const { 0128 return q->parentAspect()->name(); 0129 } 0130 0131 void ErrorBarPrivate::update() { 0132 Q_EMIT q->updateRequested(); 0133 } 0134 0135 // ############################################################################## 0136 // ################## Serialization/Deserialization ########################### 0137 // ############################################################################## 0138 //! Save as XML 0139 void ErrorBar::save(QXmlStreamWriter* writer) const { 0140 Q_D(const ErrorBar); 0141 0142 if (!d->prefix.isEmpty()) { 0143 // for names in the XML file, the first letter is lower case but the camel case still remains. 0144 QString newPrefix = d->prefix; 0145 newPrefix.replace(0, 1, d->prefix.at(0).toLower()); 0146 0147 writer->writeAttribute(newPrefix + QStringLiteral("ErrorType"), QString::number(static_cast<int>(d->type))); 0148 0149 if (d->plusColumn) 0150 writer->writeAttribute(newPrefix + QStringLiteral("ErrorPlusColumn"), d->plusColumn->path()); 0151 else 0152 writer->writeAttribute(newPrefix + QStringLiteral("ErrorPlusColumn"), QString()); 0153 0154 if (d->minusColumn) 0155 writer->writeAttribute(newPrefix + QStringLiteral("ErrorMinusColumn"), d->minusColumn->path()); 0156 else 0157 writer->writeAttribute(newPrefix + QStringLiteral("ErrorMinusColumn"), QString()); 0158 } else { 0159 writer->writeAttribute(QStringLiteral("errorType"), QString::number(static_cast<int>(d->type))); 0160 WRITE_COLUMN(d->plusColumn, errorPlusColumn); 0161 WRITE_COLUMN(d->minusColumn, errorMinusColumn); 0162 } 0163 } 0164 0165 //! Load from XML 0166 bool ErrorBar::load(XmlStreamReader* reader, bool preview) { 0167 if (preview) 0168 return true; 0169 0170 Q_D(ErrorBar); 0171 QString str; 0172 auto attribs = reader->attributes(); 0173 int type = 0; 0174 0175 if (!d->prefix.isEmpty()) { 0176 QString newPrefix = d->prefix; 0177 newPrefix.replace(0, 1, d->prefix.at(0).toLower()); 0178 0179 type = attribs.value(newPrefix + QStringLiteral("ErrorType")).toInt(); 0180 d->plusColumnPath = attribs.value(newPrefix + QStringLiteral("ErrorPlusColumn")).toString(); 0181 d->minusColumnPath = attribs.value(newPrefix + QStringLiteral("ErrorMinusColumn")).toString(); 0182 } else { 0183 type = attribs.value(QStringLiteral("errorType")).toInt(); 0184 d->plusColumnPath = attribs.value(QStringLiteral("errorPlusColumn")).toString(); 0185 d->minusColumnPath = attribs.value(QStringLiteral("errorMinusColumn")).toString(); 0186 } 0187 0188 // prior to XML version 11, a different order of enum values for the error type was used in Histogram 0189 // (old "{ NoError, Poisson, CustomSymmetric, CustomAsymmetric }" instead of 0190 // the new "{ NoError, Symmetric, Asymmetric, Poisson }") 0191 // and we need to map from the old to the new values 0192 if (Project::xmlVersion() < 11 && parentAspect()->type() == AspectType::Histogram) { 0193 if (type == 0) 0194 d->type = ErrorBar::Type::NoError; 0195 else if (type == 1) 0196 d->type = ErrorBar::Type::Poisson; 0197 else if (type == 2) 0198 d->type = ErrorBar::Type::Symmetric; 0199 else if (type == 3) 0200 d->type = ErrorBar::Type::Asymmetric; 0201 } else 0202 d->type = static_cast<Type>(type); 0203 0204 return true; 0205 }