File indexing completed on 2024-04-28 03:48:08

0001 /*
0002     File                 : DatapickerTest.cpp
0003     Project              : LabPlot
0004     Description          : Tests for Datapicker
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2022 Martin Marmsoler <martin.marmsoler@gmail.com>
0007     SPDX-FileCopyrightText: 2022 Alexander Semke <alexander.semke@web.de>
0008 
0009     SPDX-License-Identifier: GPL-2.0-or-later
0010 */
0011 
0012 #include "DatapickerTest.h"
0013 #include "backend/core/AbstractColumn.h"
0014 #include "backend/core/Project.h"
0015 #include "backend/datapicker/Datapicker.h"
0016 #include "backend/datapicker/DatapickerCurve.h"
0017 #include "backend/datapicker/DatapickerCurvePrivate.h"
0018 #include "backend/datapicker/DatapickerImage.h"
0019 #include "backend/datapicker/DatapickerPoint.h"
0020 #include "backend/datapicker/DatapickerPointPrivate.h"
0021 #include "backend/datapicker/Transform.h"
0022 #include "commonfrontend/datapicker/DatapickerImageView.h"
0023 #include "kdefrontend/widgets/DatapickerImageWidget.h"
0024 
0025 #include <QAction>
0026 #include <QUndoStack>
0027 
0028 #define VECTOR3D_EQUAL(vec, ref)                                                                                                                               \
0029     VALUES_EQUAL(vec.x(), ref.x());                                                                                                                            \
0030     VALUES_EQUAL(vec.y(), ref.y());                                                                                                                            \
0031     VALUES_EQUAL(vec.z(), ref.z());
0032 
0033 namespace {
0034 QImage createImage() {
0035     QImage image(1000, 1000, QImage::Format_RGB32);
0036     QRgb value;
0037 
0038     value = qRgb(189, 149, 39); // 0xffbd9527
0039     image.setPixel(1, 1, value);
0040 
0041     value = qRgb(122, 163, 39); // 0xff7aa327
0042     image.setPixel(0, 1, value);
0043     image.setPixel(1, 0, value);
0044 
0045     value = qRgb(237, 187, 51); // 0xffedba31
0046     image.setPixel(2, 1, value);
0047     return image;
0048 }
0049 
0050 // Different image to the one created by createImage()
0051 QImage createImage2() {
0052     QImage image(3, 3, QImage::Format_RGB32);
0053     QRgb value;
0054 
0055     value = qRgb(189, 149, 39); // 0xffbd9527
0056     image.setPixel(0, 1, value);
0057 
0058     value = qRgb(122, 163, 39); // 0xff7aa327
0059     image.setPixel(1, 1, value);
0060     image.setPixel(1, 0, value);
0061 
0062     value = qRgb(237, 187, 51); // 0xffedba31
0063     image.setPixel(2, 1, value);
0064     return image;
0065 }
0066 } // anonymous namespace
0067 
0068 void DatapickerTest::mapCartesianToCartesian() {
0069     DatapickerImage::ReferencePoints points;
0070     points.type = DatapickerImage::GraphType::Linear;
0071     points.logicalPos[0].setX(1);
0072     points.logicalPos[0].setY(2);
0073     points.logicalPos[1].setX(3);
0074     points.logicalPos[1].setY(4);
0075     points.logicalPos[2].setX(5);
0076     points.logicalPos[2].setY(6);
0077     points.scenePos[0].setX(6.21);
0078     points.scenePos[0].setY(7.23);
0079     points.scenePos[1].setX(-51.2);
0080     points.scenePos[1].setY(3234);
0081     points.scenePos[2].setX(-23);
0082     points.scenePos[2].setY(+5e6);
0083 
0084     Transform t;
0085     QCOMPARE(t.mapTypeToCartesian(points), true);
0086     VALUES_EQUAL(t.x[0], 1.);
0087     VALUES_EQUAL(t.y[0], 2.);
0088     VALUES_EQUAL(t.x[1], 3.);
0089     VALUES_EQUAL(t.y[1], 4.);
0090     VALUES_EQUAL(t.x[2], 5.);
0091     VALUES_EQUAL(t.y[2], 6.);
0092     VALUES_EQUAL(t.X[0], 6.21);
0093     VALUES_EQUAL(t.Y[0], 7.23);
0094     VALUES_EQUAL(t.X[1], -51.2);
0095     VALUES_EQUAL(t.Y[1], 3234.);
0096     VALUES_EQUAL(t.X[2], -23.);
0097     VALUES_EQUAL(t.Y[2], +5.e6);
0098 }
0099 
0100 void DatapickerTest::maplnXToCartesian() {
0101     DatapickerImage::ReferencePoints points;
0102     points.type = DatapickerImage::GraphType::LnX;
0103     points.logicalPos[0].setX(exp(1));
0104     points.logicalPos[0].setY(2);
0105     points.logicalPos[1].setX(exp(2));
0106     points.logicalPos[1].setY(4);
0107     points.logicalPos[2].setX(exp(3));
0108     points.logicalPos[2].setY(6);
0109     points.scenePos[0].setX(6.21);
0110     points.scenePos[0].setY(7.23);
0111     points.scenePos[1].setX(-51.2);
0112     points.scenePos[1].setY(3234);
0113     points.scenePos[2].setX(-23);
0114     points.scenePos[2].setY(+5e6);
0115 
0116     Transform t;
0117     QCOMPARE(t.mapTypeToCartesian(points), true);
0118     VALUES_EQUAL(t.x[0], 1.);
0119     VALUES_EQUAL(t.y[0], 2.);
0120     VALUES_EQUAL(t.x[1], 2.);
0121     VALUES_EQUAL(t.y[1], 4.);
0122     VALUES_EQUAL(t.x[2], 3.);
0123     VALUES_EQUAL(t.y[2], 6.);
0124     VALUES_EQUAL(t.X[0], 6.21);
0125     VALUES_EQUAL(t.Y[0], 7.23);
0126     VALUES_EQUAL(t.X[1], -51.2);
0127     VALUES_EQUAL(t.Y[1], 3234.);
0128     VALUES_EQUAL(t.X[2], -23.);
0129     VALUES_EQUAL(t.Y[2], +5.e6);
0130 }
0131 
0132 void DatapickerTest::maplnYToCartesian() {
0133     DatapickerImage::ReferencePoints points;
0134     points.type = DatapickerImage::GraphType::LnY;
0135     points.logicalPos[0].setX(1);
0136     points.logicalPos[0].setY(exp(1));
0137     points.logicalPos[1].setX(3);
0138     points.logicalPos[1].setY(exp(2));
0139     points.logicalPos[2].setX(5);
0140     points.logicalPos[2].setY(exp(3));
0141     points.scenePos[0].setX(6.21);
0142     points.scenePos[0].setY(7.23);
0143     points.scenePos[1].setX(-51.2);
0144     points.scenePos[1].setY(3234);
0145     points.scenePos[2].setX(-23);
0146     points.scenePos[2].setY(+5e6);
0147 
0148     Transform t;
0149     QCOMPARE(t.mapTypeToCartesian(points), true);
0150     VALUES_EQUAL(t.x[0], 1.);
0151     VALUES_EQUAL(t.y[0], 1.);
0152     VALUES_EQUAL(t.x[1], 3.);
0153     VALUES_EQUAL(t.y[1], 2.);
0154     VALUES_EQUAL(t.x[2], 5.);
0155     VALUES_EQUAL(t.y[2], 3.);
0156     VALUES_EQUAL(t.X[0], 6.21);
0157     VALUES_EQUAL(t.Y[0], 7.23);
0158     VALUES_EQUAL(t.X[1], -51.2);
0159     VALUES_EQUAL(t.Y[1], 3234.);
0160     VALUES_EQUAL(t.X[2], -23.);
0161     VALUES_EQUAL(t.Y[2], +5.e6);
0162 }
0163 
0164 void DatapickerTest::maplnXYToCartesian() {
0165     DatapickerImage::ReferencePoints points;
0166     points.type = DatapickerImage::GraphType::LnXY;
0167     points.logicalPos[0].setX(exp(5));
0168     points.logicalPos[0].setY(exp(1));
0169     points.logicalPos[1].setX(exp(6));
0170     points.logicalPos[1].setY(exp(2));
0171     points.logicalPos[2].setX(exp(7));
0172     points.logicalPos[2].setY(exp(3));
0173     points.scenePos[0].setX(6.21);
0174     points.scenePos[0].setY(7.23);
0175     points.scenePos[1].setX(-51.2);
0176     points.scenePos[1].setY(3234);
0177     points.scenePos[2].setX(-23);
0178     points.scenePos[2].setY(+5e6);
0179 
0180     Transform t;
0181     QCOMPARE(t.mapTypeToCartesian(points), true);
0182     VALUES_EQUAL(t.x[0], 5.);
0183     VALUES_EQUAL(t.y[0], 1.);
0184     VALUES_EQUAL(t.x[1], 6.);
0185     VALUES_EQUAL(t.y[1], 2.);
0186     VALUES_EQUAL(t.x[2], 7.);
0187     VALUES_EQUAL(t.y[2], 3.);
0188     VALUES_EQUAL(t.X[0], 6.21);
0189     VALUES_EQUAL(t.Y[0], 7.23);
0190     VALUES_EQUAL(t.X[1], -51.2);
0191     VALUES_EQUAL(t.Y[1], 3234.);
0192     VALUES_EQUAL(t.X[2], -23.);
0193     VALUES_EQUAL(t.Y[2], +5.e6);
0194 }
0195 
0196 void DatapickerTest::maplog10XToCartesian() {
0197     DatapickerImage::ReferencePoints points;
0198     points.type = DatapickerImage::GraphType::Log10X;
0199     points.logicalPos[0].setX(pow(10, 1));
0200     points.logicalPos[0].setY(2);
0201     points.logicalPos[1].setX(pow(10, 2));
0202     points.logicalPos[1].setY(4);
0203     points.logicalPos[2].setX(pow(10, 3));
0204     points.logicalPos[2].setY(6);
0205     points.scenePos[0].setX(6.21);
0206     points.scenePos[0].setY(7.23);
0207     points.scenePos[1].setX(-51.2);
0208     points.scenePos[1].setY(3234);
0209     points.scenePos[2].setX(-23);
0210     points.scenePos[2].setY(+5e6);
0211 
0212     Transform t;
0213     QCOMPARE(t.mapTypeToCartesian(points), true);
0214     VALUES_EQUAL(t.x[0], 1.);
0215     VALUES_EQUAL(t.y[0], 2.);
0216     VALUES_EQUAL(t.x[1], 2.);
0217     VALUES_EQUAL(t.y[1], 4.);
0218     VALUES_EQUAL(t.x[2], 3.);
0219     VALUES_EQUAL(t.y[2], 6.);
0220     VALUES_EQUAL(t.X[0], 6.21);
0221     VALUES_EQUAL(t.Y[0], 7.23);
0222     VALUES_EQUAL(t.X[1], -51.2);
0223     VALUES_EQUAL(t.Y[1], 3234.);
0224     VALUES_EQUAL(t.X[2], -23.);
0225     VALUES_EQUAL(t.Y[2], +5.e6);
0226 }
0227 
0228 void DatapickerTest::maplog10YToCartesian() {
0229     DatapickerImage::ReferencePoints points;
0230     points.type = DatapickerImage::GraphType::Log10Y;
0231     points.logicalPos[0].setX(1);
0232     points.logicalPos[0].setY(pow(10, 1));
0233     points.logicalPos[1].setX(3);
0234     points.logicalPos[1].setY(pow(10, 2));
0235     points.logicalPos[2].setX(5);
0236     points.logicalPos[2].setY(pow(10, 3));
0237     points.scenePos[0].setX(6.21);
0238     points.scenePos[0].setY(7.23);
0239     points.scenePos[1].setX(-51.2);
0240     points.scenePos[1].setY(3234);
0241     points.scenePos[2].setX(-23);
0242     points.scenePos[2].setY(+5e6);
0243 
0244     Transform t;
0245     QCOMPARE(t.mapTypeToCartesian(points), true);
0246     VALUES_EQUAL(t.x[0], 1.);
0247     VALUES_EQUAL(t.y[0], 1.);
0248     VALUES_EQUAL(t.x[1], 3.);
0249     VALUES_EQUAL(t.y[1], 2.);
0250     VALUES_EQUAL(t.x[2], 5.);
0251     VALUES_EQUAL(t.y[2], 3.);
0252     VALUES_EQUAL(t.X[0], 6.21);
0253     VALUES_EQUAL(t.Y[0], 7.23);
0254     VALUES_EQUAL(t.X[1], -51.2);
0255     VALUES_EQUAL(t.Y[1], 3234.);
0256     VALUES_EQUAL(t.X[2], -23.);
0257     VALUES_EQUAL(t.Y[2], +5.e6);
0258 }
0259 
0260 void DatapickerTest::maplog10XYToCartesian() {
0261     DatapickerImage::ReferencePoints points;
0262     points.type = DatapickerImage::GraphType::Log10XY;
0263     points.logicalPos[0].setX(pow(10, 5));
0264     points.logicalPos[0].setY(pow(10, 1));
0265     points.logicalPos[1].setX(pow(10, 6));
0266     points.logicalPos[1].setY(pow(10, 2));
0267     points.logicalPos[2].setX(pow(10, 7));
0268     points.logicalPos[2].setY(pow(10, 3));
0269     points.scenePos[0].setX(6.21);
0270     points.scenePos[0].setY(7.23);
0271     points.scenePos[1].setX(-51.2);
0272     points.scenePos[1].setY(3234);
0273     points.scenePos[2].setX(-23);
0274     points.scenePos[2].setY(+5e6);
0275 
0276     Transform t;
0277     QCOMPARE(t.mapTypeToCartesian(points), true);
0278     VALUES_EQUAL(t.x[0], 5.);
0279     VALUES_EQUAL(t.y[0], 1.);
0280     VALUES_EQUAL(t.x[1], 6.);
0281     VALUES_EQUAL(t.y[1], 2.);
0282     VALUES_EQUAL(t.x[2], 7.);
0283     VALUES_EQUAL(t.y[2], 3.);
0284     VALUES_EQUAL(t.X[0], 6.21);
0285     VALUES_EQUAL(t.Y[0], 7.23);
0286     VALUES_EQUAL(t.X[1], -51.2);
0287     VALUES_EQUAL(t.Y[1], 3234.);
0288     VALUES_EQUAL(t.X[2], -23.);
0289     VALUES_EQUAL(t.Y[2], +5.e6);
0290 }
0291 
0292 void DatapickerTest::mapPolarInRadiansToCartesian() {
0293     DatapickerImage::ReferencePoints points;
0294     points.type = DatapickerImage::GraphType::PolarInRadians;
0295     points.logicalPos[0].setX(1);
0296     points.logicalPos[0].setY(0);
0297     points.logicalPos[1].setX(3);
0298     points.logicalPos[1].setY(2.1f);
0299     points.logicalPos[2].setX(5);
0300     points.logicalPos[2].setY(3.8f);
0301     points.scenePos[0].setX(6.21);
0302     points.scenePos[0].setY(7.23);
0303     points.scenePos[1].setX(-51.2);
0304     points.scenePos[1].setY(3234);
0305     points.scenePos[2].setX(-23);
0306     points.scenePos[2].setY(+5e6);
0307 
0308     Transform t;
0309     QCOMPARE(t.mapTypeToCartesian(points), true);
0310     VALUES_EQUAL(t.x[0], 1.);
0311     VALUES_EQUAL(t.y[0], 0.);
0312 
0313     // TODO: VALUES_EQUAL doesn't work for the next comparions since the precision 1.e-7 is too high for the numerical error involved here.
0314     // to improve the precision we need to get rid of QVector3D using floats internally and to switch to doubles. For now, just use a somewhat
0315     // lower precision here since it's not essential.
0316     // VALUES_EQUAL(t.x[1], -1.5145383137996); // precision seems to be not correct. Referece value is correct
0317     double v1 = t.x[1];
0318     double ref = -1.5145383137996;
0319     QVERIFY2(nsl_math_approximately_equal_eps(v1, ref, 1.e-5) == true,
0320              qPrintable(QStringLiteral("v1:%1, ref:%2").arg(v1, 0, 'g', 15, QLatin1Char(' ')).arg(ref, 0, 'g', 15, QLatin1Char(' '))));
0321 
0322     VALUES_EQUAL(t.y[1], 2.5896280999466);
0323     VALUES_EQUAL(t.x[2], -3.9548385595721);
0324     VALUES_EQUAL(t.y[2], -3.0592894547136);
0325     VALUES_EQUAL(t.X[0], 6.21);
0326     VALUES_EQUAL(t.Y[0], 7.23);
0327     VALUES_EQUAL(t.X[1], -51.2);
0328     VALUES_EQUAL(t.Y[1], 3234.);
0329     VALUES_EQUAL(t.X[2], -23.);
0330     VALUES_EQUAL(t.Y[2], +5.e6);
0331 }
0332 
0333 void DatapickerTest::mapPolarInDegreeToCartesian() {
0334     DatapickerImage::ReferencePoints points;
0335     points.type = DatapickerImage::GraphType::PolarInDegree;
0336     points.logicalPos[0].setX(1);
0337     points.logicalPos[0].setY(0);
0338     points.logicalPos[1].setX(3);
0339     points.logicalPos[1].setY(30);
0340     points.logicalPos[2].setX(5);
0341     points.logicalPos[2].setY(50);
0342     points.scenePos[0].setX(6.21);
0343     points.scenePos[0].setY(7.23);
0344     points.scenePos[1].setX(-51.2);
0345     points.scenePos[1].setY(3234);
0346     points.scenePos[2].setX(-23);
0347     points.scenePos[2].setY(+5e6);
0348 
0349     Transform t;
0350     QCOMPARE(t.mapTypeToCartesian(points), true);
0351     VALUES_EQUAL(t.x[0], 1.);
0352     VALUES_EQUAL(t.y[0], 0.);
0353     VALUES_EQUAL(t.x[1], 2.5980762113533);
0354     VALUES_EQUAL(t.y[1], 1.5);
0355     VALUES_EQUAL(t.x[2], 3.2139380484327);
0356     VALUES_EQUAL(t.y[2], 3.8302222155949);
0357     VALUES_EQUAL(t.X[0], 6.21);
0358     VALUES_EQUAL(t.Y[0], 7.23);
0359     VALUES_EQUAL(t.X[1], -51.2);
0360     VALUES_EQUAL(t.Y[1], 3234.);
0361     VALUES_EQUAL(t.X[2], -23.);
0362     VALUES_EQUAL(t.Y[2], +5.e6);
0363 }
0364 
0365 // TODO: implement ternary
0366 
0367 // Reference calculations done with https://keisan.casio.com/exec/system/1223526375
0368 
0369 void DatapickerTest::mapCartesianToLinear() {
0370     DatapickerImage::ReferencePoints points;
0371     points.type = DatapickerImage::GraphType::Linear;
0372     QPointF point{5, 2343.23};
0373 
0374     Transform t;
0375     VECTOR3D_EQUAL(t.mapCartesianToType(point, points), QVector3D(5, 2343.23f, 0));
0376 }
0377 
0378 void DatapickerTest::mapCartesianToLnX() {
0379     DatapickerImage::ReferencePoints points;
0380     points.type = DatapickerImage::GraphType::LnX;
0381     QPointF point{5, 2343.23};
0382 
0383     Transform t;
0384     VECTOR3D_EQUAL(t.mapCartesianToType(point, points), QVector3D(exp(5), 2343.23f, 0));
0385 }
0386 
0387 void DatapickerTest::mapCartesianToLnY() {
0388     DatapickerImage::ReferencePoints points;
0389     points.type = DatapickerImage::GraphType::LnY;
0390     QPointF point{5, 2.23};
0391 
0392     Transform t;
0393     VECTOR3D_EQUAL(t.mapCartesianToType(point, points), QVector3D(5, exp(2.23), 0));
0394 }
0395 
0396 void DatapickerTest::mapCartesianToLnXY() {
0397     DatapickerImage::ReferencePoints points;
0398     points.type = DatapickerImage::GraphType::LnXY;
0399     QPointF point{5, 2.23};
0400 
0401     Transform t;
0402     VECTOR3D_EQUAL(t.mapCartesianToType(point, points), QVector3D(exp(5), exp(2.23), 0));
0403 }
0404 
0405 void DatapickerTest::mapCartesianToLog10X() {
0406     DatapickerImage::ReferencePoints points;
0407     points.type = DatapickerImage::GraphType::Log10X;
0408     QPointF point{5, 2343.23};
0409 
0410     Transform t;
0411     VECTOR3D_EQUAL(t.mapCartesianToType(point, points), QVector3D(pow(10, 5), 2343.23f, 0));
0412 }
0413 
0414 void DatapickerTest::mapCartesianToLog10Y() {
0415     DatapickerImage::ReferencePoints points;
0416     points.type = DatapickerImage::GraphType::Log10Y;
0417     QPointF point{5, 2.23};
0418 
0419     Transform t;
0420     VECTOR3D_EQUAL(t.mapCartesianToType(point, points), QVector3D(5, pow(10, 2.23), 0));
0421 }
0422 
0423 void DatapickerTest::mapCartesianToLog10XY() {
0424     DatapickerImage::ReferencePoints points;
0425     points.type = DatapickerImage::GraphType::Log10XY;
0426     QPointF point{5, 2.23};
0427 
0428     Transform t;
0429     VECTOR3D_EQUAL(t.mapCartesianToType(point, points), QVector3D(pow(10, 5), pow(10, 2.23), 0));
0430 }
0431 
0432 void DatapickerTest::mapCartesianToPolarInDegree() {
0433     DatapickerImage::ReferencePoints points;
0434     points.type = DatapickerImage::GraphType::PolarInDegree;
0435     QPointF point{5, 30};
0436 
0437     Transform t;
0438     VECTOR3D_EQUAL(t.mapCartesianToType(point, points), QVector3D(30.413812651491f, 80.537677791974f, 0));
0439 }
0440 
0441 void DatapickerTest::mapCartesianToPolarInRadians() {
0442     DatapickerImage::ReferencePoints points;
0443     points.type = DatapickerImage::GraphType::PolarInRadians;
0444     QPointF point{5, 30};
0445 
0446     Transform t;
0447     VECTOR3D_EQUAL(t.mapCartesianToType(point, points), QVector3D(30.413812651491f, 1.4056476493803f, 0)); // first is radius, second theta
0448 }
0449 
0450 // TODO: implement Ternary
0451 
0452 // Test if setting curve points on the image result in correct values for Linear mapping
0453 void DatapickerTest::linearMapping() {
0454     Datapicker datapicker(QStringLiteral("Test"));
0455     auto* image = datapicker.image();
0456 
0457     // Set reference points
0458     datapicker.addNewPoint(QPointF(0, 1), image);
0459     datapicker.addNewPoint(QPointF(0, 0), image);
0460     datapicker.addNewPoint(QPointF(1, 0), image);
0461 
0462     auto ap = image->axisPoints();
0463     ap.type = DatapickerImage::GraphType::Linear;
0464     image->setAxisPoints(ap);
0465 
0466     DatapickerImageWidget w(nullptr);
0467     w.setImages({image});
0468     w.ui.sbPositionX1->setValue(0);
0469     w.ui.sbPositionY1->setValue(10);
0470     w.ui.sbPositionZ1->setValue(0);
0471     w.ui.sbPositionX2->setValue(0);
0472     w.ui.sbPositionY2->setValue(0);
0473     w.ui.sbPositionZ2->setValue(0);
0474     w.ui.sbPositionX3->setValue(10);
0475     w.ui.sbPositionY3->setValue(0);
0476     w.ui.sbPositionZ3->setValue(0);
0477     w.logicalPositionChanged();
0478 
0479     auto* curve = new DatapickerCurve(i18n("Curve"));
0480     curve->addDatasheet(image->axisPoints().type);
0481     datapicker.addChild(curve);
0482 
0483     datapicker.addNewPoint(QPointF(0.5, 0.5), curve); // updates the curve data
0484     VALUES_EQUAL(curve->posXColumn()->valueAt(0), 5.);
0485     VALUES_EQUAL(curve->posYColumn()->valueAt(0), 5.);
0486 
0487     datapicker.addNewPoint(QPointF(0.7, 0.65), curve); // updates the curve data
0488     VALUES_EQUAL(curve->posXColumn()->valueAt(1), 7.);
0489     VALUES_EQUAL(curve->posYColumn()->valueAt(1), 6.5);
0490 }
0491 
0492 // Test if setting curve points on the image result in correct values for lnX mapping
0493 void DatapickerTest::logarithmicNaturalXMapping() {
0494     Datapicker datapicker(QStringLiteral("Test"));
0495     auto* image = datapicker.image();
0496 
0497     // Set reference points
0498     datapicker.addNewPoint(QPointF(3, 10), image);
0499     datapicker.addNewPoint(QPointF(3, 0), image);
0500     datapicker.addNewPoint(QPointF(13, 0), image);
0501 
0502     auto ap = image->axisPoints();
0503     ap.type = DatapickerImage::GraphType::LnX;
0504     image->setAxisPoints(ap);
0505 
0506     DatapickerImageWidget w(nullptr);
0507     w.setImages({image});
0508     w.ui.sbPositionX1->setValue(0);
0509     w.ui.sbPositionY1->setValue(100);
0510     w.ui.sbPositionZ1->setValue(0);
0511     w.ui.sbPositionX2->setValue(0);
0512     w.ui.sbPositionY2->setValue(0);
0513     w.ui.sbPositionZ2->setValue(0);
0514     w.ui.sbPositionX3->setValue(100);
0515     w.ui.sbPositionY3->setValue(0);
0516     w.ui.sbPositionZ3->setValue(0);
0517     w.logicalPositionChanged();
0518 
0519     auto* curve = new DatapickerCurve(i18n("Curve"));
0520     curve->addDatasheet(image->axisPoints().type);
0521     datapicker.addChild(curve);
0522 
0523     datapicker.addNewPoint(QPointF(5, 6), curve); // updates the curve data
0524     VALUES_EQUAL(curve->posXColumn()->valueAt(0), 0.); // x start is zero, which is not valid therefore the result is 0
0525     VALUES_EQUAL(curve->posYColumn()->valueAt(0), 0.); // x start is zero, which is not valid therefore the result is 0
0526 
0527     QCOMPARE(w.ui.sbPositionX1->setValue(1), true);
0528     QCOMPARE(w.ui.sbPositionX2->setValue(1), true);
0529     w.ui.sbPositionX1->valueChanged(1); // axisPointsChanged will call updatePoint()
0530 
0531     // Value validated manually, not reverse calculated
0532     VALUES_EQUAL(curve->posXColumn()->valueAt(0), 2.51188635826);
0533     VALUES_EQUAL(curve->posYColumn()->valueAt(0), 60.);
0534 }
0535 
0536 // Test if setting curve points on the image result in correct values for lnY mapping
0537 void DatapickerTest::logarithmicNaturalYMapping() {
0538     Datapicker datapicker(QStringLiteral("Test"));
0539     auto* image = datapicker.image();
0540 
0541     // Set reference points
0542     datapicker.addNewPoint(QPointF(3, 10), image);
0543     datapicker.addNewPoint(QPointF(3, 0), image);
0544     datapicker.addNewPoint(QPointF(13, 0), image);
0545 
0546     auto ap = image->axisPoints();
0547     ap.type = DatapickerImage::GraphType::LnY;
0548     image->setAxisPoints(ap);
0549 
0550     DatapickerImageWidget w(nullptr);
0551     w.setImages({image});
0552     w.ui.sbPositionX1->setValue(0);
0553     w.ui.sbPositionY1->setValue(100);
0554     w.ui.sbPositionZ1->setValue(0);
0555     w.ui.sbPositionX2->setValue(0);
0556     w.ui.sbPositionY2->setValue(0);
0557     w.ui.sbPositionZ2->setValue(0);
0558     w.ui.sbPositionX3->setValue(100);
0559     w.ui.sbPositionY3->setValue(0);
0560     w.ui.sbPositionZ3->setValue(0);
0561     w.logicalPositionChanged();
0562 
0563     auto* curve = new DatapickerCurve(i18n("Curve"));
0564     curve->addDatasheet(image->axisPoints().type);
0565     datapicker.addChild(curve);
0566 
0567     datapicker.addNewPoint(QPointF(5, 6), curve); // updates the curve data
0568     VALUES_EQUAL(curve->posXColumn()->valueAt(0), 0.); // x start is zero, which is not valid therefore the result is 0
0569     VALUES_EQUAL(curve->posYColumn()->valueAt(0), 0.); // x start is zero, which is not valid therefore the result is 0
0570 
0571     QCOMPARE(w.ui.sbPositionY2->setValue(1), true); // axisPointsChanged will call updatePoint()
0572     QCOMPARE(w.ui.sbPositionY3->setValue(1), true); // axisPointsChanged will call updatePoint()
0573     w.ui.sbPositionY3->valueChanged(1); // axisPointsChanged will call updatePoint()
0574 
0575     VALUES_EQUAL(curve->posXColumn()->valueAt(0), 20.);
0576     // Value validated manually, not reverse calculated
0577     VALUES_EQUAL(curve->posYColumn()->valueAt(0), 15.8489322662);
0578 }
0579 
0580 // Test if setting curve points on the image result in correct values for lnXY mapping
0581 void DatapickerTest::logarithmicNaturalXYMapping() {
0582     Datapicker datapicker(QStringLiteral("Test"));
0583     auto* image = datapicker.image();
0584 
0585     // Set reference points
0586     datapicker.addNewPoint(QPointF(3, 10), image);
0587     datapicker.addNewPoint(QPointF(3, 0), image);
0588     datapicker.addNewPoint(QPointF(13, 0), image);
0589 
0590     auto ap = image->axisPoints();
0591     ap.type = DatapickerImage::GraphType::LnXY;
0592     image->setAxisPoints(ap);
0593 
0594     DatapickerImageWidget w(nullptr);
0595     w.setImages({image});
0596     w.ui.sbPositionX1->setValue(0);
0597     w.ui.sbPositionY1->setValue(100);
0598     w.ui.sbPositionZ1->setValue(0);
0599     w.ui.sbPositionX2->setValue(0);
0600     w.ui.sbPositionY2->setValue(0);
0601     w.ui.sbPositionZ2->setValue(0);
0602     w.ui.sbPositionX3->setValue(100);
0603     w.ui.sbPositionY3->setValue(0);
0604     w.ui.sbPositionZ3->setValue(0);
0605     w.logicalPositionChanged();
0606 
0607     auto* curve = new DatapickerCurve(i18n("Curve"));
0608     curve->addDatasheet(image->axisPoints().type);
0609     datapicker.addChild(curve);
0610 
0611     datapicker.addNewPoint(QPointF(5, 6), curve); // updates the curve data
0612     VALUES_EQUAL(curve->posXColumn()->valueAt(0), 0.); // x start is zero, which is not valid therefore the result is 0
0613     VALUES_EQUAL(curve->posYColumn()->valueAt(0), 0.); // x start is zero, which is not valid therefore the result is 0
0614 
0615     QCOMPARE(w.ui.sbPositionX1->setValue(1), true); // axisPointsChanged will call updatePoint()
0616     QCOMPARE(w.ui.sbPositionX2->setValue(1), true); // axisPointsChanged will call updatePoint()
0617     QCOMPARE(w.ui.sbPositionY2->setValue(1), true); // axisPointsChanged will call updatePoint()
0618     QCOMPARE(w.ui.sbPositionY3->setValue(1), true); // axisPointsChanged will call updatePoint()
0619     w.ui.sbPositionY1->valueChanged(1); // axisPointsChanged will call updatePoint()
0620 
0621     // Values validated manually, not reverse calculated
0622     VALUES_EQUAL(curve->posXColumn()->valueAt(0), 2.51188635826);
0623     VALUES_EQUAL(curve->posYColumn()->valueAt(0), 15.8489322662);
0624 }
0625 
0626 // Test if setting curve points on the image result in correct values for logX mapping
0627 void DatapickerTest::logarithmic10XMapping() {
0628     Datapicker datapicker(QStringLiteral("Test"));
0629     auto* image = datapicker.image();
0630 
0631     // Set reference points
0632     datapicker.addNewPoint(QPointF(3, 10), image);
0633     datapicker.addNewPoint(QPointF(3, 0), image);
0634     datapicker.addNewPoint(QPointF(13, 0), image);
0635 
0636     auto ap = image->axisPoints();
0637     ap.type = DatapickerImage::GraphType::Log10X;
0638     image->setAxisPoints(ap);
0639 
0640     DatapickerImageWidget w(nullptr);
0641     w.setImages({image});
0642     w.ui.sbPositionX1->setValue(0);
0643     w.ui.sbPositionY1->setValue(100);
0644     w.ui.sbPositionZ1->setValue(0);
0645     w.ui.sbPositionX2->setValue(0);
0646     w.ui.sbPositionY2->setValue(0);
0647     w.ui.sbPositionZ2->setValue(0);
0648     w.ui.sbPositionX3->setValue(100);
0649     w.ui.sbPositionY3->setValue(0);
0650     w.ui.sbPositionZ3->setValue(0);
0651     w.logicalPositionChanged();
0652 
0653     auto* curve = new DatapickerCurve(i18n("Curve"));
0654     curve->addDatasheet(image->axisPoints().type);
0655     datapicker.addChild(curve);
0656 
0657     datapicker.addNewPoint(QPointF(5, 6), curve); // updates the curve data
0658     VALUES_EQUAL(curve->posXColumn()->valueAt(0), 0.); // x start is zero, which is not valid therefore the result is 0
0659     VALUES_EQUAL(curve->posYColumn()->valueAt(0), 0.); // x start is zero, which is not valid therefore the result is 0
0660 
0661     QCOMPARE(w.ui.sbPositionX1->setValue(1), true);
0662     QCOMPARE(w.ui.sbPositionX2->setValue(1), true);
0663     w.ui.sbPositionX2->valueChanged(1);
0664     QCOMPARE(image->axisPoints().type, DatapickerImage::GraphType::Log10X);
0665 
0666     // Value validated manually, not reverse calculated
0667     VALUES_EQUAL(curve->posXColumn()->valueAt(0), 2.51188635826); // TODO: correct?
0668     VALUES_EQUAL(curve->posYColumn()->valueAt(0), 60.);
0669 }
0670 
0671 // Test if setting curve points on the image result in correct values for logY mapping
0672 void DatapickerTest::logarithmic10YMapping() {
0673     Datapicker datapicker(QStringLiteral("Test"));
0674     auto* image = datapicker.image();
0675 
0676     // Set reference points
0677     datapicker.addNewPoint(QPointF(3, 10), image);
0678     datapicker.addNewPoint(QPointF(3, 0), image);
0679     datapicker.addNewPoint(QPointF(13, 0), image);
0680 
0681     auto ap = image->axisPoints();
0682     ap.type = DatapickerImage::GraphType::Log10Y;
0683     image->setAxisPoints(ap);
0684 
0685     DatapickerImageWidget w(nullptr);
0686     w.setImages({image});
0687     w.ui.sbPositionX1->setValue(0);
0688     w.ui.sbPositionY1->setValue(100);
0689     w.ui.sbPositionZ1->setValue(0);
0690     w.ui.sbPositionX2->setValue(0);
0691     w.ui.sbPositionY2->setValue(0);
0692     w.ui.sbPositionZ2->setValue(0);
0693     w.ui.sbPositionX3->setValue(100);
0694     w.ui.sbPositionY3->setValue(0);
0695     w.ui.sbPositionZ3->setValue(0);
0696     w.logicalPositionChanged();
0697 
0698     auto* curve = new DatapickerCurve(i18n("Curve"));
0699     curve->addDatasheet(image->axisPoints().type);
0700     datapicker.addChild(curve);
0701 
0702     datapicker.addNewPoint(QPointF(5, 6), curve); // updates the curve data
0703     VALUES_EQUAL(curve->posXColumn()->valueAt(0), 0.); // x start is zero, which is not valid therefore the result is 0
0704     VALUES_EQUAL(curve->posYColumn()->valueAt(0), 0.); // x start is zero, which is not valid therefore the result is 0
0705 
0706     QCOMPARE(w.ui.sbPositionY2->setValue(1), true);
0707     QCOMPARE(w.ui.sbPositionY3->setValue(1), true);
0708     w.ui.sbPositionY3->valueChanged(1); // axisPointsChanged will call updatePoint()
0709     QCOMPARE(image->axisPoints().type, DatapickerImage::GraphType::Log10Y);
0710 
0711     VALUES_EQUAL(curve->posXColumn()->valueAt(0), 20.);
0712     // Value validated manually, not reverse calculated
0713     VALUES_EQUAL(curve->posYColumn()->valueAt(0), 15.8489322662);
0714 }
0715 
0716 // Test if setting curve points on the image result in correct values for logXY mapping
0717 void DatapickerTest::logarithmic10XYMapping() {
0718     Datapicker datapicker(QStringLiteral("Test"));
0719     auto* image = datapicker.image();
0720 
0721     // Set reference points
0722     datapicker.addNewPoint(QPointF(3, 10), image);
0723     datapicker.addNewPoint(QPointF(3, 0), image);
0724     datapicker.addNewPoint(QPointF(13, 0), image);
0725 
0726     auto ap = image->axisPoints();
0727     ap.type = DatapickerImage::GraphType::Log10XY;
0728     image->setAxisPoints(ap);
0729 
0730     DatapickerImageWidget w(nullptr);
0731     w.setImages({image});
0732     w.ui.sbPositionX1->setValue(0);
0733     w.ui.sbPositionY1->setValue(100);
0734     w.ui.sbPositionZ1->setValue(0);
0735     w.ui.sbPositionX2->setValue(0);
0736     w.ui.sbPositionY2->setValue(0);
0737     w.ui.sbPositionZ2->setValue(0);
0738     w.ui.sbPositionX3->setValue(100);
0739     w.ui.sbPositionY3->setValue(0);
0740     w.ui.sbPositionZ3->setValue(0);
0741     w.logicalPositionChanged();
0742 
0743     auto* curve = new DatapickerCurve(i18n("Curve"));
0744     curve->addDatasheet(image->axisPoints().type);
0745     datapicker.addChild(curve);
0746 
0747     datapicker.addNewPoint(QPointF(5, 6), curve); // updates the curve data
0748     VALUES_EQUAL(curve->posXColumn()->valueAt(0), 0.); // x start is zero, which is not valid therefore the result is 0
0749     VALUES_EQUAL(curve->posYColumn()->valueAt(0), 0.); // x start is zero, which is not valid therefore the result is 0
0750 
0751     QCOMPARE(w.ui.sbPositionX1->setValue(1), true);
0752     QCOMPARE(w.ui.sbPositionX2->setValue(1), true);
0753     QCOMPARE(w.ui.sbPositionY2->setValue(1), true);
0754     QCOMPARE(w.ui.sbPositionY3->setValue(1), true);
0755     w.ui.sbPositionY3->valueChanged(1); // axisPointsChanged will call updatePoint()
0756     // Values validated manually, not reverse calculated
0757     VALUES_EQUAL(curve->posXColumn()->valueAt(0), 2.51188635826);
0758     VALUES_EQUAL(curve->posYColumn()->valueAt(0), 15.8489322662);
0759 }
0760 
0761 /*!
0762  * check the correctness of the data points after one of the reference points was moved on the scene.
0763  * In real this is not possible, because it is not implemented, but neverthless it shall be shown
0764  * that when moving reference points, the curves will be updated
0765  */
0766 void DatapickerTest::referenceMove() {
0767     Datapicker datapicker(QStringLiteral("Test"));
0768     datapicker.addNewPoint(QPointF(0, 1), datapicker.image());
0769     datapicker.addNewPoint(QPointF(0, 0), datapicker.image());
0770     datapicker.addNewPoint(QPointF(1, 0), datapicker.image());
0771 
0772     auto ap = datapicker.image()->axisPoints();
0773     ap.type = DatapickerImage::GraphType::Linear;
0774     datapicker.image()->setAxisPoints(ap);
0775 
0776     DatapickerImageWidget w(nullptr);
0777     w.setImages({datapicker.image()});
0778     w.ui.sbPositionX1->setValue(0);
0779     w.ui.sbPositionY1->setValue(10);
0780     w.ui.sbPositionZ1->setValue(0);
0781     w.ui.sbPositionX2->setValue(0);
0782     w.ui.sbPositionY2->setValue(0);
0783     w.ui.sbPositionZ2->setValue(0);
0784     w.ui.sbPositionX3->setValue(10);
0785     w.ui.sbPositionY3->setValue(0);
0786     w.ui.sbPositionZ3->setValue(0);
0787     w.logicalPositionChanged();
0788 
0789     auto* curve = new DatapickerCurve(i18n("Curve"));
0790     curve->addDatasheet(datapicker.image()->axisPoints().type);
0791     datapicker.addChild(curve);
0792 
0793     datapicker.addNewPoint(QPointF(0.5, 0.6), curve); // updates the curve data
0794     VALUES_EQUAL(curve->posXColumn()->valueAt(0), 5.);
0795     VALUES_EQUAL(curve->posYColumn()->valueAt(0), 6.);
0796 
0797     // Points are stored in the image
0798     auto points = datapicker.image()->children<DatapickerPoint>(AbstractAspect::ChildIndexFlag::IncludeHidden);
0799     QCOMPARE(points.count(), 3);
0800 
0801     // set position after mouse was released
0802     points[0]->setPosition(QPointF(0., 4));
0803     // points[1]->setPosition(QPointF(0.1, 0.));
0804     points[2]->setPosition(QPointF(2., 0.));
0805 
0806     // Currently not supported
0807     //    VALUES_EQUAL(curve->posXColumn()->valueAt(0), 0.5 / 2 * 10);
0808     //    VALUES_EQUAL(curve->posYColumn()->valueAt(0), 0.6 / 4  * 10);
0809 }
0810 
0811 void DatapickerTest::referenceMoveKeyPress() {
0812     Datapicker datapicker(QStringLiteral("Test"));
0813     datapicker.addNewPoint(QPointF(0, 1), datapicker.image());
0814     datapicker.addNewPoint(QPointF(0, 0), datapicker.image());
0815     datapicker.addNewPoint(QPointF(1, 0), datapicker.image());
0816 
0817     auto ap = datapicker.image()->axisPoints();
0818     ap.type = DatapickerImage::GraphType::Linear;
0819     datapicker.image()->setAxisPoints(ap);
0820 
0821     DatapickerImageWidget w(nullptr);
0822     w.setImages({datapicker.image()});
0823     w.ui.sbPositionX1->setValue(0);
0824     w.ui.sbPositionY1->setValue(10);
0825     w.ui.sbPositionZ1->setValue(0);
0826     w.ui.sbPositionX2->setValue(0);
0827     w.ui.sbPositionY2->setValue(0);
0828     w.ui.sbPositionZ2->setValue(0);
0829     w.ui.sbPositionX3->setValue(10);
0830     w.ui.sbPositionY3->setValue(0);
0831     w.ui.sbPositionZ3->setValue(0);
0832     w.logicalPositionChanged();
0833 
0834     auto* curve = new DatapickerCurve(i18n("Curve"));
0835     curve->addDatasheet(datapicker.image()->axisPoints().type);
0836     datapicker.addChild(curve);
0837 
0838     datapicker.addNewPoint(QPointF(0.5, 0.6), curve); // (scene coordinates) updates the curve data
0839     VALUES_EQUAL(curve->posXColumn()->valueAt(0), 5.);
0840     VALUES_EQUAL(curve->posYColumn()->valueAt(0), 6.);
0841 
0842     // Points are stored in the image
0843     auto points = datapicker.image()->children<DatapickerPoint>(AbstractAspect::ChildIndexFlag::IncludeHidden);
0844     QCOMPARE(points.count(), 3);
0845 
0846     points[0]->d_ptr->setSelected(false);
0847     points[1]->d_ptr->setSelected(false);
0848     points[2]->d_ptr->setSelected(true);
0849     auto view = static_cast<DatapickerImageView*>(datapicker.image()->view());
0850     view->shiftLeftAction->triggered(true);
0851 
0852     VALUES_EQUAL(points[0]->position().x(), 0.);
0853     VALUES_EQUAL(points[1]->position().x(), 0.);
0854     VALUES_EQUAL(points[2]->position().x(), 2.);
0855 
0856     VALUES_EQUAL(curve->posXColumn()->valueAt(0), 0.5 / 2 * 10);
0857     VALUES_EQUAL(curve->posYColumn()->valueAt(0), 6.);
0858 }
0859 
0860 /*!
0861  * check the correctness of the data point after the point was moved on the scene.
0862  */
0863 void DatapickerTest::curvePointMove() {
0864     Datapicker datapicker(QStringLiteral("Test"));
0865     auto* image = datapicker.image();
0866 
0867     // add reference points
0868     datapicker.addNewPoint(QPointF(0, 1), image);
0869     datapicker.addNewPoint(QPointF(0, 0), image);
0870     datapicker.addNewPoint(QPointF(1, 0), image);
0871 
0872     auto ap = image->axisPoints();
0873     ap.type = DatapickerImage::GraphType::Linear;
0874     image->setAxisPoints(ap);
0875 
0876     // set logical coordinates for the reference points
0877     DatapickerImageWidget w(nullptr);
0878     w.setImages({image});
0879     w.ui.sbPositionX1->setValue(0);
0880     w.ui.sbPositionY1->setValue(10);
0881     w.ui.sbPositionZ1->setValue(0);
0882     w.ui.sbPositionX2->setValue(0);
0883     w.ui.sbPositionY2->setValue(0);
0884     w.ui.sbPositionZ2->setValue(0);
0885     w.ui.sbPositionX3->setValue(10);
0886     w.ui.sbPositionY3->setValue(0);
0887     w.ui.sbPositionZ3->setValue(0);
0888     w.logicalPositionChanged();
0889 
0890     auto* curve = new DatapickerCurve(i18n("Curve"));
0891     curve->addDatasheet(image->axisPoints().type);
0892     datapicker.addChild(curve);
0893 
0894     // add new curve point and check its logical coordinates
0895     datapicker.addNewPoint(QPointF(0.5, 0.6), curve);
0896     VALUES_EQUAL(curve->posXColumn()->valueAt(0), 5.);
0897     VALUES_EQUAL(curve->posYColumn()->valueAt(0), 6.);
0898 
0899     // move the last added point to a new position and check its logical coordinates again
0900     auto points = curve->children<DatapickerPoint>(AbstractAspect::ChildIndexFlag::IncludeHidden);
0901     QCOMPARE(points.count(), 1);
0902     points[0]->setPosition(QPointF(0.2, 0.9)); // Changing the position of the point
0903     VALUES_EQUAL(curve->posXColumn()->valueAt(0), 2.);
0904     VALUES_EQUAL(curve->posYColumn()->valueAt(0), 9.);
0905 }
0906 
0907 /*!
0908  * check the correctness of the data point after the point was moved on the scene with undo and redo after this.
0909  */
0910 void DatapickerTest::curvePointMoveUndoRedo() {
0911     Project project;
0912     auto* datapicker = new Datapicker(QStringLiteral("Test"));
0913     project.addChild(datapicker);
0914     auto* image = datapicker->image();
0915 
0916     // add reference points
0917     datapicker->addNewPoint(QPointF(0, 1), image);
0918     datapicker->addNewPoint(QPointF(0, 0), image);
0919     datapicker->addNewPoint(QPointF(1, 0), image);
0920 
0921     auto ap = image->axisPoints();
0922     ap.type = DatapickerImage::GraphType::Linear;
0923     image->setAxisPoints(ap);
0924 
0925     // set logical coordinates for the reference points
0926     DatapickerImageWidget w(nullptr);
0927     w.setImages({image});
0928     w.ui.sbPositionX1->setValue(0);
0929     w.ui.sbPositionY1->setValue(10);
0930     w.ui.sbPositionZ1->setValue(0);
0931     w.ui.sbPositionX2->setValue(0);
0932     w.ui.sbPositionY2->setValue(0);
0933     w.ui.sbPositionZ2->setValue(0);
0934     w.ui.sbPositionX3->setValue(10);
0935     w.ui.sbPositionY3->setValue(0);
0936     w.ui.sbPositionZ3->setValue(0);
0937     w.logicalPositionChanged();
0938 
0939     auto* curve = new DatapickerCurve(i18n("Curve"));
0940     curve->addDatasheet(image->axisPoints().type);
0941     datapicker->addChild(curve);
0942 
0943     // add new curve point and check its logical coordinates
0944     datapicker->addNewPoint(QPointF(0.5, 0.6), curve);
0945     VALUES_EQUAL(curve->posXColumn()->valueAt(0), 5.);
0946     VALUES_EQUAL(curve->posYColumn()->valueAt(0), 6.);
0947 
0948     // move the last added point to a new position and check its logical coordinates again
0949     auto points = curve->children<DatapickerPoint>(AbstractAspect::ChildIndexFlag::IncludeHidden);
0950     QCOMPARE(points.count(), 1);
0951     points[0]->setPosition(QPointF(0.2, 0.9)); // Changing the position of the point
0952     VALUES_EQUAL(curve->posXColumn()->valueAt(0), 2.);
0953     VALUES_EQUAL(curve->posYColumn()->valueAt(0), 9.);
0954 
0955     // undo the move step and check the position again
0956     auto* undoStack = project.undoStack();
0957     undoStack->undo();
0958     points = curve->children<DatapickerPoint>(AbstractAspect::ChildIndexFlag::IncludeHidden);
0959     QCOMPARE(points.count(), 1);
0960     QCOMPARE(points[0]->position(), QPointF(0.5, 0.6));
0961     VALUES_EQUAL(curve->posXColumn()->valueAt(0), 5.);
0962     VALUES_EQUAL(curve->posYColumn()->valueAt(0), 6.);
0963 
0964     // redo the last step and check the position again
0965     undoStack->redo();
0966     points = curve->children<DatapickerPoint>(AbstractAspect::ChildIndexFlag::IncludeHidden);
0967     QCOMPARE(points.count(), 1);
0968     QCOMPARE(points[0]->position(), QPointF(0.2, 0.9));
0969     VALUES_EQUAL(curve->posXColumn()->valueAt(0), 2.);
0970     VALUES_EQUAL(curve->posYColumn()->valueAt(0), 9.);
0971 }
0972 
0973 void DatapickerTest::selectReferencePoint() {
0974     Datapicker datapicker(QStringLiteral("Test"));
0975     auto* image = datapicker.image();
0976 
0977     // Set reference points
0978     datapicker.addNewPoint(QPointF(0, 1), image);
0979     datapicker.addNewPoint(QPointF(0, 0), image);
0980     datapicker.addNewPoint(QPointF(1, 0), image);
0981 
0982     auto ap = image->axisPoints();
0983     ap.type = DatapickerImage::GraphType::Linear;
0984     image->setAxisPoints(ap);
0985 
0986     DatapickerImageWidget w(nullptr);
0987     w.setImages({image});
0988 
0989     QCOMPARE(w.ui.rbRefPoint1->isChecked(), false);
0990     QCOMPARE(w.ui.rbRefPoint2->isChecked(), false);
0991     QCOMPARE(w.ui.rbRefPoint3->isChecked(), false);
0992 
0993     auto points = image->children<DatapickerPoint>(AbstractAspect::ChildIndexFlag::IncludeHidden);
0994     QCOMPARE(points.count(), 3);
0995 
0996     // Change reference point selection
0997     points[0]->pointSelected(points[0]);
0998     QCOMPARE(w.ui.rbRefPoint1->isChecked(), true);
0999     QCOMPARE(w.ui.rbRefPoint2->isChecked(), false);
1000     QCOMPARE(w.ui.rbRefPoint3->isChecked(), false);
1001 
1002     points[1]->pointSelected(points[1]);
1003     QCOMPARE(w.ui.rbRefPoint1->isChecked(), false);
1004     QCOMPARE(w.ui.rbRefPoint2->isChecked(), true);
1005     QCOMPARE(w.ui.rbRefPoint3->isChecked(), false);
1006 
1007     points[2]->pointSelected(points[2]);
1008     QCOMPARE(w.ui.rbRefPoint1->isChecked(), false);
1009     QCOMPARE(w.ui.rbRefPoint2->isChecked(), false);
1010     QCOMPARE(w.ui.rbRefPoint3->isChecked(), true);
1011 }
1012 
1013 void DatapickerTest::imageAxisPointsChanged() {
1014     DatapickerImageWidget w(nullptr);
1015     Datapicker datapicker(QStringLiteral("Test"));
1016     auto* image = datapicker.image();
1017     w.setImages({image});
1018 
1019     DatapickerImage::ReferencePoints points;
1020     points.logicalPos[0] = Vector3D(-1., 2., 4.);
1021     points.logicalPos[1] = Vector3D(-5., -867., 236.);
1022     points.logicalPos[2] = Vector3D(43., -231.2f, 234.);
1023     points.scenePos[0] = QPointF(-3, 2);
1024     points.scenePos[1] = QPointF(-291, 3249);
1025     points.scenePos[2] = QPointF(-239, 349);
1026     points.ternaryScale = -23;
1027 
1028     points.type = DatapickerImage::GraphType::Linear;
1029     w.imageAxisPointsChanged(points);
1030     QCOMPARE(static_cast<DatapickerImage::GraphType>(w.ui.cbGraphType->currentData().toInt()), DatapickerImage::GraphType::Linear);
1031 
1032     points.type = DatapickerImage::GraphType::PolarInDegree;
1033     w.imageAxisPointsChanged(points);
1034     QCOMPARE(static_cast<DatapickerImage::GraphType>(w.ui.cbGraphType->currentData().toInt()), DatapickerImage::GraphType::PolarInDegree);
1035 
1036     points.type = DatapickerImage::GraphType::PolarInRadians;
1037     w.imageAxisPointsChanged(points);
1038     QCOMPARE(static_cast<DatapickerImage::GraphType>(w.ui.cbGraphType->currentData().toInt()), DatapickerImage::GraphType::PolarInRadians);
1039 
1040     points.type = DatapickerImage::GraphType::LnX;
1041     w.imageAxisPointsChanged(points);
1042     QCOMPARE(static_cast<DatapickerImage::GraphType>(w.ui.cbGraphType->currentData().toInt()), DatapickerImage::GraphType::LnX);
1043 
1044     points.type = DatapickerImage::GraphType::LnY;
1045     w.imageAxisPointsChanged(points);
1046     QCOMPARE(static_cast<DatapickerImage::GraphType>(w.ui.cbGraphType->currentData().toInt()), DatapickerImage::GraphType::LnY);
1047 
1048     points.type = DatapickerImage::GraphType::Ternary;
1049     w.imageAxisPointsChanged(points);
1050     QCOMPARE(static_cast<DatapickerImage::GraphType>(w.ui.cbGraphType->currentData().toInt()), DatapickerImage::GraphType::Ternary);
1051 
1052     points.type = DatapickerImage::GraphType::LnXY;
1053     w.imageAxisPointsChanged(points);
1054     QCOMPARE(static_cast<DatapickerImage::GraphType>(w.ui.cbGraphType->currentData().toInt()), DatapickerImage::GraphType::LnXY);
1055 
1056     points.type = DatapickerImage::GraphType::Log10XY;
1057     w.imageAxisPointsChanged(points);
1058     QCOMPARE(static_cast<DatapickerImage::GraphType>(w.ui.cbGraphType->currentData().toInt()), DatapickerImage::GraphType::Log10XY);
1059 
1060     points.type = DatapickerImage::GraphType::Log10X;
1061     w.imageAxisPointsChanged(points);
1062     QCOMPARE(static_cast<DatapickerImage::GraphType>(w.ui.cbGraphType->currentData().toInt()), DatapickerImage::GraphType::Log10X);
1063 
1064     points.type = DatapickerImage::GraphType::Log10Y;
1065     w.imageAxisPointsChanged(points);
1066     QCOMPARE(static_cast<DatapickerImage::GraphType>(w.ui.cbGraphType->currentData().toInt()), DatapickerImage::GraphType::Log10Y);
1067 }
1068 
1069 void DatapickerTest::datapickerDateTime() {
1070     DatapickerImageWidget w(nullptr);
1071     Datapicker datapicker(QStringLiteral("Test"));
1072     auto* image = datapicker.image();
1073     image->setImage(createImage(), QStringLiteral("Image"), true);
1074 
1075     // add reference points
1076     datapicker.addNewPoint(QPointF(0., 1.), image); // scene coordinates
1077     datapicker.addNewPoint(QPointF(0., 0.), image); // scene coordinates
1078     datapicker.addNewPoint(QPointF(1., 0.), image); // scene coordinates
1079 
1080     w.setImages({image});
1081 
1082     w.ui.sbPositionX1->setValue(0);
1083     w.ui.sbPositionY1->setValue(10.);
1084     w.ui.sbPositionZ1->setValue(0);
1085     w.ui.sbPositionX2->setValue(0);
1086     w.ui.sbPositionY2->setValue(0);
1087     w.ui.sbPositionZ2->setValue(0);
1088     w.ui.sbPositionX3->setValue(10.);
1089     w.ui.sbPositionY3->setValue(0);
1090     w.ui.sbPositionZ3->setValue(0);
1091     w.logicalPositionChanged();
1092 
1093     auto* curve = new DatapickerCurve(i18n("Curve"));
1094     curve->addDatasheet(image->axisPoints().type);
1095     datapicker.addChild(curve);
1096 
1097     // add new curve point and check its logical coordinates
1098     datapicker.addNewPoint(QPointF(0.5, 0.6), curve); // scene coordinates
1099     VALUES_EQUAL(curve->posXColumn()->valueAt(0), 5.); // logical coordinates
1100     VALUES_EQUAL(curve->posYColumn()->valueAt(0), 6.); // logical coordinates
1101 
1102     QCOMPARE(w.ui.cbDatetime->isChecked(), false);
1103     QCOMPARE(w.ui.dtePositionX1->isVisible(), false);
1104     QCOMPARE(w.ui.dtePositionX2->isVisible(), false);
1105     QCOMPARE(w.ui.dtePositionX3->isVisible(), false);
1106     // QCOMPARE(w.ui.sbPositionX1->isVisible(), true); // Not possible if no MainWin?
1107     // QCOMPARE(w.ui.sbPositionX2->isVisible(), true);
1108     // QCOMPARE(w.ui.sbPositionX3->isVisible(), true);
1109 
1110     QCOMPARE(curve->posXColumn()->columnMode(), AbstractColumn::ColumnMode::Double);
1111 
1112     QCOMPARE(w.ui.cbDatetime->isEnabled(), true);
1113     w.ui.cbDatetime->clicked(true);
1114 
1115     // QCOMPARE(w.ui.cbDatetime->isChecked(), true);
1116     // QCOMPARE(w.ui.dtePositionX1->isVisible(), true);
1117     // QCOMPARE(w.ui.dtePositionX2->isVisible(), true);
1118     // QCOMPARE(w.ui.dtePositionX3->isVisible(), true);
1119     QCOMPARE(w.ui.sbPositionX1->isVisible(), false);
1120     QCOMPARE(w.ui.sbPositionX2->isVisible(), false);
1121     QCOMPARE(w.ui.sbPositionX3->isVisible(), false);
1122 
1123     QDateTime dt1 = QDateTime::fromString(QLatin1String("2000-12-01 00:00:00:000Z"), QStringLiteral("yyyy-MM-dd hh:mm:ss:zzzt"));
1124     QDateTime dt2 = QDateTime::fromString(QLatin1String("2000-12-01 00:00:00:000Z"), QStringLiteral("yyyy-MM-dd hh:mm:ss:zzzt"));
1125     QDateTime dt3 = QDateTime::fromString(QLatin1String("2000-12-01 06:00:00:000Z"), QStringLiteral("yyyy-MM-dd hh:mm:ss:zzzt"));
1126     w.ui.dtePositionX1->setMSecsSinceEpochUTC(dt1.toMSecsSinceEpoch());
1127     w.ui.dtePositionX2->setMSecsSinceEpochUTC(dt2.toMSecsSinceEpoch());
1128     w.ui.dtePositionX3->setMSecsSinceEpochUTC(dt3.toMSecsSinceEpoch());
1129 
1130     QCOMPARE(curve->posXColumn()->rowCount(), 1);
1131     QCOMPARE(curve->posXColumn()->columnMode(), AbstractColumn::ColumnMode::DateTime);
1132 #if !defined(_WIN32)
1133     QCOMPARE(curve->posXColumn()->dateTimeAt(0),
1134              QDateTime::fromString(QLatin1String("2000-12-01 03:00:00:000Z"), QStringLiteral("yyyy-MM-dd hh:mm:ss:zzzt"))); // logical coordinates
1135 #endif
1136     QCOMPARE(curve->posYColumn()->rowCount(), 1);
1137     VALUES_EQUAL(curve->posYColumn()->valueAt(0), 6.); // logical coordinates
1138 }
1139 
1140 void DatapickerTest::datapickerDeleteCurvePoint() {
1141     DatapickerImageWidget w(nullptr);
1142     Datapicker datapicker(QStringLiteral("Test"));
1143     auto* image = datapicker.image();
1144 
1145     // add reference points
1146     datapicker.addNewPoint(QPointF(0, 1), image); // scene coordinates
1147     datapicker.addNewPoint(QPointF(0, 0), image); // scene coordinates
1148     datapicker.addNewPoint(QPointF(1, 0), image); // scene coordinates
1149 
1150     w.setImages({image});
1151 
1152     w.ui.sbPositionX1->setValue(0);
1153     w.ui.sbPositionY1->setValue(10.);
1154     w.ui.sbPositionZ1->setValue(0);
1155     w.ui.sbPositionX2->setValue(0);
1156     w.ui.sbPositionY2->setValue(0);
1157     w.ui.sbPositionZ2->setValue(0);
1158     w.ui.sbPositionX3->setValue(10.);
1159     w.ui.sbPositionY3->setValue(0);
1160     w.ui.sbPositionZ3->setValue(0);
1161     w.logicalPositionChanged();
1162 
1163     auto* curve = new DatapickerCurve(i18n("Curve"));
1164     curve->addDatasheet(image->axisPoints().type);
1165     datapicker.addChild(curve);
1166 
1167     // add new curve point and check its logical coordinates
1168     datapicker.addNewPoint(QPointF(0.5, 0.6), curve); // scene coordinates
1169     QCOMPARE(curve->posXColumn()->rowCount(), 1);
1170     QCOMPARE(curve->posYColumn()->rowCount(), 1);
1171 
1172     datapicker.addNewPoint(QPointF(0.5, 0.7), curve); // scene coordinates
1173     QCOMPARE(curve->posXColumn()->rowCount(), 2);
1174     QCOMPARE(curve->posYColumn()->rowCount(), 2);
1175 
1176     auto points = curve->children<DatapickerPoint>(AbstractAspect::ChildIndexFlag::IncludeHidden);
1177     QCOMPARE(points.count(), 2);
1178 
1179     points.at(0)->remove();
1180 
1181     QCOMPARE(curve->posXColumn()->rowCount(), 1);
1182     QCOMPARE(curve->posYColumn()->rowCount(), 1);
1183 }
1184 
1185 void DatapickerTest::datapickerImageLoadImageAbsolute() {
1186     QString savePath;
1187     QString imgFileName;
1188     {
1189         QTemporaryFile imgFile(QStringLiteral("Testimage_XXXXXX.png"));
1190         const auto img = createImage();
1191         QVERIFY(imgFile.open());
1192         imgFileName = imgFile.fileName();
1193         QVERIFY(img.save(imgFileName, "PNG"));
1194         QVERIFY(QFile::exists(imgFile.fileName()));
1195 
1196         {
1197             Project project;
1198             auto* datapicker = new Datapicker(QStringLiteral("Test"));
1199             project.addChild(datapicker);
1200             auto* image = datapicker->image();
1201 
1202             DatapickerImageWidget w(nullptr);
1203             w.setImages({image});
1204 
1205             QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), false);
1206             QCOMPARE(w.ui.cbFileRelativePath->isEnabled(), false);
1207             QCOMPARE(w.ui.cbFileEmbedd->isChecked(), false);
1208             QCOMPARE(w.ui.cbFileRelativePath->isChecked(), false);
1209 
1210             w.ui.leFileName->setText(imgFileName);
1211             // w.fileNameChanged(); will be called
1212 
1213             QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), true);
1214             QCOMPARE(w.ui.cbFileRelativePath->isEnabled(), false); // project is not saved
1215             QCOMPARE(w.ui.cbFileEmbedd->isChecked(), false);
1216             QCOMPARE(w.ui.cbFileRelativePath->isChecked(), false);
1217 
1218             QCOMPARE(image->fileName(), imgFile.fileName());
1219             QCOMPARE(image->originalPlotImage.isNull(), false); // valid image loaded
1220             QCOMPARE(w.ui.leFileName->text(), imgFile.fileName());
1221             QCOMPARE(w.ui.leFileName->styleSheet(), QStringLiteral("")); // Valid image
1222 
1223             SAVE_PROJECT("DatapickerTestProject");
1224 
1225             QCOMPARE(w.ui.cbFileRelativePath->isEnabled(), true); // project is now saved so calculating the relative path is possible
1226         }
1227 
1228         // Load project
1229         {
1230             Project project;
1231             QCOMPARE(project.load(savePath), true);
1232 
1233             auto datapicker = project.child<Datapicker>(0);
1234             QVERIFY(datapicker);
1235             auto* image = datapicker->image();
1236 
1237             DatapickerImageWidget w(nullptr);
1238             w.setImages({image});
1239 
1240             QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), true);
1241             QCOMPARE(w.ui.cbFileRelativePath->isEnabled(), true); // project was loaded
1242             QCOMPARE(w.ui.cbFileEmbedd->isChecked(), false);
1243             QCOMPARE(w.ui.cbFileRelativePath->isChecked(), false);
1244 
1245             QCOMPARE(image->fileName(), imgFileName);
1246             QCOMPARE(image->originalPlotImage.isNull(), false); // valid image loaded
1247             QCOMPARE(w.ui.leFileName->text(), imgFileName);
1248             QCOMPARE(w.ui.leFileName->styleSheet(), QStringLiteral("")); // Valid image
1249         }
1250     }
1251 
1252     // Deleting image
1253     QCOMPARE(QFile::exists(imgFileName), false); // Deleted because QTemporaryFile goes out of scope
1254     //  QFile f(imgFileName.fileName());
1255     //  QVERIFY(f.remove()); // Does not work on windows, see MR for more info
1256 
1257     // Load project
1258     {
1259         Project project;
1260         QCOMPARE(project.load(savePath), true);
1261 
1262         auto datapicker = project.child<Datapicker>(0);
1263         QVERIFY(datapicker);
1264         auto* image = datapicker->image();
1265 
1266         DatapickerImageWidget w(nullptr);
1267         w.setImages({image});
1268 
1269         QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), false); // image is invalid, because it is anymore available
1270         QCOMPARE(w.ui.cbFileRelativePath->isEnabled(), false); // image is invalid
1271         QCOMPARE(w.ui.cbFileEmbedd->isChecked(), false);
1272         QCOMPARE(w.ui.cbFileRelativePath->isChecked(), false);
1273 
1274         QCOMPARE(image->fileName(), imgFileName);
1275         QCOMPARE(image->originalPlotImage.isNull(), true); // invalid image loaded
1276         QCOMPARE(w.ui.leFileName->text(), imgFileName);
1277         QVERIFY(w.ui.leFileName->styleSheet() != QStringLiteral("")); // Invalid image
1278     }
1279 }
1280 
1281 void DatapickerTest::datapickerImageLoadImageRelative() {
1282     QString savePath;
1283     QString imgFileName;
1284     {
1285         const auto img = createImage();
1286 
1287         QTemporaryFile imgFile(QStringLiteral("Testimage_XXXXXX.png"));
1288         QVERIFY(imgFile.open());
1289         imgFileName = imgFile.fileName();
1290         img.save(imgFileName, "PNG");
1291         QVERIFY(QFile::exists(imgFileName));
1292         {
1293             Project project;
1294             auto* datapicker = new Datapicker(QStringLiteral("Test"));
1295             project.addChild(datapicker);
1296             auto* image = datapicker->image();
1297 
1298             DatapickerImageWidget w(nullptr);
1299             w.setImages({image});
1300 
1301             QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), false);
1302             QCOMPARE(w.ui.cbFileRelativePath->isEnabled(), false);
1303             QCOMPARE(w.ui.cbFileEmbedd->isChecked(), false);
1304             QCOMPARE(w.ui.cbFileRelativePath->isChecked(), false);
1305 
1306             w.ui.leFileName->setText(imgFileName);
1307             // w.fileNameChanged(); will be called
1308 
1309             QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), true);
1310             QCOMPARE(w.ui.cbFileRelativePath->isEnabled(), false); // project is not saved
1311             QCOMPARE(w.ui.cbFileEmbedd->isChecked(), false);
1312             QCOMPARE(w.ui.cbFileRelativePath->isChecked(), false);
1313 
1314             QCOMPARE(image->fileName(), imgFileName);
1315             QCOMPARE(image->originalPlotImage.isNull(), false); // valid image loaded
1316             QCOMPARE(w.ui.leFileName->text(), imgFileName);
1317             QCOMPARE(w.ui.leFileName->styleSheet(), QStringLiteral("")); // Valid image
1318 
1319             SAVE_PROJECT("DatapickerTestProject");
1320 
1321             QCOMPARE(w.ui.cbFileRelativePath->isEnabled(), true); // project is now saved so calculating the relative path is possible
1322 
1323             w.ui.cbFileRelativePath->clicked(true);
1324 
1325             // QCOMPARE(w.ui.cbFileRelativePath->isChecked(), true);
1326             QFileInfo fi(imgFile);
1327             QCOMPARE(image->fileName(), fi.fileName());
1328             QCOMPARE(w.ui.leFileName->text(), fi.fileName());
1329 
1330             SAVE_PROJECT("DatapickerTestProject"); // Save again to save relative path
1331         }
1332 
1333         // Load project
1334         {
1335             Project project;
1336             QCOMPARE(project.load(savePath), true);
1337 
1338             auto datapicker = project.child<Datapicker>(0);
1339             QVERIFY(datapicker);
1340             auto* image = datapicker->image();
1341 
1342             DatapickerImageWidget w(nullptr);
1343             w.setImages({image});
1344 
1345             QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), true);
1346             QCOMPARE(w.ui.cbFileRelativePath->isEnabled(), true); // project was loaded
1347             QCOMPARE(w.ui.cbFileEmbedd->isChecked(), false);
1348             QCOMPARE(w.ui.cbFileRelativePath->isChecked(), true);
1349 
1350             QFileInfo fi(imgFileName);
1351             QCOMPARE(image->fileName(), fi.fileName());
1352             QCOMPARE(image->originalPlotImage.isNull(), false); // valid image loaded
1353             QCOMPARE(w.ui.leFileName->text(), fi.fileName());
1354             QCOMPARE(w.ui.leFileName->styleSheet(), QStringLiteral("")); // Valid image
1355         }
1356     }
1357 
1358     // Deleting image
1359     QCOMPARE(QFile::exists(imgFileName), false); // Deleted because QTemporaryFile goes out of scope
1360     //  QFile f(imgFileName.fileName());
1361     //  QVERIFY(f.remove()); // Does not work on windows, see MR for more info
1362 
1363     // Load project
1364     {
1365         Project project;
1366         QCOMPARE(project.load(savePath), true);
1367 
1368         auto datapicker = project.child<Datapicker>(0);
1369         QVERIFY(datapicker);
1370         auto* image = datapicker->image();
1371 
1372         DatapickerImageWidget w(nullptr);
1373         w.setImages({image});
1374 
1375         QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), false); // image is invalid, because it is anymore available
1376         QCOMPARE(w.ui.cbFileRelativePath->isEnabled(), false); // image is invalid
1377         QCOMPARE(w.ui.cbFileEmbedd->isChecked(), false);
1378         QCOMPARE(w.ui.cbFileRelativePath->isChecked(), true);
1379 
1380         QFileInfo fi(imgFileName);
1381         QCOMPARE(image->fileName(), fi.fileName());
1382         QCOMPARE(image->originalPlotImage.isNull(), true); // invalid image loaded
1383         QCOMPARE(w.ui.leFileName->text(), fi.fileName());
1384         QVERIFY(w.ui.leFileName->styleSheet() != QStringLiteral("")); // Invalid image
1385     }
1386 }
1387 
1388 void DatapickerTest::datapickerImageLoadImageEmbeddAbsolute() {
1389     QString savePath;
1390     QString imgFileName;
1391 
1392     {
1393         const auto img = createImage();
1394 
1395         QTemporaryFile imgFile(QStringLiteral("Testimage_XXXXXX.png"));
1396         QVERIFY(imgFile.open());
1397         imgFileName = imgFile.fileName();
1398         img.save(imgFileName, "PNG");
1399         QVERIFY(QFile::exists(imgFileName));
1400 
1401         Project project;
1402         auto* datapicker = new Datapicker(QStringLiteral("Test"));
1403         project.addChild(datapicker);
1404         auto* image = datapicker->image();
1405 
1406         DatapickerImageWidget w(nullptr);
1407         w.setImages({image});
1408 
1409         QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), false);
1410         QCOMPARE(w.ui.cbFileRelativePath->isEnabled(), false);
1411         QCOMPARE(w.ui.cbFileEmbedd->isChecked(), false);
1412         QCOMPARE(w.ui.cbFileRelativePath->isChecked(), false);
1413 
1414         w.ui.leFileName->setText(imgFileName);
1415         // w.fileNameChanged(); will be called
1416 
1417         QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), true);
1418         QCOMPARE(w.ui.cbFileRelativePath->isEnabled(), false); // project is not saved
1419         QCOMPARE(w.ui.cbFileEmbedd->isChecked(), false);
1420         QCOMPARE(w.ui.cbFileRelativePath->isChecked(), false);
1421 
1422         QCOMPARE(image->fileName(), imgFileName);
1423         QCOMPARE(image->originalPlotImage.isNull(), false); // valid image loaded
1424         QCOMPARE(w.ui.leFileName->text(), imgFileName);
1425         QCOMPARE(w.ui.leFileName->styleSheet(), QStringLiteral("")); // Valid image
1426 
1427         w.ui.cbFileEmbedd->clicked(true); // Embedding image
1428 
1429         SAVE_PROJECT("DatapickerTestProject");
1430     }
1431 
1432     QCOMPARE(QFile::exists(imgFileName), false); // Deleted because QTemporaryFile goes out of scope
1433 
1434     // Load project
1435     // Image was deleted before
1436     {
1437         Project project;
1438         QCOMPARE(project.load(savePath), true);
1439 
1440         auto datapicker = project.child<Datapicker>(0);
1441         QVERIFY(datapicker);
1442         auto* image = datapicker->image();
1443 
1444         DatapickerImageWidget w(nullptr);
1445         w.setImages({image});
1446 
1447         QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), true);
1448         QCOMPARE(w.ui.cbFileRelativePath->isEnabled(), false); // project was loaded, but file does not exist
1449         QCOMPARE(w.ui.cbFileEmbedd->isChecked(), true);
1450         QCOMPARE(w.ui.cbFileRelativePath->isChecked(), false);
1451 
1452         QCOMPARE(image->fileName(), imgFileName);
1453         QCOMPARE(image->originalPlotImage.isNull(), false); // valid image loaded
1454         QCOMPARE(w.ui.leFileName->text(), imgFileName);
1455         QCOMPARE(w.ui.leFileName->styleSheet(), QStringLiteral("")); // Valid image
1456     }
1457 }
1458 
1459 void DatapickerTest::datapickerImageLoadImageEmbeddAbsoluteUndoRedo() {
1460     QString savePath;
1461     QString imgFileName;
1462 
1463     Project project;
1464     auto* datapicker = new Datapicker(QStringLiteral("Test"));
1465     project.addChild(datapicker);
1466     auto* image = datapicker->image();
1467 
1468     DatapickerImageWidget w(nullptr);
1469     w.setImages({image});
1470 
1471     {
1472         const auto img = createImage();
1473 
1474         QTemporaryFile imgFile(QStringLiteral("Testimage_XXXXXX.png"));
1475         QVERIFY(imgFile.open());
1476         imgFileName = imgFile.fileName();
1477         img.save(imgFileName, "PNG");
1478         QVERIFY(QFile::exists(imgFileName));
1479 
1480         QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), false);
1481         QCOMPARE(w.ui.cbFileRelativePath->isEnabled(), false);
1482         QCOMPARE(w.ui.cbFileEmbedd->isChecked(), false);
1483         QCOMPARE(w.ui.cbFileRelativePath->isChecked(), false);
1484 
1485         w.ui.leFileName->setText(imgFileName);
1486         // w.fileNameChanged(); will be called
1487 
1488         QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), true);
1489         QCOMPARE(w.ui.cbFileRelativePath->isEnabled(), false); // project is not saved
1490         QCOMPARE(w.ui.cbFileEmbedd->isChecked(), false);
1491         QCOMPARE(w.ui.cbFileRelativePath->isChecked(), false);
1492 
1493         QCOMPARE(image->fileName(), imgFileName);
1494         QCOMPARE(image->originalPlotImage.isNull(), false); // valid image loaded
1495         QCOMPARE(w.ui.leFileName->text(), imgFileName);
1496         QCOMPARE(w.ui.leFileName->styleSheet(), QStringLiteral("")); // Valid image
1497 
1498         w.ui.cbFileEmbedd->clicked(true); // Embedding image
1499 
1500         SAVE_PROJECT("DatapickerTestProject");
1501     }
1502 
1503     // Deleting image to verify embedding worked
1504     QCOMPARE(QFile::exists(imgFileName), false); // Deleted because QTemporaryFile goes out of scope
1505 
1506     image->undoStack()->undo();
1507     QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), false);
1508     QCOMPARE(w.ui.cbFileEmbedd->isChecked(), false);
1509     QCOMPARE(image->originalPlotImage.isNull(), true); // image does not exist anymore
1510     QCOMPARE(w.ui.leFileName->text(), imgFileName);
1511     QVERIFY(w.ui.leFileName->styleSheet() != QStringLiteral("")); // image does not exist anymore
1512 
1513     image->undoStack()->redo();
1514     QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), true);
1515     QCOMPARE(w.ui.cbFileEmbedd->isChecked(), true);
1516     QCOMPARE(image->originalPlotImage.isNull(), false); // image is embedded
1517     QCOMPARE(w.ui.leFileName->text(), imgFileName);
1518     QCOMPARE(w.ui.leFileName->styleSheet(), QStringLiteral("")); // image is embedded
1519 }
1520 
1521 void DatapickerTest::datapickerImageLoadImageEmbeddRelative() {
1522     QString savePath;
1523     QString imgFileName;
1524     DatapickerImageWidget w(nullptr);
1525 
1526     {
1527         const auto img = createImage();
1528 
1529         QTemporaryFile imgFile(QStringLiteral("Testimage_XXXXXX.png"));
1530         QVERIFY(imgFile.open());
1531         imgFileName = imgFile.fileName();
1532         img.save(imgFileName, "PNG");
1533         QVERIFY(QFile::exists(imgFileName));
1534 
1535         Project project;
1536         auto* datapicker = new Datapicker(QStringLiteral("Test"));
1537         project.addChild(datapicker);
1538         auto* image = datapicker->image();
1539 
1540         w.setImages({image});
1541 
1542         QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), false);
1543         QCOMPARE(w.ui.cbFileRelativePath->isEnabled(), false);
1544         QCOMPARE(w.ui.cbFileEmbedd->isChecked(), false);
1545         QCOMPARE(w.ui.cbFileRelativePath->isChecked(), false);
1546 
1547         w.ui.leFileName->setText(imgFileName);
1548         // w.fileNameChanged(); will be called
1549 
1550         QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), true);
1551         QCOMPARE(w.ui.cbFileRelativePath->isEnabled(), false); // project is not saved
1552         QCOMPARE(w.ui.cbFileEmbedd->isChecked(), false);
1553         QCOMPARE(w.ui.cbFileRelativePath->isChecked(), false);
1554 
1555         QCOMPARE(image->fileName(), imgFileName);
1556         QCOMPARE(image->originalPlotImage.isNull(), false); // valid image loaded
1557         QCOMPARE(w.ui.leFileName->text(), imgFileName);
1558         QCOMPARE(w.ui.leFileName->styleSheet(), QStringLiteral("")); // Valid image
1559 
1560         SAVE_PROJECT("DatapickerTestProject");
1561 
1562         QCOMPARE(w.ui.cbFileRelativePath->isEnabled(), true); // project is now saved so calculating the relative path is possible
1563 
1564         w.ui.cbFileRelativePath->clicked(true);
1565 
1566         // QCOMPARE(w.ui.cbFileRelativePath->isChecked(), true);
1567         QFileInfo fi(imgFileName);
1568         QCOMPARE(image->fileName(), fi.fileName());
1569         QCOMPARE(w.ui.leFileName->text(), fi.fileName());
1570 
1571         w.ui.cbFileEmbedd->clicked(true); // Embedding image
1572 
1573         SAVE_PROJECT("DatapickerTestProject"); // Save again to save relative path
1574     }
1575 
1576     // Deleting image
1577     QCOMPARE(QFile::exists(imgFileName), false); // Deleted because QTemporaryFile goes out of scope
1578 
1579     // Load project
1580     {
1581         Project project;
1582         QCOMPARE(project.load(savePath), true);
1583 
1584         auto datapicker = project.child<Datapicker>(0);
1585         QVERIFY(datapicker);
1586         auto* image = datapicker->image();
1587 
1588         DatapickerImageWidget w(nullptr);
1589         w.setImages({image});
1590 
1591         QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), true); // image is valid because embedded
1592         QCOMPARE(w.ui.cbFileRelativePath->isEnabled(), false); // image is valid, but embedd is turned on
1593         QCOMPARE(w.ui.cbFileEmbedd->isChecked(), true);
1594         QCOMPARE(w.ui.cbFileRelativePath->isChecked(), true);
1595 
1596         QFileInfo fi(imgFileName);
1597         QCOMPARE(image->fileName(), fi.fileName());
1598         QCOMPARE(image->originalPlotImage.isNull(), false); // valid image loaded
1599         QCOMPARE(w.ui.leFileName->text(), fi.fileName());
1600         QCOMPARE(w.ui.leFileName->styleSheet(), QStringLiteral("")); // Valid image
1601     }
1602 }
1603 
1604 void DatapickerTest::datapickerImageLoadImageEmbeddRelativeUndoRedo() {
1605     QString savePath;
1606     QString imgFileName;
1607 
1608     Project project;
1609     auto* datapicker = new Datapicker(QStringLiteral("Test"));
1610     project.addChild(datapicker);
1611     auto* image = datapicker->image();
1612 
1613     DatapickerImageWidget w(nullptr);
1614     w.setImages({image});
1615 
1616     {
1617         const auto img = createImage();
1618 
1619         QTemporaryFile imgFile(QStringLiteral("Testimage_XXXXXX.png"));
1620         QVERIFY(imgFile.open());
1621         imgFileName = imgFile.fileName();
1622         img.save(imgFileName, "PNG");
1623         QVERIFY(QFile::exists(imgFileName));
1624 
1625         QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), false);
1626         QCOMPARE(w.ui.cbFileRelativePath->isEnabled(), false);
1627         QCOMPARE(w.ui.cbFileEmbedd->isChecked(), false);
1628         QCOMPARE(w.ui.cbFileRelativePath->isChecked(), false);
1629 
1630         w.ui.leFileName->setText(imgFileName);
1631         // w.fileNameChanged(); will be called
1632 
1633         QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), true);
1634         QCOMPARE(w.ui.cbFileRelativePath->isEnabled(), false); // project is not saved
1635         QCOMPARE(w.ui.cbFileEmbedd->isChecked(), false);
1636         QCOMPARE(w.ui.cbFileRelativePath->isChecked(), false);
1637 
1638         QCOMPARE(image->fileName(), imgFileName);
1639         QCOMPARE(image->originalPlotImage.isNull(), false); // valid image loaded
1640         QCOMPARE(w.ui.leFileName->text(), imgFileName);
1641         QCOMPARE(w.ui.leFileName->styleSheet(), QStringLiteral("")); // Valid image
1642 
1643         SAVE_PROJECT("DatapickerTestProject");
1644 
1645         QCOMPARE(w.ui.cbFileRelativePath->isEnabled(), true); // project is now saved so calculating the relative path is possible
1646 
1647         w.ui.cbFileRelativePath->clicked(true);
1648 
1649         // QCOMPARE(w.ui.cbFileRelativePath->isChecked(), true);
1650         QFileInfo fi(imgFileName);
1651         QCOMPARE(image->fileName(), fi.fileName());
1652         QCOMPARE(w.ui.leFileName->text(), fi.fileName());
1653 
1654         w.ui.cbFileEmbedd->clicked(true); // Embedding image
1655 
1656         SAVE_PROJECT("DatapickerTestProject"); // Save again to save relative path
1657     }
1658 
1659     // Deleting image
1660     QCOMPARE(QFile::exists(imgFileName), false); // Deleted because QTemporaryFile goes out of scope
1661 
1662     image->undoStack()->undo();
1663 
1664     QFileInfo fi(imgFileName);
1665     QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), false);
1666     QCOMPARE(w.ui.cbFileEmbedd->isChecked(), false);
1667     QCOMPARE(image->originalPlotImage.isNull(), true); // image does not exist anymore
1668     QCOMPARE(w.ui.leFileName->text(), fi.fileName());
1669     QVERIFY(w.ui.leFileName->styleSheet() != QStringLiteral("")); // image does not exist anymore
1670 
1671     image->undoStack()->redo();
1672     QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), true);
1673     QCOMPARE(w.ui.cbFileEmbedd->isChecked(), true);
1674     QCOMPARE(image->originalPlotImage.isNull(), false); // image is embedded
1675     QCOMPARE(w.ui.leFileName->text(), fi.fileName());
1676     QCOMPARE(w.ui.leFileName->styleSheet(), QStringLiteral("")); // image is embedded
1677 }
1678 
1679 void DatapickerTest::datapickerImageClipboard() {
1680     const auto img = createImage();
1681 
1682     QTemporaryFile imgFileName(QStringLiteral("Testimage_XXXXXX.png"));
1683     QVERIFY(imgFileName.open());
1684     img.save(imgFileName.fileName(), "PNG");
1685     QVERIFY(QFile::exists(imgFileName.fileName()));
1686 
1687     Project project;
1688     auto* datapicker = new Datapicker(QStringLiteral("Test"));
1689     project.addChild(datapicker);
1690     auto* image = datapicker->image();
1691 
1692     DatapickerImageWidget w(nullptr);
1693     w.setImages({image});
1694 
1695     QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), false);
1696     QCOMPARE(w.ui.cbFileRelativePath->isEnabled(), false);
1697     QCOMPARE(w.ui.cbFileEmbedd->isChecked(), false);
1698     QCOMPARE(w.ui.cbFileRelativePath->isChecked(), false);
1699 
1700     // Set image from clipboard
1701     image->setImage(img, QStringLiteral(""), true);
1702 
1703     QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), true);
1704     QCOMPARE(w.ui.cbFileRelativePath->isEnabled(), false);
1705     QCOMPARE(w.ui.cbFileEmbedd->isChecked(), true);
1706     QCOMPARE(w.ui.cbFileRelativePath->isChecked(), false);
1707 
1708     QCOMPARE(w.ui.leFileName->isEnabled(), false);
1709 }
1710 
1711 void DatapickerTest::datapickerImageClipboardSelectImageFromPath() {
1712     const auto img = createImage();
1713     const auto img2 = createImage2();
1714 
1715     QTemporaryFile imgFileName(QStringLiteral("Testimage_XXXXXX.png"));
1716     QVERIFY(imgFileName.open());
1717     img.save(imgFileName.fileName(), "PNG");
1718     QVERIFY(QFile::exists(imgFileName.fileName()));
1719 
1720     Project project;
1721     auto* datapicker = new Datapicker(QStringLiteral("Test"));
1722     project.addChild(datapicker);
1723     auto* image = datapicker->image();
1724 
1725     DatapickerImageWidget w(nullptr);
1726     w.setImages({image});
1727 
1728     QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), false);
1729     QCOMPARE(w.ui.cbFileRelativePath->isEnabled(), false);
1730     QCOMPARE(w.ui.cbFileEmbedd->isChecked(), false);
1731     QCOMPARE(w.ui.cbFileRelativePath->isChecked(), false);
1732 
1733     // Set image from clipboard
1734     image->setImage(img2, QStringLiteral(""), true);
1735 
1736     QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), true);
1737     QCOMPARE(w.ui.cbFileRelativePath->isEnabled(), false);
1738     QCOMPARE(w.ui.cbFileEmbedd->isChecked(), true);
1739     QCOMPARE(w.ui.cbFileRelativePath->isChecked(), false);
1740 
1741     QCOMPARE(w.ui.leFileName->isEnabled(), false);
1742 
1743     QCOMPARE(image->originalPlotImage, img2);
1744 
1745     w.ui.leFileName->setText(imgFileName.fileName());
1746 
1747     // Embedded is still turned on
1748     QCOMPARE(w.ui.leFileName->isEnabled(), false);
1749     QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), true);
1750     QCOMPARE(w.ui.cbFileEmbedd->isChecked(), true);
1751 
1752     QCOMPARE(image->originalPlotImage.isNull(), false); // valid image
1753 
1754     Q_EMIT w.ui.cbFileEmbedd->clicked(false);
1755 
1756     QCOMPARE(w.ui.leFileName->isEnabled(), true);
1757     QCOMPARE(w.ui.cbFileEmbedd->isEnabled(), true);
1758     QCOMPARE(w.ui.cbFileEmbedd->isChecked(), true);
1759 
1760     QCOMPARE(image->originalPlotImage.isNull(), false); // valid image
1761 
1762     QCOMPARE(image->originalPlotImage, img);
1763 }
1764 
1765 QTEST_MAIN(DatapickerTest)