File indexing completed on 2025-09-14 03:43:01

0001 /*
0002     File                 : AxisDock.cpp
0003     Project              : LabPlot
0004     Description          : axes widget class
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2011-2023 Alexander Semke <alexander.semke@web.de>
0007     SPDX-FileCopyrightText: 2012-2021 Stefan Gerlach <stefan.gerlach@uni-konstanz.de>
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "AxisDock.h"
0012 #include "backend/core/column/Column.h"
0013 #include "backend/lib/macros.h"
0014 #include "backend/worksheet/Worksheet.h"
0015 #include "commonfrontend/widgets/DateTimeSpinBox.h"
0016 #include "commonfrontend/widgets/NumberSpinBox.h"
0017 #include "commonfrontend/widgets/TreeViewComboBox.h"
0018 #include "kdefrontend/GuiTools.h"
0019 #include "kdefrontend/TemplateHandler.h"
0020 #include "kdefrontend/widgets/LabelWidget.h"
0021 #include "kdefrontend/widgets/LineWidget.h"
0022 
0023 #include <KConfig>
0024 #include <KLineEdit>
0025 #include <KLocalizedString>
0026 #include <KMessageBox>
0027 
0028 #include <QDir>
0029 #include <QPainter>
0030 #include <QTimer>
0031 
0032 #include "backend/nsl/nsl_math.h"
0033 #include <gsl/gsl_math.h>
0034 
0035 namespace {
0036 enum PositionAlignmentComboBoxIndex {
0037     Top_Left = 0,
0038     Bottom_Right = 1,
0039     Center = 2,
0040     Logical = 3,
0041 };
0042 }
0043 
0044 using Dimension = CartesianCoordinateSystem::Dimension;
0045 
0046 /*!
0047  \class AxisDock
0048  \brief Provides a widget for editing the properties of the axes currently selected in the project explorer.
0049 
0050  \ingroup kdefrontend
0051 */
0052 
0053 AxisDock::AxisDock(QWidget* parent)
0054     : BaseDock(parent) {
0055     ui.setupUi(this);
0056     setPlotRangeCombobox(ui.cbPlotRanges);
0057     setBaseWidgets(ui.leName, ui.teComment);
0058     setVisibilityWidgets(ui.chkVisible);
0059 
0060     //"Title"-tab
0061     auto* hboxLayout = new QHBoxLayout(ui.tabTitle);
0062     labelWidget = new LabelWidget(ui.tabTitle);
0063     labelWidget->setFixedLabelMode(true);
0064     hboxLayout->addWidget(labelWidget);
0065     hboxLayout->setContentsMargins(0, 0, 0, 0);
0066     hboxLayout->setSpacing(0);
0067 
0068     // "Line"-tab
0069     auto* gridLayout = qobject_cast<QGridLayout*>(ui.tabLine->layout());
0070     lineWidget = new LineWidget(ui.tabLine);
0071     gridLayout->addWidget(lineWidget, 1, 0, 1, 3);
0072 
0073     //"Ticks"-tab
0074     // major ticks
0075     gridLayout = static_cast<QGridLayout*>(ui.tabTicks->layout());
0076     dtsbMajorTicksIncrement = new DateTimeSpinBox(ui.tabTicks);
0077     gridLayout->addWidget(dtsbMajorTicksIncrement, 5, 2);
0078 
0079     auto layout = ui.tabTicks->findChild<QHBoxLayout*>(QStringLiteral("layoutMajorTickStartOffset"));
0080     dtsbMajorTicksDateTimeStartOffset = new DateTimeSpinBox(ui.tabTicks);
0081     layout->insertWidget(0, dtsbMajorTicksDateTimeStartOffset);
0082 
0083     cbMajorTicksColumn = new TreeViewComboBox(ui.tabTicks);
0084     gridLayout->addWidget(cbMajorTicksColumn, 10, 2);
0085 
0086     cbLabelsTextColumn = new TreeViewComboBox(ui.tabTicks);
0087     gridLayout->addWidget(cbLabelsTextColumn, 12, 2);
0088 
0089     majorTicksLineWidget = new LineWidget(ui.tabTicks);
0090     gridLayout->addWidget(majorTicksLineWidget, 15, 0, 1, 3);
0091 
0092     // minor ticks
0093     dtsbMinorTicksIncrement = new DateTimeSpinBox(ui.tabTicks);
0094     gridLayout->addWidget(dtsbMinorTicksIncrement, 22, 2);
0095 
0096     cbMinorTicksColumn = new TreeViewComboBox(ui.tabTicks);
0097     gridLayout->addWidget(cbMinorTicksColumn, 23, 2);
0098 
0099     minorTicksLineWidget = new LineWidget(ui.tabTicks);
0100     gridLayout->addWidget(minorTicksLineWidget, 26, 0, 1, 3);
0101 
0102     // "Grid"-tab
0103     gridLayout = qobject_cast<QGridLayout*>(ui.tabGrid->layout());
0104     majorGridLineWidget = new LineWidget(ui.tabLine);
0105     gridLayout->addWidget(majorGridLineWidget, 1, 0, 1, 3);
0106 
0107     minorGridLineWidget = new LineWidget(ui.tabLine);
0108     gridLayout->addWidget(minorGridLineWidget, 4, 0, 1, 3);
0109 
0110     // adjust layouts in the tabs
0111     for (int i = 0; i < ui.tabWidget->count(); ++i) {
0112         auto* layout = dynamic_cast<QGridLayout*>(ui.tabWidget->widget(i)->layout());
0113         if (!layout)
0114             continue;
0115 
0116         layout->setContentsMargins(2, 2, 2, 2);
0117         layout->setHorizontalSpacing(2);
0118         layout->setVerticalSpacing(2);
0119     }
0120 
0121     init();
0122 
0123     //**********************************  Slots **********************************************
0124 
0125     //"General"-tab
0126     connect(ui.chkVisible, &QCheckBox::clicked, this, &AxisDock::visibilityChanged);
0127 
0128     connect(ui.kcbAxisColor, &KColorButton::changed, this, &AxisDock::colorChanged);
0129 
0130     connect(ui.cbOrientation, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AxisDock::orientationChanged);
0131     connect(ui.cbPosition, QOverload<int>::of(&QComboBox::currentIndexChanged), this, QOverload<int>::of(&AxisDock::positionChanged));
0132     connect(ui.sbPosition, QOverload<double>::of(&NumberSpinBox::valueChanged), this, QOverload<double>::of(&AxisDock::positionChanged));
0133     connect(ui.sbPositionLogical, QOverload<double>::of(&NumberSpinBox::valueChanged), this, QOverload<double>::of(&AxisDock::logicalPositionChanged));
0134     connect(ui.cbScale, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AxisDock::scaleChanged);
0135     connect(ui.cbRangeScale, &QCheckBox::toggled, this, &AxisDock::rangeScaleChanged);
0136 
0137     connect(ui.cbRangeType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AxisDock::rangeTypeChanged);
0138     connect(ui.sbStart, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &AxisDock::startChanged);
0139     connect(ui.sbEnd, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &AxisDock::endChanged);
0140     connect(ui.dateTimeEditStart, &UTCDateTimeEdit::mSecsSinceEpochUTCChanged, this, &AxisDock::startDateTimeChanged);
0141     connect(ui.dateTimeEditEnd, &UTCDateTimeEdit::mSecsSinceEpochUTCChanged, this, &AxisDock::endDateTimeChanged);
0142     connect(ui.sbZeroOffset, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &AxisDock::zeroOffsetChanged);
0143     connect(ui.tbOffsetLeft, &QToolButton::clicked, this, &AxisDock::setLeftOffset);
0144     connect(ui.tbOffsetCenter, &QToolButton::clicked, this, &AxisDock::setCenterOffset);
0145     connect(ui.tbOffsetRight, &QToolButton::clicked, this, &AxisDock::setRightOffset);
0146 
0147     connect(ui.sbScalingFactor, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &AxisDock::scalingFactorChanged);
0148     connect(ui.tbUnityScale, &QToolButton::clicked, this, &AxisDock::setUnityScale);
0149     connect(ui.tbUnityRange, &QToolButton::clicked, this, &AxisDock::setUnityRange);
0150 
0151     connect(ui.chkShowScaleOffset, &QCheckBox::toggled, this, &AxisDock::showScaleOffsetChanged);
0152 
0153     //"Line"-tab
0154     connect(lineWidget, &LineWidget::colorChanged, this, &AxisDock::updateArrowLineColor);
0155     connect(ui.cbArrowPosition, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AxisDock::arrowPositionChanged);
0156     connect(ui.cbArrowType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AxisDock::arrowTypeChanged);
0157     connect(ui.sbArrowSize, QOverload<int>::of(&QSpinBox::valueChanged), this, &AxisDock::arrowSizeChanged);
0158 
0159     //"Major ticks"-tab
0160     connect(ui.cbMajorTicksDirection, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AxisDock::majorTicksDirectionChanged);
0161     connect(ui.cbMajorTicksType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AxisDock::majorTicksTypeChanged);
0162     connect(ui.cbMajorTicksAutoNumber, &QCheckBox::stateChanged, this, &AxisDock::majorTicksAutoNumberChanged);
0163     connect(ui.sbMajorTicksNumber, QOverload<int>::of(&QSpinBox::valueChanged), this, &AxisDock::majorTicksNumberChanged);
0164     connect(ui.sbMajorTicksSpacingNumeric, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &AxisDock::majorTicksSpacingChanged);
0165     connect(dtsbMajorTicksIncrement, &DateTimeSpinBox::valueChanged, this, &AxisDock::majorTicksSpacingChanged);
0166     connect(ui.cbMajorTicksStartType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AxisDock::majorTicksStartTypeChanged);
0167     connect(ui.sbMajorTickStartOffset, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &AxisDock::majorTicksStartOffsetChanged);
0168     connect(dtsbMajorTicksDateTimeStartOffset, &DateTimeSpinBox::valueChanged, this, &AxisDock::majorTicksDateTimeStartOffsetChanged);
0169     connect(ui.sbMajorTickStartValue, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &AxisDock::majorTicksStartValueChanged);
0170     connect(ui.sbMajorTickStartDateTime, &UTCDateTimeEdit::mSecsSinceEpochUTCChanged, this, &AxisDock::majorTicksStartDateTimeChanged);
0171     connect(ui.tbFirstTickData, &QToolButton::clicked, this, &AxisDock::setTickOffsetData);
0172     connect(ui.tbFirstTickAuto, &QToolButton::clicked, this, &AxisDock::setTickOffsetAuto);
0173     connect(cbMajorTicksColumn, &TreeViewComboBox::currentModelIndexChanged, this, &AxisDock::majorTicksColumnChanged);
0174     connect(ui.sbMajorTicksLength, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &AxisDock::majorTicksLengthChanged);
0175 
0176     //"Minor ticks"-tab
0177     connect(ui.cbMinorTicksDirection, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AxisDock::minorTicksDirectionChanged);
0178     connect(ui.cbMinorTicksType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AxisDock::minorTicksTypeChanged);
0179     connect(ui.cbMinorTicksAutoNumber, &QCheckBox::stateChanged, this, &AxisDock::minorTicksAutoNumberChanged);
0180     connect(ui.sbMinorTicksNumber, QOverload<int>::of(&QSpinBox::valueChanged), this, &AxisDock::minorTicksNumberChanged);
0181     connect(ui.sbMinorTicksSpacingNumeric, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &AxisDock::minorTicksSpacingChanged);
0182     connect(dtsbMinorTicksIncrement, &DateTimeSpinBox::valueChanged, this, &AxisDock::minorTicksSpacingChanged);
0183     connect(cbMinorTicksColumn, &TreeViewComboBox::currentModelIndexChanged, this, &AxisDock::minorTicksColumnChanged);
0184     connect(ui.sbMinorTicksLength, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &AxisDock::minorTicksLengthChanged);
0185 
0186     //"Extra ticks"-tab
0187 
0188     //"Tick labels"-tab
0189     connect(ui.cbLabelsFormat, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AxisDock::labelsFormatChanged);
0190     connect(ui.chkLabelsFormatAuto, &QCheckBox::toggled, this, &AxisDock::labelsFormatAutoChanged);
0191     connect(ui.sbLabelsPrecision, QOverload<int>::of(&QSpinBox::valueChanged), this, &AxisDock::labelsPrecisionChanged);
0192     connect(ui.chkLabelsAutoPrecision, &QCheckBox::toggled, this, &AxisDock::labelsAutoPrecisionChanged);
0193     connect(ui.cbLabelsDateTimeFormat, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AxisDock::labelsDateTimeFormatChanged);
0194     connect(ui.cbLabelsDateTimeFormat, &QComboBox::currentTextChanged, this, &AxisDock::labelsDateTimeFormatChanged);
0195     connect(ui.cbLabelsPosition, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AxisDock::labelsPositionChanged);
0196     connect(ui.sbLabelsOffset, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &AxisDock::labelsOffsetChanged);
0197     connect(ui.sbLabelsRotation, QOverload<int>::of(&QSpinBox::valueChanged), this, &AxisDock::labelsRotationChanged);
0198     connect(ui.cbLabelsTextType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AxisDock::labelsTextTypeChanged);
0199     connect(cbLabelsTextColumn, &TreeViewComboBox::currentModelIndexChanged, this, &AxisDock::labelsTextColumnChanged);
0200     connect(ui.kfrLabelsFont, &KFontRequester::fontSelected, this, &AxisDock::labelsFontChanged);
0201     connect(ui.kcbLabelsFontColor, &KColorButton::changed, this, &AxisDock::labelsFontColorChanged);
0202     connect(ui.cbLabelsBackgroundType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AxisDock::labelsBackgroundTypeChanged);
0203     connect(ui.kcbLabelsBackgroundColor, &KColorButton::changed, this, &AxisDock::labelsBackgroundColorChanged);
0204     connect(ui.leLabelsPrefix, &QLineEdit::textChanged, this, &AxisDock::labelsPrefixChanged);
0205     connect(ui.leLabelsSuffix, &QLineEdit::textChanged, this, &AxisDock::labelsSuffixChanged);
0206     connect(ui.sbLabelsOpacity, QOverload<int>::of(&QSpinBox::valueChanged), this, &AxisDock::labelsOpacityChanged);
0207 
0208     // Updating the axis color widget if one of the other color widgets color changes
0209     connect(lineWidget, &LineWidget::colorChanged, this, &AxisDock::setAxisColor);
0210     connect(majorTicksLineWidget, &LineWidget::colorChanged, this, &AxisDock::setAxisColor);
0211     connect(minorTicksLineWidget, &LineWidget::colorChanged, this, &AxisDock::setAxisColor);
0212     connect(labelWidget, &LabelWidget::labelFontColorChangedSignal, this, &AxisDock::setAxisColor);
0213 
0214     // template handler
0215     auto* frame = new QFrame(this);
0216     auto* hlayout = new QHBoxLayout(frame);
0217     hlayout->setContentsMargins(0, 11, 0, 11);
0218 
0219     auto* templateHandler = new TemplateHandler(this, QLatin1String("Axis"));
0220     hlayout->addWidget(templateHandler);
0221     connect(templateHandler, &TemplateHandler::loadConfigRequested, this, &AxisDock::loadConfigFromTemplate);
0222     connect(templateHandler, &TemplateHandler::saveConfigRequested, this, &AxisDock::saveConfigAsTemplate);
0223     connect(templateHandler, &TemplateHandler::info, this, &AxisDock::info);
0224 
0225     ui.verticalLayout->addWidget(frame);
0226 }
0227 
0228 AxisDock::~AxisDock() = default;
0229 
0230 void AxisDock::init() {
0231     CONDITIONAL_LOCK_RETURN;
0232 
0233     // TODO move this stuff to retranslateUI()
0234     ui.cbPosition->addItem(i18n("Top")); // Left
0235     ui.cbPosition->addItem(i18n("Bottom")); // Right
0236     ui.cbPosition->addItem(i18n("Centered"));
0237     ui.cbPosition->addItem(i18n("Logical"));
0238 
0239     // range types
0240     ui.cbRangeType->addItem(i18n("Auto"));
0241     ui.cbRangeType->addItem(i18n("Auto Data"));
0242     ui.cbRangeType->addItem(i18n("Custom"));
0243 
0244     QString msg = i18n(
0245         "Axis range:"
0246         "<ul>"
0247         "<li>Auto - automatically set the start and end points of the axis to the current plot ranges</li>"
0248         "<li>Auto Data - automatically set the start and end points of the axis to the minimal and maximal plotted data points, respectively</li>"
0249         "<li>Custom - manually specify the start and end points of the axis</li>"
0250         "</ul>");
0251     ui.lRangeType->setToolTip(msg);
0252     ui.cbRangeType->setToolTip(msg);
0253 
0254     // scales
0255     for (const auto& name : RangeT::scaleNames)
0256         ui.cbScale->addItem(name);
0257 
0258     ui.cbOrientation->addItem(i18n("Horizontal"));
0259     ui.cbOrientation->addItem(i18n("Vertical"));
0260 
0261     // Arrows
0262     ui.cbArrowType->setIconSize(QSize(20, 20));
0263     ui.cbArrowType->addItem(i18n("No arrow"));
0264     ui.cbArrowType->addItem(i18n("Simple, Small"));
0265     ui.cbArrowType->addItem(i18n("Simple, Big"));
0266     ui.cbArrowType->addItem(i18n("Filled, Small"));
0267     ui.cbArrowType->addItem(i18n("Filled, Big"));
0268     ui.cbArrowType->addItem(i18n("Semi-filled, Small"));
0269     ui.cbArrowType->addItem(i18n("Semi-filled, Big"));
0270 
0271     ui.cbArrowPosition->addItem(i18n("Left"));
0272     ui.cbArrowPosition->addItem(i18n("Right"));
0273     ui.cbArrowPosition->addItem(i18n("Both"));
0274 
0275     ui.cbMajorTicksDirection->addItem(i18n("None"));
0276     ui.cbMajorTicksDirection->addItem(i18n("In"));
0277     ui.cbMajorTicksDirection->addItem(i18n("Out"));
0278     ui.cbMajorTicksDirection->addItem(i18n("In and Out"));
0279 
0280     ui.cbMajorTicksType->addItem(i18n("Number"), (int)Axis::TicksType::TotalNumber);
0281     ui.cbMajorTicksType->addItem(i18n("Spacing"), (int)Axis::TicksType::Spacing);
0282     ui.cbMajorTicksType->addItem(i18n("Custom column"), (int)Axis::TicksType::CustomColumn);
0283     ui.cbMajorTicksType->addItem(i18n("Column labels"), (int)Axis::TicksType::ColumnLabels);
0284 
0285     ui.cbMajorTicksStartType->addItem(i18n("Absolute Value"));
0286     ui.cbMajorTicksStartType->addItem(i18n("Offset"));
0287 
0288     ui.cbMinorTicksDirection->addItem(i18n("None"));
0289     ui.cbMinorTicksDirection->addItem(i18n("In"));
0290     ui.cbMinorTicksDirection->addItem(i18n("Out"));
0291     ui.cbMinorTicksDirection->addItem(i18n("In and Out"));
0292 
0293     ui.cbMinorTicksType->addItem(i18n("Number"));
0294     ui.cbMinorTicksType->addItem(i18n("Spacing"));
0295     ui.cbMinorTicksType->addItem(i18n("Custom column"));
0296     // ui.cbMinorTicksType->addItem(i18n("Column labels"));
0297 
0298     // labels
0299     ui.cbLabelsPosition->addItem(i18n("No labels"));
0300     ui.cbLabelsPosition->addItem(i18n("Top"));
0301     ui.cbLabelsPosition->addItem(i18n("Bottom"));
0302 
0303     ui.cbLabelsTextType->addItem(i18n("Position values"), (int)Axis::LabelsTextType::PositionValues);
0304     ui.cbLabelsTextType->addItem(i18n("Custom column"), (int)Axis::LabelsTextType::CustomValues);
0305 
0306     // see Axis::labelsFormatToIndex() and Axis::indexToLabelsFormat()
0307     ui.cbLabelsFormat->addItem(i18n("Decimal notation"));
0308     ui.cbLabelsFormat->addItem(i18n("Scientific notation"));
0309     ui.cbLabelsFormat->addItem(i18n("Scientific E notation"));
0310     ui.cbLabelsFormat->addItem(i18n("Powers of 10"));
0311     ui.cbLabelsFormat->addItem(i18n("Powers of 2"));
0312     ui.cbLabelsFormat->addItem(i18n("Powers of e"));
0313     ui.cbLabelsFormat->addItem(i18n("Multiples of π"));
0314 
0315     ui.cbLabelsDateTimeFormat->addItems(AbstractColumn::dateTimeFormats());
0316 
0317     ui.cbLabelsBackgroundType->addItem(i18n("Transparent"));
0318     ui.cbLabelsBackgroundType->addItem(i18n("Color"));
0319 }
0320 
0321 void AxisDock::setModel() {
0322     QList<AspectType> list{AspectType::Folder, AspectType::Workbook, AspectType::Spreadsheet, AspectType::CantorWorksheet, AspectType::Column};
0323     cbMajorTicksColumn->setTopLevelClasses(list);
0324     cbMinorTicksColumn->setTopLevelClasses(list);
0325     cbLabelsTextColumn->setTopLevelClasses(list);
0326 
0327     list = {AspectType::Column};
0328     auto* model = aspectModel();
0329     model->setSelectableAspects(list);
0330 
0331     cbMajorTicksColumn->setModel(model);
0332     cbMinorTicksColumn->setModel(model);
0333     cbLabelsTextColumn->setModel(model);
0334 }
0335 
0336 /*!
0337   sets the axes. The properties of the axes in the list \c list can be edited in this widget.
0338 */
0339 void AxisDock::setAxes(QList<Axis*> list) {
0340     QDEBUG(Q_FUNC_INFO << ", Axis LIST =" << list)
0341     CONDITIONAL_LOCK_RETURN;
0342     m_axesList = list;
0343     m_axis = list.first();
0344     setAspects(list);
0345     Q_ASSERT(m_axis != nullptr);
0346     this->setModel();
0347 
0348     labelWidget->setAxes(list);
0349 
0350     // if there are more than one axis in the list, disable the tab "general"
0351     if (list.size() == 1) {
0352         this->setModelIndexFromColumn(cbMajorTicksColumn, m_axis->majorTicksColumn());
0353         this->setModelIndexFromColumn(cbMinorTicksColumn, m_axis->minorTicksColumn());
0354         this->setModelIndexFromColumn(cbLabelsTextColumn, m_axis->labelsTextColumn());
0355     } else {
0356         cbMajorTicksColumn->setCurrentModelIndex(QModelIndex());
0357         cbMinorTicksColumn->setCurrentModelIndex(QModelIndex());
0358         cbLabelsTextColumn->setCurrentModelIndex(QModelIndex());
0359     }
0360 
0361     // show the properties of the first axis
0362     this->load();
0363 
0364     QList<Line*> lines;
0365     QList<Line*> majorTicksLines;
0366     QList<Line*> minorTicksLines;
0367     QList<Line*> majorGridLines;
0368     QList<Line*> minorGridLines;
0369     for (auto* axis : m_axesList) {
0370         lines << axis->line();
0371         majorTicksLines << axis->majorTicksLine();
0372         minorTicksLines << axis->minorTicksLine();
0373         majorGridLines << axis->majorGridLine();
0374         minorGridLines << axis->minorGridLine();
0375     }
0376 
0377     lineWidget->setLines(lines);
0378     majorTicksLineWidget->setLines(majorTicksLines);
0379     minorTicksLineWidget->setLines(minorTicksLines);
0380     majorGridLineWidget->setLines(majorGridLines);
0381     minorGridLineWidget->setLines(minorGridLines);
0382 
0383     updatePlotRangeList();
0384     initConnections();
0385 }
0386 
0387 void AxisDock::initConnections() {
0388     // general
0389     connect(m_axis, &Axis::orientationChanged, this, QOverload<Axis::Orientation>::of(&AxisDock::axisOrientationChanged));
0390     connect(m_axis, QOverload<Axis::Position>::of(&Axis::positionChanged), this, QOverload<Axis::Position>::of(&AxisDock::axisPositionChanged));
0391     connect(m_axis, QOverload<double>::of(&Axis::positionChanged), this, QOverload<double>::of(&AxisDock::axisPositionChanged));
0392     connect(m_axis, &Axis::logicalPositionChanged, this, &AxisDock::axisLogicalPositionChanged);
0393     connect(m_axis, &Axis::scaleChanged, this, &AxisDock::axisScaleChanged);
0394     connect(m_axis, &Axis::rangeScaleChanged, this, &AxisDock::axisRangeScaleChanged);
0395     connect(m_axis, &Axis::rangeTypeChanged, this, &AxisDock::axisRangeTypeChanged);
0396     connect(m_axis, &Axis::startChanged, this, &AxisDock::axisStartChanged);
0397     connect(m_axis, &Axis::endChanged, this, &AxisDock::axisEndChanged);
0398     connect(m_axis, &Axis::zeroOffsetChanged, this, &AxisDock::axisZeroOffsetChanged);
0399     connect(m_axis, &Axis::scalingFactorChanged, this, &AxisDock::axisScalingFactorChanged);
0400     connect(m_axis, &Axis::showScaleOffsetChanged, this, &AxisDock::axisShowScaleOffsetChanged);
0401 
0402     // line
0403     connect(m_axis, &Axis::arrowTypeChanged, this, &AxisDock::axisArrowTypeChanged);
0404     connect(m_axis, &Axis::arrowPositionChanged, this, &AxisDock::axisArrowPositionChanged);
0405     connect(m_axis, &Axis::arrowSizeChanged, this, &AxisDock::axisArrowSizeChanged);
0406 
0407     // ticks
0408     connect(m_axis, &Axis::majorTicksDirectionChanged, this, &AxisDock::axisMajorTicksDirectionChanged);
0409     connect(m_axis, &Axis::majorTicksTypeChanged, this, &AxisDock::axisMajorTicksTypeChanged);
0410     connect(m_axis, &Axis::majorTicksAutoNumberChanged, this, &AxisDock::axisMajorTicksAutoNumberChanged);
0411     connect(m_axis, &Axis::majorTicksNumberChanged, this, &AxisDock::axisMajorTicksNumberChanged);
0412     connect(m_axis, &Axis::majorTicksSpacingChanged, this, &AxisDock::axisMajorTicksSpacingChanged);
0413     connect(m_axis, &Axis::majorTicksStartTypeChanged, this, &AxisDock::axisMajorTicksStartTypeChanged);
0414     connect(m_axis, &Axis::majorTickStartOffsetChanged, this, &AxisDock::axisMajorTicksStartOffsetChanged);
0415     connect(m_axis, &Axis::majorTickStartValueChanged, this, &AxisDock::axisMajorTicksStartValueChanged);
0416     connect(m_axis, &Axis::majorTicksColumnChanged, this, &AxisDock::axisMajorTicksColumnChanged);
0417     connect(m_axis, &Axis::majorTicksLengthChanged, this, &AxisDock::axisMajorTicksLengthChanged);
0418     connect(m_axis, &Axis::minorTicksDirectionChanged, this, &AxisDock::axisMinorTicksDirectionChanged);
0419     connect(m_axis, &Axis::minorTicksTypeChanged, this, &AxisDock::axisMinorTicksTypeChanged);
0420     connect(m_axis, &Axis::minorTicksAutoNumberChanged, this, &AxisDock::axisMinorTicksAutoNumberChanged);
0421     connect(m_axis, &Axis::minorTicksNumberChanged, this, &AxisDock::axisMinorTicksNumberChanged);
0422     connect(m_axis, &Axis::minorTicksIncrementChanged, this, &AxisDock::axisMinorTicksSpacingChanged);
0423     connect(m_axis, &Axis::minorTicksColumnChanged, this, &AxisDock::axisMinorTicksColumnChanged);
0424     connect(m_axis, &Axis::minorTicksLengthChanged, this, &AxisDock::axisMinorTicksLengthChanged);
0425 
0426     // labels
0427     connect(m_axis, &Axis::labelsFormatChanged, this, &AxisDock::axisLabelsFormatChanged);
0428     connect(m_axis, &Axis::labelsFormatAutoChanged, this, &AxisDock::axisLabelsFormatAutoChanged);
0429     connect(m_axis, &Axis::labelsAutoPrecisionChanged, this, &AxisDock::axisLabelsAutoPrecisionChanged);
0430     connect(m_axis, &Axis::labelsPrecisionChanged, this, &AxisDock::axisLabelsPrecisionChanged);
0431     connect(m_axis, &Axis::labelsDateTimeFormatChanged, this, &AxisDock::axisLabelsDateTimeFormatChanged);
0432     connect(m_axis, &Axis::labelsPositionChanged, this, &AxisDock::axisLabelsPositionChanged);
0433     connect(m_axis, &Axis::labelsOffsetChanged, this, &AxisDock::axisLabelsOffsetChanged);
0434     connect(m_axis, &Axis::labelsRotationAngleChanged, this, &AxisDock::axisLabelsRotationAngleChanged);
0435     connect(m_axis, &Axis::labelsTextTypeChanged, this, &AxisDock::axisLabelsTextTypeChanged);
0436     connect(m_axis, &Axis::labelsTextColumnChanged, this, &AxisDock::axisLabelsTextColumnChanged);
0437     connect(m_axis, &Axis::labelsFontChanged, this, &AxisDock::axisLabelsFontChanged);
0438     connect(m_axis, &Axis::labelsColorChanged, this, &AxisDock::axisLabelsFontColorChanged);
0439     connect(m_axis, &Axis::labelsBackgroundTypeChanged, this, &AxisDock::axisLabelsBackgroundTypeChanged);
0440     connect(m_axis, &Axis::labelsBackgroundColorChanged, this, &AxisDock::axisLabelsBackgroundColorChanged);
0441     connect(m_axis, &Axis::labelsPrefixChanged, this, &AxisDock::axisLabelsPrefixChanged);
0442     connect(m_axis, &Axis::labelsSuffixChanged, this, &AxisDock::axisLabelsSuffixChanged);
0443     connect(m_axis, &Axis::labelsOpacityChanged, this, &AxisDock::axisLabelsOpacityChanged);
0444 
0445     connect(m_axis, &Axis::visibleChanged, this, &AxisDock::axisVisibilityChanged);
0446 }
0447 
0448 /*
0449  * updates the locale in the widgets. called when the application settins are changed.
0450  */
0451 void AxisDock::updateLocale() {
0452     const auto numberLocale = QLocale();
0453     ui.sbMajorTicksSpacingNumeric->setLocale(numberLocale);
0454     ui.sbMajorTicksLength->setLocale(numberLocale);
0455     ui.sbMinorTicksSpacingNumeric->setLocale(numberLocale);
0456     ui.sbMinorTicksLength->setLocale(numberLocale);
0457     ui.sbLabelsOffset->setLocale(numberLocale);
0458 
0459     // update the QLineEdits, avoid the change events
0460     CONDITIONAL_LOCK_RETURN;
0461     ui.sbPosition->setLocale(numberLocale);
0462     ui.sbStart->setLocale(numberLocale);
0463     ui.sbEnd->setLocale(numberLocale);
0464 
0465     // scales
0466     ui.cbScale->clear();
0467     for (const auto& name : RangeT::scaleNames)
0468         ui.cbScale->addItem(name);
0469 
0470     labelWidget->updateLocale();
0471     lineWidget->updateLocale();
0472     majorTicksLineWidget->updateLocale();
0473     minorTicksLineWidget->updateLocale();
0474     majorGridLineWidget->updateLocale();
0475     minorGridLineWidget->updateLocale();
0476 }
0477 
0478 void AxisDock::updatePositionText(Axis::Orientation orientation) {
0479     switch (orientation) {
0480     case Axis::Orientation::Horizontal: {
0481         ui.cbPosition->setItemText(Top_Left, i18n("Top"));
0482         ui.cbPosition->setItemText(Bottom_Right, i18n("Bottom"));
0483         // ui.cbPosition->setItemText(Center, i18n("Center") ); // must not updated
0484         ui.cbLabelsPosition->setItemText(1, i18n("Top"));
0485         ui.cbLabelsPosition->setItemText(2, i18n("Bottom"));
0486         break;
0487     }
0488     case Axis::Orientation::Vertical: {
0489         ui.cbPosition->setItemText(Top_Left, i18n("Left"));
0490         ui.cbPosition->setItemText(Bottom_Right, i18n("Right"));
0491         // ui.cbPosition->setItemText(Center, i18n("Center") ); // must not updated
0492         ui.cbLabelsPosition->setItemText(1, i18n("Right"));
0493         ui.cbLabelsPosition->setItemText(2, i18n("Left"));
0494         break;
0495     }
0496     case Axis::Orientation::Both:
0497         break;
0498     }
0499 }
0500 
0501 void AxisDock::activateTitleTab() {
0502     ui.tabWidget->setCurrentWidget(ui.tabTitle);
0503 }
0504 
0505 void AxisDock::setModelIndexFromColumn(TreeViewComboBox* cb, const AbstractColumn* column) {
0506     if (column)
0507         cb->setCurrentModelIndex(aspectModel()->modelIndexOfAspect(column));
0508     else
0509         cb->setCurrentModelIndex(QModelIndex());
0510 }
0511 
0512 void AxisDock::updatePlotRangeList() {
0513     BaseDock::updatePlotRangeList();
0514 
0515     if (m_axis->coordinateSystemCount() == 0)
0516         return;
0517 
0518     Axis::Orientation orientation = m_axis->orientation();
0519     Range<double> logicalRange;
0520     if (orientation == Axis::Orientation::Horizontal)
0521         logicalRange = m_axis->plot()->range(Dimension::Y, m_axis->plot()->coordinateSystem(m_axis->coordinateSystemIndex())->index(Dimension::Y));
0522     else
0523         logicalRange = m_axis->plot()->range(Dimension::X, m_axis->plot()->coordinateSystem(m_axis->coordinateSystemIndex())->index(Dimension::X));
0524     spinBoxCalculateMinMax(ui.sbPositionLogical, logicalRange, ui.sbPositionLogical->value());
0525 }
0526 
0527 void AxisDock::updateAutoScale() {
0528     m_axis->setRangeType(static_cast<Axis::RangeType>(ui.cbRangeType->currentIndex()));
0529 }
0530 
0531 void AxisDock::updateLabelsPosition(Axis::LabelsPosition position) {
0532     bool b = (position != Axis::LabelsPosition::NoLabels);
0533     ui.lLabelsOffset->setEnabled(b);
0534     ui.sbLabelsOffset->setEnabled(b);
0535     ui.lLabelsRotation->setEnabled(b);
0536     ui.sbLabelsRotation->setEnabled(b);
0537     ui.lLabelsFont->setEnabled(b);
0538     ui.kfrLabelsFont->setEnabled(b);
0539     ui.lLabelsColor->setEnabled(b);
0540     ui.kcbLabelsFontColor->setEnabled(b);
0541     ui.lLabelsPrefix->setEnabled(b);
0542     ui.leLabelsPrefix->setEnabled(b);
0543     ui.lLabelsSuffix->setEnabled(b);
0544     ui.leLabelsSuffix->setEnabled(b);
0545     ui.lLabelsOpacity->setEnabled(b);
0546     ui.sbLabelsOpacity->setEnabled(b);
0547 }
0548 
0549 //*************************************************************
0550 //********** SLOTs for changes triggered in AxisDock **********
0551 //*************************************************************
0552 //"General"-tab
0553 void AxisDock::visibilityChanged(bool state) {
0554     CONDITIONAL_LOCK_RETURN;
0555 
0556     for (auto* axis : m_axesList)
0557         axis->setVisible(state);
0558 }
0559 
0560 /*!
0561  * \brief AxisDock::colorChanged
0562  * The general color of the axis changes (Title, line, ticks, labels, ...)
0563  */
0564 void AxisDock::colorChanged(const QColor& color) {
0565     CONDITIONAL_LOCK_RETURN;
0566 
0567     // Set colors of all other ui elements
0568     // - Line widget color
0569     // - Title color
0570     // - Major tick color
0571     // - Minor tick color
0572     // - Tick label color
0573 
0574     const int axesCount = m_axesList.count();
0575     if (axesCount == 1)
0576         m_axis->beginMacro(i18n("%1: set axis color", m_axis->name()));
0577     else
0578         m_axis->beginMacro(i18n("%1 axes: set color", axesCount));
0579 
0580     lineWidget->setColor(color);
0581     ui.kcbLabelsFontColor->setColor(color);
0582     majorTicksLineWidget->setColor(color);
0583     minorTicksLineWidget->setColor(color);
0584 
0585     for (auto* axis : m_axesList) {
0586         labelWidget->fontColorChanged(color);
0587         labelWidget->labelFontColorChanged(color);
0588         // must be done, because kcbLabelsFontColor is in this class and
0589         // because of the CONDITIONAL_LOCK_RETURN this function will not be called
0590         axis->setLabelsColor(color);
0591     }
0592     m_axis->endMacro();
0593 }
0594 
0595 /*!
0596     called if the orientation (horizontal or vertical) of the current axis is changed.
0597 */
0598 void AxisDock::orientationChanged(int item) {
0599     CONDITIONAL_LOCK_RETURN;
0600 
0601     auto orientation{Axis::Orientation(item)};
0602     updatePositionText(orientation);
0603 
0604     // depending on the current orientation we need to update axis position and labels position
0605 
0606     // axis position, map from the current index in the combobox to the enum value in Axis::Position
0607     Axis::Position axisPosition;
0608     int posIndex = ui.cbPosition->currentIndex();
0609     if (orientation == Axis::Orientation::Horizontal) {
0610         if (posIndex > 1)
0611             posIndex += 2;
0612         axisPosition = Axis::Position(posIndex);
0613     } else
0614         axisPosition = Axis::Position(posIndex + 2);
0615 
0616     // labels position
0617     posIndex = ui.cbLabelsPosition->currentIndex();
0618     auto labelsPosition = Axis::LabelsPosition(posIndex);
0619 
0620     for (auto* axis : m_axesList) {
0621         axis->beginMacro(i18n("%1: set axis orientation", axis->name()));
0622         axis->setOrientation(orientation);
0623         axis->setPosition(axisPosition);
0624         axis->setLabelsPosition(labelsPosition);
0625         axis->endMacro();
0626     }
0627 }
0628 
0629 /*!
0630     called if one of the predefined axis positions
0631     (top, bottom, left, right, center or custom) was changed.
0632 */
0633 void AxisDock::positionChanged(int index) {
0634     if (index == -1)
0635         return; // we occasionally get -1 here, nothing to do in this case
0636 
0637     CONDITIONAL_LOCK_RETURN;
0638 
0639     // map from the current index in the combo box to the enum value in Axis::Position,
0640     // depends on the current orientation
0641     bool logical = false;
0642     Axis::Position position;
0643     if (index == Logical) {
0644         position = Axis::Position::Logical;
0645         logical = true;
0646     } else if (index == Center)
0647         position = Axis::Position::Centered;
0648     else if (ui.cbOrientation->currentIndex() == 0) {
0649         // horizontal
0650         switch (index) {
0651         case Bottom_Right:
0652             position = Axis::Position::Bottom;
0653             break;
0654         case Top_Left:
0655         default:
0656             position = Axis::Position::Top;
0657             break;
0658         }
0659     } else {
0660         // vertical
0661         switch (index) {
0662         case Bottom_Right:
0663             position = Axis::Position::Right;
0664             break;
0665         case Top_Left:
0666         default:
0667             position = Axis::Position::Left;
0668             break;
0669         }
0670     }
0671 
0672     ui.sbPosition->setVisible(!logical);
0673     ui.sbPositionLogical->setVisible(logical);
0674 
0675     for (auto* axis : m_axesList)
0676         axis->setPosition(position);
0677 }
0678 
0679 /*!
0680     called when the custom position of the axis in the corresponding LineEdit is changed.
0681 */
0682 void AxisDock::positionChanged(double value) {
0683     CONDITIONAL_RETURN_NO_LOCK;
0684 
0685     double offset = Worksheet::convertToSceneUnits(value, m_worksheetUnit);
0686     for (auto* axis : m_axesList)
0687         axis->setOffset(offset);
0688 }
0689 
0690 void AxisDock::logicalPositionChanged(double value) {
0691     CONDITIONAL_RETURN_NO_LOCK;
0692 
0693     for (auto* axis : m_axesList)
0694         axis->setLogicalPosition(value);
0695 }
0696 
0697 void AxisDock::scaleChanged(int index) {
0698     CONDITIONAL_LOCK_RETURN;
0699 
0700     auto scale = static_cast<RangeT::Scale>(index);
0701     for (auto* axis : m_axesList) {
0702         axis->setScale(scale);
0703 
0704         if (axis->majorTicksAutoNumber())
0705             ui.sbMajorTicksNumber->setValue(axis->majorTicksNumber());
0706     }
0707 }
0708 
0709 void AxisDock::rangeScaleChanged(bool set) {
0710     CONDITIONAL_LOCK_RETURN;
0711     for (auto* axis : m_axesList)
0712         axis->setRangeScale(set);
0713 }
0714 
0715 void AxisDock::rangeTypeChanged(int index) {
0716     CONDITIONAL_LOCK_RETURN;
0717 
0718     auto rangeType = static_cast<Axis::RangeType>(index);
0719     bool autoScale = (rangeType != Axis::RangeType::Custom);
0720     ui.sbStart->setEnabled(!autoScale);
0721     ui.sbEnd->setEnabled(!autoScale);
0722     ui.dateTimeEditStart->setEnabled(!autoScale);
0723     ui.dateTimeEditEnd->setEnabled(!autoScale);
0724 
0725     for (auto* axis : m_axesList)
0726         axis->setRangeType(rangeType);
0727 
0728     updateLocale(); // update values
0729 }
0730 
0731 void AxisDock::startChanged(double value) {
0732     CONDITIONAL_RETURN_NO_LOCK;
0733 
0734     for (auto* axis : m_axesList)
0735         axis->setStart(value);
0736 }
0737 
0738 void AxisDock::endChanged(double value) {
0739     CONDITIONAL_RETURN_NO_LOCK;
0740 
0741     for (auto* axis : m_axesList)
0742         axis->setEnd(value);
0743 }
0744 
0745 void AxisDock::startDateTimeChanged(qint64 value) {
0746     CONDITIONAL_LOCK_RETURN;
0747 
0748     for (auto* axis : m_axesList)
0749         axis->setStart(value);
0750 }
0751 
0752 void AxisDock::endDateTimeChanged(qint64 value) {
0753     CONDITIONAL_LOCK_RETURN;
0754 
0755     for (auto* axis : m_axesList)
0756         axis->setEnd(value);
0757 }
0758 
0759 void AxisDock::zeroOffsetChanged(double offset) {
0760     DEBUG(Q_FUNC_INFO)
0761     CONDITIONAL_RETURN_NO_LOCK;
0762 
0763     for (auto* axis : m_axesList)
0764         axis->setZeroOffset(offset);
0765 }
0766 
0767 void AxisDock::setOffset(double offset) {
0768     ui.sbZeroOffset->setValue(-offset);
0769 }
0770 void AxisDock::setLeftOffset() {
0771     setOffset(m_axis->range().start());
0772 }
0773 void AxisDock::setCenterOffset() {
0774     setOffset(m_axis->range().center());
0775 }
0776 void AxisDock::setRightOffset() {
0777     setOffset(m_axis->range().end());
0778 }
0779 
0780 void AxisDock::scalingFactorChanged(double value) {
0781     CONDITIONAL_RETURN_NO_LOCK;
0782 
0783     for (auto* axis : m_axesList)
0784         axis->setScalingFactor(value);
0785 }
0786 void AxisDock::setUnityScale() {
0787     ui.sbScalingFactor->setValue(1. / m_axis->range().size());
0788 }
0789 // set scale and offset to get a range of 0 .. 1
0790 void AxisDock::setUnityRange() {
0791     ui.sbScalingFactor->setValue(1. / m_axis->range().size());
0792     ui.sbZeroOffset->setValue(-m_axis->range().start() / m_axis->range().size());
0793 }
0794 
0795 void AxisDock::showScaleOffsetChanged(bool state) {
0796     DEBUG(Q_FUNC_INFO)
0797     CONDITIONAL_LOCK_RETURN;
0798     for (auto* axis : m_axesList)
0799         axis->setShowScaleOffset(state);
0800 }
0801 
0802 // "Line"-tab
0803 void AxisDock::updateArrowLineColor(const QColor& color) {
0804     QPainter pa;
0805     QPixmap pm(20, 20);
0806 
0807     // no arrow
0808     pm.fill(Qt::transparent);
0809     pa.begin(&pm);
0810     pa.setRenderHint(QPainter::Antialiasing);
0811     pa.setPen(QPen(color));
0812     pa.drawLine(3, 10, 17, 10);
0813     pa.end();
0814     ui.cbArrowType->setItemIcon(0, pm);
0815 
0816     // simple, small
0817     const double cos_phi = cos(M_PI / 6.);
0818     pm.fill(Qt::transparent);
0819     pa.begin(&pm);
0820     pa.setRenderHint(QPainter::Antialiasing);
0821     pa.setPen(QPen(color));
0822     pa.drawLine(3, 10, 17, 10);
0823     pa.drawLine(17, 10, 10, 10 - 5 * cos_phi);
0824     pa.drawLine(17, 10, 10, 10 + 5 * cos_phi);
0825     pa.end();
0826     ui.cbArrowType->setItemIcon(1, pm);
0827 
0828     // simple, big
0829     pm.fill(Qt::transparent);
0830     pa.begin(&pm);
0831     pa.setRenderHint(QPainter::Antialiasing);
0832     pa.setPen(QPen(color));
0833     pa.drawLine(3, 10, 17, 10);
0834     pa.drawLine(17, 10, 10, 10 - 10 * cos_phi);
0835     pa.drawLine(17, 10, 10, 10 + 10 * cos_phi);
0836     pa.end();
0837     ui.cbArrowType->setItemIcon(2, pm);
0838 
0839     // filled, small
0840     pm.fill(Qt::transparent);
0841     pa.begin(&pm);
0842     pa.setRenderHint(QPainter::Antialiasing);
0843     pa.setPen(QPen(color));
0844     pa.setBrush(QBrush(color, Qt::SolidPattern));
0845     pa.drawLine(3, 10, 17, 10);
0846     QPolygonF points3;
0847     points3 << QPointF(17, 10) << QPointF(10, 10 - 4 * cos_phi) << QPointF(10, 10 + 4 * cos_phi);
0848     pa.drawPolygon(points3);
0849     pa.end();
0850     ui.cbArrowType->setItemIcon(3, pm);
0851 
0852     // filled, big
0853     pm.fill(Qt::transparent);
0854     pa.begin(&pm);
0855     pa.setRenderHint(QPainter::Antialiasing);
0856     pa.setPen(QPen(color));
0857     pa.setBrush(QBrush(color, Qt::SolidPattern));
0858     pa.drawLine(3, 10, 17, 10);
0859     QPolygonF points4;
0860     points4 << QPointF(17, 10) << QPointF(10, 10 - 10 * cos_phi) << QPointF(10, 10 + 10 * cos_phi);
0861     pa.drawPolygon(points4);
0862     pa.end();
0863     ui.cbArrowType->setItemIcon(4, pm);
0864 
0865     // semi-filled, small
0866     pm.fill(Qt::transparent);
0867     pa.begin(&pm);
0868     pa.setRenderHint(QPainter::Antialiasing);
0869     pa.setPen(QPen(color));
0870     pa.setBrush(QBrush(color, Qt::SolidPattern));
0871     pa.drawLine(3, 10, 17, 10);
0872     QPolygonF points5;
0873     points5 << QPointF(17, 10) << QPointF(10, 10 - 4 * cos_phi) << QPointF(13, 10) << QPointF(10, 10 + 4 * cos_phi);
0874     pa.drawPolygon(points5);
0875     pa.end();
0876     ui.cbArrowType->setItemIcon(5, pm);
0877 
0878     // semi-filled, big
0879     pm.fill(Qt::transparent);
0880     pa.begin(&pm);
0881     pa.setRenderHint(QPainter::Antialiasing);
0882     pa.setPen(QPen(color));
0883     pa.setBrush(QBrush(color, Qt::SolidPattern));
0884     pa.drawLine(3, 10, 17, 10);
0885     QPolygonF points6;
0886     points6 << QPointF(17, 10) << QPointF(10, 10 - 10 * cos_phi) << QPointF(13, 10) << QPointF(10, 10 + 10 * cos_phi);
0887     pa.drawPolygon(points6);
0888     pa.end();
0889     ui.cbArrowType->setItemIcon(6, pm);
0890 }
0891 
0892 void AxisDock::arrowTypeChanged(int index) {
0893     CONDITIONAL_LOCK_RETURN;
0894 
0895     auto type = (Axis::ArrowType)index;
0896     if (type == Axis::ArrowType::NoArrow) {
0897         ui.cbArrowPosition->setEnabled(false);
0898         ui.sbArrowSize->setEnabled(false);
0899     } else {
0900         ui.cbArrowPosition->setEnabled(true);
0901         ui.sbArrowSize->setEnabled(true);
0902     }
0903 
0904     for (auto* axis : m_axesList)
0905         axis->setArrowType(type);
0906 }
0907 
0908 void AxisDock::arrowPositionChanged(int index) {
0909     CONDITIONAL_LOCK_RETURN;
0910 
0911     auto position = (Axis::ArrowPosition)index;
0912     for (auto* axis : m_axesList)
0913         axis->setArrowPosition(position);
0914 }
0915 
0916 void AxisDock::arrowSizeChanged(int value) {
0917     CONDITIONAL_LOCK_RETURN;
0918 
0919     double v = Worksheet::convertToSceneUnits(value, Worksheet::Unit::Point);
0920     for (auto* axis : m_axesList)
0921         axis->setArrowSize(v);
0922 }
0923 
0924 //"Major ticks" tab
0925 void AxisDock::majorTicksDirectionChanged(int index) {
0926     const auto direction = Axis::TicksDirection(index);
0927     const bool b = (direction != Axis::noTicks);
0928     const bool numeric = m_axis->isNumeric();
0929     ui.cbMajorTicksType->setEnabled(b);
0930     ui.cbMajorTicksType->setEnabled(b);
0931     ui.cbMajorTicksAutoNumber->setEnabled(b);
0932 
0933     if (b) {
0934         if (ui.cbMajorTicksAutoNumber->isChecked())
0935             ui.sbMajorTicksNumber->setEnabled(false);
0936         else
0937             ui.sbMajorTicksNumber->setEnabled(true);
0938     } else
0939         ui.sbMajorTicksNumber->setEnabled(false);
0940 
0941     ui.sbMajorTicksSpacingNumeric->setEnabled(b);
0942     dtsbMajorTicksIncrement->setEnabled(b);
0943     ui.cbMajorTicksStartType->setEnabled(b);
0944     ui.sbMajorTickStartValue->setEnabled(b && numeric);
0945     ui.sbMajorTickStartDateTime->setEnabled(b && !numeric);
0946     ui.sbMajorTickStartOffset->setEnabled(b && numeric);
0947     dtsbMajorTicksDateTimeStartOffset->setEnabled(b && !numeric);
0948     ui.tbFirstTickData->setEnabled(b);
0949     ui.tbFirstTickAuto->setEnabled(b);
0950     cbMajorTicksColumn->setEnabled(b);
0951     ui.cbLabelsTextType->setEnabled(b);
0952     cbLabelsTextColumn->setEnabled(b);
0953     ui.sbMajorTicksLength->setEnabled(b);
0954     majorTicksLineWidget->setEnabled(b);
0955 
0956     CONDITIONAL_LOCK_RETURN;
0957 
0958     for (auto* axis : m_axesList)
0959         axis->setMajorTicksDirection(direction);
0960 }
0961 
0962 /*!
0963     called if the current type of the ticks is changed.
0964     Shows/hides the corresponding widgets.
0965 */
0966 void AxisDock::majorTicksTypeChanged(int index) {
0967     if (!m_axis) // If elements are added to the combobox 'cbMajorTicksType' (at init of this class), then this function is called, which is a problem if no
0968                  // axis are available
0969         return;
0970 
0971     auto type = (Axis::TicksType)ui.cbMajorTicksType->itemData(index).toInt(); // WRONG!
0972 
0973     ui.lLabelsTextType->setVisible(type != Axis::TicksType::ColumnLabels);
0974     ui.cbLabelsTextType->setVisible(type != Axis::TicksType::ColumnLabels);
0975     const auto customValues = m_axis->labelsTextType() == Axis::LabelsTextType::CustomValues;
0976     ui.lLabelsTextColumn->setVisible(type != Axis::TicksType::ColumnLabels && customValues);
0977     cbLabelsTextColumn->setVisible(type != Axis::TicksType::ColumnLabels && customValues);
0978 
0979     switch (type) {
0980     case Axis::TicksType::TotalNumber: {
0981         ui.lMajorTicksNumber->show();
0982         ui.sbMajorTicksNumber->show();
0983         ui.lMajorTicksSpacingNumeric->hide();
0984         ui.sbMajorTicksSpacingNumeric->hide();
0985         ui.cbMajorTicksAutoNumber->show();
0986         ui.lMajorTicksStartType->show();
0987         ui.cbMajorTicksStartType->show();
0988         ui.lMajorTicksIncrementDateTime->hide();
0989         dtsbMajorTicksIncrement->hide();
0990         ui.lMajorTicksColumn->hide();
0991         cbMajorTicksColumn->hide();
0992         ui.sbZeroOffset->show();
0993         ui.tbFirstTickAuto->show();
0994         ui.tbFirstTickData->show();
0995         updateMajorTicksStartType(true);
0996         break;
0997     }
0998     case Axis::TicksType::Spacing: {
0999         ui.lMajorTicksNumber->hide();
1000         ui.sbMajorTicksNumber->hide();
1001         ui.cbMajorTicksAutoNumber->hide();
1002         ui.lMajorTicksSpacingNumeric->show();
1003         ui.lMajorTicksStartType->show();
1004         ui.cbMajorTicksStartType->show();
1005 
1006         const bool numeric = m_axis->isNumeric();
1007 
1008         ui.lMajorTicksSpacingNumeric->setVisible(numeric);
1009         ui.sbMajorTicksSpacingNumeric->setVisible(numeric);
1010 
1011         ui.lMajorTicksIncrementDateTime->setVisible(!numeric);
1012         dtsbMajorTicksIncrement->setVisible(!numeric);
1013         ui.lMajorTicksIncrementDateTime->setVisible(!numeric);
1014         dtsbMajorTicksDateTimeStartOffset->setVisible(!numeric);
1015 
1016         ui.lMajorTicksColumn->hide();
1017         cbMajorTicksColumn->hide();
1018         ui.sbZeroOffset->show();
1019         ui.tbFirstTickAuto->show();
1020         ui.tbFirstTickData->show();
1021         updateMajorTicksStartType(true);
1022 
1023         // Check if spacing is not too small
1024         majorTicksSpacingChanged();
1025         break;
1026     }
1027     case Axis::TicksType::ColumnLabels:
1028         // Fall through
1029     case Axis::TicksType::CustomColumn: {
1030         ui.lMajorTicksNumber->show();
1031         ui.sbMajorTicksNumber->show();
1032         ui.cbMajorTicksAutoNumber->show();
1033         ui.lMajorTicksSpacingNumeric->hide();
1034         ui.sbMajorTicksSpacingNumeric->hide();
1035         ui.lMajorTicksIncrementDateTime->hide();
1036         dtsbMajorTicksIncrement->hide();
1037         ui.lMajorTicksStartType->hide();
1038         ui.cbMajorTicksStartType->hide();
1039         ui.sbZeroOffset->hide();
1040         ui.tbFirstTickAuto->hide();
1041         ui.tbFirstTickData->hide();
1042 
1043         ui.lMajorTicksColumn->show();
1044         cbMajorTicksColumn->show();
1045 
1046         updateMajorTicksStartType(false);
1047         break;
1048     }
1049     case Axis::TicksType::CustomValues:
1050         break;
1051     }
1052 
1053     CONDITIONAL_LOCK_RETURN;
1054 
1055     for (auto* axis : m_axesList)
1056         axis->setMajorTicksType(type);
1057 }
1058 
1059 void AxisDock::majorTicksAutoNumberChanged(int state) {
1060     bool automatic = (state == Qt::CheckState::Checked ? true : false);
1061     ui.sbMajorTicksNumber->setEnabled(!automatic);
1062 
1063     CONDITIONAL_LOCK_RETURN;
1064 
1065     for (auto* axis : m_axesList)
1066         axis->setMajorTicksAutoNumber(automatic);
1067 
1068     if (automatic)
1069         ui.sbMajorTicksNumber->setValue(m_axis->majorTicksNumber()); // set new value
1070 }
1071 
1072 void AxisDock::majorTicksNumberChanged(int value) {
1073     DEBUG(Q_FUNC_INFO << ", number = " << value)
1074     CONDITIONAL_LOCK_RETURN;
1075 
1076     for (auto* axis : m_axesList)
1077         axis->setMajorTicksNumber(value);
1078 }
1079 
1080 void AxisDock::majorTicksSpacingChanged() {
1081     bool numeric = m_axis->isNumeric();
1082     double spacing = numeric ? ui.sbMajorTicksSpacingNumeric->value() : dtsbMajorTicksIncrement->value();
1083     if (numeric) {
1084         CONDITIONAL_RETURN_NO_LOCK;
1085 
1086         for (auto* axis : m_axesList)
1087             axis->setMajorTicksSpacing(spacing);
1088     } else {
1089         CONDITIONAL_LOCK_RETURN;
1090 
1091         for (auto* axis : m_axesList)
1092             axis->setMajorTicksSpacing(spacing);
1093     }
1094 }
1095 
1096 void AxisDock::majorTicksStartTypeChanged(int state) {
1097     updateMajorTicksStartType(true);
1098 
1099     CONDITIONAL_LOCK_RETURN;
1100 
1101     auto type = static_cast<Axis::TicksStartType>(state);
1102     for (auto* axis : m_axesList)
1103         axis->setMajorTicksStartType(type);
1104 }
1105 
1106 void AxisDock::majorTicksDateTimeStartOffsetChanged() {
1107     if (m_axis->isNumeric())
1108         return;
1109     const qint64 value = dtsbMajorTicksDateTimeStartOffset->value();
1110     ui.sbMajorTickStartOffset->setClearButtonEnabled(value != 0);
1111 
1112     CONDITIONAL_LOCK_RETURN;
1113     for (auto* axis : m_axesList)
1114         axis->setMajorTickStartOffset(value);
1115 }
1116 
1117 void AxisDock::majorTicksStartOffsetChanged(double value) {
1118     ui.sbMajorTickStartOffset->setClearButtonEnabled(value != 0);
1119 
1120     CONDITIONAL_RETURN_NO_LOCK;
1121 
1122     for (auto* axis : m_axesList)
1123         axis->setMajorTickStartOffset(value);
1124 }
1125 
1126 void AxisDock::majorTicksStartDateTimeChanged(qint64 value) {
1127     ui.sbMajorTickStartValue->setClearButtonEnabled(value != 0);
1128 
1129     CONDITIONAL_RETURN_NO_LOCK;
1130 
1131     for (auto* axis : m_axesList)
1132         axis->setMajorTickStartValue(value);
1133 }
1134 
1135 void AxisDock::majorTicksStartValueChanged(double value) {
1136     ui.sbMajorTickStartValue->setClearButtonEnabled(value != 0);
1137 
1138     CONDITIONAL_RETURN_NO_LOCK;
1139 
1140     for (auto* axis : m_axesList)
1141         axis->setMajorTickStartValue(value);
1142 }
1143 
1144 void AxisDock::setTickOffsetData(bool nice) {
1145     Range<double> dataRange;
1146     if (m_axis->orientation() == Axis::Orientation::Horizontal)
1147         dataRange = m_axis->plot()->dataRange(Dimension::X);
1148     else
1149         dataRange = m_axis->plot()->dataRange(Dimension::Y);
1150 
1151     if (nice)
1152         dataRange.niceExtend();
1153 
1154     DEBUG(Q_FUNC_INFO << ", data range = " << dataRange.toStdString())
1155     const double offset = dataRange.start() - m_axis->range().start();
1156 
1157     ui.sbMajorTickStartOffset->setValue(offset);
1158     dtsbMajorTicksDateTimeStartOffset->setValue(offset);
1159 }
1160 
1161 void AxisDock::majorTicksColumnChanged(const QModelIndex& index) {
1162     CONDITIONAL_LOCK_RETURN;
1163 
1164     auto* aspect = static_cast<AbstractAspect*>(index.internalPointer());
1165     AbstractColumn* column = nullptr;
1166     if (aspect) {
1167         column = dynamic_cast<AbstractColumn*>(aspect);
1168         Q_ASSERT(column != nullptr);
1169     }
1170 
1171     for (auto* axis : m_axesList)
1172         axis->setMajorTicksColumn(column);
1173 }
1174 
1175 void AxisDock::majorTicksLengthChanged(double value) {
1176     CONDITIONAL_RETURN_NO_LOCK;
1177 
1178     for (auto* axis : m_axesList)
1179         axis->setMajorTicksLength(Worksheet::convertToSceneUnits(value, Worksheet::Unit::Point));
1180 }
1181 
1182 //"Minor ticks" tab
1183 void AxisDock::minorTicksDirectionChanged(int index) {
1184     const auto direction = Axis::TicksDirection(index);
1185     const bool b = (direction != Axis::noTicks);
1186     ui.cbMinorTicksType->setEnabled(b);
1187     ui.cbMinorTicksType->setEnabled(b);
1188 
1189     if (b) {
1190         if (ui.cbMinorTicksAutoNumber->isChecked())
1191             ui.sbMinorTicksNumber->setEnabled(false);
1192         else
1193             ui.sbMinorTicksNumber->setEnabled(true);
1194     } else
1195         ui.sbMinorTicksNumber->setEnabled(false);
1196 
1197     ui.sbMinorTicksSpacingNumeric->setEnabled(b);
1198     dtsbMinorTicksIncrement->setEnabled(b);
1199     ui.sbMinorTicksLength->setEnabled(b);
1200     minorTicksLineWidget->setEnabled(b);
1201 
1202     CONDITIONAL_LOCK_RETURN;
1203 
1204     for (auto* axis : m_axesList)
1205         axis->setMinorTicksDirection(direction);
1206 }
1207 
1208 void AxisDock::minorTicksTypeChanged(int index) {
1209     if (!m_axis) // If elements are added to the combobox 'cbMajorTicksType' (at init of this class), then this function is called, which is a problem if no
1210                  // axis are available
1211         return;
1212 
1213     auto type = Axis::TicksType(index);
1214     if (type == Axis::TicksType::TotalNumber) {
1215         ui.lMinorTicksNumber->show();
1216         ui.sbMinorTicksNumber->show();
1217         ui.cbMinorTicksAutoNumber->show();
1218         ui.lMinorTicksSpacingNumeric->hide();
1219         ui.sbMinorTicksSpacingNumeric->hide();
1220         ui.lMinorTicksColumn->hide();
1221         cbMinorTicksColumn->hide();
1222         ui.lMinorTicksIncrementDateTime->hide();
1223         dtsbMinorTicksIncrement->hide();
1224     } else if (type == Axis::TicksType::Spacing) {
1225         ui.lMinorTicksNumber->hide();
1226         ui.sbMinorTicksNumber->hide();
1227         ui.cbMinorTicksAutoNumber->hide();
1228 
1229         if (m_axis->isNumeric()) {
1230             ui.lMinorTicksSpacingNumeric->show();
1231             ui.sbMinorTicksSpacingNumeric->show();
1232             ui.lMinorTicksIncrementDateTime->hide();
1233             dtsbMinorTicksIncrement->hide();
1234         } else {
1235             ui.lMinorTicksSpacingNumeric->hide();
1236             ui.sbMinorTicksSpacingNumeric->hide();
1237             ui.lMinorTicksIncrementDateTime->show();
1238             dtsbMinorTicksIncrement->show();
1239         }
1240 
1241         ui.lMinorTicksColumn->hide();
1242         cbMinorTicksColumn->hide();
1243 
1244         // Check if spacing is not to small
1245         minorTicksSpacingChanged();
1246     } else {
1247         ui.lMinorTicksNumber->hide();
1248         ui.sbMinorTicksNumber->hide();
1249         ui.cbMinorTicksAutoNumber->hide();
1250         ui.lMinorTicksSpacingNumeric->hide();
1251         ui.sbMinorTicksSpacingNumeric->hide();
1252         ui.lMinorTicksIncrementDateTime->hide();
1253         dtsbMinorTicksIncrement->hide();
1254         ui.lMinorTicksColumn->show();
1255         cbMinorTicksColumn->show();
1256     }
1257 
1258     CONDITIONAL_LOCK_RETURN;
1259 
1260     for (auto* axis : m_axesList)
1261         axis->setMinorTicksType(type);
1262 }
1263 
1264 void AxisDock::minorTicksAutoNumberChanged(int state) {
1265     bool automatic = (state == Qt::CheckState::Checked ? true : false);
1266     ui.sbMinorTicksNumber->setEnabled(!automatic);
1267 
1268     CONDITIONAL_LOCK_RETURN;
1269 
1270     for (auto* axis : m_axesList)
1271         axis->setMinorTicksAutoNumber(automatic);
1272 
1273     if (automatic)
1274         ui.sbMinorTicksNumber->setValue(m_axis->minorTicksNumber()); // set new value
1275 }
1276 
1277 void AxisDock::minorTicksNumberChanged(int value) {
1278     CONDITIONAL_LOCK_RETURN;
1279 
1280     for (auto* axis : m_axesList)
1281         axis->setMinorTicksNumber(value);
1282 }
1283 
1284 void AxisDock::minorTicksSpacingChanged() {
1285     bool numeric = m_axis->isNumeric();
1286     double spacing = numeric ? ui.sbMinorTicksSpacingNumeric->value() : dtsbMinorTicksIncrement->value();
1287     if (numeric) {
1288         CONDITIONAL_RETURN_NO_LOCK;
1289 
1290         for (auto* axis : m_axesList)
1291             axis->setMinorTicksSpacing(spacing);
1292     } else {
1293         CONDITIONAL_LOCK_RETURN;
1294         for (auto* axis : m_axesList)
1295             axis->setMinorTicksSpacing(spacing);
1296     }
1297 }
1298 
1299 void AxisDock::minorTicksColumnChanged(const QModelIndex& index) {
1300     CONDITIONAL_LOCK_RETURN;
1301 
1302     auto* aspect = static_cast<AbstractAspect*>(index.internalPointer());
1303     auto* column = dynamic_cast<AbstractColumn*>(aspect);
1304     Q_ASSERT(column != nullptr);
1305 
1306     for (auto* axis : m_axesList)
1307         axis->setMinorTicksColumn(column);
1308 }
1309 
1310 void AxisDock::minorTicksLengthChanged(double value) {
1311     CONDITIONAL_RETURN_NO_LOCK;
1312 
1313     for (auto* axis : m_axesList)
1314         axis->setMinorTicksLength(Worksheet::convertToSceneUnits(value, Worksheet::Unit::Point));
1315 }
1316 
1317 //"Tick labels"-tab
1318 void AxisDock::labelsFormatChanged(int index) {
1319     CONDITIONAL_LOCK_RETURN;
1320 
1321     for (auto* axis : m_axesList)
1322         axis->setLabelsFormat(Axis::indexToLabelsFormat(index));
1323 }
1324 
1325 void AxisDock::labelsFormatAutoChanged(bool automatic) {
1326     // Must be above the lock, because if the axis changes the value without interacting with the
1327     // dock, this should also change
1328     ui.cbLabelsFormat->setEnabled(!automatic);
1329 
1330     CONDITIONAL_LOCK_RETURN;
1331 
1332     for (auto* axis : m_axesList)
1333         axis->setLabelsFormatAuto(automatic);
1334 }
1335 
1336 void AxisDock::labelsPrecisionChanged(int value) {
1337     CONDITIONAL_LOCK_RETURN;
1338 
1339     for (auto* axis : m_axesList)
1340         axis->setLabelsPrecision(value);
1341 }
1342 
1343 void AxisDock::labelsAutoPrecisionChanged(bool state) {
1344     ui.sbLabelsPrecision->setEnabled(!state);
1345 
1346     CONDITIONAL_LOCK_RETURN;
1347 
1348     for (auto* axis : m_axesList)
1349         axis->setLabelsAutoPrecision(state);
1350 }
1351 
1352 void AxisDock::labelsDateTimeFormatChanged() {
1353     CONDITIONAL_LOCK_RETURN;
1354 
1355     for (auto* axis : m_axesList)
1356         axis->setLabelsDateTimeFormat(ui.cbLabelsDateTimeFormat->currentText());
1357 }
1358 
1359 void AxisDock::labelsPositionChanged(int index) {
1360     auto position = Axis::LabelsPosition(index);
1361     updateLabelsPosition(position);
1362 
1363     CONDITIONAL_LOCK_RETURN;
1364 
1365     for (auto* axis : m_axesList)
1366         axis->setLabelsPosition(position);
1367 }
1368 
1369 void AxisDock::labelsOffsetChanged(double value) {
1370     CONDITIONAL_RETURN_NO_LOCK;
1371 
1372     for (auto* axis : m_axesList)
1373         axis->setLabelsOffset(Worksheet::convertToSceneUnits(value, Worksheet::Unit::Point));
1374 }
1375 
1376 void AxisDock::labelsRotationChanged(int value) {
1377     CONDITIONAL_LOCK_RETURN;
1378 
1379     for (auto* axis : m_axesList)
1380         axis->setLabelsRotationAngle(value);
1381 }
1382 
1383 void AxisDock::labelsTextTypeChanged(int index) {
1384     if (!m_axis)
1385         return; // don't do anything when we're addItem()'ing strings and the axis is not available yet
1386 
1387     const auto type = static_cast<Axis::LabelsTextType>(ui.cbLabelsTextType->itemData(index).toInt());
1388     switch (type) {
1389     case Axis::LabelsTextType::PositionValues: {
1390         ui.lLabelsTextColumn->hide();
1391         cbLabelsTextColumn->hide();
1392 
1393         bool numeric = m_axis->isNumeric();
1394         ui.lLabelsFormat->setVisible(numeric);
1395         ui.frameLabelsFormat->setVisible(numeric);
1396         ui.lLabelsPrecision->setVisible(numeric);
1397         ui.frameLabelsPrecision->setVisible(numeric);
1398         ui.lLabelsDateTimeFormat->setVisible(!numeric);
1399         ui.cbLabelsDateTimeFormat->setVisible(!numeric);
1400         break;
1401     }
1402     case Axis::LabelsTextType::CustomValues: {
1403         ui.lLabelsTextColumn->show();
1404         cbLabelsTextColumn->show();
1405         labelsTextColumnChanged(cbLabelsTextColumn->currentModelIndex());
1406         break;
1407     }
1408     }
1409 
1410     CONDITIONAL_LOCK_RETURN;
1411 
1412     for (auto* axis : m_axesList)
1413         axis->setLabelsTextType(type);
1414 }
1415 
1416 void AxisDock::labelsTextColumnChanged(const QModelIndex& index) {
1417     auto* aspect = static_cast<AbstractAspect*>(index.internalPointer());
1418     auto* column = dynamic_cast<AbstractColumn*>(aspect);
1419 
1420     if (column) {
1421         // depending on data format of the column (numeric vs. datetime vs. text),
1422         // show/hide the corresponding widgets for the tick labels format
1423         switch (column->columnMode()) {
1424         case AbstractColumn::ColumnMode::Double:
1425         case AbstractColumn::ColumnMode::Integer:
1426         case AbstractColumn::ColumnMode::BigInt:
1427             ui.lLabelsFormat->show();
1428             ui.frameLabelsFormat->show();
1429             ui.lLabelsPrecision->show();
1430             ui.frameLabelsPrecision->show();
1431             ui.lLabelsDateTimeFormat->hide();
1432             ui.cbLabelsDateTimeFormat->hide();
1433             break;
1434         case AbstractColumn::ColumnMode::Text:
1435             ui.lLabelsFormat->hide();
1436             ui.frameLabelsFormat->hide();
1437             ui.lLabelsPrecision->hide();
1438             ui.frameLabelsPrecision->hide();
1439             ui.lLabelsDateTimeFormat->hide();
1440             ui.cbLabelsDateTimeFormat->hide();
1441             break;
1442         case AbstractColumn::ColumnMode::DateTime:
1443         case AbstractColumn::ColumnMode::Month:
1444         case AbstractColumn::ColumnMode::Day:
1445             ui.lLabelsFormat->hide();
1446             ui.frameLabelsFormat->hide();
1447             ui.lLabelsPrecision->hide();
1448             ui.frameLabelsPrecision->hide();
1449             ui.lLabelsDateTimeFormat->show();
1450             ui.cbLabelsDateTimeFormat->show();
1451             break;
1452         }
1453     } else {
1454         auto type = Axis::LabelsTextType(ui.cbLabelsTextType->currentData().toInt());
1455         switch (type) {
1456         case Axis::LabelsTextType::CustomValues:
1457             ui.lLabelsFormat->hide();
1458             ui.frameLabelsFormat->hide();
1459             ui.lLabelsPrecision->hide();
1460             ui.frameLabelsPrecision->hide();
1461             ui.lLabelsDateTimeFormat->hide();
1462             ui.cbLabelsDateTimeFormat->hide();
1463             break;
1464         case Axis::LabelsTextType::PositionValues:
1465             break;
1466         }
1467     }
1468 
1469     CONDITIONAL_LOCK_RETURN;
1470 
1471     for (auto* axis : m_axesList)
1472         axis->setLabelsTextColumn(column);
1473 }
1474 
1475 void AxisDock::labelsPrefixChanged() {
1476     CONDITIONAL_LOCK_RETURN;
1477 
1478     const QString& prefix = ui.leLabelsPrefix->text();
1479     for (auto* axis : m_axesList)
1480         axis->setLabelsPrefix(prefix);
1481 }
1482 
1483 void AxisDock::labelsSuffixChanged() {
1484     CONDITIONAL_LOCK_RETURN;
1485 
1486     const QString& suffix = ui.leLabelsSuffix->text();
1487     for (auto* axis : m_axesList)
1488         axis->setLabelsSuffix(suffix);
1489 }
1490 
1491 void AxisDock::labelsFontChanged(const QFont& font) {
1492     CONDITIONAL_LOCK_RETURN;
1493 
1494     QFont labelsFont = font;
1495     labelsFont.setPixelSize(Worksheet::convertToSceneUnits(font.pointSizeF(), Worksheet::Unit::Point));
1496     for (auto* axis : m_axesList)
1497         axis->setLabelsFont(labelsFont);
1498 }
1499 
1500 void AxisDock::labelsFontColorChanged(const QColor& color) {
1501     CONDITIONAL_LOCK_RETURN;
1502 
1503     for (auto* axis : m_axesList)
1504         axis->setLabelsColor(color);
1505 
1506     updateAxisColor();
1507 }
1508 
1509 void AxisDock::labelsBackgroundTypeChanged(int index) {
1510     auto type = Axis::LabelsBackgroundType(index);
1511 
1512     bool transparent = (type == Axis::LabelsBackgroundType::Transparent);
1513     ui.lLabelsBackgroundColor->setVisible(!transparent);
1514     ui.kcbLabelsBackgroundColor->setVisible(!transparent);
1515 
1516     CONDITIONAL_LOCK_RETURN;
1517 
1518     for (auto* axis : m_axesList)
1519         axis->setLabelsBackgroundType(type);
1520 }
1521 
1522 void AxisDock::labelsBackgroundColorChanged(const QColor& color) {
1523     CONDITIONAL_LOCK_RETURN;
1524 
1525     for (auto* axis : m_axesList)
1526         axis->setLabelsBackgroundColor(color);
1527 }
1528 
1529 void AxisDock::labelsOpacityChanged(int value) {
1530     CONDITIONAL_LOCK_RETURN;
1531 
1532     qreal opacity{value / 100.};
1533     for (auto* axis : m_axesList)
1534         axis->setLabelsOpacity(opacity);
1535 }
1536 
1537 //*************************************************************
1538 //************ SLOTs for changes triggered in Axis ************
1539 //*************************************************************
1540 void AxisDock::axisOrientationChanged(Axis::Orientation orientation) {
1541     CONDITIONAL_LOCK_RETURN;
1542     ui.cbOrientation->setCurrentIndex(static_cast<int>(orientation));
1543 }
1544 
1545 void AxisDock::axisPositionChanged(Axis::Position position) {
1546     CONDITIONAL_LOCK_RETURN;
1547 
1548     // map from the enum Qt::Orientation to the index in the combo box
1549     int index{static_cast<int>(position)};
1550     switch (index) {
1551     case static_cast<int>(Axis::Position::Top):
1552     case static_cast<int>(Axis::Position::Left):
1553         ui.cbPosition->setCurrentIndex(Top_Left);
1554         break;
1555     case static_cast<int>(Axis::Position::Bottom):
1556     case static_cast<int>(Axis::Position::Right):
1557         ui.cbPosition->setCurrentIndex(Bottom_Right);
1558         break;
1559     case static_cast<int>(Axis::Position::Centered):
1560         ui.cbPosition->setCurrentIndex(Center);
1561         break;
1562     case static_cast<int>(Axis::Position::Logical):
1563         ui.cbPosition->setCurrentIndex(Logical);
1564     }
1565 }
1566 
1567 void AxisDock::axisPositionChanged(double value) {
1568     CONDITIONAL_LOCK_RETURN;
1569     ui.sbPosition->setValue(Worksheet::convertFromSceneUnits(value, m_worksheetUnit));
1570 }
1571 
1572 void AxisDock::axisLogicalPositionChanged(double value) {
1573     CONDITIONAL_LOCK_RETURN;
1574     ui.sbPositionLogical->setValue(value);
1575 }
1576 
1577 void AxisDock::axisScaleChanged(RangeT::Scale scale) {
1578     CONDITIONAL_LOCK_RETURN;
1579     ui.cbScale->setCurrentIndex(static_cast<int>(scale));
1580 }
1581 
1582 void AxisDock::updateScale() {
1583     if (m_axis->rangeScale()) {
1584         ui.cbScale->setEnabled(false);
1585         ui.cbScale->setToolTip(i18n("Scale is in sync with the plot scale"));
1586     } else {
1587         ui.cbScale->setEnabled(true);
1588         ui.cbScale->setToolTip(i18n("Scale is async with the plot"));
1589     }
1590 }
1591 
1592 void AxisDock::axisRangeScaleChanged(bool rangeScale) {
1593     updateScale();
1594 
1595     CONDITIONAL_LOCK_RETURN;
1596     ui.cbRangeScale->setChecked(rangeScale);
1597 }
1598 
1599 void AxisDock::axisRangeTypeChanged(Axis::RangeType type) {
1600     CONDITIONAL_LOCK_RETURN;
1601     ui.cbRangeType->setCurrentIndex(static_cast<int>(type));
1602 }
1603 
1604 void AxisDock::axisStartChanged(double value) {
1605     CONDITIONAL_LOCK_RETURN;
1606 
1607     ui.sbStart->setValue(value);
1608     ui.dateTimeEditStart->setMSecsSinceEpochUTC(value);
1609 
1610     // determine stepsize and number of decimals
1611     const double range{m_axis->range().length()};
1612     const int decimals{nsl_math_rounded_decimals(range) + 1};
1613     DEBUG("range = " << range << ", decimals = " << decimals)
1614     ui.sbMajorTicksSpacingNumeric->setDecimals(decimals);
1615     ui.sbMajorTicksSpacingNumeric->setSingleStep(gsl_pow_int(10., -decimals));
1616     ui.sbMajorTicksSpacingNumeric->setMaximum(range);
1617 }
1618 
1619 void AxisDock::axisEndChanged(double value) {
1620     CONDITIONAL_LOCK_RETURN;
1621 
1622     ui.sbEnd->setValue(value);
1623     ui.dateTimeEditEnd->setMSecsSinceEpochUTC(value);
1624 
1625     // determine stepsize and number of decimals
1626     const double range{m_axis->range().length()};
1627     const int decimals{nsl_math_rounded_decimals(range) + 1};
1628     DEBUG("range = " << range << ", decimals = " << decimals)
1629     ui.sbMajorTicksSpacingNumeric->setDecimals(decimals);
1630     ui.sbMajorTicksSpacingNumeric->setSingleStep(gsl_pow_int(10., -decimals));
1631     ui.sbMajorTicksSpacingNumeric->setMaximum(range);
1632 }
1633 
1634 void AxisDock::axisZeroOffsetChanged(qreal value) {
1635     DEBUG(Q_FUNC_INFO)
1636     CONDITIONAL_LOCK_RETURN;
1637     ui.sbZeroOffset->setValue(value);
1638 }
1639 void AxisDock::axisScalingFactorChanged(qreal value) {
1640     CONDITIONAL_LOCK_RETURN;
1641     ui.sbScalingFactor->setValue(value);
1642 }
1643 void AxisDock::axisShowScaleOffsetChanged(bool b) {
1644     CONDITIONAL_LOCK_RETURN;
1645     ui.chkShowScaleOffset->setChecked(b);
1646 }
1647 
1648 // line
1649 void AxisDock::axisArrowTypeChanged(Axis::ArrowType type) {
1650     CONDITIONAL_LOCK_RETURN;
1651     ui.cbArrowType->setCurrentIndex(static_cast<int>(type));
1652 }
1653 
1654 void AxisDock::axisArrowPositionChanged(Axis::ArrowPosition position) {
1655     CONDITIONAL_LOCK_RETURN;
1656     ui.cbArrowPosition->setCurrentIndex(static_cast<int>(position));
1657 }
1658 
1659 void AxisDock::axisArrowSizeChanged(qreal size) {
1660     CONDITIONAL_LOCK_RETURN;
1661     ui.sbArrowSize->setValue((int)Worksheet::convertFromSceneUnits(size, Worksheet::Unit::Point));
1662 }
1663 
1664 // major ticks
1665 void AxisDock::axisMajorTicksDirectionChanged(Axis::TicksDirection direction) {
1666     CONDITIONAL_LOCK_RETURN;
1667     ui.cbMajorTicksDirection->setCurrentIndex(direction);
1668 }
1669 void AxisDock::axisMajorTicksTypeChanged(Axis::TicksType type) {
1670     CONDITIONAL_LOCK_RETURN;
1671     const int index = ui.cbMajorTicksType->findData((int)type);
1672     ui.cbMajorTicksType->itemData(index);
1673 }
1674 void AxisDock::axisMajorTicksAutoNumberChanged(bool automatic) {
1675     CONDITIONAL_LOCK_RETURN;
1676     ui.cbMajorTicksAutoNumber->setChecked(automatic);
1677 }
1678 void AxisDock::axisMajorTicksNumberChanged(int number) {
1679     CONDITIONAL_LOCK_RETURN;
1680     ui.sbMajorTicksNumber->setValue(number);
1681 }
1682 void AxisDock::axisMajorTicksSpacingChanged(qreal increment) {
1683     CONDITIONAL_LOCK_RETURN;
1684     if (m_axis->isNumeric())
1685         ui.sbMajorTicksSpacingNumeric->setValue(increment);
1686     else
1687         dtsbMajorTicksIncrement->setValue(increment);
1688 }
1689 void AxisDock::axisMajorTicksStartTypeChanged(Axis::TicksStartType type) {
1690     CONDITIONAL_LOCK_RETURN;
1691     ui.cbMajorTicksStartType->setCurrentIndex(static_cast<int>(type));
1692 }
1693 void AxisDock::axisMajorTicksStartOffsetChanged(qreal value) {
1694     CONDITIONAL_LOCK_RETURN;
1695     ui.sbMajorTickStartOffset->setValue(value);
1696     dtsbMajorTicksDateTimeStartOffset->setValue(value);
1697 }
1698 void AxisDock::axisMajorTicksStartValueChanged(qreal value) {
1699     CONDITIONAL_LOCK_RETURN;
1700     ui.sbMajorTickStartValue->setValue(value);
1701     ui.sbMajorTickStartDateTime->setMSecsSinceEpochUTC(value);
1702 }
1703 void AxisDock::axisMajorTicksColumnChanged(const AbstractColumn* column) {
1704     CONDITIONAL_LOCK_RETURN;
1705     cbMajorTicksColumn->setColumn(column, m_axis->majorTicksColumnPath());
1706 }
1707 void AxisDock::axisMajorTicksLengthChanged(qreal length) {
1708     CONDITIONAL_LOCK_RETURN;
1709     ui.sbMajorTicksLength->setValue(Worksheet::convertFromSceneUnits(length, Worksheet::Unit::Point));
1710 }
1711 
1712 // minor ticks
1713 void AxisDock::axisMinorTicksDirectionChanged(Axis::TicksDirection direction) {
1714     CONDITIONAL_LOCK_RETURN;
1715     ui.cbMinorTicksDirection->setCurrentIndex(direction);
1716 }
1717 void AxisDock::axisMinorTicksTypeChanged(Axis::TicksType type) {
1718     CONDITIONAL_LOCK_RETURN;
1719     ui.cbMinorTicksType->setCurrentIndex(static_cast<int>(type));
1720 }
1721 void AxisDock::axisMinorTicksAutoNumberChanged(bool automatic) {
1722     CONDITIONAL_LOCK_RETURN;
1723     ui.cbMinorTicksAutoNumber->setChecked(automatic);
1724 }
1725 void AxisDock::axisMinorTicksNumberChanged(int number) {
1726     CONDITIONAL_LOCK_RETURN;
1727     ui.sbMinorTicksNumber->setValue(number);
1728 }
1729 void AxisDock::axisMinorTicksSpacingChanged(qreal increment) {
1730     CONDITIONAL_LOCK_RETURN;
1731     if (m_axis->isNumeric())
1732         ui.sbMinorTicksSpacingNumeric->setValue(increment);
1733     else
1734         dtsbMinorTicksIncrement->setValue(increment);
1735 }
1736 void AxisDock::axisMinorTicksColumnChanged(const AbstractColumn* column) {
1737     CONDITIONAL_LOCK_RETURN;
1738     cbMinorTicksColumn->setColumn(column, m_axis->minorTicksColumnPath());
1739 }
1740 void AxisDock::axisMinorTicksLengthChanged(qreal length) {
1741     CONDITIONAL_LOCK_RETURN;
1742     ui.sbMinorTicksLength->setValue(Worksheet::convertFromSceneUnits(length, Worksheet::Unit::Point));
1743 }
1744 
1745 // labels
1746 void AxisDock::axisLabelsFormatChanged(Axis::LabelsFormat format) {
1747     CONDITIONAL_LOCK_RETURN;
1748     ui.cbLabelsFormat->setCurrentIndex(Axis::labelsFormatToIndex(format));
1749 }
1750 void AxisDock::axisLabelsFormatAutoChanged(bool automatic) {
1751     CONDITIONAL_LOCK_RETURN;
1752     ui.chkLabelsFormatAuto->setChecked(automatic);
1753 }
1754 void AxisDock::axisLabelsAutoPrecisionChanged(bool on) {
1755     CONDITIONAL_LOCK_RETURN;
1756     ui.chkLabelsAutoPrecision->setChecked(on);
1757 }
1758 void AxisDock::axisLabelsPrecisionChanged(int precision) {
1759     CONDITIONAL_LOCK_RETURN;
1760     ui.sbLabelsPrecision->setValue(precision);
1761 }
1762 void AxisDock::axisLabelsDateTimeFormatChanged(const QString& format) {
1763     CONDITIONAL_LOCK_RETURN;
1764     ui.cbLabelsDateTimeFormat->setCurrentText(format);
1765 }
1766 void AxisDock::axisLabelsPositionChanged(Axis::LabelsPosition position) {
1767     CONDITIONAL_LOCK_RETURN;
1768     ui.cbLabelsPosition->setCurrentIndex(static_cast<int>(position));
1769 }
1770 void AxisDock::axisLabelsOffsetChanged(double offset) {
1771     CONDITIONAL_LOCK_RETURN;
1772     ui.sbLabelsOffset->setValue(Worksheet::convertFromSceneUnits(offset, Worksheet::Unit::Point));
1773 }
1774 void AxisDock::axisLabelsRotationAngleChanged(qreal rotation) {
1775     CONDITIONAL_LOCK_RETURN;
1776     ui.sbLabelsRotation->setValue(rotation);
1777 }
1778 void AxisDock::axisLabelsTextTypeChanged(Axis::LabelsTextType type) {
1779     CONDITIONAL_LOCK_RETURN;
1780     const int index = ui.cbLabelsTextType->findData((int)type);
1781     ui.cbLabelsTextType->setCurrentIndex(index);
1782 }
1783 void AxisDock::axisLabelsTextColumnChanged(const AbstractColumn* column) {
1784     CONDITIONAL_LOCK_RETURN;
1785     cbLabelsTextColumn->setColumn(column, m_axis->labelsTextColumnPath());
1786 }
1787 void AxisDock::axisLabelsFontChanged(const QFont& font) {
1788     CONDITIONAL_LOCK_RETURN;
1789     // we need to set the font size in points for KFontRequester
1790     QFont newFont(font);
1791     newFont.setPointSizeF(round(Worksheet::convertFromSceneUnits(font.pixelSize(), Worksheet::Unit::Point)));
1792     ui.kfrLabelsFont->setFont(newFont);
1793 }
1794 void AxisDock::axisLabelsFontColorChanged(const QColor& color) {
1795     CONDITIONAL_LOCK_RETURN;
1796     updateAxisColor();
1797     ui.kcbLabelsFontColor->setColor(color);
1798 }
1799 void AxisDock::axisLabelsBackgroundTypeChanged(Axis::LabelsBackgroundType type) {
1800     CONDITIONAL_LOCK_RETURN;
1801     ui.cbLabelsBackgroundType->setCurrentIndex(static_cast<int>(type));
1802 }
1803 void AxisDock::axisLabelsBackgroundColorChanged(const QColor& color) {
1804     CONDITIONAL_LOCK_RETURN;
1805     ui.kcbLabelsBackgroundColor->setColor(color);
1806 }
1807 void AxisDock::axisLabelsPrefixChanged(const QString& prefix) {
1808     CONDITIONAL_LOCK_RETURN;
1809     ui.leLabelsPrefix->setText(prefix);
1810 }
1811 void AxisDock::axisLabelsSuffixChanged(const QString& suffix) {
1812     CONDITIONAL_LOCK_RETURN;
1813     ui.leLabelsSuffix->setText(suffix);
1814 }
1815 void AxisDock::axisLabelsOpacityChanged(qreal opacity) {
1816     CONDITIONAL_LOCK_RETURN;
1817     ui.sbLabelsOpacity->setValue(round(opacity * 100.0));
1818 }
1819 
1820 void AxisDock::updateMajorTicksStartType(bool visible) {
1821     const bool absoluteValue = (ui.cbMajorTicksStartType->currentIndex() == 0);
1822     const bool numeric = m_axis->isNumeric();
1823 
1824     ui.lMajorTickStartOffset->setVisible(visible && !absoluteValue); // for datetime and numeric
1825     ui.sbMajorTickStartOffset->setVisible(visible && !absoluteValue && numeric);
1826     dtsbMajorTicksDateTimeStartOffset->setVisible(visible && !absoluteValue && !numeric);
1827     ui.tbFirstTickData->setVisible(visible && !absoluteValue);
1828     ui.tbFirstTickAuto->setVisible(visible && !absoluteValue);
1829 
1830     ui.sbMajorTickStartValue->setVisible(visible && absoluteValue && numeric);
1831     ui.lMajorTickStartValue->setVisible(visible && absoluteValue && numeric);
1832     ui.lMajorTickStartDateTime->setVisible(visible && absoluteValue && !numeric);
1833     ui.sbMajorTickStartDateTime->setVisible(visible && absoluteValue && !numeric);
1834 }
1835 
1836 void AxisDock::axisVisibilityChanged(bool on) {
1837     CONDITIONAL_LOCK_RETURN;
1838     ui.chkVisible->setChecked(on);
1839 }
1840 
1841 //*************************************************************
1842 //************************* Settings **************************
1843 //*************************************************************
1844 void AxisDock::load() {
1845     // General
1846     ui.chkVisible->setChecked(m_axis->isVisible());
1847 
1848     updateAxisColor();
1849 
1850     Axis::Orientation orientation = m_axis->orientation();
1851     ui.cbOrientation->setCurrentIndex(static_cast<int>(orientation));
1852 
1853     const auto* plot = static_cast<const CartesianPlot*>(m_axis->parentAspect());
1854     const auto* cSystem = plot->coordinateSystem(m_axis->coordinateSystemIndex());
1855     const int xIndex{cSystem->index(Dimension::X)}, yIndex{cSystem->index(Dimension::Y)};
1856 
1857     Range<double> logicalRange(0, 0);
1858     if (orientation == Axis::Orientation::Horizontal)
1859         logicalRange = plot->range(Dimension::Y, yIndex);
1860     else
1861         logicalRange = plot->range(Dimension::X, xIndex);
1862     updatePositionText(orientation);
1863 
1864     int index{static_cast<int>(m_axis->position())};
1865     bool logical = false;
1866     switch (index) {
1867     case static_cast<int>(Axis::Position::Top):
1868     case static_cast<int>(Axis::Position::Left):
1869         ui.cbPosition->setCurrentIndex(Top_Left);
1870         break;
1871     case static_cast<int>(Axis::Position::Bottom):
1872     case static_cast<int>(Axis::Position::Right):
1873         ui.cbPosition->setCurrentIndex(Bottom_Right);
1874         break;
1875     case static_cast<int>(Axis::Position::Centered):
1876         ui.cbPosition->setCurrentIndex(Center);
1877         break;
1878     case static_cast<int>(Axis::Position::Logical):
1879         ui.cbPosition->setCurrentIndex(Logical);
1880         logical = true;
1881     }
1882 
1883     ui.sbPositionLogical->setVisible(logical);
1884     ui.sbPosition->setVisible(!logical);
1885 
1886     ui.sbPosition->setValue(Worksheet::convertFromSceneUnits(m_axis->offset(), m_worksheetUnit));
1887 
1888     spinBoxCalculateMinMax(ui.sbPositionLogical, logicalRange, m_axis->logicalPosition());
1889     ui.sbPositionLogical->setValue(m_axis->logicalPosition());
1890 
1891     updateScale();
1892     const bool rangeScale = m_axis->rangeScale();
1893     ui.cbRangeScale->setChecked(rangeScale);
1894     ui.cbScale->setCurrentIndex(static_cast<int>(m_axis->scale()));
1895     // Changing the scale in the axis for the ticks is deprecated
1896     // So show the options only if rangeScale is not turned on.
1897     // So the user is once able to enable it and then the dialog
1898     // disappears
1899     ui.cbRangeScale->setVisible(!rangeScale);
1900     ui.cbScale->setVisible(!rangeScale);
1901     ui.lScale->setVisible(!rangeScale);
1902 
1903     ui.cbRangeType->setCurrentIndex(static_cast<int>(m_axis->rangeType()));
1904     ui.sbStart->setValue(m_axis->range().start());
1905     ui.sbEnd->setValue(m_axis->range().end());
1906 
1907     // depending on the range format of the axis (numeric vs. datetime), show/hide the corresponding widgets
1908     const bool numeric = m_axis->isNumeric();
1909 
1910     updateLabelsPosition(m_axis->labelsPosition());
1911 
1912     // ranges
1913     ui.lStart->setVisible(numeric);
1914     ui.lEnd->setVisible(numeric);
1915     ui.sbStart->setVisible(numeric);
1916     ui.sbEnd->setVisible(numeric);
1917     ui.lStartDateTime->setVisible(!numeric);
1918     ui.dateTimeEditStart->setVisible(!numeric);
1919     ui.lEndDateTime->setVisible(!numeric);
1920     ui.dateTimeEditEnd->setVisible(!numeric);
1921 
1922     // tick labels format
1923     ui.lLabelsFormat->setVisible(numeric);
1924     ui.chkLabelsFormatAuto->setVisible(numeric);
1925     ui.cbLabelsFormat->setVisible(numeric);
1926     ui.chkLabelsAutoPrecision->setVisible(numeric);
1927     ui.lLabelsPrecision->setVisible(numeric);
1928     ui.sbLabelsPrecision->setVisible(numeric);
1929     ui.lLabelsDateTimeFormat->setVisible(!numeric);
1930     ui.cbLabelsDateTimeFormat->setVisible(!numeric);
1931 
1932     if (!numeric) {
1933         if (m_axis->orientation() == Axis::Orientation::Horizontal) {
1934             ui.dateTimeEditStart->setDisplayFormat(plot->rangeDateTimeFormat(Dimension::X, xIndex));
1935             ui.dateTimeEditEnd->setDisplayFormat(plot->rangeDateTimeFormat(Dimension::X, xIndex));
1936         } else {
1937             // TODO
1938             ui.dateTimeEditStart->setDisplayFormat(plot->rangeDateTimeFormat(Dimension::Y));
1939             ui.dateTimeEditEnd->setDisplayFormat(plot->rangeDateTimeFormat(Dimension::Y));
1940         }
1941         ui.dateTimeEditStart->setMSecsSinceEpochUTC(m_axis->range().start());
1942         ui.dateTimeEditEnd->setMSecsSinceEpochUTC(m_axis->range().end());
1943     }
1944 
1945     ui.sbZeroOffset->setValue(m_axis->zeroOffset());
1946     ui.sbScalingFactor->setValue(m_axis->scalingFactor());
1947     ui.chkShowScaleOffset->setChecked(m_axis->showScaleOffset());
1948 
1949     // Line
1950     ui.cbArrowType->setCurrentIndex((int)m_axis->arrowType());
1951     ui.cbArrowPosition->setCurrentIndex((int)m_axis->arrowPosition());
1952     ui.sbArrowSize->setValue((int)Worksheet::convertFromSceneUnits(m_axis->arrowSize(), Worksheet::Unit::Point));
1953     updateArrowLineColor(m_axis->line()->color());
1954 
1955     // Major ticks
1956     ui.cbMajorTicksDirection->setCurrentIndex((int)m_axis->majorTicksDirection());
1957     ui.cbMajorTicksType->setCurrentIndex(ui.cbMajorTicksType->findData((int)m_axis->majorTicksType()));
1958     ui.cbMajorTicksAutoNumber->setChecked(m_axis->majorTicksAutoNumber());
1959     ui.sbMajorTicksNumber->setEnabled(!m_axis->majorTicksAutoNumber());
1960 
1961     ui.sbMajorTicksNumber->setValue(m_axis->majorTicksNumber());
1962     auto value{m_axis->majorTicksSpacing()};
1963     if (numeric) {
1964         ui.sbMajorTicksSpacingNumeric->setDecimals(nsl_math_decimal_places(value) + 1);
1965         ui.sbMajorTicksSpacingNumeric->setValue(value);
1966         ui.sbMajorTicksSpacingNumeric->setSingleStep(value / 10.);
1967     } else
1968         dtsbMajorTicksIncrement->setValue(value);
1969     ui.cbMajorTicksStartType->setCurrentIndex(static_cast<int>(m_axis->majorTicksStartType()));
1970     ui.sbMajorTickStartOffset->setValue(m_axis->majorTickStartOffset());
1971     dtsbMajorTicksDateTimeStartOffset->setValue(m_axis->majorTickStartOffset());
1972     ui.sbMajorTickStartValue->setValue(m_axis->majorTickStartValue());
1973     ui.sbMajorTickStartDateTime->setMSecsSinceEpochUTC(m_axis->majorTickStartValue());
1974     ui.sbMajorTicksLength->setValue(Worksheet::convertFromSceneUnits(m_axis->majorTicksLength(), Worksheet::Unit::Point));
1975 
1976     // Minor ticks
1977     ui.cbMinorTicksDirection->setCurrentIndex((int)m_axis->minorTicksDirection());
1978     ui.cbMinorTicksType->setCurrentIndex((int)m_axis->minorTicksType());
1979     ui.cbMinorTicksAutoNumber->setChecked(m_axis->minorTicksAutoNumber());
1980     ui.sbMinorTicksNumber->setEnabled(!m_axis->minorTicksAutoNumber());
1981     ui.sbMinorTicksNumber->setValue(m_axis->minorTicksNumber());
1982     ui.sbMinorTicksLength->setValue(Worksheet::convertFromSceneUnits(m_axis->minorTicksLength(), Worksheet::Unit::Point));
1983 
1984     // Extra ticks
1985     // TODO
1986 
1987     // Tick label
1988     ui.cbLabelsPosition->setCurrentIndex((int)m_axis->labelsPosition());
1989     ui.sbLabelsOffset->setValue(Worksheet::convertFromSceneUnits(m_axis->labelsOffset(), Worksheet::Unit::Point));
1990     ui.sbLabelsRotation->setValue(m_axis->labelsRotationAngle());
1991     const int idx = ui.cbLabelsTextType->findData((int)m_axis->labelsTextType());
1992     ui.cbLabelsTextType->setCurrentIndex(idx);
1993     ui.cbLabelsFormat->setCurrentIndex(Axis::labelsFormatToIndex(m_axis->labelsFormat()));
1994     ui.cbLabelsFormat->setEnabled(!m_axis->labelsFormatAuto());
1995     ui.chkLabelsFormatAuto->setChecked(m_axis->labelsFormatAuto());
1996     ui.chkLabelsAutoPrecision->setChecked((int)m_axis->labelsAutoPrecision());
1997     ui.sbLabelsPrecision->setValue((int)m_axis->labelsPrecision());
1998     ui.cbLabelsDateTimeFormat->setCurrentText(m_axis->labelsDateTimeFormat());
1999 
2000     // we need to set the font size in points for KFontRequester
2001     QFont font = m_axis->labelsFont();
2002     font.setPointSizeF(round(Worksheet::convertFromSceneUnits(font.pixelSize(), Worksheet::Unit::Point)));
2003     ui.kfrLabelsFont->setFont(font);
2004     ui.kcbLabelsFontColor->setColor(m_axis->labelsColor());
2005     ui.cbLabelsBackgroundType->setCurrentIndex((int)m_axis->labelsBackgroundType());
2006     ui.kcbLabelsBackgroundColor->setColor(m_axis->labelsBackgroundColor());
2007     ui.leLabelsPrefix->setText(m_axis->labelsPrefix());
2008     ui.leLabelsSuffix->setText(m_axis->labelsSuffix());
2009     ui.sbLabelsOpacity->setValue(round(m_axis->labelsOpacity() * 100.0));
2010 
2011     majorTicksDirectionChanged(ui.cbMajorTicksDirection->currentIndex());
2012     majorTicksTypeChanged(ui.cbMajorTicksType->currentIndex());
2013     minorTicksTypeChanged(ui.cbMinorTicksType->currentIndex());
2014     labelsTextTypeChanged(ui.cbLabelsTextType->currentIndex());
2015     labelsTextColumnChanged(cbLabelsTextColumn->currentModelIndex());
2016 }
2017 
2018 void AxisDock::setAxisColor() {
2019     CONDITIONAL_LOCK_RETURN;
2020     updateAxisColor();
2021 }
2022 
2023 void AxisDock::updateAxisColor() {
2024     // Set color of the global
2025     // - Line widget color
2026     // - Title color
2027     // - Major tick color
2028     // - Minor tick color
2029     // - Tick label color
2030     QColor color = m_axis->line()->color();
2031     if (m_axis->title()->fontColor() == color && m_axis->majorTicksLine()->color() == color && m_axis->minorTicksLine()->color() == color
2032         && m_axis->labelsColor() == color) {
2033         // All have same color
2034         ui.kcbAxisColor->setColor(color);
2035     } else
2036         ui.kcbAxisColor->setColor(QColor(0, 0, 0, 0));
2037 }
2038 
2039 void AxisDock::loadConfigFromTemplate(KConfig& config) {
2040     auto name = TemplateHandler::templateName(config);
2041     int size = m_axesList.size();
2042     if (size > 1)
2043         m_axis->beginMacro(i18n("%1 axes: template \"%2\" loaded", size, name));
2044     else
2045         m_axis->beginMacro(i18n("%1: template \"%2\" loaded", m_axis->name(), name));
2046 
2047     this->loadConfig(config);
2048 
2049     m_axis->endMacro();
2050 }
2051 
2052 void AxisDock::loadConfig(KConfig& config) {
2053     KConfigGroup group = config.group(QStringLiteral("Axis"));
2054 
2055     // General
2056     ui.cbOrientation->setCurrentIndex(group.readEntry(QStringLiteral("Orientation"), (int)m_axis->orientation()));
2057 
2058     int index = group.readEntry(QStringLiteral("Position"), (int)m_axis->position());
2059     if (index > 1)
2060         ui.cbPosition->setCurrentIndex(index - 2);
2061     else
2062         ui.cbPosition->setCurrentIndex(index);
2063 
2064     ui.sbPositionLogical->setValue(group.readEntry(QStringLiteral("LogicalPosition"), m_axis->logicalPosition()));
2065     ui.sbPosition->setValue(Worksheet::convertFromSceneUnits(group.readEntry(QStringLiteral("PositionOffset"), m_axis->offset()), m_worksheetUnit));
2066     ui.cbScale->setCurrentIndex(group.readEntry(QStringLiteral("Scale"), static_cast<int>(m_axis->scale())));
2067     ui.cbRangeType->setCurrentIndex(group.readEntry(QStringLiteral("RangeType"), static_cast<int>(m_axis->rangeType())));
2068     ui.sbStart->setValue(group.readEntry(QStringLiteral("Start"), m_axis->range().start()));
2069     ui.sbEnd->setValue(group.readEntry(QStringLiteral("End"), m_axis->range().end()));
2070     ui.sbZeroOffset->setValue(group.readEntry(QStringLiteral("ZeroOffset"), m_axis->zeroOffset()));
2071     ui.sbScalingFactor->setValue(group.readEntry(QStringLiteral("ScalingFactor"), m_axis->scalingFactor()));
2072     ui.chkShowScaleOffset->setChecked(group.readEntry(QStringLiteral("ShowScaleOffset"), static_cast<int>(m_axis->showScaleOffset())));
2073 
2074     // Title
2075     KConfigGroup axisLabelGroup = config.group(QStringLiteral("AxisLabel"));
2076     labelWidget->loadConfig(axisLabelGroup);
2077 
2078     // Line
2079     lineWidget->loadConfig(group);
2080     ui.cbArrowType->setCurrentIndex(group.readEntry(QStringLiteral("ArrowType"), (int)m_axis->arrowType()));
2081     ui.cbArrowPosition->setCurrentIndex(group.readEntry(QStringLiteral("ArrowPosition"), (int)m_axis->arrowPosition()));
2082     ui.sbArrowSize->setValue(Worksheet::convertFromSceneUnits(group.readEntry(QStringLiteral("ArrowSize"), m_axis->arrowSize()), Worksheet::Unit::Point));
2083     updateArrowLineColor(m_axis->line()->color());
2084 
2085     // Major ticks
2086     ui.cbMajorTicksDirection->setCurrentIndex(group.readEntry(QStringLiteral("MajorTicksDirection"), (int)m_axis->majorTicksDirection()));
2087     ui.cbMajorTicksType->setCurrentIndex(ui.cbMajorTicksType->findData(group.readEntry(QStringLiteral("MajorTicksType"), (int)m_axis->majorTicksType())));
2088     ui.sbMajorTicksNumber->setValue(group.readEntry(QStringLiteral("MajorTicksNumber"), m_axis->majorTicksNumber()));
2089     auto value{group.readEntry(QStringLiteral("MajorTicksIncrement"), m_axis->majorTicksSpacing())};
2090     bool numeric = m_axis->isNumeric();
2091     if (numeric) {
2092         ui.sbMajorTicksSpacingNumeric->setDecimals(nsl_math_decimal_places(value) + 1);
2093         ui.sbMajorTicksSpacingNumeric->setValue(value);
2094         ui.sbMajorTicksSpacingNumeric->setSingleStep(value / 10.);
2095     } else
2096         dtsbMajorTicksIncrement->setValue(value);
2097     ui.cbMajorTicksStartType->setCurrentIndex(group.readEntry(QStringLiteral("MajorTicksStartType"), (int)m_axis->majorTicksStartType()));
2098     const auto majorTickStartOffset = group.readEntry(QStringLiteral("MajorTickStartOffset"), m_axis->majorTickStartOffset());
2099     ui.sbMajorTickStartOffset->setValue(majorTickStartOffset);
2100     dtsbMajorTicksDateTimeStartOffset->setValue(majorTickStartOffset);
2101     const auto majorTickStartValue = group.readEntry(QStringLiteral("MajorTickStartValue"), m_axis->majorTickStartValue());
2102     ui.sbMajorTickStartValue->setValue(majorTickStartValue);
2103     ui.sbMajorTickStartDateTime->setMSecsSinceEpochUTC(majorTickStartValue);
2104     ui.sbMajorTicksLength->setValue(
2105         Worksheet::convertFromSceneUnits(group.readEntry(QStringLiteral("MajorTicksLength"), m_axis->majorTicksLength()), Worksheet::Unit::Point));
2106     majorTicksLineWidget->loadConfig(group);
2107 
2108     // Minor ticks
2109     ui.cbMinorTicksDirection->setCurrentIndex(group.readEntry(QStringLiteral("MinorTicksDirection"), (int)m_axis->minorTicksDirection()));
2110     ui.cbMinorTicksType->setCurrentIndex(group.readEntry(QStringLiteral("MinorTicksType"), (int)m_axis->minorTicksType()));
2111     ui.sbMinorTicksNumber->setValue(group.readEntry(QStringLiteral("MinorTicksNumber"), m_axis->minorTicksNumber()));
2112     value = group.readEntry(QStringLiteral("MinorTicksIncrement"), m_axis->minorTicksSpacing());
2113     if (numeric)
2114         ui.sbMinorTicksSpacingNumeric->setValue(value);
2115     else
2116         dtsbMinorTicksIncrement->setValue(value);
2117     ui.sbMinorTicksLength->setValue(Worksheet::convertFromSceneUnits(group.readEntry("MinorTicksLength", m_axis->minorTicksLength()), Worksheet::Unit::Point));
2118     minorTicksLineWidget->loadConfig(group);
2119 
2120     // Extra ticks
2121     // TODO
2122 
2123     // Tick label
2124     ui.cbLabelsFormat->setCurrentIndex(
2125         Axis::labelsFormatToIndex((Axis::LabelsFormat)(group.readEntry(QStringLiteral("LabelsFormat"), Axis::labelsFormatToIndex(m_axis->labelsFormat())))));
2126     ui.chkLabelsAutoPrecision->setChecked(group.readEntry(QStringLiteral("LabelsAutoPrecision"), (int)m_axis->labelsAutoPrecision()));
2127     ui.sbLabelsPrecision->setValue(group.readEntry(QStringLiteral("LabelsPrecision"), (int)m_axis->labelsPrecision()));
2128     ui.cbLabelsDateTimeFormat->setCurrentText(group.readEntry(QStringLiteral("LabelsDateTimeFormat"), QStringLiteral("yyyy-MM-dd hh:mm:ss")));
2129     ui.cbLabelsPosition->setCurrentIndex(group.readEntry(QStringLiteral("LabelsPosition"), (int)m_axis->labelsPosition()));
2130     ui.sbLabelsOffset->setValue(
2131         Worksheet::convertFromSceneUnits(group.readEntry(QStringLiteral("LabelsOffset"), m_axis->labelsOffset()), Worksheet::Unit::Point));
2132     ui.sbLabelsRotation->setValue(group.readEntry(QStringLiteral("LabelsRotation"), m_axis->labelsRotationAngle()));
2133     ui.cbLabelsTextType->setCurrentIndex(group.readEntry(QStringLiteral("LabelsTextType"), (int)m_axis->labelsTextType()));
2134 
2135     // we need to set the font size in points for KFontRequester
2136     QFont font = m_axis->labelsFont();
2137     font.setPointSizeF(round(Worksheet::convertFromSceneUnits(font.pixelSize(), Worksheet::Unit::Point)));
2138     ui.kfrLabelsFont->setFont(group.readEntry(QStringLiteral("LabelsFont"), font));
2139 
2140     ui.kcbLabelsFontColor->setColor(group.readEntry(QStringLiteral("LabelsFontColor"), m_axis->labelsColor()));
2141     ui.cbLabelsBackgroundType->setCurrentIndex(group.readEntry(QStringLiteral("LabelsBackgroundType"), (int)m_axis->labelsBackgroundType()));
2142     ui.kcbLabelsBackgroundColor->setColor(group.readEntry(QStringLiteral("LabelsBackgroundColor"), m_axis->labelsBackgroundColor()));
2143     ui.leLabelsPrefix->setText(group.readEntry(QStringLiteral("LabelsPrefix"), m_axis->labelsPrefix()));
2144     ui.leLabelsSuffix->setText(group.readEntry(QStringLiteral("LabelsSuffix"), m_axis->labelsSuffix()));
2145     ui.sbLabelsOpacity->setValue(round(group.readEntry(QStringLiteral("LabelsOpacity"), m_axis->labelsOpacity()) * 100.0));
2146 
2147     // Grid
2148     majorGridLineWidget->loadConfig(group);
2149     minorGridLineWidget->loadConfig(group);
2150 
2151     CONDITIONAL_LOCK_RETURN;
2152     this->majorTicksTypeChanged(ui.cbMajorTicksType->currentIndex());
2153     this->minorTicksTypeChanged(ui.cbMinorTicksType->currentIndex());
2154 }
2155 
2156 void AxisDock::saveConfigAsTemplate(KConfig& config) {
2157     KConfigGroup group = config.group(QStringLiteral("Axis"));
2158 
2159     // General
2160     group.writeEntry(QStringLiteral("Orientation"), ui.cbOrientation->currentIndex());
2161 
2162     if (ui.cbPosition->currentIndex() == 2) {
2163         group.writeEntry(QStringLiteral("Position"), static_cast<int>(Axis::Position::Centered));
2164     } else if (ui.cbPosition->currentIndex() == 3) {
2165         group.writeEntry(QStringLiteral("Position"), static_cast<int>(Axis::Position::Centered));
2166     } else {
2167         if (ui.cbOrientation->currentIndex() == static_cast<int>(Axis::Orientation::Horizontal))
2168             group.writeEntry(QStringLiteral("Position"), ui.cbPosition->currentIndex());
2169         else
2170             group.writeEntry(QStringLiteral("Position"), ui.cbPosition->currentIndex() + 2);
2171     }
2172 
2173     group.writeEntry(QStringLiteral("LogicalPosition"), ui.sbPositionLogical->value());
2174     group.writeEntry(QStringLiteral("PositionOffset"), Worksheet::convertToSceneUnits(ui.sbPosition->value(), m_worksheetUnit));
2175     group.writeEntry(QStringLiteral("Scale"), ui.cbScale->currentIndex());
2176     group.writeEntry(QStringLiteral("RangeType"), ui.cbRangeType->currentIndex());
2177     group.writeEntry(QStringLiteral("Start"), ui.sbStart->value());
2178     group.writeEntry(QStringLiteral("End"), ui.sbEnd->value());
2179     group.writeEntry(QStringLiteral("ZeroOffset"), ui.sbZeroOffset->value());
2180     group.writeEntry(QStringLiteral("ScalingFactor"), ui.sbScalingFactor->value());
2181     group.writeEntry(QStringLiteral("ShowScaleOffset"), ui.chkShowScaleOffset->isChecked());
2182 
2183     // Title
2184     KConfigGroup axisLabelGroup = config.group(QStringLiteral("AxisLabel"));
2185     labelWidget->saveConfig(axisLabelGroup);
2186 
2187     // Line
2188     lineWidget->saveConfig(group);
2189 
2190     // Major ticks
2191     group.writeEntry(QStringLiteral("MajorTicksDirection"), ui.cbMajorTicksDirection->currentIndex());
2192     group.writeEntry(QStringLiteral("MajorTicksType"), ui.cbMajorTicksType->itemData(ui.cbMajorTicksType->currentIndex()));
2193     group.writeEntry(QStringLiteral("MajorTicksNumber"), ui.sbMajorTicksNumber->value());
2194     bool numeric = m_axis->isNumeric();
2195     if (numeric)
2196         group.writeEntry(QStringLiteral("MajorTicksIncrement"), QString::number(ui.sbMajorTicksSpacingNumeric->value()));
2197     else
2198         group.writeEntry(QStringLiteral("MajorTicksIncrement"), QString::number(dtsbMajorTicksIncrement->value()));
2199     group.writeEntry(QStringLiteral("MajorTicksStartType"), ui.cbMajorTicksStartType->currentIndex());
2200     if (numeric) {
2201         group.writeEntry(QStringLiteral("MajorTickStartOffset"), ui.sbMajorTickStartOffset->value());
2202         group.writeEntry(QStringLiteral("MajorTickStartValue"), ui.sbMajorTickStartValue->value());
2203     } else {
2204         group.writeEntry(QStringLiteral("MajorTickStartOffset"), dtsbMajorTicksDateTimeStartOffset->value());
2205         group.writeEntry(QStringLiteral("MajorTickStartValue"), ui.sbMajorTickStartDateTime->dateTime().toMSecsSinceEpoch());
2206     }
2207     group.writeEntry(QStringLiteral("MajorTicksLength"), Worksheet::convertToSceneUnits(ui.sbMajorTicksLength->value(), Worksheet::Unit::Point));
2208     majorTicksLineWidget->saveConfig(group);
2209 
2210     // Minor ticks
2211     group.writeEntry(QStringLiteral("MinorTicksDirection"), ui.cbMinorTicksDirection->currentIndex());
2212     group.writeEntry(QStringLiteral("MinorTicksType"), ui.cbMinorTicksType->currentIndex());
2213     group.writeEntry(QStringLiteral("MinorTicksNumber"), ui.sbMinorTicksNumber->value());
2214     if (numeric)
2215         group.writeEntry(QStringLiteral("MinorTicksIncrement"), QString::number(ui.sbMinorTicksSpacingNumeric->value()));
2216     else
2217         group.writeEntry(QStringLiteral("MinorTicksIncrement"), QString::number(dtsbMinorTicksIncrement->value()));
2218     group.writeEntry(QStringLiteral("MinorTicksLength"), Worksheet::convertFromSceneUnits(ui.sbMinorTicksLength->value(), Worksheet::Unit::Point));
2219     minorTicksLineWidget->saveConfig(group);
2220 
2221     // Extra ticks
2222     //  TODO
2223 
2224     // Tick label
2225     group.writeEntry(QStringLiteral("LabelsFormat"), static_cast<int>(Axis::indexToLabelsFormat(ui.cbLabelsFormat->currentIndex())));
2226     group.writeEntry(QStringLiteral("LabelsAutoPrecision"), ui.chkLabelsAutoPrecision->isChecked());
2227     group.writeEntry(QStringLiteral("LabelsPrecision"), ui.sbLabelsPrecision->value());
2228     group.writeEntry(QStringLiteral("LabelsPosition"), ui.cbLabelsPosition->currentIndex());
2229     group.writeEntry(QStringLiteral("LabelsOffset"), Worksheet::convertToSceneUnits(ui.sbLabelsOffset->value(), Worksheet::Unit::Point));
2230     group.writeEntry(QStringLiteral("LabelsRotation"), ui.sbLabelsRotation->value());
2231     group.writeEntry(QStringLiteral("LabelsFont"), ui.kfrLabelsFont->font());
2232     group.writeEntry(QStringLiteral("LabelsFontColor"), ui.kcbLabelsFontColor->color());
2233     group.writeEntry(QStringLiteral("LabelsBackgroundType"), ui.cbLabelsBackgroundType->currentIndex());
2234     group.writeEntry(QStringLiteral("LabelsBackgroundColor"), ui.kcbLabelsBackgroundColor->color());
2235     group.writeEntry(QStringLiteral("LabelsPrefix"), ui.leLabelsPrefix->text());
2236     group.writeEntry(QStringLiteral("LabelsSuffix"), ui.leLabelsSuffix->text());
2237     group.writeEntry(QStringLiteral("LabelsOpacity"), ui.sbLabelsOpacity->value() / 100.);
2238 
2239     // Grid
2240     majorGridLineWidget->saveConfig(group);
2241     minorGridLineWidget->saveConfig(group);
2242 
2243     config.sync();
2244 }