File indexing completed on 2024-10-06 06:35:02

0001 /*
0002     File                 : AxisTest3.cpp
0003     Project              : LabPlot
0004     Description          : Second tests for Axis
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2022 Martin Marmsoler <martin.marmsoler@gmail.com>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "AxisTest3.h"
0012 #include "backend/core/Project.h"
0013 #include "backend/spreadsheet/Spreadsheet.h"
0014 #include "backend/worksheet/Worksheet.h"
0015 #include "backend/worksheet/plots/cartesian/CartesianPlot.h"
0016 #include "src/backend/core/Time.h"
0017 #include "src/backend/worksheet/Line.h"
0018 #include "src/backend/worksheet/TextLabel.h"
0019 #include "src/backend/worksheet/WorksheetElement.h"
0020 #include "src/backend/worksheet/plots/cartesian/Axis.h" // already included in CartesianPlot
0021 #include "src/backend/worksheet/plots/cartesian/AxisPrivate.h"
0022 #include "src/kdefrontend/dockwidgets/AxisDock.h" // access ui elements
0023 #include "src/kdefrontend/widgets/LabelWidget.h"
0024 #include "src/kdefrontend/widgets/LineWidget.h"
0025 
0026 #include <QUndoStack>
0027 
0028 void AxisTest3::dateTime() {
0029     QLocale::setDefault(QLocale::C); // . as decimal separator
0030     Project project;
0031     auto* ws = new Worksheet(QStringLiteral("worksheet"));
0032     QVERIFY(ws != nullptr);
0033     project.addChild(ws);
0034 
0035     Spreadsheet* spreadsheetData = new Spreadsheet(QStringLiteral("data"), false);
0036     spreadsheetData->setColumnCount(2);
0037     spreadsheetData->setRowCount(3);
0038     project.addChild(spreadsheetData);
0039 
0040     auto* xCol = spreadsheetData->column(0);
0041     xCol->setColumnMode(AbstractColumn::ColumnMode::DateTime);
0042     QDateTime dt1 = QDateTime::fromString(QStringLiteral("2017-07-24T00:00:00Z"), Qt::ISODate);
0043     QDateTime dt2 = QDateTime::fromString(QStringLiteral("2017-08-24T00:00:00Z"), Qt::ISODate);
0044     QDateTime dt3 = QDateTime::fromString(QStringLiteral("2017-09-24T00:00:00Z"), Qt::ISODate);
0045     xCol->replaceDateTimes(-1, QVector<QDateTime>({dt1, dt2, dt3}));
0046 
0047     auto* yCol = spreadsheetData->column(1);
0048     yCol->replaceValues(-1, QVector<double>({2., 3., 4.}));
0049 
0050     QCOMPARE(spreadsheetData->rowCount(), 3);
0051     QCOMPARE(spreadsheetData->columnCount(), 2);
0052 
0053     auto* p = new CartesianPlot(QStringLiteral("plot"));
0054     p->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created
0055     p->setNiceExtend(false);
0056     QVERIFY(p != nullptr);
0057     ws->addChild(p);
0058 
0059     auto* curve = new XYCurve(QStringLiteral("xy-curve"));
0060     curve->setXColumn(xCol);
0061     curve->setYColumn(yCol);
0062     p->addChild(curve);
0063 
0064     auto axes = p->children<Axis>();
0065     QCOMPARE(axes.count(), 2);
0066     QCOMPARE(axes.at(0)->name(), QStringLiteral("x"));
0067     QCOMPARE(axes.at(1)->name(), QStringLiteral("y"));
0068 
0069     auto* xAxis = static_cast<Axis*>(axes.at(0));
0070     xAxis->setMajorTicksNumber(3, false);
0071     QCOMPARE(xAxis->range().start(), dt1.toMSecsSinceEpoch());
0072     QCOMPARE(xAxis->range().end(), dt3.toMSecsSinceEpoch());
0073     QCOMPARE(xAxis->majorTicksType(), Axis::TicksType::TotalNumber);
0074     QCOMPARE(xAxis->majorTicksNumber(), 3);
0075     xAxis->setLabelsDateTimeFormat(QStringLiteral("yyyy-MM-dd hh:mm:ss"));
0076     QCOMPARE(xAxis->labelsTextType(), Axis::LabelsTextType::PositionValues);
0077 
0078     {
0079         const auto v = xAxis->tickLabelStrings();
0080         QStringList expectedStrings{
0081             QStringLiteral("2017-07-24 00:00:00"),
0082             QStringLiteral("2017-08-24 00:00:00"),
0083             QStringLiteral("2017-09-24 00:00:00"),
0084         };
0085         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
0086     }
0087 }
0088 
0089 void AxisTest3::dateTimeSpacing() {
0090     QLocale::setDefault(QLocale::C); // . as decimal separator
0091     Project project;
0092     auto* ws = new Worksheet(QStringLiteral("worksheet"));
0093     QVERIFY(ws != nullptr);
0094     project.addChild(ws);
0095 
0096     Spreadsheet* spreadsheetData = new Spreadsheet(QStringLiteral("data"), false);
0097     spreadsheetData->setColumnCount(2);
0098     spreadsheetData->setRowCount(3);
0099     project.addChild(spreadsheetData);
0100 
0101     auto* xCol = spreadsheetData->column(0);
0102     xCol->setColumnMode(AbstractColumn::ColumnMode::DateTime);
0103     QDateTime dt1 = QDateTime::fromString(QStringLiteral("2017-07-24T00:00:00Z"), Qt::ISODate);
0104     QDateTime dt2 = QDateTime::fromString(QStringLiteral("2017-11-24T12:03:00Z"), Qt::ISODate);
0105     QDateTime dt3 = QDateTime::fromString(QStringLiteral("2017-12-24T00:05:03Z"), Qt::ISODate);
0106     xCol->replaceDateTimes(-1, QVector<QDateTime>({dt1, dt2, dt3}));
0107 
0108     auto* yCol = spreadsheetData->column(1);
0109     yCol->replaceValues(-1, QVector<double>({2., 3., 4.}));
0110 
0111     QCOMPARE(spreadsheetData->rowCount(), 3);
0112     QCOMPARE(spreadsheetData->columnCount(), 2);
0113 
0114     auto* p = new CartesianPlot(QStringLiteral("plot"));
0115     p->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created
0116     p->setNiceExtend(false);
0117     QVERIFY(p != nullptr);
0118     ws->addChild(p);
0119 
0120     auto* curve = new XYCurve(QStringLiteral("xy-curve"));
0121     curve->setXColumn(xCol);
0122     curve->setYColumn(yCol);
0123     p->addChild(curve);
0124 
0125     auto axes = p->children<Axis>();
0126     QCOMPARE(axes.count(), 2);
0127     QCOMPARE(axes.at(0)->name(), QStringLiteral("x"));
0128     QCOMPARE(axes.at(1)->name(), QStringLiteral("y"));
0129 
0130     auto* xAxis = static_cast<Axis*>(axes.at(0));
0131     xAxis->setMajorTicksSpacing(DateTime::createValue(0, 1, 0, 0, 0, 0, 0)); // 1 month
0132     QCOMPARE(xAxis->range().start(), dt1.toMSecsSinceEpoch());
0133     QCOMPARE(xAxis->range().end(), dt3.toMSecsSinceEpoch());
0134     xAxis->setMajorTicksType(Axis::TicksType::Spacing);
0135     // QCOMPARE(xAxis->majorTicksNumber(), 3);
0136     xAxis->setLabelsDateTimeFormat(QStringLiteral("yyyy-MM-dd hh:mm:ss"));
0137     QCOMPARE(xAxis->labelsTextType(), Axis::LabelsTextType::PositionValues);
0138     QCOMPARE(xAxis->majorTicksStartType(), Axis::TicksStartType::Offset);
0139     QCOMPARE(xAxis->majorTickStartOffset(), 0);
0140     QCOMPARE(xAxis->majorTickStartValue(), 0);
0141 
0142     {
0143         const auto v = xAxis->tickLabelStrings();
0144         QStringList expectedStrings{
0145             QStringLiteral("2017-07-24 00:00:00"),
0146             QStringLiteral("2017-08-24 00:00:00"),
0147             QStringLiteral("2017-09-24 00:00:00"),
0148             QStringLiteral("2017-10-24 00:00:00"),
0149             QStringLiteral("2017-11-24 00:00:00"),
0150             QStringLiteral("2017-12-24 00:00:00"),
0151         };
0152         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
0153     }
0154 }
0155 
0156 void AxisTest3::dateTimeSpacingOffsetNonZero() {
0157     QLocale::setDefault(QLocale::C); // . as decimal separator
0158     Project project;
0159     auto* ws = new Worksheet(QStringLiteral("worksheet"));
0160     QVERIFY(ws != nullptr);
0161     project.addChild(ws);
0162 
0163     Spreadsheet* spreadsheetData = new Spreadsheet(QStringLiteral("data"), false);
0164     spreadsheetData->setColumnCount(2);
0165     spreadsheetData->setRowCount(3);
0166     project.addChild(spreadsheetData);
0167 
0168     auto* xCol = spreadsheetData->column(0);
0169     xCol->setColumnMode(AbstractColumn::ColumnMode::DateTime);
0170     QDateTime dt1 = QDateTime::fromString(QStringLiteral("2017-07-24T00:00:00Z"), Qt::ISODate);
0171     QDateTime dt2 = QDateTime::fromString(QStringLiteral("2017-11-24T12:03:00Z"), Qt::ISODate);
0172     QDateTime dt3 = QDateTime::fromString(QStringLiteral("2019-12-24T00:05:03Z"), Qt::ISODate);
0173     xCol->replaceDateTimes(-1, QVector<QDateTime>({dt1, dt2, dt3}));
0174 
0175     auto* yCol = spreadsheetData->column(1);
0176     yCol->replaceValues(-1, QVector<double>({2., 3., 4.}));
0177 
0178     QCOMPARE(spreadsheetData->rowCount(), 3);
0179     QCOMPARE(spreadsheetData->columnCount(), 2);
0180 
0181     auto* p = new CartesianPlot(QStringLiteral("plot"));
0182     p->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created
0183     p->setNiceExtend(false);
0184     QVERIFY(p != nullptr);
0185     ws->addChild(p);
0186 
0187     auto* curve = new XYCurve(QStringLiteral("xy-curve"));
0188     curve->setXColumn(xCol);
0189     curve->setYColumn(yCol);
0190     p->addChild(curve);
0191 
0192     auto axes = p->children<Axis>();
0193     QCOMPARE(axes.count(), 2);
0194     QCOMPARE(axes.at(0)->name(), QStringLiteral("x"));
0195     QCOMPARE(axes.at(1)->name(), QStringLiteral("y"));
0196 
0197     auto* xAxis = static_cast<Axis*>(axes.at(0));
0198     xAxis->setMajorTicksSpacing(DateTime::createValue(0, 1, 0, 0, 0, 0, 0)); // 1 month
0199     QCOMPARE(xAxis->range().start(), dt1.toMSecsSinceEpoch());
0200     QCOMPARE(xAxis->range().end(), dt3.toMSecsSinceEpoch());
0201     xAxis->setMajorTicksType(Axis::TicksType::Spacing);
0202     // QCOMPARE(xAxis->majorTicksNumber(), 3);
0203     xAxis->setLabelsDateTimeFormat(QStringLiteral("yyyy-MM-dd hh:mm:ss"));
0204     QCOMPARE(xAxis->labelsTextType(), Axis::LabelsTextType::PositionValues);
0205     QCOMPARE(xAxis->majorTicksStartType(), Axis::TicksStartType::Offset);
0206     xAxis->setMajorTickStartOffset(DateTime::createValue(1, 2, 3, 4, 5, 6, 7));
0207     QVERIFY(xAxis->majorTickStartOffset() > 0);
0208     QCOMPARE(xAxis->majorTickStartValue(), 0);
0209 
0210     {
0211         const auto v = xAxis->tickLabelStrings();
0212         QStringList expectedStrings{
0213             QStringLiteral("2018-09-27 04:05:06"),
0214             QStringLiteral("2018-10-27 04:05:06"),
0215             QStringLiteral("2018-11-27 04:05:06"),
0216             QStringLiteral("2018-12-27 04:05:06"),
0217             QStringLiteral("2019-01-27 04:05:06"),
0218             QStringLiteral("2019-02-27 04:05:06"),
0219             QStringLiteral("2019-03-27 04:05:06"),
0220             QStringLiteral("2019-04-27 04:05:06"),
0221             QStringLiteral("2019-05-27 04:05:06"),
0222             QStringLiteral("2019-06-27 04:05:06"),
0223             QStringLiteral("2019-07-27 04:05:06"),
0224             QStringLiteral("2019-08-27 04:05:06"),
0225             QStringLiteral("2019-09-27 04:05:06"),
0226             QStringLiteral("2019-10-27 04:05:06"),
0227             QStringLiteral("2019-11-27 04:05:06"),
0228         };
0229         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
0230     }
0231 }
0232 
0233 void AxisTest3::dateTimeSpacingStartValueNonZero() {
0234     QLocale::setDefault(QLocale::C); // . as decimal separator
0235     Project project;
0236     auto* ws = new Worksheet(QStringLiteral("worksheet"));
0237     QVERIFY(ws != nullptr);
0238     project.addChild(ws);
0239 
0240     Spreadsheet* spreadsheetData = new Spreadsheet(QStringLiteral("data"), false);
0241     spreadsheetData->setColumnCount(2);
0242     spreadsheetData->setRowCount(3);
0243     project.addChild(spreadsheetData);
0244 
0245     auto* xCol = spreadsheetData->column(0);
0246     xCol->setColumnMode(AbstractColumn::ColumnMode::DateTime);
0247     QDateTime dt1 = QDateTime::fromString(QStringLiteral("2017-07-24T00:00:00Z"), Qt::ISODate);
0248     QDateTime dt2 = QDateTime::fromString(QStringLiteral("2017-11-24T12:03:00Z"), Qt::ISODate);
0249     QDateTime dt3 = QDateTime::fromString(QStringLiteral("2019-03-01T00:00:00Z"), Qt::ISODate);
0250     xCol->replaceDateTimes(-1, QVector<QDateTime>({dt1, dt2, dt3}));
0251 
0252     auto* yCol = spreadsheetData->column(1);
0253     yCol->replaceValues(-1, QVector<double>({2., 3., 4.}));
0254 
0255     QCOMPARE(spreadsheetData->rowCount(), 3);
0256     QCOMPARE(spreadsheetData->columnCount(), 2);
0257 
0258     auto* p = new CartesianPlot(QStringLiteral("plot"));
0259     p->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created
0260     p->setNiceExtend(false);
0261     QVERIFY(p != nullptr);
0262     ws->addChild(p);
0263 
0264     auto* curve = new XYCurve(QStringLiteral("xy-curve"));
0265     curve->setXColumn(xCol);
0266     curve->setYColumn(yCol);
0267     p->addChild(curve);
0268 
0269     auto axes = p->children<Axis>();
0270     QCOMPARE(axes.count(), 2);
0271     QCOMPARE(axes.at(0)->name(), QStringLiteral("x"));
0272     QCOMPARE(axes.at(1)->name(), QStringLiteral("y"));
0273 
0274     auto* xAxis = static_cast<Axis*>(axes.at(0));
0275     xAxis->setMajorTicksSpacing(DateTime::createValue(0, 1, 0, 0, 0, 0, 0)); // 1 month
0276     QCOMPARE(xAxis->range().start(), dt1.toMSecsSinceEpoch());
0277     QCOMPARE(xAxis->range().end(), dt3.toMSecsSinceEpoch());
0278     xAxis->setMajorTicksType(Axis::TicksType::Spacing);
0279     // QCOMPARE(xAxis->majorTicksNumber(), 3);
0280     xAxis->setLabelsDateTimeFormat(QStringLiteral("yyyy-MM-dd hh:mm:ss"));
0281     QCOMPARE(xAxis->labelsTextType(), Axis::LabelsTextType::PositionValues);
0282     xAxis->setMajorTicksStartType(Axis::TicksStartType::Absolute);
0283     xAxis->setMajorTickStartValue(QDateTime::fromString(QStringLiteral("2018-09-27T16:05:06Z"), Qt::ISODate).toMSecsSinceEpoch());
0284     QVERIFY(xAxis->majorTickStartValue() > 0);
0285     {
0286         const auto v = xAxis->tickLabelStrings();
0287         QStringList expectedStrings{
0288             QStringLiteral("2018-09-27 16:05:06"),
0289             QStringLiteral("2018-10-27 16:05:06"),
0290             QStringLiteral("2018-11-27 16:05:06"),
0291             QStringLiteral("2018-12-27 16:05:06"),
0292             QStringLiteral("2019-01-27 16:05:06"),
0293             QStringLiteral("2019-02-27 16:05:06"),
0294         };
0295         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
0296     }
0297 }
0298 
0299 void AxisTest3::numeric() {
0300     QLocale::setDefault(QLocale::C); // . as decimal separator
0301     Project project;
0302     auto* ws = new Worksheet(QStringLiteral("worksheet"));
0303     QVERIFY(ws != nullptr);
0304     project.addChild(ws);
0305 
0306     Spreadsheet* spreadsheetData = new Spreadsheet(QStringLiteral("data"), false);
0307     spreadsheetData->setColumnCount(2);
0308     spreadsheetData->setRowCount(3);
0309     project.addChild(spreadsheetData);
0310 
0311     auto* xCol = spreadsheetData->column(0);
0312     xCol->setColumnMode(AbstractColumn::ColumnMode::Double);
0313     xCol->replaceValues(-1, QVector<double>({1., 2., 5.}));
0314 
0315     auto* yCol = spreadsheetData->column(1);
0316     yCol->replaceValues(-1, QVector<double>({2., 3., 4.}));
0317 
0318     QCOMPARE(spreadsheetData->rowCount(), 3);
0319     QCOMPARE(spreadsheetData->columnCount(), 2);
0320 
0321     auto* p = new CartesianPlot(QStringLiteral("plot"));
0322     p->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created
0323     p->setNiceExtend(false);
0324     QVERIFY(p != nullptr);
0325     ws->addChild(p);
0326 
0327     auto* curve = new XYCurve(QStringLiteral("xy-curve"));
0328     curve->setXColumn(xCol);
0329     curve->setYColumn(yCol);
0330     p->addChild(curve);
0331 
0332     auto axes = p->children<Axis>();
0333     QCOMPARE(axes.count(), 2);
0334     QCOMPARE(axes.at(0)->name(), QStringLiteral("x"));
0335     QCOMPARE(axes.at(1)->name(), QStringLiteral("y"));
0336 
0337     auto* xAxis = static_cast<Axis*>(axes.at(0));
0338     xAxis->setMajorTicksNumber(3, false);
0339     QCOMPARE(xAxis->range().start(), 1.);
0340     QCOMPARE(xAxis->range().end(), 5.);
0341     QCOMPARE(xAxis->majorTicksType(), Axis::TicksType::TotalNumber);
0342     QCOMPARE(xAxis->majorTicksNumber(), 3);
0343     QCOMPARE(xAxis->labelsTextType(), Axis::LabelsTextType::PositionValues);
0344 
0345     {
0346         const auto v = xAxis->tickLabelStrings();
0347         QStringList expectedStrings{
0348             QStringLiteral("1"),
0349             QStringLiteral("3"),
0350             QStringLiteral("5"),
0351         };
0352         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
0353     }
0354 }
0355 
0356 void AxisTest3::numericSpacing() {
0357     QLocale::setDefault(QLocale::C); // . as decimal separator
0358     Project project;
0359     auto* ws = new Worksheet(QStringLiteral("worksheet"));
0360     QVERIFY(ws != nullptr);
0361     project.addChild(ws);
0362 
0363     Spreadsheet* spreadsheetData = new Spreadsheet(QStringLiteral("data"), false);
0364     spreadsheetData->setColumnCount(2);
0365     spreadsheetData->setRowCount(3);
0366     project.addChild(spreadsheetData);
0367 
0368     auto* xCol = spreadsheetData->column(0);
0369     xCol->setColumnMode(AbstractColumn::ColumnMode::Double);
0370     xCol->replaceValues(-1, QVector<double>({1., 2., 5.}));
0371 
0372     auto* yCol = spreadsheetData->column(1);
0373     yCol->replaceValues(-1, QVector<double>({2., 3., 4.}));
0374 
0375     QCOMPARE(spreadsheetData->rowCount(), 3);
0376     QCOMPARE(spreadsheetData->columnCount(), 2);
0377 
0378     auto* p = new CartesianPlot(QStringLiteral("plot"));
0379     p->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created
0380     p->setNiceExtend(false);
0381     QVERIFY(p != nullptr);
0382     ws->addChild(p);
0383 
0384     auto* curve = new XYCurve(QStringLiteral("xy-curve"));
0385     curve->setXColumn(xCol);
0386     curve->setYColumn(yCol);
0387     p->addChild(curve);
0388 
0389     auto axes = p->children<Axis>();
0390     QCOMPARE(axes.count(), 2);
0391     QCOMPARE(axes.at(0)->name(), QStringLiteral("x"));
0392     QCOMPARE(axes.at(1)->name(), QStringLiteral("y"));
0393 
0394     auto* xAxis = static_cast<Axis*>(axes.at(0));
0395     xAxis->setMajorTicksSpacing(0.5);
0396     QCOMPARE(xAxis->range().start(), 1.);
0397     QCOMPARE(xAxis->range().end(), 5.);
0398     xAxis->setMajorTicksType(Axis::TicksType::Spacing);
0399     // QCOMPARE(xAxis->majorTicksNumber(), 3);
0400     QCOMPARE(xAxis->labelsTextType(), Axis::LabelsTextType::PositionValues);
0401     QCOMPARE(xAxis->majorTicksStartType(), Axis::TicksStartType::Offset);
0402     QCOMPARE(xAxis->majorTickStartOffset(), 0.);
0403     QCOMPARE(xAxis->majorTickStartValue(), 0.);
0404 
0405     {
0406         const auto v = xAxis->tickLabelStrings();
0407         QStringList expectedStrings{
0408             QStringLiteral("1.0"),
0409             QStringLiteral("1.5"),
0410             QStringLiteral("2.0"),
0411             QStringLiteral("2.5"),
0412             QStringLiteral("3.0"),
0413             QStringLiteral("3.5"),
0414             QStringLiteral("4.0"),
0415             QStringLiteral("4.5"),
0416             QStringLiteral("5.0"),
0417         };
0418         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
0419     }
0420 }
0421 
0422 void AxisTest3::numericSpacingOffsetNonZero() {
0423     QLocale::setDefault(QLocale::C); // . as decimal separator
0424     Project project;
0425     auto* ws = new Worksheet(QStringLiteral("worksheet"));
0426     QVERIFY(ws != nullptr);
0427     project.addChild(ws);
0428 
0429     Spreadsheet* spreadsheetData = new Spreadsheet(QStringLiteral("data"), false);
0430     spreadsheetData->setColumnCount(2);
0431     spreadsheetData->setRowCount(3);
0432     project.addChild(spreadsheetData);
0433 
0434     auto* xCol = spreadsheetData->column(0);
0435     xCol->setColumnMode(AbstractColumn::ColumnMode::Double);
0436     xCol->replaceValues(-1, QVector<double>({1., 2., 5.}));
0437 
0438     auto* yCol = spreadsheetData->column(1);
0439     yCol->replaceValues(-1, QVector<double>({2., 3., 4.}));
0440 
0441     QCOMPARE(spreadsheetData->rowCount(), 3);
0442     QCOMPARE(spreadsheetData->columnCount(), 2);
0443 
0444     auto* p = new CartesianPlot(QStringLiteral("plot"));
0445     p->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created
0446     p->setNiceExtend(false);
0447     QVERIFY(p != nullptr);
0448     ws->addChild(p);
0449 
0450     auto* curve = new XYCurve(QStringLiteral("xy-curve"));
0451     curve->setXColumn(xCol);
0452     curve->setYColumn(yCol);
0453     p->addChild(curve);
0454 
0455     auto axes = p->children<Axis>();
0456     QCOMPARE(axes.count(), 2);
0457     QCOMPARE(axes.at(0)->name(), QStringLiteral("x"));
0458     QCOMPARE(axes.at(1)->name(), QStringLiteral("y"));
0459 
0460     auto* xAxis = static_cast<Axis*>(axes.at(0));
0461     xAxis->setMajorTicksSpacing(0.5);
0462     QCOMPARE(xAxis->range().start(), 1.);
0463     QCOMPARE(xAxis->range().end(), 5.);
0464     xAxis->setMajorTicksType(Axis::TicksType::Spacing);
0465     // QCOMPARE(xAxis->majorTicksNumber(), 3);
0466     QCOMPARE(xAxis->labelsTextType(), Axis::LabelsTextType::PositionValues);
0467     QCOMPARE(xAxis->majorTicksStartType(), Axis::TicksStartType::Offset);
0468     xAxis->setMajorTickStartOffset(1.2);
0469     QVERIFY(xAxis->majorTickStartOffset() > 0);
0470     QCOMPARE(xAxis->majorTickStartValue(), 0.);
0471 
0472     {
0473         const auto v = xAxis->tickLabelStrings();
0474         QStringList expectedStrings{
0475             QStringLiteral("2.2"),
0476             QStringLiteral("2.7"),
0477             QStringLiteral("3.2"),
0478             QStringLiteral("3.7"),
0479             QStringLiteral("4.2"),
0480             QStringLiteral("4.7"),
0481         };
0482         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
0483     }
0484 }
0485 
0486 void AxisTest3::numericSpacingStartValueNonZero() {
0487     QLocale::setDefault(QLocale::C); // . as decimal separator
0488     Project project;
0489     auto* ws = new Worksheet(QStringLiteral("worksheet"));
0490     QVERIFY(ws != nullptr);
0491     project.addChild(ws);
0492 
0493     Spreadsheet* spreadsheetData = new Spreadsheet(QStringLiteral("data"), false);
0494     spreadsheetData->setColumnCount(2);
0495     spreadsheetData->setRowCount(3);
0496     project.addChild(spreadsheetData);
0497 
0498     auto* xCol = spreadsheetData->column(0);
0499     xCol->setColumnMode(AbstractColumn::ColumnMode::Double);
0500     xCol->replaceValues(-1, QVector<double>({1., 2., 5.}));
0501 
0502     auto* yCol = spreadsheetData->column(1);
0503     yCol->replaceValues(-1, QVector<double>({2., 3., 4.}));
0504 
0505     QCOMPARE(spreadsheetData->rowCount(), 3);
0506     QCOMPARE(spreadsheetData->columnCount(), 2);
0507 
0508     auto* p = new CartesianPlot(QStringLiteral("plot"));
0509     p->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created
0510     p->setNiceExtend(false);
0511     QVERIFY(p != nullptr);
0512     ws->addChild(p);
0513 
0514     auto* curve = new XYCurve(QStringLiteral("xy-curve"));
0515     curve->setXColumn(xCol);
0516     curve->setYColumn(yCol);
0517     p->addChild(curve);
0518 
0519     auto axes = p->children<Axis>();
0520     QCOMPARE(axes.count(), 2);
0521     QCOMPARE(axes.at(0)->name(), QStringLiteral("x"));
0522     QCOMPARE(axes.at(1)->name(), QStringLiteral("y"));
0523 
0524     auto* xAxis = static_cast<Axis*>(axes.at(0));
0525     xAxis->setMajorTicksSpacing(0.7);
0526     QCOMPARE(xAxis->range().start(), 1.);
0527     QCOMPARE(xAxis->range().end(), 5.);
0528     xAxis->setMajorTicksType(Axis::TicksType::Spacing);
0529     // QCOMPARE(xAxis->majorTicksNumber(), 3);
0530     QCOMPARE(xAxis->labelsTextType(), Axis::LabelsTextType::PositionValues);
0531     xAxis->setMajorTicksStartType(Axis::TicksStartType::Absolute);
0532     xAxis->setMajorTickStartValue(1.7);
0533     QVERIFY(xAxis->majorTickStartValue() > 0);
0534     {
0535         QStringList expectedStrings{
0536             QStringLiteral("1.7"),
0537             QStringLiteral("2.4"),
0538             QStringLiteral("3.1"),
0539             QStringLiteral("3.8"),
0540             QStringLiteral("4.5"),
0541         };
0542         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
0543     }
0544 }
0545 
0546 /*!
0547  * \brief AxisTest3::customColumnNumeric
0548  * Test setting a custom column as major tick once with the custom column values and
0549  * once with another column as ticks label
0550  */
0551 void AxisTest3::customColumnNumeric() {
0552     Project project;
0553     auto* ws = new Worksheet(QStringLiteral("worksheet"));
0554     QVERIFY(ws != nullptr);
0555     project.addChild(ws);
0556     ws->setPageRect(QRectF(0, 0, 300, 300));
0557     ws->setLayoutBottomMargin(0);
0558     ws->setLayoutTopMargin(0);
0559     ws->setLayoutRightMargin(0);
0560     ws->setLayoutLeftMargin(0);
0561 
0562     Spreadsheet* spreadsheetData = new Spreadsheet(QStringLiteral("data"), false);
0563     spreadsheetData->setColumnCount(2);
0564     spreadsheetData->setRowCount(3);
0565     project.addChild(spreadsheetData);
0566     auto* xCol = spreadsheetData->column(0);
0567     xCol->setColumnMode(AbstractColumn::ColumnMode::Double);
0568     xCol->replaceValues(-1, QVector<double>({1., 2., 5.}));
0569     auto* yCol = spreadsheetData->column(1);
0570     yCol->replaceValues(-1, QVector<double>({2., 3., 4.}));
0571 
0572     Spreadsheet* spreadsheetLabels = new Spreadsheet(QStringLiteral("labels"), false);
0573     spreadsheetLabels->setColumnCount(2);
0574     spreadsheetLabels->setRowCount(3);
0575     project.addChild(spreadsheetLabels);
0576     auto* posCol = spreadsheetLabels->column(0);
0577     posCol->setColumnMode(AbstractColumn::ColumnMode::Double);
0578     posCol->replaceValues(-1, QVector<double>({1.7, 2.2, 2.5}));
0579     auto* labelsCol = spreadsheetLabels->column(1);
0580     labelsCol->setColumnMode(AbstractColumn::ColumnMode::Text);
0581     labelsCol->replaceTexts(-1, QVector<QString>({QStringLiteral("first"), QStringLiteral("second"), QStringLiteral("third")}));
0582 
0583     auto* p = new CartesianPlot(QStringLiteral("plot"));
0584     p->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created
0585     p->setNiceExtend(false);
0586     QVERIFY(p != nullptr);
0587     p->setBottomPadding(0);
0588     p->setHorizontalPadding(0);
0589     p->setRightPadding(0);
0590     p->setVerticalPadding(0);
0591     ws->addChild(p);
0592 
0593     auto* curve = new XYCurve(QStringLiteral("xy-curve"));
0594     curve->setXColumn(xCol);
0595     curve->setYColumn(yCol);
0596     p->addChild(curve);
0597 
0598     auto axes = p->children<Axis>();
0599     QCOMPARE(axes.count(), 2);
0600     QCOMPARE(axes.at(0)->name(), QStringLiteral("x"));
0601     QCOMPARE(axes.at(1)->name(), QStringLiteral("y"));
0602 
0603     auto* xAxis = static_cast<Axis*>(axes.at(0));
0604     QCOMPARE(xAxis->range().start(), 1.);
0605     QCOMPARE(xAxis->range().end(), 5.);
0606     xAxis->setMajorTicksType(Axis::TicksType::CustomColumn);
0607     xAxis->setMajorTicksColumn(posCol);
0608     QCOMPARE(xAxis->labelsTextType(), Axis::LabelsTextType::PositionValues);
0609     {
0610         const auto v = xAxis->tickLabelStrings();
0611         QStringList expectedStrings{
0612             QStringLiteral("1.7"),
0613             QStringLiteral("2.2"),
0614             QStringLiteral("2.5"),
0615         };
0616         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
0617     }
0618 
0619     xAxis->setLabelsTextType(Axis::LabelsTextType::CustomValues);
0620     xAxis->setLabelsTextColumn(labelsCol);
0621     {
0622         QStringList expectedStrings{
0623             QStringLiteral("first"),
0624             QStringLiteral("second"),
0625             QStringLiteral("third"),
0626         };
0627         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
0628     }
0629     QVERIFY(p->dataRect().width() > 0.);
0630     QVERIFY(p->dataRect().height() > 0.);
0631     QCOMPARE(xAxis->d_func()->majorTickPoints.size(), 3);
0632     VALUES_EQUAL(xAxis->d_func()->majorTickPoints.at(0).x(), p->dataRect().x() + p->dataRect().width() * (1.7 - 1.) / (5. - 1.));
0633     VALUES_EQUAL(xAxis->d_func()->majorTickPoints.at(1).x(), p->dataRect().x() + p->dataRect().width() * (2.2 - 1.) / (5. - 1.));
0634     VALUES_EQUAL(xAxis->d_func()->majorTickPoints.at(2).x(), p->dataRect().x() + p->dataRect().width() * (2.5 - 1.) / (5. - 1.));
0635 }
0636 
0637 /*!
0638  * \brief AxisTest3::customColumnNumericMaxValues
0639  * The number of rows in custom column are higher than the maximum. Therefore
0640  * the number of ticks is limited
0641  */
0642 void AxisTest3::customColumnNumericMaxValues() {
0643     constexpr int rowCountCustomColumn = 1000;
0644 
0645     Project project;
0646     auto* ws = new Worksheet(QStringLiteral("worksheet"));
0647     QVERIFY(ws != nullptr);
0648     project.addChild(ws);
0649     ws->setPageRect(QRectF(0, 0, 300, 300));
0650     ws->setLayoutBottomMargin(0);
0651     ws->setLayoutTopMargin(0);
0652     ws->setLayoutRightMargin(0);
0653     ws->setLayoutLeftMargin(0);
0654 
0655     Spreadsheet* spreadsheetData = new Spreadsheet(QStringLiteral("data"), false);
0656     spreadsheetData->setColumnCount(2);
0657     spreadsheetData->setRowCount(3);
0658     project.addChild(spreadsheetData);
0659     auto* xCol = spreadsheetData->column(0);
0660     xCol->setColumnMode(AbstractColumn::ColumnMode::Double);
0661     xCol->replaceValues(-1, QVector<double>({0., 1000.}));
0662     auto* yCol = spreadsheetData->column(1);
0663     yCol->replaceValues(-1, QVector<double>({0., 1000.}));
0664 
0665     Spreadsheet* spreadsheetLabels = new Spreadsheet(QStringLiteral("labels"), false);
0666     spreadsheetLabels->setColumnCount(2);
0667     spreadsheetLabels->setRowCount(3);
0668     project.addChild(spreadsheetLabels);
0669     auto* posCol = spreadsheetLabels->column(0);
0670     posCol->setColumnMode(AbstractColumn::ColumnMode::Integer);
0671     QVector<int> posValues;
0672     QVector<QString> customLabels;
0673     for (int i = 0; i <= rowCountCustomColumn; i++) {
0674         posValues.push_back(i);
0675         customLabels.push_back(QStringLiteral("Some text") + QString::number(i));
0676     }
0677     posCol->replaceInteger(-1, posValues);
0678     auto* labelsCol = spreadsheetLabels->column(1);
0679     labelsCol->setColumnMode(AbstractColumn::ColumnMode::Text);
0680     labelsCol->replaceTexts(-1, customLabels);
0681 
0682     auto* p = new CartesianPlot(QStringLiteral("plot"));
0683     p->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created
0684     p->setNiceExtend(false);
0685     QVERIFY(p != nullptr);
0686     p->setBottomPadding(0);
0687     p->setHorizontalPadding(0);
0688     p->setRightPadding(0);
0689     p->setVerticalPadding(0);
0690     ws->addChild(p);
0691 
0692     auto* curve = new XYCurve(QStringLiteral("xy-curve"));
0693     curve->setXColumn(xCol);
0694     curve->setYColumn(yCol);
0695     p->addChild(curve);
0696 
0697     auto axes = p->children<Axis>();
0698     QCOMPARE(axes.count(), 2);
0699     QCOMPARE(axes.at(0)->name(), QStringLiteral("x"));
0700     QCOMPARE(axes.at(1)->name(), QStringLiteral("y"));
0701 
0702     auto* xAxis = static_cast<Axis*>(axes.at(0));
0703     QCOMPARE(xAxis->range().start(), 0.);
0704     QCOMPARE(xAxis->range().end(), 1000.);
0705     xAxis->setMajorTicksType(Axis::TicksType::CustomColumn);
0706     xAxis->setMajorTicksColumn(posCol);
0707     QCOMPARE(xAxis->majorTicksAutoNumber(), true);
0708     QCOMPARE(xAxis->labelsTextType(), Axis::LabelsTextType::PositionValues);
0709     {
0710         const auto v = xAxis->tickLabelStrings();
0711         QStringList expectedStrings;
0712         for (int i = 0; i <= rowCountCustomColumn; i += rowCountCustomColumn / (Axis::maxNumberMajorTicksCustomColumn() - 1))
0713             expectedStrings.push_back(QString::number(i));
0714 
0715         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
0716     }
0717 
0718     xAxis->setLabelsTextType(Axis::LabelsTextType::CustomValues);
0719     xAxis->setLabelsTextColumn(labelsCol);
0720     {
0721         QStringList expectedStrings;
0722         for (int i = 0; i <= rowCountCustomColumn; i += rowCountCustomColumn / (Axis::maxNumberMajorTicksCustomColumn() - 1))
0723             expectedStrings.push_back(QStringLiteral("Some text") + QString::number(i));
0724         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
0725     }
0726     QVERIFY(p->dataRect().width() > 0.);
0727     QVERIFY(p->dataRect().height() > 0.);
0728     QCOMPARE(xAxis->d_func()->majorTickPoints.size(), Axis::maxNumberMajorTicksCustomColumn());
0729     for (int i = 0; i < Axis::maxNumberMajorTicksCustomColumn(); i++) {
0730         const double xVal = ((double)i * rowCountCustomColumn / (Axis::maxNumberMajorTicksCustomColumn() - 1) - 0.) / (1000. - 0.);
0731         VALUES_EQUAL(xAxis->d_func()->majorTickPoints.at(i).x(), p->dataRect().x() + p->dataRect().width() * xVal);
0732     }
0733 }
0734 
0735 void AxisTest3::customColumnNonMonotonicColumnValues() {
0736     Project project;
0737     auto* ws = new Worksheet(QStringLiteral("worksheet"));
0738     QVERIFY(ws != nullptr);
0739     project.addChild(ws);
0740     ws->setPageRect(QRectF(0, 0, 300, 300));
0741     ws->setLayoutBottomMargin(0);
0742     ws->setLayoutTopMargin(0);
0743     ws->setLayoutRightMargin(0);
0744     ws->setLayoutLeftMargin(0);
0745 
0746     Spreadsheet* spreadsheetData = new Spreadsheet(QStringLiteral("data"), false);
0747     spreadsheetData->setColumnCount(2);
0748     spreadsheetData->setRowCount(3);
0749     project.addChild(spreadsheetData);
0750     auto* xCol = spreadsheetData->column(0);
0751     xCol->setColumnMode(AbstractColumn::ColumnMode::Double);
0752     xCol->replaceValues(-1, QVector<double>({0., 1000.}));
0753     auto* yCol = spreadsheetData->column(1);
0754     yCol->replaceValues(-1, QVector<double>({0., 1000.}));
0755 
0756     Spreadsheet* spreadsheetLabels = new Spreadsheet(QStringLiteral("labels"), false);
0757     spreadsheetLabels->setColumnCount(2);
0758     spreadsheetLabels->setRowCount(3);
0759     project.addChild(spreadsheetLabels);
0760     auto* posCol = spreadsheetLabels->column(0);
0761     posCol->setColumnMode(AbstractColumn::ColumnMode::Double);
0762     QVector<double> posValues({
0763         0., 5., 3., 800., 500., 300., 200., 1., 6., 2., 900., 787., 333., 128., 999., 650., 11., 14., 18., 20., 576., 238., 239.,
0764     });
0765     for (int i = 100; i < 200; i++)
0766         posValues.push_back(i); // Add more posValues which are between 100 and 200
0767 
0768     posCol->replaceValues(-1, posValues);
0769     QVERIFY(posCol->rowCount() > Axis::maxNumberMajorTicksCustomColumn());
0770 
0771     auto* p = new CartesianPlot(QStringLiteral("plot"));
0772     p->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created
0773     p->setNiceExtend(false);
0774     QVERIFY(p != nullptr);
0775     p->setBottomPadding(0);
0776     p->setHorizontalPadding(0);
0777     p->setRightPadding(0);
0778     p->setVerticalPadding(0);
0779     ws->addChild(p);
0780 
0781     auto* curve = new XYCurve(QStringLiteral("xy-curve"));
0782     curve->setXColumn(xCol);
0783     curve->setYColumn(yCol);
0784     p->addChild(curve);
0785     p->enableAutoScale(Dimension::X, 0, false);
0786     auto r = p->range(Dimension::X, 0);
0787     r.setStart(100.);
0788     r.setEnd(200.);
0789     p->setRange(Dimension::X, 0, r);
0790 
0791     auto axes = p->children<Axis>();
0792     QCOMPARE(axes.count(), 2);
0793     QCOMPARE(axes.at(0)->name(), QStringLiteral("x"));
0794     QCOMPARE(axes.at(1)->name(), QStringLiteral("y"));
0795 
0796     auto* xAxis = static_cast<Axis*>(axes.at(0));
0797     QCOMPARE(xAxis->range().start(), 100.);
0798     QCOMPARE(xAxis->range().end(), 200.);
0799     xAxis->setMajorTicksType(Axis::TicksType::CustomColumn);
0800     xAxis->setMajorTicksColumn(posCol);
0801     QCOMPARE(xAxis->majorTicksAutoNumber(), true);
0802     QCOMPARE(xAxis->labelsTextType(), Axis::LabelsTextType::PositionValues);
0803     {
0804         const auto v = xAxis->tickLabelStrings();
0805         QStringList expectedStrings;
0806         for (int i = 100; i <= 200.; i += (200. - 100.) / (Axis::maxNumberMajorTicksCustomColumn() - 1))
0807             expectedStrings.push_back(QString::number(i));
0808 
0809         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
0810     }
0811 }
0812 
0813 /*!
0814  * \brief AxisTest3::customColumnNumericMaxValuesLimitedRange
0815  * The range is limited to 100-200 (max Range: 0-1000). But still 20 ticks shall be visible
0816  */
0817 void AxisTest3::customColumnNumericMaxValuesLimitedRange() {
0818     constexpr int rowCountCustomColumn = 1000;
0819 
0820     Project project;
0821     auto* ws = new Worksheet(QStringLiteral("worksheet"));
0822     QVERIFY(ws != nullptr);
0823     project.addChild(ws);
0824     ws->setPageRect(QRectF(0, 0, 300, 300));
0825     ws->setLayoutBottomMargin(0);
0826     ws->setLayoutTopMargin(0);
0827     ws->setLayoutRightMargin(0);
0828     ws->setLayoutLeftMargin(0);
0829 
0830     Spreadsheet* spreadsheetData = new Spreadsheet(QStringLiteral("data"), false);
0831     spreadsheetData->setColumnCount(2);
0832     spreadsheetData->setRowCount(3);
0833     project.addChild(spreadsheetData);
0834     auto* xCol = spreadsheetData->column(0);
0835     xCol->setColumnMode(AbstractColumn::ColumnMode::Double);
0836     xCol->replaceValues(-1, QVector<double>({0., 1000.}));
0837     auto* yCol = spreadsheetData->column(1);
0838     yCol->replaceValues(-1, QVector<double>({0., 1000.}));
0839 
0840     Spreadsheet* spreadsheetLabels = new Spreadsheet(QStringLiteral("labels"), false);
0841     spreadsheetLabels->setColumnCount(2);
0842     spreadsheetLabels->setRowCount(3);
0843     project.addChild(spreadsheetLabels);
0844     auto* posCol = spreadsheetLabels->column(0);
0845     posCol->setColumnMode(AbstractColumn::ColumnMode::Integer);
0846     QVector<int> posValues;
0847     QVector<QString> customLabels;
0848     for (int i = 0; i < rowCountCustomColumn; i++) {
0849         posValues.push_back(i);
0850         customLabels.push_back(QStringLiteral("Some text") + QString::number(i));
0851     }
0852     posCol->replaceInteger(-1, posValues);
0853     auto* labelsCol = spreadsheetLabels->column(1);
0854     labelsCol->setColumnMode(AbstractColumn::ColumnMode::Text);
0855     labelsCol->replaceTexts(-1, customLabels);
0856 
0857     auto* p = new CartesianPlot(QStringLiteral("plot"));
0858     p->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created
0859     p->setNiceExtend(false);
0860     QVERIFY(p != nullptr);
0861     p->setBottomPadding(0);
0862     p->setHorizontalPadding(0);
0863     p->setRightPadding(0);
0864     p->setVerticalPadding(0);
0865     ws->addChild(p);
0866 
0867     auto* curve = new XYCurve(QStringLiteral("xy-curve"));
0868     curve->setXColumn(xCol);
0869     curve->setYColumn(yCol);
0870     p->addChild(curve);
0871     p->enableAutoScale(Dimension::X, 0, false);
0872     auto r = p->range(Dimension::X, 0);
0873     r.setStart(100.);
0874     r.setEnd(200.);
0875     p->setRange(Dimension::X, 0, r);
0876 
0877     auto axes = p->children<Axis>();
0878     QCOMPARE(axes.count(), 2);
0879     QCOMPARE(axes.at(0)->name(), QStringLiteral("x"));
0880     QCOMPARE(axes.at(1)->name(), QStringLiteral("y"));
0881 
0882     auto* xAxis = static_cast<Axis*>(axes.at(0));
0883     QCOMPARE(xAxis->range().start(), 100.);
0884     QCOMPARE(xAxis->range().end(), 200.);
0885     xAxis->setMajorTicksType(Axis::TicksType::CustomColumn);
0886     xAxis->setMajorTicksColumn(posCol);
0887     QCOMPARE(xAxis->majorTicksAutoNumber(), true);
0888     QCOMPARE(xAxis->labelsTextType(), Axis::LabelsTextType::PositionValues);
0889     {
0890         QStringList expectedStrings;
0891         for (int i = 100; i <= 200.; i += (200. - 100.) / (Axis::maxNumberMajorTicksCustomColumn() - 1))
0892             expectedStrings.push_back(QString::number(i));
0893 
0894         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
0895     }
0896 
0897     xAxis->setLabelsTextType(Axis::LabelsTextType::CustomValues);
0898     xAxis->setLabelsTextColumn(labelsCol);
0899     {
0900         QStringList expectedStrings;
0901         for (int i = 100; i <= 200.; i += (200. - 100.) / (Axis::maxNumberMajorTicksCustomColumn() - 1))
0902             expectedStrings.push_back(QStringLiteral("Some text") + QString::number(i));
0903         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
0904     }
0905     QVERIFY(p->dataRect().width() > 0.);
0906     QVERIFY(p->dataRect().height() > 0.);
0907     QCOMPARE(xAxis->d_func()->majorTickPoints.size(), Axis::maxNumberMajorTicksCustomColumn());
0908     for (int i = 0; i < Axis::maxNumberMajorTicksCustomColumn(); i++) {
0909         const double xValExpected = (100. + (double)i * (200. - 100.) / (Axis::maxNumberMajorTicksCustomColumn() - 1));
0910         const double posExpected = p->dataRect().x() + p->dataRect().width() * (xValExpected - 100.) / (200. - 100.);
0911         const double pos = xAxis->d_func()->majorTickPoints.at(i).x();
0912         VALUES_EQUAL(pos, posExpected);
0913     }
0914 
0915     r = p->range(Dimension::X, 0);
0916     r.setStart(100.);
0917     r.setEnd(110.);
0918     p->setRange(Dimension::X, 0, r);
0919 
0920     {
0921         QStringList expectedStrings;
0922         for (int i = 100; i <= 110.; i += (110. - 100.) / 10) // maximum 10 labels are visible because not more labels exist in this range
0923             expectedStrings.push_back(QStringLiteral("Some text") + QString::number(i));
0924         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
0925     }
0926 }
0927 
0928 /*!
0929  * \brief AxisTest3::customColumnNumericMaxValuesLimitedRangeNotCompleteRange
0930  * Same as customColumnNumericMaxValuesLimitedRange() but in this case the range starts from -100, but the labels will start from 100
0931  */
0932 void AxisTest3::customColumnNumericMaxValuesLimitedRangeNotCompleteRange() {
0933     constexpr int rowCountCustomColumn = 1000;
0934 
0935     Project project;
0936     auto* ws = new Worksheet(QStringLiteral("worksheet"));
0937     QVERIFY(ws != nullptr);
0938     project.addChild(ws);
0939     ws->setPageRect(QRectF(0, 0, 300, 300));
0940     ws->setLayoutBottomMargin(0);
0941     ws->setLayoutTopMargin(0);
0942     ws->setLayoutRightMargin(0);
0943     ws->setLayoutLeftMargin(0);
0944 
0945     Spreadsheet* spreadsheetData = new Spreadsheet(QStringLiteral("data"), false);
0946     spreadsheetData->setColumnCount(2);
0947     spreadsheetData->setRowCount(3);
0948     project.addChild(spreadsheetData);
0949     auto* xCol = spreadsheetData->column(0);
0950     xCol->setColumnMode(AbstractColumn::ColumnMode::Double);
0951     xCol->replaceValues(-1, QVector<double>({0., 1000.}));
0952     auto* yCol = spreadsheetData->column(1);
0953     yCol->replaceValues(-1, QVector<double>({0., 1000.}));
0954 
0955     Spreadsheet* spreadsheetLabels = new Spreadsheet(QStringLiteral("labels"), false);
0956     spreadsheetLabels->setColumnCount(2);
0957     spreadsheetLabels->setRowCount(3);
0958     project.addChild(spreadsheetLabels);
0959     auto* posCol = spreadsheetLabels->column(0);
0960     posCol->setColumnMode(AbstractColumn::ColumnMode::Integer);
0961     QVector<int> posValues;
0962     QVector<QString> customLabels;
0963     for (int i = 0; i < rowCountCustomColumn; i++) {
0964         posValues.push_back(i);
0965         customLabels.push_back(QStringLiteral("Some text") + QString::number(i));
0966     }
0967     posCol->replaceInteger(-1, posValues);
0968     auto* labelsCol = spreadsheetLabels->column(1);
0969     labelsCol->setColumnMode(AbstractColumn::ColumnMode::Text);
0970     labelsCol->replaceTexts(-1, customLabels);
0971 
0972     auto* p = new CartesianPlot(QStringLiteral("plot"));
0973     p->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created
0974     p->setNiceExtend(false);
0975     QVERIFY(p != nullptr);
0976     p->setBottomPadding(0);
0977     p->setHorizontalPadding(0);
0978     p->setRightPadding(0);
0979     p->setVerticalPadding(0);
0980     ws->addChild(p);
0981 
0982     auto* curve = new XYCurve(QStringLiteral("xy-curve"));
0983     curve->setXColumn(xCol);
0984     curve->setYColumn(yCol);
0985     p->addChild(curve);
0986     p->enableAutoScale(Dimension::X, 0, false);
0987     auto r = p->range(Dimension::X, 0);
0988     r.setStart(-100);
0989     r.setEnd(200.);
0990     p->setRange(Dimension::X, 0, r);
0991 
0992     auto axes = p->children<Axis>();
0993     QCOMPARE(axes.count(), 2);
0994     QCOMPARE(axes.at(0)->name(), QStringLiteral("x"));
0995     QCOMPARE(axes.at(1)->name(), QStringLiteral("y"));
0996 
0997     auto* xAxis = static_cast<Axis*>(axes.at(0));
0998     QCOMPARE(xAxis->range().start(), -100.);
0999     QCOMPARE(xAxis->range().end(), 200.);
1000     xAxis->setMajorTicksType(Axis::TicksType::CustomColumn);
1001     xAxis->setMajorTicksColumn(posCol);
1002     QCOMPARE(xAxis->majorTicksAutoNumber(), true);
1003     QCOMPARE(xAxis->labelsTextType(), Axis::LabelsTextType::PositionValues);
1004 
1005     // |          |          |          |
1006     //-100        0         100        200
1007     //            ^
1008     //       labels begin here.
1009 
1010     {
1011         const auto v = xAxis->tickLabelStrings();
1012         QStringList expectedStrings;
1013         for (int i = 0; i <= 200.; i += (200. - 0.) / (Axis::maxNumberMajorTicksCustomColumn() - 1))
1014             expectedStrings.push_back(QString::number(i));
1015 
1016         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
1017     }
1018 
1019     xAxis->setLabelsTextType(Axis::LabelsTextType::CustomValues);
1020     xAxis->setLabelsTextColumn(labelsCol);
1021     {
1022         QStringList expectedStrings;
1023         for (int i = 0; i <= 200.; i += (200. - 0.) / (Axis::maxNumberMajorTicksCustomColumn() - 1))
1024             expectedStrings.push_back(QStringLiteral("Some text") + QString::number(i));
1025         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
1026     }
1027     QVERIFY(p->dataRect().width() > 0.);
1028     QVERIFY(p->dataRect().height() > 0.);
1029     QCOMPARE(xAxis->d_func()->majorTickPoints.size(), Axis::maxNumberMajorTicksCustomColumn());
1030     for (int i = 0; i < Axis::maxNumberMajorTicksCustomColumn(); i++) {
1031         const double xValExpected = (0. + (double)i * (200. - 0.) / (Axis::maxNumberMajorTicksCustomColumn() - 1));
1032         const double posExpected = p->dataRect().x() + p->dataRect().width() * (xValExpected - (-100.)) / (200. - (-100.));
1033         const double pos = xAxis->d_func()->majorTickPoints.at(i).x();
1034         VALUES_EQUAL(pos, posExpected);
1035     }
1036 }
1037 
1038 /*!
1039  * \brief AxisTest3::customColumnDateTime
1040  * Test setting a custom column as major tick once with the custom column values and
1041  * once with another column as ticks label
1042  */
1043 void AxisTest3::customColumnDateTime() {
1044     Project project;
1045     auto* ws = new Worksheet(QStringLiteral("worksheet"));
1046     QVERIFY(ws != nullptr);
1047     project.addChild(ws);
1048     ws->setPageRect(QRectF(0, 0, 300, 300));
1049     ws->setLayoutBottomMargin(0);
1050     ws->setLayoutTopMargin(0);
1051     ws->setLayoutRightMargin(0);
1052     ws->setLayoutLeftMargin(0);
1053 
1054     Spreadsheet* spreadsheetData = new Spreadsheet(QStringLiteral("data"), false);
1055     spreadsheetData->setColumnCount(2);
1056     spreadsheetData->setRowCount(3);
1057     project.addChild(spreadsheetData);
1058     auto* xCol = spreadsheetData->column(0);
1059     xCol->setColumnMode(AbstractColumn::ColumnMode::DateTime);
1060     QDateTime dt1 = QDateTime::fromString(QStringLiteral("2017-07-24T00:00:00Z"), Qt::ISODate);
1061     QDateTime dt2 = QDateTime::fromString(QStringLiteral("2017-07-25T00:00:00Z"), Qt::ISODate);
1062     QDateTime dt3 = QDateTime::fromString(QStringLiteral("2019-07-26T00:00:00Z"), Qt::ISODate);
1063     xCol->replaceDateTimes(-1, QVector<QDateTime>({dt1, dt2, dt3}));
1064     auto* yCol = spreadsheetData->column(1);
1065     yCol->replaceValues(-1, QVector<double>({2., 3., 4.}));
1066 
1067     Spreadsheet* spreadsheetLabels = new Spreadsheet(QStringLiteral("labels"), false);
1068     spreadsheetLabels->setColumnCount(2);
1069     spreadsheetLabels->setRowCount(3);
1070     project.addChild(spreadsheetLabels);
1071     auto* posCol = spreadsheetLabels->column(0);
1072     posCol->setColumnMode(AbstractColumn::ColumnMode::DateTime);
1073     QDateTime dt1Label = QDateTime::fromString(QStringLiteral("2017-07-24T11:03:02Z"), Qt::ISODate);
1074     QDateTime dt2Label = QDateTime::fromString(QStringLiteral("2017-07-24T15:30:00Z"), Qt::ISODate);
1075     QDateTime dt3Label = QDateTime::fromString(QStringLiteral("2019-07-25T13:25:00Z"), Qt::ISODate);
1076     posCol->replaceDateTimes(-1, QVector<QDateTime>({dt1Label, dt2Label, dt3Label}));
1077     auto* labelsCol = spreadsheetLabels->column(1);
1078     labelsCol->setColumnMode(AbstractColumn::ColumnMode::Text);
1079     labelsCol->replaceTexts(-1, QVector<QString>({QStringLiteral("first"), QStringLiteral("second"), QStringLiteral("third")}));
1080 
1081     auto* p = new CartesianPlot(QStringLiteral("plot"));
1082     p->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created
1083     p->setNiceExtend(false);
1084     QVERIFY(p != nullptr);
1085     p->setBottomPadding(0);
1086     p->setHorizontalPadding(0);
1087     p->setRightPadding(0);
1088     p->setVerticalPadding(0);
1089     ws->addChild(p);
1090 
1091     auto* curve = new XYCurve(QStringLiteral("xy-curve"));
1092     curve->setXColumn(xCol);
1093     curve->setYColumn(yCol);
1094     p->addChild(curve);
1095 
1096     auto axes = p->children<Axis>();
1097     QCOMPARE(axes.count(), 2);
1098     QCOMPARE(axes.at(0)->name(), QStringLiteral("x"));
1099     QCOMPARE(axes.at(1)->name(), QStringLiteral("y"));
1100 
1101     auto* xAxis = static_cast<Axis*>(axes.at(0));
1102     QCOMPARE(xAxis->range().start(), dt1.toMSecsSinceEpoch());
1103     QCOMPARE(xAxis->range().end(), dt3.toMSecsSinceEpoch());
1104     xAxis->setMajorTicksType(Axis::TicksType::CustomColumn);
1105     xAxis->setMajorTicksColumn(posCol);
1106 
1107     QCOMPARE(xAxis->labelsDateTimeFormat(), QStringLiteral("yyyy-MM-dd hh:mm:ss.zzz"));
1108     QCOMPARE(xAxis->labelsTextType(), Axis::LabelsTextType::PositionValues);
1109     {
1110         QStringList expectedStrings{
1111             QStringLiteral("2017-07-24 11:03:02.000"),
1112             QStringLiteral("2017-07-24 15:30:00.000"),
1113             QStringLiteral("2019-07-25 13:25:00.000"),
1114         };
1115         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
1116     }
1117 
1118     xAxis->setLabelsTextType(Axis::LabelsTextType::CustomValues);
1119     xAxis->setLabelsTextColumn(labelsCol);
1120     {
1121         QStringList expectedStrings{
1122             QStringLiteral("first"),
1123             QStringLiteral("second"),
1124             QStringLiteral("third"),
1125         };
1126         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
1127     }
1128 
1129     QVERIFY(p->dataRect().width() > 0.);
1130     QVERIFY(p->dataRect().height() > 0.);
1131     QCOMPARE(xAxis->d_func()->majorTickPoints.size(), 3);
1132     const auto span = dt3.toMSecsSinceEpoch() - dt1.toMSecsSinceEpoch();
1133     VALUES_EQUAL(xAxis->d_func()->majorTickPoints.at(0).x(),
1134                  p->dataRect().x() + p->dataRect().width() * (dt1Label.toMSecsSinceEpoch() - dt1.toMSecsSinceEpoch()) / span);
1135     VALUES_EQUAL(xAxis->d_func()->majorTickPoints.at(1).x(),
1136                  p->dataRect().x() + p->dataRect().width() * (dt2Label.toMSecsSinceEpoch() - dt1.toMSecsSinceEpoch()) / span);
1137     VALUES_EQUAL(xAxis->d_func()->majorTickPoints.at(2).x(),
1138                  p->dataRect().x() + p->dataRect().width() * (dt3Label.toMSecsSinceEpoch() - dt1.toMSecsSinceEpoch()) / span);
1139 }
1140 
1141 void AxisTest3::autoScale() {
1142     QLocale::setDefault(QLocale::C); // . as decimal separator
1143     Project project;
1144     auto* ws = new Worksheet(QStringLiteral("worksheet"));
1145     QVERIFY(ws != nullptr);
1146     project.addChild(ws);
1147 
1148     auto* p = new CartesianPlot(QStringLiteral("plot"));
1149     p->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created
1150     QVERIFY(p != nullptr);
1151     ws->addChild(p);
1152 
1153     auto axes = p->children<Axis>();
1154     QCOMPARE(axes.count(), 2);
1155     QCOMPARE(axes.at(0)->name(), QStringLiteral("x"));
1156     QCOMPARE(axes.at(1)->name(), QStringLiteral("y"));
1157     auto* xAxis = static_cast<Axis*>(axes.at(0));
1158     xAxis->setMajorTicksNumber(4);
1159     QCOMPARE(xAxis->scale(), RangeT::Scale::Linear);
1160     QCOMPARE(xAxis->rangeScale(), true);
1161 
1162     auto range = p->range(Dimension::X, 0);
1163     range.setStart(10);
1164     range.setEnd(10000);
1165     p->setRange(Dimension::X, 0, range);
1166     p->setNiceExtend(false);
1167 
1168     {
1169         QStringList expectedStrings{
1170             QStringLiteral("10"),
1171             QStringLiteral("3340"),
1172             QStringLiteral("6670"),
1173             QStringLiteral("10000"),
1174         };
1175         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
1176     }
1177 
1178     p->enableAutoScale(Dimension::X, 0, false, true);
1179     range = p->range(Dimension::X, 0);
1180     range.setScale(RangeT::Scale::Log10);
1181     p->setRange(Dimension::X, 0, range);
1182 
1183     QCOMPARE(xAxis->range(), range);
1184     QCOMPARE(xAxis->scale(), RangeT::Scale::Log10);
1185 
1186     {
1187         QStringList expectedStrings{
1188             QStringLiteral("10"),
1189             QStringLiteral("100"),
1190             QStringLiteral("1000"),
1191             QStringLiteral("10000"),
1192         };
1193         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
1194     }
1195 
1196     xAxis->setScale(RangeT::Scale::Square); // Shall not change anything
1197     {
1198         QStringList expectedStrings{
1199             QStringLiteral("10"),
1200             QStringLiteral("100"),
1201             QStringLiteral("1000"),
1202             QStringLiteral("10000"),
1203         };
1204         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
1205     }
1206 
1207     xAxis->setRangeScale(false);
1208     {
1209         QStringList expectedStrings{
1210             QStringLiteral("10"),
1211             QStringLiteral("5774"),
1212             QStringLiteral("8165"),
1213             QStringLiteral("10000"),
1214         };
1215         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
1216     }
1217     xAxis->undoStack()->undo();
1218     QCOMPARE(xAxis->rangeScale(), true);
1219     QCOMPARE(xAxis->scale(), RangeT::Scale::Log10);
1220     {
1221         QStringList expectedStrings{
1222             QStringLiteral("10"),
1223             QStringLiteral("100"),
1224             QStringLiteral("1000"),
1225             QStringLiteral("10000"),
1226         };
1227         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
1228     }
1229 
1230     xAxis->undoStack()->redo();
1231     QCOMPARE(xAxis->rangeScale(), false);
1232     QCOMPARE(xAxis->scale(), RangeT::Scale::Square);
1233     {
1234         QStringList expectedStrings{
1235             QStringLiteral("10"),
1236             QStringLiteral("5774"),
1237             QStringLiteral("8165"),
1238             QStringLiteral("10000"),
1239         };
1240         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
1241     }
1242 
1243     xAxis->setScale(RangeT::Scale::Linear);
1244     {
1245         QStringList expectedStrings{
1246             QStringLiteral("10"),
1247             QStringLiteral("3340"),
1248             QStringLiteral("6670"),
1249             QStringLiteral("10000"),
1250         };
1251         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
1252     }
1253 }
1254 
1255 void AxisTest3::autoScale2() {
1256     QLocale::setDefault(QLocale::C); // . as decimal separator
1257     Project project;
1258     auto* ws = new Worksheet(QStringLiteral("worksheet"));
1259     QVERIFY(ws != nullptr);
1260     project.addChild(ws);
1261 
1262     auto* p = new CartesianPlot(QStringLiteral("plot"));
1263     p->setType(CartesianPlot::Type::TwoAxes); // Otherwise no axis are created
1264     QVERIFY(p != nullptr);
1265     ws->addChild(p);
1266 
1267     auto axes = p->children<Axis>();
1268     QCOMPARE(axes.count(), 2);
1269     QCOMPARE(axes.at(0)->name(), QStringLiteral("x"));
1270     QCOMPARE(axes.at(1)->name(), QStringLiteral("y"));
1271     auto* xAxis = static_cast<Axis*>(axes.at(0));
1272     xAxis->setMajorTicksNumber(4);
1273     QCOMPARE(xAxis->scale(), RangeT::Scale::Linear);
1274     QCOMPARE(xAxis->rangeScale(), true);
1275     xAxis->setLabelsAutoPrecision(false);
1276     xAxis->setLabelsPrecision(2);
1277 
1278     auto range = p->range(Dimension::X, 0);
1279     range.setStart(0);
1280     range.setEnd(1);
1281     p->setRange(Dimension::X, 0, range);
1282     p->setNiceExtend(false);
1283     p->enableAutoScale(Dimension::X, 0, false, true);
1284     p->setRangeScale(Dimension::X, 0, RangeT::Scale::Log10); // use different method
1285 
1286     QCOMPARE(xAxis->range(), p->range(Dimension::X, 0));
1287     QCOMPARE(xAxis->scale(), RangeT::Scale::Log10);
1288 
1289     {
1290         const auto s = xAxis->tickLabelStrings();
1291         QStringList expectedStrings{
1292             QStringLiteral("0.01"),
1293             QStringLiteral("0.05"),
1294             QStringLiteral("0.22"),
1295             QStringLiteral("1.00"),
1296         };
1297         COMPARE_STRING_VECTORS(xAxis->tickLabelStrings(), expectedStrings);
1298     }
1299 }
1300 
1301 QTEST_MAIN(AxisTest3)