File indexing completed on 2025-09-14 03:43:12
0001 /* 0002 File : XYCurveDock.cpp 0003 Project : LabPlot 0004 Description : widget for XYCurve properties 0005 -------------------------------------------------------------------- 0006 SPDX-FileCopyrightText: 2010-2024 Alexander Semke <alexander.semke@web.de> 0007 SPDX-FileCopyrightText: 2012-2022 Stefan Gerlach <stefan.gerlach@uni-konstanz.de> 0008 0009 SPDX-License-Identifier: GPL-2.0-or-later 0010 */ 0011 0012 #include "XYCurveDock.h" 0013 #include "backend/core/Project.h" 0014 #include "backend/core/Settings.h" 0015 #include "backend/core/column/Column.h" 0016 #include "backend/core/datatypes/DateTime2StringFilter.h" 0017 #include "backend/core/datatypes/Double2StringFilter.h" 0018 #include "backend/worksheet/Worksheet.h" 0019 #include "backend/worksheet/plots/cartesian/ErrorBarStyle.h" 0020 #include "backend/worksheet/plots/cartesian/XYCurve.h" 0021 #include "commonfrontend/widgets/TreeViewComboBox.h" 0022 #include "kdefrontend/GuiTools.h" 0023 #include "kdefrontend/TemplateHandler.h" 0024 #include "kdefrontend/widgets/BackgroundWidget.h" 0025 #include "kdefrontend/widgets/ErrorBarStyleWidget.h" 0026 #include "kdefrontend/widgets/LineWidget.h" 0027 #include "kdefrontend/widgets/SymbolWidget.h" 0028 0029 #include <QPainter> 0030 0031 #include <KConfig> 0032 #include <KConfigGroup> 0033 #include <KLocalizedString> 0034 0035 /*! 0036 \class XYCurveDock 0037 \brief Provides a widget for editing the properties of the XYCurves (2D-curves) currently selected in the project explorer. 0038 0039 If more than one curves are set, the properties of the first column are shown. The changes of the properties are applied to all curves. 0040 The exclusions are the name, the comment and the datasets (columns) of the curves - these properties can only be changed if there is only one single curve. 0041 0042 \ingroup kdefrontend 0043 */ 0044 0045 XYCurveDock::XYCurveDock(QWidget* parent) 0046 : BaseDock(parent) { 0047 ui.setupUi(this); 0048 0049 // Tab "Line" 0050 auto* gridLayout = qobject_cast<QGridLayout*>(ui.tabLine->layout()); 0051 lineWidget = new LineWidget(ui.tabLine); 0052 gridLayout->addWidget(lineWidget, 5, 0, 1, 3); 0053 0054 dropLineWidget = new LineWidget(ui.tabLine); 0055 gridLayout->addWidget(dropLineWidget, 8, 0, 1, 3); 0056 0057 // Tab "Symbol" 0058 auto* hboxLayout = new QHBoxLayout(ui.tabSymbol); 0059 symbolWidget = new SymbolWidget(ui.tabSymbol); 0060 hboxLayout->addWidget(symbolWidget); 0061 hboxLayout->setContentsMargins(2, 2, 2, 2); 0062 hboxLayout->setSpacing(2); 0063 0064 // Tab "Values" 0065 gridLayout = qobject_cast<QGridLayout*>(ui.tabValues->layout()); 0066 cbValuesColumn = new TreeViewComboBox(ui.tabValues); 0067 gridLayout->addWidget(cbValuesColumn, 2, 2, 1, 1); 0068 0069 // add formats for numeric values 0070 ui.cbValuesNumericFormat->addItem(i18n("Decimal"), QVariant('f')); 0071 ui.cbValuesNumericFormat->addItem(i18n("Scientific (e)"), QVariant('e')); 0072 ui.cbValuesNumericFormat->addItem(i18n("Scientific (E)"), QVariant('E')); 0073 ui.cbValuesNumericFormat->addItem(i18n("Automatic (e)"), QVariant('g')); 0074 ui.cbValuesNumericFormat->addItem(i18n("Automatic (E)"), QVariant('G')); 0075 0076 // add format for date, time and datetime values 0077 for (const auto& s : AbstractColumn::dateTimeFormats()) 0078 ui.cbValuesDateTimeFormat->addItem(s, QVariant(s)); 0079 0080 ui.cbValuesDateTimeFormat->setEditable(true); 0081 0082 // Tab "Filling" 0083 auto* layout = static_cast<QHBoxLayout*>(ui.tabAreaFilling->layout()); 0084 backgroundWidget = new BackgroundWidget(ui.tabAreaFilling); 0085 layout->insertWidget(0, backgroundWidget); 0086 0087 // Tab "Error Bars" 0088 const KConfigGroup group = Settings::group(QStringLiteral("Settings_General")); 0089 if (group.readEntry(QStringLiteral("GUMTerms"), false)) { 0090 ui.tabWidget->setTabText(ui.tabWidget->indexOf(ui.tabErrorBars), i18n("Uncertainty Bars")); 0091 ui.lErrorBarX->setText(i18n("X Uncertainty")); 0092 ui.lErrorBarY->setText(i18n("Y Uncertainty")); 0093 } 0094 0095 gridLayout = qobject_cast<QGridLayout*>(ui.tabErrorBars->layout()); 0096 0097 cbXErrorPlusColumn = new TreeViewComboBox(ui.tabErrorBars); 0098 gridLayout->addWidget(cbXErrorPlusColumn, 2, 2, 1, 1); 0099 0100 cbXErrorMinusColumn = new TreeViewComboBox(ui.tabErrorBars); 0101 gridLayout->addWidget(cbXErrorMinusColumn, 3, 2, 1, 1); 0102 0103 cbYErrorPlusColumn = new TreeViewComboBox(ui.tabErrorBars); 0104 gridLayout->addWidget(cbYErrorPlusColumn, 7, 2, 1, 1); 0105 0106 cbYErrorMinusColumn = new TreeViewComboBox(ui.tabErrorBars); 0107 gridLayout->addWidget(cbYErrorMinusColumn, 8, 2, 1, 1); 0108 0109 errorBarStyleWidget = new ErrorBarStyleWidget(ui.tabErrorBars); 0110 gridLayout->addWidget(errorBarStyleWidget, 11, 0, 1, 3); 0111 0112 // Tab "Margin Plots" 0113 ui.cbRugOrientation->addItem(i18n("Vertical")); 0114 ui.cbRugOrientation->addItem(i18n("Horizontal")); 0115 ui.cbRugOrientation->addItem(i18n("Both")); 0116 0117 // adjust layouts in the tabs 0118 for (int i = 0; i < ui.tabWidget->count(); ++i) { 0119 auto* layout = dynamic_cast<QGridLayout*>(ui.tabWidget->widget(i)->layout()); 0120 if (!layout) 0121 continue; 0122 0123 layout->setContentsMargins(2, 2, 2, 2); 0124 layout->setHorizontalSpacing(2); 0125 layout->setVerticalSpacing(2); 0126 } 0127 0128 XYCurveDock::updateLocale(); 0129 0130 // Slots 0131 0132 // Lines 0133 connect(ui.cbLineType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYCurveDock::lineTypeChanged); 0134 connect(ui.sbLineInterpolationPointsCount, QOverload<int>::of(&QSpinBox::valueChanged), this, &XYCurveDock::lineInterpolationPointsCountChanged); 0135 connect(ui.chkLineSkipGaps, &QCheckBox::clicked, this, &XYCurveDock::lineSkipGapsChanged); 0136 connect(ui.chkLineIncreasingXOnly, &QCheckBox::clicked, this, &XYCurveDock::lineIncreasingXOnlyChanged); 0137 0138 // Values 0139 connect(ui.cbValuesType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYCurveDock::valuesTypeChanged); 0140 connect(cbValuesColumn, &TreeViewComboBox::currentModelIndexChanged, this, &XYCurveDock::valuesColumnChanged); 0141 connect(ui.cbValuesPosition, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYCurveDock::valuesPositionChanged); 0142 connect(ui.sbValuesDistance, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &XYCurveDock::valuesDistanceChanged); 0143 connect(ui.sbValuesRotation, QOverload<int>::of(&QSpinBox::valueChanged), this, &XYCurveDock::valuesRotationChanged); 0144 connect(ui.sbValuesOpacity, QOverload<int>::of(&QSpinBox::valueChanged), this, &XYCurveDock::valuesOpacityChanged); 0145 connect(ui.cbValuesNumericFormat, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYCurveDock::valuesNumericFormatChanged); 0146 connect(ui.sbValuesPrecision, QOverload<int>::of(&QSpinBox::valueChanged), this, &XYCurveDock::valuesPrecisionChanged); 0147 connect(ui.cbValuesDateTimeFormat, &QComboBox::currentTextChanged, this, &XYCurveDock::valuesDateTimeFormatChanged); 0148 connect(ui.leValuesPrefix, &QLineEdit::textChanged, this, &XYCurveDock::valuesPrefixChanged); 0149 connect(ui.leValuesSuffix, &QLineEdit::textChanged, this, &XYCurveDock::valuesSuffixChanged); 0150 connect(ui.kfrValuesFont, &KFontRequester::fontSelected, this, &XYCurveDock::valuesFontChanged); 0151 connect(ui.kcbValuesColor, &KColorButton::changed, this, &XYCurveDock::valuesColorChanged); 0152 0153 // Error bars 0154 connect(ui.cbXErrorType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYCurveDock::xErrorTypeChanged); 0155 connect(cbXErrorPlusColumn, &TreeViewComboBox::currentModelIndexChanged, this, &XYCurveDock::xErrorPlusColumnChanged); 0156 connect(cbXErrorMinusColumn, &TreeViewComboBox::currentModelIndexChanged, this, &XYCurveDock::xErrorMinusColumnChanged); 0157 connect(ui.cbYErrorType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYCurveDock::yErrorTypeChanged); 0158 connect(cbYErrorPlusColumn, &TreeViewComboBox::currentModelIndexChanged, this, &XYCurveDock::yErrorPlusColumnChanged); 0159 connect(cbYErrorMinusColumn, &TreeViewComboBox::currentModelIndexChanged, this, &XYCurveDock::yErrorMinusColumnChanged); 0160 0161 // Margin Plots 0162 connect(ui.chkRugEnabled, &QCheckBox::toggled, this, &XYCurveDock::rugEnabledChanged); 0163 connect(ui.cbRugOrientation, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYCurveDock::rugOrientationChanged); 0164 connect(ui.sbRugLength, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &XYCurveDock::rugLengthChanged); 0165 connect(ui.sbRugWidth, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &XYCurveDock::rugWidthChanged); 0166 connect(ui.sbRugOffset, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &XYCurveDock::rugOffsetChanged); 0167 0168 // template handler 0169 auto* frame = new QFrame(this); 0170 layout = new QHBoxLayout(frame); 0171 layout->setContentsMargins(0, 11, 0, 11); 0172 0173 auto* templateHandler = new TemplateHandler(this, QLatin1String("XYCurve")); 0174 layout->addWidget(templateHandler); 0175 connect(templateHandler, &TemplateHandler::loadConfigRequested, this, &XYCurveDock::loadConfigFromTemplate); 0176 connect(templateHandler, &TemplateHandler::saveConfigRequested, this, &XYCurveDock::saveConfigAsTemplate); 0177 connect(templateHandler, &TemplateHandler::info, this, &XYCurveDock::info); 0178 0179 ui.verticalLayout->addWidget(frame); 0180 0181 retranslateUi(); 0182 init(); 0183 } 0184 0185 XYCurveDock::~XYCurveDock() { 0186 delete m_valuesModel; 0187 } 0188 0189 void XYCurveDock::setupGeneral() { 0190 auto* generalTab = new QWidget(ui.tabGeneral); 0191 uiGeneralTab.setupUi(generalTab); 0192 setPlotRangeCombobox(uiGeneralTab.cbPlotRanges); 0193 setBaseWidgets(uiGeneralTab.leName, uiGeneralTab.teComment); 0194 setVisibilityWidgets(uiGeneralTab.chkVisible, uiGeneralTab.chkLegendVisible); 0195 0196 auto* layout = new QHBoxLayout(ui.tabGeneral); 0197 layout->setContentsMargins(0, 0, 0, 0); 0198 layout->addWidget(generalTab); 0199 0200 // Tab "General" (see xycurvedockgeneraltab.ui) 0201 auto* gridLayout = qobject_cast<QGridLayout*>(generalTab->layout()); 0202 0203 cbXColumn = new TreeViewComboBox(generalTab); 0204 cbXColumn->useCurrentIndexText(false); 0205 gridLayout->addWidget(cbXColumn, 4, 2, 1, 1); 0206 0207 cbYColumn = new TreeViewComboBox(generalTab); 0208 cbYColumn->useCurrentIndexText(false); 0209 gridLayout->addWidget(cbYColumn, 5, 2, 1, 1); 0210 0211 // General 0212 connect(cbXColumn, &TreeViewComboBox::currentModelIndexChanged, this, &XYCurveDock::xColumnChanged); 0213 connect(cbYColumn, &TreeViewComboBox::currentModelIndexChanged, this, &XYCurveDock::yColumnChanged); 0214 } 0215 0216 void XYCurveDock::init() { 0217 m_initializing = true; 0218 0219 // Line 0220 ui.cbLineType->addItem(i18n("None")); 0221 ui.cbLineType->addItem(i18n("Line")); 0222 ui.cbLineType->addItem(i18n("Horiz. Start")); 0223 ui.cbLineType->addItem(i18n("Vert. Start")); 0224 ui.cbLineType->addItem(i18n("Horiz. Midpoint")); 0225 ui.cbLineType->addItem(i18n("Vert. Midpoint")); 0226 ui.cbLineType->addItem(i18n("2-segments")); 0227 ui.cbLineType->addItem(i18n("3-segments")); 0228 ui.cbLineType->addItem(i18n("Cubic Spline (Natural)")); 0229 ui.cbLineType->addItem(i18n("Cubic Spline (Periodic)")); 0230 ui.cbLineType->addItem(i18n("Akima-spline (Natural)")); 0231 ui.cbLineType->addItem(i18n("Akima-spline (Periodic)")); 0232 0233 QPainter pa; 0234 // TODO size of the icon depending on the actual height of the combobox? 0235 int iconSize = 20; 0236 QPixmap pm(iconSize, iconSize); 0237 ui.cbLineType->setIconSize(QSize(iconSize, iconSize)); 0238 0239 QPen pen(Qt::SolidPattern, 0); 0240 const QColor& color = GuiTools::isDarkMode() ? Qt::white : Qt::black; 0241 pen.setColor(color); 0242 pa.setPen(pen); 0243 0244 // no line 0245 pm.fill(Qt::transparent); 0246 pa.begin(&pm); 0247 pa.setPen(pen); 0248 pa.setRenderHint(QPainter::Antialiasing); 0249 pa.drawEllipse(1, 1, 4, 4); 0250 pa.drawEllipse(15, 15, 4, 4); 0251 pa.end(); 0252 ui.cbLineType->setItemIcon(0, pm); 0253 0254 // line 0255 pm.fill(Qt::transparent); 0256 pa.begin(&pm); 0257 pa.setPen(pen); 0258 pa.setRenderHint(QPainter::Antialiasing); 0259 pa.drawEllipse(1, 1, 4, 4); 0260 pa.drawEllipse(15, 15, 4, 4); 0261 pa.drawLine(3, 3, 17, 17); 0262 pa.end(); 0263 ui.cbLineType->setItemIcon(1, pm); 0264 0265 pm.fill(Qt::transparent); 0266 pa.begin(&pm); 0267 pa.setPen(pen); 0268 pa.setRenderHint(QPainter::Antialiasing); 0269 pa.drawEllipse(1, 1, 4, 4); 0270 pa.drawEllipse(15, 15, 4, 4); 0271 pa.drawLine(3, 3, 17, 3); 0272 pa.drawLine(17, 3, 17, 17); 0273 pa.end(); 0274 ui.cbLineType->setItemIcon(2, pm); 0275 0276 pm.fill(Qt::transparent); 0277 pa.begin(&pm); 0278 pa.setPen(pen); 0279 pa.setRenderHint(QPainter::Antialiasing); 0280 pa.drawEllipse(1, 1, 4, 4); 0281 pa.drawEllipse(15, 15, 4, 4); 0282 pa.drawLine(3, 3, 3, 17); 0283 pa.drawLine(3, 17, 17, 17); 0284 pa.end(); 0285 ui.cbLineType->setItemIcon(3, pm); 0286 0287 // horizontal midpoint 0288 pm.fill(Qt::transparent); 0289 pa.begin(&pm); 0290 pa.setPen(pen); 0291 pa.setRenderHint(QPainter::Antialiasing); 0292 pa.drawEllipse(1, 1, 4, 4); 0293 pa.drawEllipse(15, 15, 4, 4); 0294 pa.drawLine(3, 3, 10, 3); 0295 pa.drawLine(10, 3, 10, 17); 0296 pa.drawLine(10, 17, 17, 17); 0297 pa.end(); 0298 ui.cbLineType->setItemIcon(4, pm); 0299 0300 // vertical midpoint 0301 pm.fill(Qt::transparent); 0302 pa.begin(&pm); 0303 pa.setPen(pen); 0304 pa.setRenderHint(QPainter::Antialiasing); 0305 pa.drawEllipse(1, 1, 4, 4); 0306 pa.drawEllipse(15, 15, 4, 4); 0307 pa.drawLine(3, 3, 3, 10); 0308 pa.drawLine(3, 10, 17, 10); 0309 pa.drawLine(17, 10, 17, 17); 0310 pa.end(); 0311 ui.cbLineType->setItemIcon(5, pm); 0312 0313 // 2-segments 0314 pm.fill(Qt::transparent); 0315 pa.begin(&pm); 0316 pa.setPen(pen); 0317 pa.setRenderHint(QPainter::Antialiasing); 0318 pa.drawEllipse(1, 1, 4, 4); 0319 pa.drawEllipse(8, 8, 4, 4); 0320 pa.drawEllipse(15, 15, 4, 4); 0321 pa.drawLine(3, 3, 10, 10); 0322 pa.end(); 0323 ui.cbLineType->setItemIcon(6, pm); 0324 0325 // 3-segments 0326 pm.fill(Qt::transparent); 0327 pa.begin(&pm); 0328 pa.setPen(pen); 0329 pa.setRenderHint(QPainter::Antialiasing); 0330 pa.drawEllipse(1, 1, 4, 4); 0331 pa.drawEllipse(8, 8, 4, 4); 0332 pa.drawEllipse(15, 15, 4, 4); 0333 pa.drawLine(3, 3, 17, 17); 0334 pa.end(); 0335 ui.cbLineType->setItemIcon(7, pm); 0336 0337 // natural spline 0338 pm.fill(Qt::transparent); 0339 pa.begin(&pm); 0340 pa.setPen(pen); 0341 pa.setRenderHint(QPainter::Antialiasing); 0342 pa.drawEllipse(1, 1, 4, 4); 0343 pa.drawEllipse(15, 15, 4, 4); 0344 pa.rotate(45); 0345 pa.drawArc(2 * sqrt(2), -4, 17 * sqrt(2), 20, 30 * 16, 120 * 16); 0346 0347 pa.end(); 0348 ui.cbLineType->setItemIcon(8, pm); 0349 ui.cbLineType->setItemIcon(9, pm); 0350 ui.cbLineType->setItemIcon(10, pm); 0351 ui.cbLineType->setItemIcon(11, pm); 0352 0353 m_initializing = false; 0354 0355 // Values 0356 ui.cbValuesType->addItem(i18n("No Values")); 0357 ui.cbValuesType->addItem(QStringLiteral("x")); 0358 ui.cbValuesType->addItem(QStringLiteral("y")); 0359 ui.cbValuesType->addItem(QStringLiteral("x, y")); 0360 ui.cbValuesType->addItem(QStringLiteral("(x, y)")); 0361 ui.cbValuesType->addItem(i18n("Custom Column")); 0362 0363 ui.cbValuesPosition->addItem(i18n("Above")); 0364 ui.cbValuesPosition->addItem(i18n("Below")); 0365 ui.cbValuesPosition->addItem(i18n("Left")); 0366 ui.cbValuesPosition->addItem(i18n("Right")); 0367 0368 // Error Bars 0369 ui.cbXErrorType->addItem(i18n("No"), static_cast<int>(ErrorBar::Type::NoError)); 0370 ui.cbXErrorType->addItem(i18n("Symmetric"), static_cast<int>(ErrorBar::Type::Symmetric)); 0371 ui.cbXErrorType->addItem(i18n("Asymmetric"), static_cast<int>(ErrorBar::Type::Asymmetric)); 0372 0373 ui.cbYErrorType->addItem(i18n("No"), static_cast<int>(ErrorBar::Type::NoError)); 0374 ui.cbYErrorType->addItem(i18n("Symmetric"), static_cast<int>(ErrorBar::Type::Symmetric)); 0375 ui.cbYErrorType->addItem(i18n("Asymmetric"), static_cast<int>(ErrorBar::Type::Asymmetric)); 0376 } 0377 0378 QList<AspectType> XYCurveDock::defaultColumnTopLevelClasses() { 0379 return {AspectType::Folder, 0380 AspectType::Workbook, 0381 AspectType::Datapicker, 0382 AspectType::DatapickerCurve, 0383 AspectType::Spreadsheet, 0384 AspectType::LiveDataSource, 0385 AspectType::Column, 0386 AspectType::Worksheet, 0387 AspectType::CartesianPlot, 0388 AspectType::CantorWorksheet}; 0389 } 0390 0391 void XYCurveDock::setModel() { 0392 auto* model = aspectModel(); 0393 model->enablePlottableColumnsOnly(true); 0394 model->enableShowPlotDesignation(true); 0395 0396 QList<AspectType> list = defaultColumnTopLevelClasses(); 0397 list.append(AspectType::XYFitCurve); 0398 list.append(AspectType::XYSmoothCurve); 0399 0400 if (cbXColumn && cbYColumn) { 0401 cbXColumn->setTopLevelClasses(list); 0402 cbYColumn->setTopLevelClasses(list); 0403 } 0404 cbValuesColumn->setTopLevelClasses(list); 0405 cbXErrorMinusColumn->setTopLevelClasses(list); 0406 cbXErrorPlusColumn->setTopLevelClasses(list); 0407 cbYErrorMinusColumn->setTopLevelClasses(list); 0408 cbYErrorPlusColumn->setTopLevelClasses(list); 0409 0410 if (m_curve->inherits(AspectType::XYAnalysisCurve)) 0411 // the model is used in the combobox for curve data sources -> allow to also select analysis curves 0412 list = {AspectType::Column, 0413 AspectType::XYCurve, 0414 AspectType::XYFitCurve, 0415 AspectType::XYIntegrationCurve, 0416 AspectType::XYInterpolationCurve, 0417 AspectType::XYSmoothCurve, 0418 AspectType::XYFourierFilterCurve, 0419 AspectType::XYFourierTransformCurve, 0420 AspectType::XYConvolutionCurve, 0421 AspectType::XYCorrelationCurve, 0422 AspectType::XYDataReductionCurve}; 0423 else 0424 list = {AspectType::Column}; 0425 0426 model->setSelectableAspects(list); 0427 0428 if (cbXColumn && cbYColumn) { 0429 cbXColumn->setModel(model); 0430 cbYColumn->setModel(model); 0431 } 0432 0433 cbXErrorMinusColumn->setModel(model); 0434 cbXErrorPlusColumn->setModel(model); 0435 cbYErrorMinusColumn->setModel(model); 0436 cbYErrorPlusColumn->setModel(model); 0437 0438 // for value labels we need a dedicated model since we also want to allow 0439 // to select text columns and we don't want to call enablePlottableColumnsOnly(). 0440 if (!m_valuesModel) { 0441 m_valuesModel = new AspectTreeModel(m_curve->project()); 0442 m_valuesModel->setSelectableAspects(list); 0443 } 0444 cbValuesColumn->setModel(m_valuesModel); 0445 0446 // this function is called after the dock widget is initialized and the curves are set. 0447 // so, we use this function to finalize the initialization even though it's not related 0448 // to the actual set of the model (could also be solved by a new class XYAnalysisiCurveDock). 0449 0450 // hide property widgets that are not relevant for analysis curves 0451 bool visible = (m_curve->type() == AspectType::XYCurve); 0452 ui.lLineType->setVisible(visible); 0453 ui.cbLineType->setVisible(visible); 0454 ui.lLineSkipGaps->setVisible(visible); 0455 ui.chkLineSkipGaps->setVisible(visible); 0456 ui.lLineIncreasingXOnly->setVisible(visible); 0457 ui.chkLineIncreasingXOnly->setVisible(visible); 0458 0459 // if it's not a xy-curve, it's an analysis curve and the line widget is always enables since we always draw the line 0460 if (!visible) 0461 lineWidget->setEnabled(true); 0462 0463 // remove the tab "Error bars" for analysis curves 0464 if (!visible) 0465 ui.tabWidget->removeTab(5); 0466 } 0467 0468 /*! 0469 sets the curves. The properties of the curves in the list \c list can be edited in this widget. 0470 */ 0471 void XYCurveDock::setCurves(QList<XYCurve*> list) { 0472 CONDITIONAL_LOCK_RETURN; 0473 m_curvesList = list; 0474 m_curve = list.first(); 0475 setAspects(list); 0476 Q_ASSERT(m_curve); 0477 setModel(); 0478 initGeneralTab(); 0479 initTabs(); 0480 setSymbols(list); 0481 } 0482 0483 void XYCurveDock::setSymbols(QList<XYCurve*> curves) { 0484 // symbols 0485 QList<Symbol*> symbols; 0486 QList<Background*> backgrounds; 0487 QList<Line*> lines; 0488 QList<Line*> dropLines; 0489 QList<ErrorBarStyle*> errorBarStyles; 0490 for (auto* curve : curves) { 0491 symbols << curve->symbol(); 0492 backgrounds << curve->background(); 0493 lines << curve->line(); 0494 dropLines << curve->dropLine(); 0495 errorBarStyles << curve->errorBarStyle(); 0496 } 0497 0498 symbolWidget->setSymbols(symbols); 0499 backgroundWidget->setBackgrounds(backgrounds); 0500 lineWidget->setLines(lines); 0501 dropLineWidget->setLines(dropLines); 0502 errorBarStyleWidget->setErrorBarStyles(errorBarStyles); 0503 } 0504 0505 void XYCurveDock::initGeneralTab() { 0506 // show the properties of the first curve 0507 cbXColumn->setColumn(m_curve->xColumn(), m_curve->xColumnPath()); 0508 cbYColumn->setColumn(m_curve->yColumn(), m_curve->yColumnPath()); 0509 uiGeneralTab.chkLegendVisible->setChecked(m_curve->legendVisible()); 0510 uiGeneralTab.chkVisible->setChecked(m_curve->isVisible()); 0511 0512 updatePlotRangeList(); 0513 0514 // Slots 0515 connect(m_curve, &XYCurve::aspectDescriptionChanged, this, &XYCurveDock::curveDescriptionChanged); 0516 connect(m_curve, &XYCurve::xColumnChanged, this, &XYCurveDock::curveXColumnChanged); 0517 connect(m_curve, &XYCurve::yColumnChanged, this, &XYCurveDock::curveYColumnChanged); 0518 connect(m_curve, &WorksheetElement::plotRangeListChanged, this, &XYCurveDock::updatePlotRangeList); 0519 } 0520 0521 void XYCurveDock::initTabs() { 0522 // if there are more than one curve in the list, disable the tab "general" 0523 if (m_curvesList.size() == 1) { 0524 cbValuesColumn->setColumn(m_curve->valuesColumn(), m_curve->valuesColumnPath()); 0525 const auto* xErrorBar = m_curve->xErrorBar(); 0526 const auto* yErrorBar = m_curve->yErrorBar(); 0527 cbXErrorPlusColumn->setColumn(xErrorBar->plusColumn(), xErrorBar->plusColumnPath()); 0528 cbXErrorMinusColumn->setColumn(xErrorBar->minusColumn(), xErrorBar->minusColumnPath()); 0529 cbYErrorPlusColumn->setColumn(yErrorBar->plusColumn(), yErrorBar->plusColumnPath()); 0530 cbYErrorMinusColumn->setColumn(yErrorBar->minusColumn(), yErrorBar->minusColumnPath()); 0531 } else { 0532 cbValuesColumn->setCurrentModelIndex(QModelIndex()); 0533 cbXErrorPlusColumn->setCurrentModelIndex(QModelIndex()); 0534 cbXErrorMinusColumn->setCurrentModelIndex(QModelIndex()); 0535 cbYErrorPlusColumn->setCurrentModelIndex(QModelIndex()); 0536 cbYErrorMinusColumn->setCurrentModelIndex(QModelIndex()); 0537 } 0538 0539 // show the properties of the first curve 0540 load(); 0541 0542 // Slots 0543 0544 // Line-Tab 0545 connect(m_curve, &XYCurve::lineTypeChanged, this, &XYCurveDock::curveLineTypeChanged); 0546 connect(m_curve, &XYCurve::lineSkipGapsChanged, this, &XYCurveDock::curveLineSkipGapsChanged); 0547 connect(m_curve, &XYCurve::lineIncreasingXOnlyChanged, this, &XYCurveDock::curveLineIncreasingXOnlyChanged); 0548 connect(m_curve, &XYCurve::lineInterpolationPointsCountChanged, this, &XYCurveDock::curveLineInterpolationPointsCountChanged); 0549 0550 // Values-Tab 0551 connect(m_curve, &XYCurve::valuesTypeChanged, this, &XYCurveDock::curveValuesTypeChanged); 0552 connect(m_curve, &XYCurve::valuesColumnChanged, this, &XYCurveDock::curveValuesColumnChanged); 0553 connect(m_curve, &XYCurve::valuesPositionChanged, this, &XYCurveDock::curveValuesPositionChanged); 0554 connect(m_curve, &XYCurve::valuesDistanceChanged, this, &XYCurveDock::curveValuesDistanceChanged); 0555 connect(m_curve, &XYCurve::valuesOpacityChanged, this, &XYCurveDock::curveValuesOpacityChanged); 0556 connect(m_curve, &XYCurve::valuesRotationAngleChanged, this, &XYCurveDock::curveValuesRotationAngleChanged); 0557 connect(m_curve, &XYCurve::valuesNumericFormatChanged, this, &XYCurveDock::curveValuesNumericFormatChanged); 0558 connect(m_curve, &XYCurve::valuesPrecisionChanged, this, &XYCurveDock::curveValuesPrecisionChanged); 0559 connect(m_curve, &XYCurve::valuesDateTimeFormatChanged, this, &XYCurveDock::curveValuesDateTimeFormatChanged); 0560 connect(m_curve, &XYCurve::valuesPrefixChanged, this, &XYCurveDock::curveValuesPrefixChanged); 0561 connect(m_curve, &XYCurve::valuesSuffixChanged, this, &XYCurveDock::curveValuesSuffixChanged); 0562 connect(m_curve, &XYCurve::valuesFontChanged, this, &XYCurveDock::curveValuesFontChanged); 0563 connect(m_curve, &XYCurve::valuesColorChanged, this, &XYCurveDock::curveValuesColorChanged); 0564 0565 //"Error bars"-Tab 0566 connect(m_curve->xErrorBar(), &ErrorBar::typeChanged, this, &XYCurveDock::curveXErrorTypeChanged); 0567 connect(m_curve->xErrorBar(), &ErrorBar::plusColumnChanged, this, &XYCurveDock::curveXErrorPlusColumnChanged); 0568 connect(m_curve->xErrorBar(), &ErrorBar::minusColumnChanged, this, &XYCurveDock::curveXErrorMinusColumnChanged); 0569 connect(m_curve->yErrorBar(), &ErrorBar::typeChanged, this, &XYCurveDock::curveYErrorTypeChanged); 0570 connect(m_curve->yErrorBar(), &ErrorBar::plusColumnChanged, this, &XYCurveDock::curveYErrorPlusColumnChanged); 0571 connect(m_curve->yErrorBar(), &ErrorBar::minusColumnChanged, this, &XYCurveDock::curveYErrorMinusColumnChanged); 0572 0573 //"Margin Plots"-Tab 0574 connect(m_curve, &XYCurve::rugEnabledChanged, this, &XYCurveDock::curveRugEnabledChanged); 0575 connect(m_curve, &XYCurve::rugOrientationChanged, this, &XYCurveDock::curveRugOrientationChanged); 0576 connect(m_curve, &XYCurve::rugLengthChanged, this, &XYCurveDock::curveRugLengthChanged); 0577 connect(m_curve, &XYCurve::rugWidthChanged, this, &XYCurveDock::curveRugWidthChanged); 0578 connect(m_curve, &XYCurve::rugOffsetChanged, this, &XYCurveDock::curveRugOffsetChanged); 0579 } 0580 0581 void XYCurveDock::updateLocale() { 0582 ui.sbValuesDistance->setLocale(QLocale()); 0583 lineWidget->updateLocale(); 0584 dropLineWidget->updateLocale(); 0585 symbolWidget->updateLocale(); 0586 errorBarStyleWidget->updateLocale(); 0587 } 0588 0589 //************************************************************* 0590 //********** SLOTs for changes triggered in XYCurveDock ******** 0591 //************************************************************* 0592 void XYCurveDock::retranslateUi() { 0593 ui.lLineSkipGaps->setToolTip(i18n("If checked, connect neighbour points with lines even if there are gaps (invalid or masked values) between them")); 0594 ui.chkLineSkipGaps->setToolTip(i18n("If checked, connect neighbour points with lines even if there are gaps (invalid or masked values) between them")); 0595 ui.lLineIncreasingXOnly->setToolTip(i18n("If checked, connect data points only for strictly increasing values of X")); 0596 ui.chkLineIncreasingXOnly->setToolTip(i18n("If checked, connect data points only for strictly increasing values of X")); 0597 // TODO: 0598 // uiGeneralTab.lName->setText(i18n("Name")); 0599 // uiGeneralTab.lComment->setText(i18n("Comment")); 0600 // uiGeneralTab.chkVisible->setText(i18n("Visible")); 0601 // uiGeneralTab.lXColumn->setText(i18n("x-data")); 0602 // uiGeneralTab.lYColumn->setText(i18n("y-data")); 0603 0604 // TODO updatePenStyles, updateBrushStyles for all comboboxes 0605 } 0606 0607 void XYCurveDock::xColumnChanged(const QModelIndex& index) { 0608 updateValuesWidgets(); 0609 0610 CONDITIONAL_LOCK_RETURN; 0611 0612 auto* aspect = static_cast<AbstractAspect*>(index.internalPointer()); 0613 AbstractColumn* column = nullptr; 0614 if (aspect) { 0615 column = dynamic_cast<AbstractColumn*>(aspect); 0616 Q_ASSERT(column); 0617 } 0618 0619 for (auto* curve : m_curvesList) 0620 curve->setXColumn(column); 0621 } 0622 0623 void XYCurveDock::yColumnChanged(const QModelIndex& index) { 0624 updateValuesWidgets(); 0625 0626 CONDITIONAL_LOCK_RETURN; 0627 0628 auto* aspect = static_cast<AbstractAspect*>(index.internalPointer()); 0629 AbstractColumn* column = nullptr; 0630 if (aspect) { 0631 column = dynamic_cast<AbstractColumn*>(aspect); 0632 Q_ASSERT(column); 0633 } 0634 0635 for (auto* curve : m_curvesList) 0636 curve->setYColumn(column); 0637 } 0638 0639 // "Line"-tab 0640 void XYCurveDock::lineTypeChanged(int index) { 0641 const auto lineType = XYCurve::LineType(index); 0642 0643 if (lineType == XYCurve::LineType::NoLine) { 0644 ui.chkLineSkipGaps->setEnabled(false); 0645 lineWidget->setEnabled(false); 0646 ui.lLineInterpolationPointsCount->hide(); 0647 ui.sbLineInterpolationPointsCount->hide(); 0648 } else { 0649 ui.chkLineSkipGaps->setEnabled(true); 0650 lineWidget->setEnabled(true); 0651 0652 if (lineType == XYCurve::LineType::SplineCubicNatural || lineType == XYCurve::LineType::SplineCubicPeriodic 0653 || lineType == XYCurve::LineType::SplineAkimaNatural || lineType == XYCurve::LineType::SplineAkimaPeriodic) { 0654 ui.lLineInterpolationPointsCount->show(); 0655 ui.sbLineInterpolationPointsCount->show(); 0656 ui.lLineSkipGaps->hide(); 0657 ui.chkLineSkipGaps->hide(); 0658 } else { 0659 ui.lLineInterpolationPointsCount->hide(); 0660 ui.sbLineInterpolationPointsCount->hide(); 0661 ui.lLineSkipGaps->show(); 0662 ui.chkLineSkipGaps->show(); 0663 } 0664 } 0665 0666 CONDITIONAL_LOCK_RETURN; 0667 0668 for (auto* curve : m_curvesList) 0669 curve->setLineType(lineType); 0670 } 0671 0672 void XYCurveDock::lineSkipGapsChanged(bool skip) { 0673 CONDITIONAL_LOCK_RETURN; 0674 0675 for (auto* curve : m_curvesList) 0676 curve->setLineSkipGaps(skip); 0677 } 0678 0679 void XYCurveDock::lineIncreasingXOnlyChanged(bool incr) { 0680 CONDITIONAL_LOCK_RETURN; 0681 0682 for (auto* curve : m_curvesList) 0683 curve->setLineIncreasingXOnly(incr); 0684 } 0685 0686 void XYCurveDock::lineInterpolationPointsCountChanged(int count) { 0687 CONDITIONAL_LOCK_RETURN; 0688 0689 for (auto* curve : m_curvesList) 0690 curve->setLineInterpolationPointsCount(count); 0691 } 0692 0693 // Values-tab 0694 0695 /*! 0696 called when the type of the values (none, x, y, (x,y) etc.) was changed. 0697 */ 0698 void XYCurveDock::valuesTypeChanged(int index) { 0699 this->updateValuesWidgets(); 0700 0701 CONDITIONAL_LOCK_RETURN; 0702 0703 const auto type = XYCurve::ValuesType(index); 0704 for (auto* curve : m_curvesList) 0705 curve->setValuesType(type); 0706 } 0707 0708 /*! 0709 called when the custom column for the values was changed. 0710 */ 0711 void XYCurveDock::valuesColumnChanged(const QModelIndex& index) { 0712 this->updateValuesWidgets(); 0713 0714 CONDITIONAL_LOCK_RETURN; 0715 0716 auto* column = static_cast<Column*>(index.internalPointer()); 0717 for (auto* curve : m_curvesList) 0718 curve->setValuesColumn(column); 0719 } 0720 0721 /*! 0722 shows the formatting properties of the column \c column. 0723 Called, when a new column for the values was selected - either by changing the type of the values (none, x, y, etc.) or 0724 by selecting a new custom column for the values. 0725 */ 0726 0727 /*! 0728 depending on the currently selected values column type (column mode) updates the widgets for the values column format, 0729 shows/hides the allowed widgets, fills the corresponding combobox with the possible entries. 0730 Called when the values column was changed. 0731 */ 0732 void XYCurveDock::updateValuesWidgets() { 0733 const auto type{XYCurve::ValuesType(ui.cbValuesType->currentIndex())}; 0734 bool showValues{type != XYCurve::ValuesType::NoValues}; 0735 0736 ui.cbValuesPosition->setEnabled(showValues); 0737 ui.sbValuesDistance->setEnabled(showValues); 0738 ui.sbValuesRotation->setEnabled(showValues); 0739 ui.sbValuesOpacity->setEnabled(showValues); 0740 ui.kfrValuesFont->setEnabled(showValues); 0741 ui.kcbValuesColor->setEnabled(showValues); 0742 0743 bool hasInteger = false; 0744 bool hasNumeric = false; 0745 bool hasDateTime = false; 0746 0747 if (type == XYCurve::ValuesType::CustomColumn) { 0748 ui.lValuesColumn->show(); 0749 cbValuesColumn->show(); 0750 0751 auto* column = static_cast<Column*>(cbValuesColumn->currentModelIndex().internalPointer()); 0752 if (column) { 0753 if (column->columnMode() == AbstractColumn::ColumnMode::Double) 0754 hasNumeric = true; 0755 else if (column->columnMode() == AbstractColumn::ColumnMode::Integer || column->columnMode() == AbstractColumn::ColumnMode::BigInt) 0756 hasInteger = true; 0757 else if (column->columnMode() == AbstractColumn::ColumnMode::DateTime) 0758 hasDateTime = true; 0759 } 0760 } else { 0761 ui.lValuesColumn->hide(); 0762 cbValuesColumn->hide(); 0763 0764 const AbstractColumn* xColumn = nullptr; 0765 const AbstractColumn* yColumn = nullptr; 0766 switch (type) { 0767 case XYCurve::ValuesType::NoValues: 0768 break; 0769 case XYCurve::ValuesType::X: 0770 xColumn = m_curve->xColumn(); 0771 break; 0772 case XYCurve::ValuesType::Y: 0773 yColumn = m_curve->yColumn(); 0774 break; 0775 case XYCurve::ValuesType::XY: 0776 case XYCurve::ValuesType::XYBracketed: 0777 xColumn = m_curve->xColumn(); 0778 yColumn = m_curve->yColumn(); 0779 break; 0780 case XYCurve::ValuesType::CustomColumn: 0781 break; 0782 } 0783 0784 hasInteger = (xColumn && (xColumn->columnMode() == AbstractColumn::ColumnMode::Integer || xColumn->columnMode() == AbstractColumn::ColumnMode::BigInt)) 0785 || (yColumn && (yColumn->columnMode() == AbstractColumn::ColumnMode::Integer || yColumn->columnMode() == AbstractColumn::ColumnMode::BigInt)); 0786 0787 hasNumeric = (xColumn && xColumn->columnMode() == AbstractColumn::ColumnMode::Double) 0788 || (yColumn && yColumn->columnMode() == AbstractColumn::ColumnMode::Double); 0789 0790 hasDateTime = (xColumn && xColumn->columnMode() == AbstractColumn::ColumnMode::DateTime) 0791 || (yColumn && yColumn->columnMode() == AbstractColumn::ColumnMode::DateTime); 0792 } 0793 0794 // hide all the format related widgets first and 0795 // then show only what is required depending of the column mode(s) 0796 ui.lValuesFormat->hide(); 0797 ui.lValuesNumericFormat->hide(); 0798 ui.cbValuesNumericFormat->hide(); 0799 ui.lValuesPrecision->hide(); 0800 ui.sbValuesPrecision->hide(); 0801 ui.lValuesDateTimeFormat->hide(); 0802 ui.cbValuesDateTimeFormat->hide(); 0803 0804 if (hasNumeric || hasInteger) { 0805 ui.lValuesFormat->show(); 0806 ui.lValuesNumericFormat->show(); 0807 ui.cbValuesNumericFormat->show(); 0808 } 0809 0810 // precision is only available for Numeric 0811 if (hasNumeric) { 0812 ui.lValuesPrecision->show(); 0813 ui.sbValuesPrecision->show(); 0814 } 0815 0816 if (hasDateTime) { 0817 ui.lValuesFormat->show(); 0818 ui.lValuesDateTimeFormat->show(); 0819 ui.cbValuesDateTimeFormat->show(); 0820 } 0821 } 0822 0823 void XYCurveDock::valuesPositionChanged(int index) { 0824 CONDITIONAL_LOCK_RETURN; 0825 0826 for (auto* curve : m_curvesList) 0827 curve->setValuesPosition(XYCurve::ValuesPosition(index)); 0828 } 0829 0830 void XYCurveDock::valuesDistanceChanged(double value) { 0831 CONDITIONAL_RETURN_NO_LOCK; 0832 0833 for (auto* curve : m_curvesList) 0834 curve->setValuesDistance(Worksheet::convertToSceneUnits(value, Worksheet::Unit::Point)); 0835 } 0836 0837 void XYCurveDock::valuesRotationChanged(int value) { 0838 CONDITIONAL_LOCK_RETURN; 0839 0840 for (auto* curve : m_curvesList) 0841 curve->setValuesRotationAngle(value); 0842 } 0843 0844 void XYCurveDock::valuesOpacityChanged(int value) { 0845 CONDITIONAL_LOCK_RETURN; 0846 0847 qreal opacity = (float)value / 100.; 0848 for (auto* curve : m_curvesList) 0849 curve->setValuesOpacity(opacity); 0850 } 0851 0852 void XYCurveDock::valuesNumericFormatChanged(int index) { 0853 CONDITIONAL_LOCK_RETURN; 0854 0855 char format = ui.cbValuesNumericFormat->itemData(index).toChar().toLatin1(); 0856 for (auto* curve : m_curvesList) 0857 curve->setValuesNumericFormat(format); 0858 } 0859 0860 void XYCurveDock::valuesDateTimeFormatChanged(const QString& format) { 0861 CONDITIONAL_LOCK_RETURN; 0862 0863 for (auto* curve : m_curvesList) 0864 curve->setValuesDateTimeFormat(format); 0865 } 0866 0867 void XYCurveDock::valuesPrecisionChanged(int precision) { 0868 CONDITIONAL_LOCK_RETURN; 0869 0870 for (auto* curve : m_curvesList) 0871 curve->setValuesPrecision(precision); 0872 } 0873 0874 void XYCurveDock::valuesPrefixChanged() { 0875 CONDITIONAL_LOCK_RETURN; 0876 0877 QString prefix = ui.leValuesPrefix->text(); 0878 for (auto* curve : m_curvesList) 0879 curve->setValuesPrefix(prefix); 0880 } 0881 0882 void XYCurveDock::valuesSuffixChanged() { 0883 CONDITIONAL_LOCK_RETURN; 0884 0885 QString suffix = ui.leValuesSuffix->text(); 0886 for (auto* curve : m_curvesList) 0887 curve->setValuesSuffix(suffix); 0888 } 0889 0890 void XYCurveDock::valuesFontChanged(const QFont& font) { 0891 CONDITIONAL_LOCK_RETURN; 0892 0893 QFont valuesFont = font; 0894 valuesFont.setPixelSize(Worksheet::convertToSceneUnits(font.pointSizeF(), Worksheet::Unit::Point)); 0895 for (auto* curve : m_curvesList) 0896 curve->setValuesFont(valuesFont); 0897 } 0898 0899 void XYCurveDock::valuesColorChanged(const QColor& color) { 0900 CONDITIONAL_LOCK_RETURN; 0901 0902 for (auto* curve : m_curvesList) 0903 curve->setValuesColor(color); 0904 } 0905 0906 //"Error bars"-Tab 0907 void XYCurveDock::xErrorTypeChanged(int index) { 0908 if (index == 0) { 0909 // no error 0910 ui.lXErrorDataPlus->setVisible(false); 0911 cbXErrorPlusColumn->setVisible(false); 0912 ui.lXErrorDataMinus->setVisible(false); 0913 cbXErrorMinusColumn->setVisible(false); 0914 } else if (index == 1) { 0915 // symmetric error 0916 ui.lXErrorDataPlus->setVisible(true); 0917 cbXErrorPlusColumn->setVisible(true); 0918 ui.lXErrorDataMinus->setVisible(false); 0919 cbXErrorMinusColumn->setVisible(false); 0920 ui.lXErrorDataPlus->setText(i18n("Data, +-:")); 0921 } else if (index == 2) { 0922 // asymmetric error 0923 ui.lXErrorDataPlus->setVisible(true); 0924 cbXErrorPlusColumn->setVisible(true); 0925 ui.lXErrorDataMinus->setVisible(true); 0926 cbXErrorMinusColumn->setVisible(true); 0927 ui.lXErrorDataPlus->setText(i18n("Data, +:")); 0928 } 0929 0930 bool b = (index != 0 || ui.cbYErrorType->currentIndex() != 0); 0931 ui.lErrorFormat->setVisible(b); 0932 errorBarStyleWidget->setVisible(b); 0933 0934 CONDITIONAL_LOCK_RETURN; 0935 0936 for (auto* curve : m_curvesList) 0937 curve->xErrorBar()->setType(ErrorBar::Type(index)); 0938 } 0939 0940 void XYCurveDock::xErrorPlusColumnChanged(const QModelIndex& index) { 0941 CONDITIONAL_LOCK_RETURN; 0942 0943 auto* aspect = static_cast<AbstractAspect*>(index.internalPointer()); 0944 auto* column = dynamic_cast<AbstractColumn*>(aspect); 0945 Q_ASSERT(column); 0946 0947 for (auto* curve : m_curvesList) 0948 curve->xErrorBar()->setPlusColumn(column); 0949 } 0950 0951 void XYCurveDock::xErrorMinusColumnChanged(const QModelIndex& index) { 0952 CONDITIONAL_LOCK_RETURN; 0953 0954 auto* aspect = static_cast<AbstractAspect*>(index.internalPointer()); 0955 auto* column = dynamic_cast<AbstractColumn*>(aspect); 0956 Q_ASSERT(column); 0957 0958 for (auto* curve : m_curvesList) 0959 curve->xErrorBar()->setMinusColumn(column); 0960 } 0961 0962 void XYCurveDock::yErrorTypeChanged(int index) { 0963 if (index == 0) { 0964 // no error 0965 ui.lYErrorDataPlus->setVisible(false); 0966 cbYErrorPlusColumn->setVisible(false); 0967 ui.lYErrorDataMinus->setVisible(false); 0968 cbYErrorMinusColumn->setVisible(false); 0969 } else if (index == 1) { 0970 // symmetric error 0971 ui.lYErrorDataPlus->setVisible(true); 0972 cbYErrorPlusColumn->setVisible(true); 0973 ui.lYErrorDataMinus->setVisible(false); 0974 cbYErrorMinusColumn->setVisible(false); 0975 ui.lYErrorDataPlus->setText(i18n("Data, +-:")); 0976 } else if (index == 2) { 0977 // asymmetric error 0978 ui.lYErrorDataPlus->setVisible(true); 0979 cbYErrorPlusColumn->setVisible(true); 0980 ui.lYErrorDataMinus->setVisible(true); 0981 cbYErrorMinusColumn->setVisible(true); 0982 ui.lYErrorDataPlus->setText(i18n("Data, +:")); 0983 } 0984 0985 bool b = (index != 0 || ui.cbXErrorType->currentIndex() != 0); 0986 ui.lErrorFormat->setVisible(b); 0987 errorBarStyleWidget->setVisible(b); 0988 0989 CONDITIONAL_LOCK_RETURN; 0990 0991 for (auto* curve : m_curvesList) 0992 curve->yErrorBar()->setType(ErrorBar::Type(index)); 0993 } 0994 0995 void XYCurveDock::yErrorPlusColumnChanged(const QModelIndex& index) { 0996 CONDITIONAL_LOCK_RETURN; 0997 0998 auto* aspect = static_cast<AbstractAspect*>(index.internalPointer()); 0999 auto* column = dynamic_cast<AbstractColumn*>(aspect); 1000 Q_ASSERT(column); 1001 1002 for (auto* curve : m_curvesList) 1003 curve->yErrorBar()->setPlusColumn(column); 1004 } 1005 1006 void XYCurveDock::yErrorMinusColumnChanged(const QModelIndex& index) { 1007 CONDITIONAL_LOCK_RETURN; 1008 1009 auto* aspect = static_cast<AbstractAspect*>(index.internalPointer()); 1010 auto* column = dynamic_cast<AbstractColumn*>(aspect); 1011 Q_ASSERT(column); 1012 1013 for (auto* curve : m_curvesList) 1014 curve->yErrorBar()->setMinusColumn(column); 1015 } 1016 1017 //"Margin Plots"-Tab 1018 void XYCurveDock::rugEnabledChanged(bool state) { 1019 CONDITIONAL_LOCK_RETURN; 1020 1021 for (auto* curve : qAsConst(m_curvesList)) 1022 curve->setRugEnabled(state); 1023 } 1024 1025 void XYCurveDock::rugOrientationChanged(int index) { 1026 CONDITIONAL_LOCK_RETURN; 1027 1028 auto orientation = static_cast<WorksheetElement::Orientation>(index); 1029 for (auto* curve : qAsConst(m_curvesList)) 1030 curve->setRugOrientation(orientation); 1031 } 1032 1033 void XYCurveDock::rugLengthChanged(double value) { 1034 CONDITIONAL_RETURN_NO_LOCK; 1035 1036 const double length = Worksheet::convertToSceneUnits(value, Worksheet::Unit::Point); 1037 for (auto* curve : qAsConst(m_curvesList)) 1038 curve->setRugLength(length); 1039 } 1040 1041 void XYCurveDock::rugWidthChanged(double value) { 1042 CONDITIONAL_RETURN_NO_LOCK; 1043 1044 const double width = Worksheet::convertToSceneUnits(value, Worksheet::Unit::Point); 1045 for (auto* curve : qAsConst(m_curvesList)) 1046 curve->setRugWidth(width); 1047 } 1048 1049 void XYCurveDock::rugOffsetChanged(double value) { 1050 CONDITIONAL_RETURN_NO_LOCK; 1051 1052 const double offset = Worksheet::convertToSceneUnits(value, Worksheet::Unit::Point); 1053 for (auto* curve : qAsConst(m_curvesList)) 1054 curve->setRugOffset(offset); 1055 } 1056 1057 //************************************************************* 1058 //*********** SLOTs for changes triggered in XYCurve ********** 1059 //************************************************************* 1060 // General-Tab 1061 void XYCurveDock::curveDescriptionChanged(const AbstractAspect* aspect) { 1062 if (m_curve != aspect) 1063 return; 1064 1065 CONDITIONAL_LOCK_RETURN; 1066 if (aspect->name() != uiGeneralTab.leName->text()) 1067 uiGeneralTab.leName->setText(aspect->name()); 1068 else if (aspect->comment() != uiGeneralTab.teComment->text()) 1069 uiGeneralTab.teComment->setText(aspect->comment()); 1070 } 1071 1072 void XYCurveDock::curveXColumnChanged(const AbstractColumn* column) { 1073 updateValuesWidgets(); 1074 CONDITIONAL_LOCK_RETURN; 1075 cbXColumn->setColumn(column, m_curve->xColumnPath()); 1076 } 1077 1078 void XYCurveDock::curveYColumnChanged(const AbstractColumn* column) { 1079 updateValuesWidgets(); 1080 CONDITIONAL_LOCK_RETURN; 1081 cbYColumn->setColumn(column, m_curve->yColumnPath()); 1082 } 1083 1084 // Line-Tab 1085 void XYCurveDock::curveLineTypeChanged(XYCurve::LineType type) { 1086 CONDITIONAL_LOCK_RETURN; 1087 ui.cbLineType->setCurrentIndex((int)type); 1088 } 1089 void XYCurveDock::curveLineSkipGapsChanged(bool skip) { 1090 CONDITIONAL_LOCK_RETURN; 1091 ui.chkLineSkipGaps->setChecked(skip); 1092 } 1093 void XYCurveDock::curveLineIncreasingXOnlyChanged(bool incr) { 1094 CONDITIONAL_LOCK_RETURN; 1095 ui.chkLineIncreasingXOnly->setChecked(incr); 1096 } 1097 void XYCurveDock::curveLineInterpolationPointsCountChanged(int count) { 1098 CONDITIONAL_LOCK_RETURN; 1099 ui.sbLineInterpolationPointsCount->setValue(count); 1100 } 1101 1102 // Values-Tab 1103 void XYCurveDock::curveValuesTypeChanged(XYCurve::ValuesType type) { 1104 CONDITIONAL_LOCK_RETURN; 1105 ui.cbValuesType->setCurrentIndex((int)type); 1106 } 1107 void XYCurveDock::curveValuesColumnChanged(const AbstractColumn* column) { 1108 CONDITIONAL_LOCK_RETURN; 1109 cbValuesColumn->setColumn(column, m_curve->valuesColumnPath()); 1110 } 1111 void XYCurveDock::curveValuesPositionChanged(XYCurve::ValuesPosition position) { 1112 CONDITIONAL_LOCK_RETURN; 1113 ui.cbValuesPosition->setCurrentIndex((int)position); 1114 } 1115 void XYCurveDock::curveValuesDistanceChanged(qreal distance) { 1116 CONDITIONAL_LOCK_RETURN; 1117 ui.sbValuesDistance->setValue(Worksheet::convertFromSceneUnits(distance, Worksheet::Unit::Point)); 1118 } 1119 void XYCurveDock::curveValuesRotationAngleChanged(qreal angle) { 1120 CONDITIONAL_LOCK_RETURN; 1121 ui.sbValuesRotation->setValue(angle); 1122 } 1123 void XYCurveDock::curveValuesNumericFormatChanged(char format) { 1124 CONDITIONAL_LOCK_RETURN; 1125 ui.cbValuesNumericFormat->setCurrentIndex(ui.cbValuesNumericFormat->findData(format)); 1126 } 1127 void XYCurveDock::curveValuesPrecisionChanged(int precision) { 1128 CONDITIONAL_LOCK_RETURN; 1129 ui.sbValuesPrecision->setValue(precision); 1130 } 1131 void XYCurveDock::curveValuesDateTimeFormatChanged(const QString& format) { 1132 CONDITIONAL_LOCK_RETURN; 1133 ui.cbValuesDateTimeFormat->setCurrentText(format); 1134 } 1135 void XYCurveDock::curveValuesOpacityChanged(qreal opacity) { 1136 CONDITIONAL_LOCK_RETURN; 1137 ui.sbValuesOpacity->setValue(round(opacity * 100.0)); 1138 } 1139 void XYCurveDock::curveValuesPrefixChanged(const QString& prefix) { 1140 CONDITIONAL_LOCK_RETURN; 1141 ui.leValuesPrefix->setText(prefix); 1142 } 1143 void XYCurveDock::curveValuesSuffixChanged(const QString& suffix) { 1144 CONDITIONAL_LOCK_RETURN; 1145 ui.leValuesSuffix->setText(suffix); 1146 } 1147 void XYCurveDock::curveValuesFontChanged(QFont font) { 1148 CONDITIONAL_LOCK_RETURN; 1149 font.setPointSizeF(round(Worksheet::convertFromSceneUnits(font.pixelSize(), Worksheet::Unit::Point))); 1150 ui.kfrValuesFont->setFont(font); 1151 } 1152 void XYCurveDock::curveValuesColorChanged(QColor color) { 1153 CONDITIONAL_LOCK_RETURN; 1154 ui.kcbValuesColor->setColor(color); 1155 } 1156 1157 //"Error bars"-Tab 1158 void XYCurveDock::curveXErrorTypeChanged(ErrorBar::Type type) { 1159 CONDITIONAL_LOCK_RETURN; 1160 ui.cbXErrorType->setCurrentIndex((int)type); 1161 } 1162 void XYCurveDock::curveXErrorPlusColumnChanged(const AbstractColumn* column) { 1163 CONDITIONAL_LOCK_RETURN; 1164 cbXErrorPlusColumn->setColumn(column, m_curve->xErrorBar()->plusColumnPath()); 1165 } 1166 void XYCurveDock::curveXErrorMinusColumnChanged(const AbstractColumn* column) { 1167 CONDITIONAL_LOCK_RETURN; 1168 cbXErrorMinusColumn->setColumn(column, m_curve->xErrorBar()->minusColumnPath()); 1169 } 1170 void XYCurveDock::curveYErrorTypeChanged(ErrorBar::Type type) { 1171 CONDITIONAL_LOCK_RETURN; 1172 ui.cbYErrorType->setCurrentIndex((int)type); 1173 } 1174 void XYCurveDock::curveYErrorPlusColumnChanged(const AbstractColumn* column) { 1175 CONDITIONAL_LOCK_RETURN; 1176 cbYErrorPlusColumn->setColumn(column, m_curve->yErrorBar()->plusColumnPath()); 1177 } 1178 void XYCurveDock::curveYErrorMinusColumnChanged(const AbstractColumn* column) { 1179 CONDITIONAL_LOCK_RETURN; 1180 cbYErrorMinusColumn->setColumn(column, m_curve->yErrorBar()->minusColumnPath()); 1181 } 1182 1183 //"Margin Plot"-Tab 1184 void XYCurveDock::curveRugEnabledChanged(bool status) { 1185 CONDITIONAL_LOCK_RETURN; 1186 ui.chkRugEnabled->setChecked(status); 1187 } 1188 void XYCurveDock::curveRugOrientationChanged(WorksheetElement::Orientation orientation) { 1189 CONDITIONAL_LOCK_RETURN; 1190 ui.cbRugOrientation->setCurrentIndex(static_cast<int>(orientation)); 1191 } 1192 void XYCurveDock::curveRugLengthChanged(double value) { 1193 CONDITIONAL_LOCK_RETURN; 1194 ui.sbRugLength->setValue(Worksheet::convertFromSceneUnits(value, Worksheet::Unit::Point)); 1195 } 1196 void XYCurveDock::curveRugWidthChanged(double value) { 1197 CONDITIONAL_LOCK_RETURN; 1198 ui.sbRugWidth->setValue(Worksheet::convertFromSceneUnits(value, Worksheet::Unit::Point)); 1199 } 1200 void XYCurveDock::curveRugOffsetChanged(double value) { 1201 CONDITIONAL_LOCK_RETURN; 1202 ui.sbRugOffset->setValue(Worksheet::convertFromSceneUnits(value, Worksheet::Unit::Point)); 1203 } 1204 1205 //************************************************************* 1206 //************************* Settings ************************** 1207 //************************************************************* 1208 void XYCurveDock::load() { 1209 // General 1210 // This data is read in XYCurveDock::setCurves(). 1211 1212 // Line 1213 bool xyCurve = (m_curve->type() == AspectType::XYCurve); 1214 if (xyCurve) { // options available for XYCurve only and not for analysis curves 1215 ui.cbLineType->setCurrentIndex((int)m_curve->lineType()); 1216 ui.chkLineSkipGaps->setChecked(m_curve->lineSkipGaps()); 1217 ui.sbLineInterpolationPointsCount->setValue(m_curve->lineInterpolationPointsCount()); 1218 } 1219 1220 // Values 1221 ui.cbValuesType->setCurrentIndex((int)m_curve->valuesType()); 1222 ui.cbValuesPosition->setCurrentIndex((int)m_curve->valuesPosition()); 1223 ui.sbValuesDistance->setValue(Worksheet::convertFromSceneUnits(m_curve->valuesDistance(), Worksheet::Unit::Point)); 1224 ui.sbValuesRotation->setValue(m_curve->valuesRotationAngle()); 1225 ui.sbValuesOpacity->setValue(round(m_curve->valuesOpacity() * 100.0)); 1226 ui.sbValuesPrecision->setValue(m_curve->valuesPrecision()); 1227 ui.cbValuesNumericFormat->setCurrentIndex(ui.cbValuesNumericFormat->findData(m_curve->valuesNumericFormat())); 1228 ui.cbValuesDateTimeFormat->setCurrentText(m_curve->valuesDateTimeFormat()); 1229 ui.leValuesPrefix->setText(m_curve->valuesPrefix()); 1230 ui.leValuesSuffix->setText(m_curve->valuesSuffix()); 1231 QFont valuesFont = m_curve->valuesFont(); 1232 valuesFont.setPointSizeF(round(Worksheet::convertFromSceneUnits(valuesFont.pixelSize(), Worksheet::Unit::Point))); 1233 ui.kfrValuesFont->setFont(valuesFont); 1234 ui.kcbValuesColor->setColor(m_curve->valuesColor()); 1235 this->updateValuesWidgets(); 1236 1237 // Error bars 1238 if (xyCurve) { 1239 int index = ui.cbXErrorType->findData(static_cast<int>(m_curve->xErrorBar()->type())); 1240 ui.cbXErrorType->setCurrentIndex(index); 1241 index = ui.cbYErrorType->findData(static_cast<int>(m_curve->yErrorBar()->type())); 1242 ui.cbYErrorType->setCurrentIndex((int)m_curve->yErrorBar()->type()); 1243 } 1244 1245 // Margin plots 1246 ui.chkRugEnabled->setChecked(m_curve->rugEnabled()); 1247 ui.cbRugOrientation->setCurrentIndex(static_cast<int>(m_curve->rugOrientation())); 1248 ui.sbRugWidth->setValue(Worksheet::convertFromSceneUnits(m_curve->rugWidth(), Worksheet::Unit::Point)); 1249 ui.sbRugLength->setValue(Worksheet::convertFromSceneUnits(m_curve->rugLength(), Worksheet::Unit::Point)); 1250 ui.sbRugOffset->setValue(Worksheet::convertFromSceneUnits(m_curve->rugOffset(), Worksheet::Unit::Point)); 1251 } 1252 1253 void XYCurveDock::loadConfigFromTemplate(KConfig& config) { 1254 auto name = TemplateHandler::templateName(config); 1255 int size = m_curvesList.size(); 1256 if (size > 1) 1257 m_curve->beginMacro(i18n("%1 xy-curves: template \"%2\" loaded", size, name)); 1258 else 1259 m_curve->beginMacro(i18n("%1: template \"%2\" loaded", m_curve->name(), name)); 1260 1261 this->loadConfig(config); 1262 1263 m_curve->endMacro(); 1264 } 1265 1266 void XYCurveDock::loadConfig(KConfig& config) { 1267 KConfigGroup group = config.group(QStringLiteral("XYCurve")); 1268 1269 // General 1270 // we don't load/save the settings in the general-tab, since they are not style related. 1271 // It doesn't make sense to load/save them in the template. 1272 // This data is read in XYCurveDock::setCurves(). 1273 1274 // Line 1275 bool xyCurve = (m_curve->type() == AspectType::XYCurve); 1276 if (xyCurve) { 1277 ui.cbLineType->setCurrentIndex(group.readEntry(QStringLiteral("LineType"), (int)m_curve->lineType())); 1278 ui.chkLineSkipGaps->setChecked(group.readEntry(QStringLiteral("LineSkipGaps"), m_curve->lineSkipGaps())); 1279 ui.sbLineInterpolationPointsCount->setValue(group.readEntry(QStringLiteral("LineInterpolationPointsCount"), m_curve->lineInterpolationPointsCount())); 1280 } 1281 lineWidget->loadConfig(group); 1282 dropLineWidget->loadConfig(group); 1283 1284 // Symbols 1285 symbolWidget->loadConfig(group); 1286 1287 // Values 1288 ui.cbValuesType->setCurrentIndex(group.readEntry(QStringLiteral("ValuesType"), (int)m_curve->valuesType())); 1289 ui.cbValuesPosition->setCurrentIndex(group.readEntry(QStringLiteral("ValuesPosition"), (int)m_curve->valuesPosition())); 1290 ui.sbValuesDistance->setValue( 1291 Worksheet::convertFromSceneUnits(group.readEntry(QStringLiteral("ValuesDistance"), m_curve->valuesDistance()), Worksheet::Unit::Point)); 1292 ui.sbValuesRotation->setValue(group.readEntry(QStringLiteral("ValuesRotation"), m_curve->valuesRotationAngle())); 1293 ui.sbValuesOpacity->setValue(round(group.readEntry(QStringLiteral("ValuesOpacity"), m_curve->valuesOpacity()) * 100.0)); 1294 ui.leValuesPrefix->setText(group.readEntry(QStringLiteral("ValuesPrefix"), m_curve->valuesPrefix())); 1295 ui.leValuesSuffix->setText(group.readEntry(QStringLiteral("ValuesSuffix"), m_curve->valuesSuffix())); 1296 QFont valuesFont = m_curve->valuesFont(); 1297 valuesFont.setPointSizeF(round(Worksheet::convertFromSceneUnits(valuesFont.pixelSize(), Worksheet::Unit::Point))); 1298 ui.kfrValuesFont->setFont(group.readEntry(QStringLiteral("ValuesFont"), valuesFont)); 1299 ui.kcbValuesColor->setColor(group.readEntry(QStringLiteral("ValuesColor"), m_curve->valuesColor())); 1300 1301 // Filling 1302 backgroundWidget->loadConfig(group); 1303 1304 // Error bars 1305 if (xyCurve) { 1306 ui.cbXErrorType->setCurrentIndex(group.readEntry(QStringLiteral("XErrorType"), (int)m_curve->xErrorBar()->type())); 1307 ui.cbYErrorType->setCurrentIndex(group.readEntry(QStringLiteral("YErrorType"), (int)m_curve->yErrorBar()->type())); 1308 errorBarStyleWidget->loadConfig(group); 1309 } 1310 } 1311 1312 void XYCurveDock::saveConfigAsTemplate(KConfig& config) { 1313 KConfigGroup group = config.group(QStringLiteral("XYCurve")); 1314 1315 // General 1316 // we don't load/save the settings in the general-tab, since they are not style related. 1317 // It doesn't make sense to load/save them in the template. 1318 1319 bool xyCurve = (m_curve->type() == AspectType::XYCurve); 1320 if (xyCurve) { 1321 group.writeEntry(QStringLiteral("LineType"), ui.cbLineType->currentIndex()); 1322 group.writeEntry(QStringLiteral("LineSkipGaps"), ui.chkLineSkipGaps->isChecked()); 1323 group.writeEntry(QStringLiteral("LineInterpolationPointsCount"), ui.sbLineInterpolationPointsCount->value()); 1324 } 1325 1326 lineWidget->saveConfig(group); 1327 dropLineWidget->saveConfig(group); 1328 1329 // Symbols 1330 symbolWidget->saveConfig(group); 1331 1332 // Values 1333 group.writeEntry(QStringLiteral("ValuesType"), ui.cbValuesType->currentIndex()); 1334 group.writeEntry(QStringLiteral("ValuesPosition"), ui.cbValuesPosition->currentIndex()); 1335 group.writeEntry(QStringLiteral("ValuesDistance"), Worksheet::convertToSceneUnits(ui.sbValuesDistance->value(), Worksheet::Unit::Point)); 1336 group.writeEntry(QStringLiteral("ValuesRotation"), ui.sbValuesRotation->value()); 1337 group.writeEntry(QStringLiteral("ValuesOpacity"), ui.sbValuesOpacity->value() / 100.0); 1338 group.writeEntry(QStringLiteral("valuesNumericFormat"), ui.cbValuesNumericFormat->currentText()); 1339 group.writeEntry(QStringLiteral("valuesPrecision"), ui.sbValuesPrecision->value()); 1340 group.writeEntry(QStringLiteral("valuesDateTimeFormat"), ui.cbValuesDateTimeFormat->currentText()); 1341 group.writeEntry(QStringLiteral("ValuesPrefix"), ui.leValuesPrefix->text()); 1342 group.writeEntry(QStringLiteral("ValuesSuffix"), ui.leValuesSuffix->text()); 1343 group.writeEntry(QStringLiteral("ValuesFont"), ui.kfrValuesFont->font()); 1344 group.writeEntry(QStringLiteral("ValuesColor"), ui.kcbValuesColor->color()); 1345 1346 // Filling 1347 backgroundWidget->saveConfig(group); 1348 1349 // Error bars 1350 if (xyCurve) { 1351 group.writeEntry(QStringLiteral("XErrorType"), ui.cbXErrorType->currentIndex()); 1352 group.writeEntry(QStringLiteral("YErrorType"), ui.cbYErrorType->currentIndex()); 1353 errorBarStyleWidget->saveConfig(group); 1354 } 1355 1356 config.sync(); 1357 }