File indexing completed on 2024-10-20 04:17:38
0001 // SPDX-FileCopyrightText: Lukas Sommer <sommerluk@gmail.com> 0002 // SPDX-License-Identifier: BSD-2-Clause OR MIT 0003 0004 // First included header is the public header of the class we are testing; 0005 // this forces the header to be self-contained. 0006 #include "colordialog.h" 0007 // Second, the private implementation. 0008 #include "colordialog_p.h" // IWYU pragma: keep 0009 0010 #include "absolutecolor.h" 0011 #include "chromahuediagram.h" 0012 #include "colorpatch.h" 0013 #include "constpropagatinguniquepointer.h" 0014 #include "genericcolor.h" 0015 #include "gradientslider.h" 0016 #include "helperconversion.h" 0017 #include "helperqttypes.h" 0018 #include "initializetranslation.h" 0019 #include "lchadouble.h" 0020 #include "lchdouble.h" 0021 #include "multispinbox.h" 0022 #include "rgbcolor.h" 0023 #include "rgbcolorspace.h" 0024 #include "rgbcolorspacefactory.h" 0025 #include "settranslation.h" 0026 #include "wheelcolorpicker.h" 0027 #include <qaction.h> 0028 #include <qapplication.h> 0029 #include <qbenchmark.h> 0030 #include <qbytearray.h> 0031 #include <qcolor.h> 0032 #include <qcolordialog.h> 0033 #include <qcoreapplication.h> 0034 #include <qcoreevent.h> 0035 #include <qdebug.h> 0036 #include <qglobal.h> 0037 #include <qhash.h> 0038 #include <qlineedit.h> 0039 #include <qlist.h> 0040 #include <qlocale.h> 0041 #include <qmetaobject.h> 0042 #include <qnamespace.h> 0043 #include <qobject.h> 0044 #include <qpair.h> 0045 #include <qpointer.h> 0046 #include <qpushbutton.h> 0047 #include <qscopedpointer.h> 0048 #include <qsharedpointer.h> 0049 #include <qsignalspy.h> 0050 #include <qspinbox.h> 0051 #include <qstringbuilder.h> 0052 #include <qstringliteral.h> 0053 #include <qtabwidget.h> 0054 #include <qtemporaryfile.h> 0055 #include <qtest.h> 0056 #include <qtestcase.h> 0057 #include <qtestdata.h> 0058 #include <qtestkeyboard.h> 0059 #include <qwidget.h> 0060 #include <type_traits> 0061 0062 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0063 #include <qcontainerfwd.h> 0064 #include <qobjectdefs.h> 0065 #include <qstring.h> 0066 #include <qtmetamacros.h> 0067 #include <utility> 0068 #else 0069 #include <qobjectdefs.h> 0070 #include <qstring.h> 0071 #include <qstringlist.h> 0072 #include <qvector.h> 0073 #include <utility> 0074 #endif 0075 0076 // From Qt documentation: 0077 // “Note: This function is not declared in any of Qt's header files. To 0078 // use it in your application, declare the function prototype before 0079 // calling it.” 0080 void qt_set_sequence_auto_mnemonic(bool b); 0081 0082 class TestColorDialogSnippetClass : public QWidget 0083 { 0084 Q_OBJECT 0085 public Q_SLOTS: 0086 void mySlot(QColor color) 0087 { 0088 Q_UNUSED(color) 0089 } 0090 0091 public: 0092 // A constructor that is clazy-conform 0093 explicit TestColorDialogSnippetClass(QWidget *parent = nullptr) 0094 : QWidget(parent) 0095 { 0096 } 0097 0098 void testSnippet05() 0099 { 0100 //! [ColorDialog Open] 0101 PerceptualColor::ColorDialog *m_dialog = // 0102 new PerceptualColor::ColorDialog( // 0103 PerceptualColor::RgbColorSpaceFactory::createSrgb()); 0104 m_dialog->open(this, SLOT(mySlot(QColor))); 0105 //! [ColorDialog Open] 0106 delete m_dialog; 0107 } 0108 }; 0109 0110 static void snippet01() 0111 { 0112 // This function will not be called in the unit tests because getColor() 0113 // does not return without user interaction! 0114 //! [ColorDialog Get color with alpha channel] 0115 QColor myColor = PerceptualColor::ColorDialog::getColor( 0116 // Current color at widget startup: 0117 Qt::green, 0118 // Parent widget (or nullptr for no parent): 0119 nullptr, 0120 // Window title (or an empty string for default title): 0121 QStringLiteral("Window title"), 0122 // Options: 0123 PerceptualColor::ColorDialog::ColorDialogOption::ShowAlphaChannel); 0124 //! [ColorDialog Get color with alpha channel] 0125 Q_UNUSED(myColor) 0126 } 0127 0128 static void snippet02() 0129 { 0130 //! [setOptionsWithLocalEnum] 0131 auto myDialog = new PerceptualColor::ColorDialog(); 0132 myDialog->setOption( // 0133 PerceptualColor::ColorDialog::ColorDialogOption::ShowAlphaChannel, 0134 false); 0135 //! [setOptionsWithLocalEnum] 0136 QCOMPARE( // 0137 myDialog->testOption( // 0138 PerceptualColor::ColorDialog::ColorDialogOption::ShowAlphaChannel), // 0139 false); 0140 delete myDialog; 0141 } 0142 0143 static void snippet03() 0144 { 0145 //! [setOptionsWithQColorDialogEnum] 0146 auto myDialog = new PerceptualColor::ColorDialog(); 0147 myDialog->setOption(QColorDialog::ShowAlphaChannel, false); 0148 //! [setOptionsWithQColorDialogEnum] 0149 QCOMPARE( // 0150 myDialog->testOption( // 0151 PerceptualColor::ColorDialog::ColorDialogOption::ShowAlphaChannel), // 0152 false); 0153 delete myDialog; 0154 } 0155 0156 static void snippet04() 0157 { 0158 // This function will not be called in the unit tests because getColor() 0159 // does not return without user interaction! 0160 //! [ColorDialog Get color] 0161 // Show a modal color dialog and get the color that the user has chosen 0162 QColor myColor = PerceptualColor::ColorDialog::getColor(); 0163 //! [ColorDialog Get color] 0164 Q_UNUSED(myColor) 0165 } 0166 0167 namespace PerceptualColor 0168 { 0169 class TestColorDialog : public QObject 0170 { 0171 Q_OBJECT 0172 0173 public: 0174 explicit TestColorDialog(QObject *parent = nullptr) 0175 : QObject(parent) 0176 { 0177 } 0178 0179 private: 0180 QScopedPointer<ColorDialog> m_perceptualDialog; 0181 QScopedPointer<ColorDialog> m_perceptualDialog2; 0182 QScopedPointer<QColorDialog> m_qDialog; 0183 QScopedPointer<QColorDialog> m_qDialog2; 0184 QColor m_color; 0185 QSharedPointer<RgbColorSpace> m_srgbBuildinColorSpace = // 0186 RgbColorSpaceFactory::createSrgb(); 0187 0188 static void voidMessageHandler(QtMsgType, const QMessageLogContext &, const QString &) 0189 { 0190 // dummy message handler that does not print messages 0191 } 0192 0193 void helperProvideQColors() 0194 { 0195 // suppress warning for generating invalid QColor 0196 qInstallMessageHandler(voidMessageHandler); 0197 0198 QTest::addColumn<QColor>("color"); 0199 0200 QTest::newRow("RGB 1 2 3") // 0201 << QColor(1, 2, 3); 0202 QTest::newRow("RGBA 1 2 3 4") // 0203 << QColor(1, 2, 3, 4); 0204 QTest::newRow("RGB 1 2 300") // 0205 << QColor(1, 2, 300); 0206 QTest::newRow("RGB 1 2 -300") // 0207 << QColor(1, 2, -300); 0208 QTest::newRow("RGBA 1 2 300 4") // 0209 << QColor(1, 2, 300, 4); 0210 QTest::newRow("RGBA 1 2 3 400") // 0211 << QColor(1, 2, 3, 400); 0212 QTest::newRow("RGBA 1 2 3 -400") // 0213 << QColor(1, 2, 3, -400); 0214 0215 QTest::newRow("RGB 0.1 0.2 0.3") // 0216 << QColor::fromRgbF(0.1f, 0.2f, 0.3f); 0217 QTest::newRow("RGBA 0.1 0.2 0.3 0.4") // 0218 << QColor::fromRgbF(0.1f, 0.2f, 0.3f, 0.4f); 0219 QTest::newRow("RGB 0.1 6.2 0.300") // 0220 << QColor::fromRgbF(0.1f, 6.2f, 0.300f); 0221 QTest::newRow("RGBA 0.1 6.2 0.300 0.4") // 0222 << QColor::fromRgbF(0.1f, 6.2f, 0.300f, 0.4f); 0223 QTest::newRow("RGBA 0.1 0.2 0.3 -0.4") // 0224 << QColor::fromRgbF(0.1f, 0.2f, 0.3f, -0.4f); 0225 QTest::newRow("RGBA 0.1 0.2 0.3 400") // 0226 << QColor::fromRgbF(0.1f, 0.2f, 0.3f, 400); 0227 0228 QTest::newRow("CMYK 1 2 3 4") // 0229 << QColor::fromCmyk(1, 2, 3, 4); 0230 QTest::newRow("CMYK 1 2 3 4 5") // 0231 << QColor::fromCmyk(1, 2, 3, 4, 5); 0232 QTest::newRow("CMYK 1 2 300 4") // 0233 << QColor::fromCmyk(1, 2, 300, 4); 0234 QTest::newRow("CMYK 1 2 300 4 5") // 0235 << QColor::fromCmyk(1, 2, 300, 4, 5); 0236 QTest::newRow("CMYK 0.1 0.2 0.300 0.4") // 0237 << QColor::fromCmykF(0.1f, 0.2f, 0.300f, 0.4f); 0238 QTest::newRow("CMYK 0.1 0.2 0.300 0.4 0.6495217645") // 0239 << QColor::fromCmykF(0.1f, 0.2f, 0.300f, 0.4f, 0.6495217645f); 0240 QTest::newRow("CMYK 0.1 6.2 0.300 0.4") // 0241 << QColor::fromCmykF(0.1f, 6.2f, 0.300f, 0.4f); 0242 QTest::newRow("CMYK 0.1 -6.2 0.300 0.4") // 0243 << QColor::fromCmykF(0.1f, -6.2f, 0.300f, 0.4f); 0244 QTest::newRow("CMYK 0.1 6.2 0.300 0.4 0.6495217645") // 0245 << QColor::fromCmykF(0.1f, 6.2f, 0.300f, 0.4f, 0.6495217645f); 0246 QTest::newRow("CMYK 0.1 6.2 0.300 0.4 -0.6495217645") // 0247 << QColor::fromCmykF(0.1f, 6.2f, 0.300f, 0.4f, -0.6495217645f); 0248 0249 QTest::newRow("HSL 2 3 4") // 0250 << QColor::fromHsl(2, 3, 4); 0251 QTest::newRow("HSL 2 3 4 5") // 0252 << QColor::fromHsl(2, 3, 4, 5); 0253 QTest::newRow("HSL 2 300 4") // 0254 << QColor::fromHsl(2, 300, 4); 0255 QTest::newRow("HSL 2 300 4 5") // 0256 << QColor::fromHsl(2, 300, 4, 5); 0257 QTest::newRow("HSL 0.2 0.300 0.4") // 0258 << QColor::fromHslF(0.2f, 0.300f, 0.4f); 0259 QTest::newRow("HSL 0.2 0.300 0.4 0.6495217645") // 0260 << QColor::fromHslF(0.2f, 0.300f, 0.4f, 0.6495217645f); 0261 QTest::newRow("HSL 6.2 0.300 0.4") // 0262 << QColor::fromHslF(6.2f, 0.300f, 0.4f); 0263 QTest::newRow("HSL -6.2 0.300 0.4") // 0264 << QColor::fromHslF(-6.2f, 0.300f, 0.4f); 0265 QTest::newRow("HSL 6.2 0.300 0.4 0.6495217645") // 0266 << QColor::fromHslF(6.2f, 0.300f, 0.4f, 0.6495217645f); 0267 QTest::newRow("HSL 6.2 0.300 0.4 -0.6495217645") // 0268 << QColor::fromHslF(6.2f, 0.300f, 0.4f, -0.6495217645f); 0269 QTest::newRow("HSL 6.2 0.300 0.4 1.6495217645") // 0270 << QColor::fromHslF(6.2f, 0.300f, 0.4f, 1.6495217645f); 0271 0272 QTest::newRow("HSV 2 3 4") // 0273 << QColor::fromHsv(2, 3, 4); 0274 QTest::newRow("HSV 2 3 4 5") // 0275 << QColor::fromHsv(2, 3, 4, 5); 0276 QTest::newRow("HSV 2 300 4") // 0277 << QColor::fromHsv(2, 300, 4); 0278 QTest::newRow("HSV 2 300 4 5") // 0279 << QColor::fromHsv(2, 300, 4, 5); 0280 QTest::newRow("HSV 0.2 0.300 0.4") // 0281 << QColor::fromHsvF(0.2f, 0.300f, 0.4f); 0282 QTest::newRow("HSV 0.2 0.300 0.4 0.6495217645") // 0283 << QColor::fromHsvF(0.2f, 0.300f, 0.4f, 0.6495217645f); 0284 QTest::newRow("HSV 6.2 0.300 0.4") // 0285 << QColor::fromHsvF(6.2f, 0.300f, 0.4f); 0286 QTest::newRow("HSV -6.2 0.300 0.4") // 0287 << QColor::fromHsvF(-6.2f, 0.300f, 0.4f); 0288 QTest::newRow("HSV 6.2 0.300 0.4 0.6495217645") // 0289 << QColor::fromHsvF(6.2f, 0.300f, 0.4f, 0.6495217645f); 0290 QTest::newRow("HSV 6.2 0.300 0.4 -0.6495217645") // 0291 << QColor::fromHsvF(6.2f, 0.300f, 0.4f, -0.6495217645f); 0292 QTest::newRow("HSV 6.2 0.300 0.4 1.6495217645") // 0293 << QColor::fromHsvF(6.2f, 0.300f, 0.4f, 1.6495217645f); 0294 0295 QTest::newRow("invalid") << QColor(); 0296 0297 // do not suppress warning for generating invalid QColor anymore 0298 qInstallMessageHandler(nullptr); 0299 } 0300 0301 void helperCompareDialog(ColorDialog *perceptualDialog, QColorDialog *qColorDialog) 0302 { 0303 // Compare the state of perceptualDialog (actual) 0304 // to qColorDialog (expected) 0305 const QColor perceptualDialogSelected = // 0306 perceptualDialog->selectedColor(); 0307 const QColor qColorDialogSelected = qColorDialog->selectedColor(); 0308 QCOMPARE( // 0309 perceptualDialogSelected.name(), // 0310 qColorDialogSelected.name()); 0311 QCOMPARE( // 0312 perceptualDialogSelected.alpha(), // 0313 qColorDialogSelected.alpha()); 0314 QCOMPARE(perceptualDialogSelected.spec(), // 0315 qColorDialogSelected.spec()); 0316 const QColor perceptualDialogCurrent = perceptualDialog->currentColor(); 0317 const QColor qColorDialogCurrent = qColorDialog->currentColor(); 0318 QCOMPARE(perceptualDialogCurrent.name(), qColorDialogCurrent.name()); 0319 QCOMPARE(perceptualDialogCurrent.alpha(), qColorDialogCurrent.alpha()); 0320 QCOMPARE(perceptualDialogCurrent.spec(), qColorDialogCurrent.spec()); 0321 QCOMPARE(perceptualDialog->testOption(QColorDialog::NoButtons), // 0322 qColorDialog->testOption(QColorDialog::NoButtons)); 0323 QCOMPARE( // 0324 perceptualDialog->testOption(QColorDialog::ShowAlphaChannel), // 0325 qColorDialog->testOption(QColorDialog::ShowAlphaChannel)); 0326 QCOMPARE( // 0327 perceptualDialog->options().testFlag(QColorDialog::NoButtons), // 0328 qColorDialog->options().testFlag(QColorDialog::NoButtons)); 0329 QCOMPARE( // 0330 perceptualDialog->options().testFlag(QColorDialog::ShowAlphaChannel), 0331 qColorDialog->options().testFlag(QColorDialog::ShowAlphaChannel)); 0332 QCOMPARE(perceptualDialog->isVisible(), qColorDialog->isVisible()); 0333 QCOMPARE(perceptualDialog->isModal(), qColorDialog->isModal()); 0334 QCOMPARE(perceptualDialog->result(), qColorDialog->result()); 0335 QCOMPARE(perceptualDialog->parent(), qColorDialog->parent()); 0336 QCOMPARE(perceptualDialog->parentWidget(), // 0337 qColorDialog->parentWidget()); 0338 } 0339 0340 private Q_SLOTS: 0341 // This is just a helper slot, not an actual test. 0342 // It is neither called by QTest (because it has a parameter). 0343 void helperReceiveSignals(QColor color) 0344 { 0345 m_color = color; 0346 } 0347 0348 void initTestCase() 0349 { 0350 // Called before the first test function is executed 0351 } 0352 0353 void cleanupTestCase() 0354 { 0355 // Called after the last test function was executed 0356 } 0357 0358 void init() 0359 { 0360 // Called before each test function is executed 0361 0362 // Make sure to have mnemonics (like Qt::ALT+Qt::Key_X for "E&xit") 0363 // enabled, also on platforms that disable it by default. 0364 qt_set_sequence_auto_mnemonic(true); 0365 } 0366 0367 void cleanup() 0368 { 0369 // Called after every test function 0370 } 0371 0372 void testDefaultConstructorAndDestructor1() 0373 { 0374 // This should not crash! 0375 ColorDialog test(m_srgbBuildinColorSpace); 0376 Q_UNUSED(test); 0377 } 0378 0379 void testDefaultConstructorAndDestructor2() 0380 { 0381 // This should not crash! 0382 ColorDialog test; 0383 Q_UNUSED(test); 0384 } 0385 0386 void testDefaultConstructorAndDestructor3() 0387 { 0388 QWidget myWidget; 0389 { 0390 // This should not crash! 0391 ColorDialog test(m_srgbBuildinColorSpace, &myWidget); 0392 Q_UNUSED(test); 0393 } 0394 } 0395 0396 void testDefaultConstructorAndDestructor4() 0397 { 0398 QWidget myWidget; 0399 { 0400 // This should not crash! 0401 ColorDialog test(&myWidget); 0402 Q_UNUSED(test); 0403 } 0404 } 0405 0406 void testConstructorQWidget() 0407 { 0408 // Test the constructor ColorDialog(QWidget * parent = nullptr) 0409 m_perceptualDialog.reset( // 0410 new ColorDialog(m_srgbBuildinColorSpace)); 0411 QScopedPointer<QWidget> tempWidget{new QWidget()}; 0412 QScopedPointer<ColorDialog> tempPerceptualDialog2; 0413 tempPerceptualDialog2.reset( // 0414 new ColorDialog(m_srgbBuildinColorSpace, tempWidget.data())); 0415 QCOMPARE(tempPerceptualDialog2->parentWidget(), tempWidget.data()); 0416 QCOMPARE(tempPerceptualDialog2->parent(), tempWidget.data()); 0417 } 0418 0419 void testConstructorQWidgetConformance() 0420 { 0421 // Test the constructor 0422 m_perceptualDialog.reset( // 0423 new ColorDialog( // 0424 m_srgbBuildinColorSpace, // 0425 QColor(Qt::white) // 0426 ) // 0427 ); 0428 QScopedPointer<QWidget> tempWidget{new QWidget()}; 0429 ColorDialog *tempPerceptualDialog2 = // 0430 new ColorDialog( // 0431 m_srgbBuildinColorSpace, 0432 QColor(Qt::white), // 0433 tempWidget.data() // 0434 ); 0435 // Test if this coordinates is conform to QColorDialog 0436 m_qDialog.reset(new QColorDialog()); 0437 QColorDialog *tempQDialog2 = new QColorDialog(tempWidget.data()); 0438 helperCompareDialog(m_perceptualDialog.data(), m_qDialog.data()); 0439 helperCompareDialog(tempPerceptualDialog2, tempQDialog2); 0440 } 0441 0442 void testConstructorQColorQWidget_data() 0443 { 0444 helperProvideQColors(); 0445 } 0446 0447 void testConstructorQColorQWidget() 0448 { 0449 QFETCH(QColor, color); 0450 QColor colorOpaque; 0451 if (color.isValid()) { 0452 colorOpaque = color.toRgb(); 0453 colorOpaque.setAlpha(255); 0454 } else { 0455 colorOpaque = Qt::black; 0456 } 0457 0458 // Test the constructors 0459 m_perceptualDialog.reset( // 0460 new ColorDialog(m_srgbBuildinColorSpace, color)); 0461 QScopedPointer<QWidget> tempWidget{new QWidget()}; 0462 QScopedPointer<ColorDialog> tempPerceptualDialog2{ 0463 // 0464 new ColorDialog( // 0465 m_srgbBuildinColorSpace, // 0466 color, // 0467 tempWidget.data() // 0468 ) // 0469 }; 0470 0471 // Test post-condition: currentColor() is color 0472 QCOMPARE(m_perceptualDialog->currentColor().name(), // 0473 colorOpaque.name()); 0474 QCOMPARE(m_perceptualDialog->currentColor().alpha(), // 0475 colorOpaque.alpha()); 0476 QCOMPARE(m_perceptualDialog->currentColor().spec(), // 0477 colorOpaque.spec()); 0478 QCOMPARE(tempPerceptualDialog2->currentColor().name(), // 0479 colorOpaque.name()); 0480 QCOMPARE(tempPerceptualDialog2->currentColor().alpha(), // 0481 colorOpaque.alpha()); 0482 QCOMPARE(tempPerceptualDialog2->currentColor().spec(), // 0483 colorOpaque.spec()); 0484 QCOMPARE(tempPerceptualDialog2->parentWidget(), // 0485 tempWidget.data()); 0486 QCOMPARE(tempPerceptualDialog2->parent(), // 0487 tempWidget.data()); 0488 } 0489 0490 #ifdef Q_OS_LINUX 0491 // Linux has no native color dialog, so it is the only system guaranteed 0492 // to use QColorDialog’s own implementation not only after calling 0493 // QColorDialog::setOption(QColorDialog::DontUseNativeDialog, true); 0494 // but yet on QColorDialog’s constructor call. 0495 void testConstructorQColorQWidgetConformance_data() 0496 { 0497 helperProvideQColors(); 0498 } 0499 void testConstructorQColorQWidgetConformance() 0500 { 0501 QFETCH(QColor, color); 0502 0503 // Test the constructor ColorDialog(QWidget * parent = nullptr) 0504 m_perceptualDialog.reset( // 0505 new ColorDialog(m_srgbBuildinColorSpace, color)); 0506 QScopedPointer<QWidget> tempWidget{new QWidget()}; 0507 ColorDialog *tempPerceptualDialog2 = new ColorDialog( // 0508 m_srgbBuildinColorSpace, 0509 color, 0510 tempWidget.data()); 0511 // Test if this coordinates is conform to QColorDialog 0512 m_qDialog.reset(new QColorDialog(color)); 0513 QColorDialog *tempQDialog2 = // 0514 new QColorDialog(color, tempWidget.data()); 0515 helperCompareDialog(m_perceptualDialog.data(), m_qDialog.data()); 0516 helperCompareDialog(tempPerceptualDialog2, tempQDialog2); 0517 } 0518 #endif 0519 0520 #ifdef Q_OS_LINUX 0521 // Linux has no native color dialog, so it is the only system guaranteed 0522 // to use QColorDialog’s own implementation not only after calling 0523 // QColorDialog::setOption(QColorDialog::DontUseNativeDialog, true); 0524 // but yet on QColorDialog’s constructor call. 0525 void testConformanceWithQColorDialog_data() 0526 { 0527 QTest::addColumn<QColor>("initialColor"); 0528 QTest::addColumn<QColor>("secondColor"); 0529 QTest::addColumn<bool>("showAlphaChannel"); 0530 0531 QVector<QPair<QByteArray, QColor>> colorList; 0532 0533 colorList.append( // 0534 QPair<QByteArray, QColor>(QByteArrayLiteral("redOpaque"), // 0535 QColor(255, 0, 0))); 0536 0537 colorList.append( // 0538 QPair<QByteArray, QColor>(QByteArrayLiteral("greenHalf"), // 0539 QColor(0, 255, 0, 128))); 0540 0541 colorList.append( // 0542 QPair<QByteArray, QColor>(QByteArrayLiteral("greenTransparent"), // 0543 QColor(255, 0, 255, 0))); 0544 0545 colorList.append( // 0546 QPair<QByteArray, QColor>(QByteArrayLiteral("invalid"), // 0547 QColor())); 0548 0549 for (int i = 0; i < colorList.size(); ++i) { 0550 for (int j = 0; j < colorList.size(); ++j) { 0551 const QByteArray descriptionWithoutAlpha = // 0552 colorList.at(i).first // 0553 + QByteArrayLiteral("/") // 0554 + colorList.at(j).first; 0555 const QByteArray descriptionWithAlpha = // 0556 descriptionWithoutAlpha // 0557 + QByteArrayLiteral("/ShowAlphaChannel"); // 0558 QTest::newRow(descriptionWithAlpha.constData()) // 0559 << colorList.at(i).second // 0560 << colorList.at(j).second // 0561 << true; 0562 QTest::newRow(descriptionWithoutAlpha.constData()) // 0563 << colorList.at(i).second // 0564 << colorList.at(j).second // 0565 << false; 0566 } 0567 } 0568 } 0569 void testConformanceWithQColorDialog() 0570 { 0571 // Some conformance tests (without a particular systematic approach) 0572 QFETCH(QColor, initialColor); 0573 QFETCH(QColor, secondColor); 0574 QFETCH(bool, showAlphaChannel); 0575 0576 m_perceptualDialog.reset( // 0577 new ColorDialog(m_srgbBuildinColorSpace, initialColor)); 0578 m_qDialog.reset(new QColorDialog(initialColor)); 0579 helperCompareDialog(m_perceptualDialog.data(), m_qDialog.data()); 0580 0581 m_perceptualDialog->setOption( // 0582 QColorDialog::ShowAlphaChannel, // 0583 showAlphaChannel); 0584 m_qDialog->setOption( // 0585 QColorDialog::ShowAlphaChannel, 0586 showAlphaChannel); 0587 0588 helperCompareDialog(m_perceptualDialog.data(), m_qDialog.data()); 0589 0590 m_perceptualDialog->setCurrentColor(secondColor); 0591 m_qDialog->setCurrentColor(secondColor); 0592 helperCompareDialog(m_perceptualDialog.data(), m_qDialog.data()); 0593 0594 QTest::keyClick(m_perceptualDialog.data(), Qt::Key_Return); 0595 QTest::keyClick(m_qDialog.data(), Qt::Key_Return); 0596 helperCompareDialog(m_perceptualDialog.data(), m_qDialog.data()); 0597 0598 m_perceptualDialog->setCurrentColor(secondColor); 0599 m_qDialog->setCurrentColor(secondColor); 0600 helperCompareDialog(m_perceptualDialog.data(), m_qDialog.data()); 0601 0602 QTest::keyClick(m_perceptualDialog.data(), Qt::Key_Escape); 0603 QTest::keyClick(m_qDialog.data(), Qt::Key_Escape); 0604 helperCompareDialog(m_perceptualDialog.data(), m_qDialog.data()); 0605 } 0606 #endif 0607 0608 #ifdef Q_OS_LINUX 0609 // Linux has no native color dialog, so it is the only system guaranteed 0610 // to use QColorDialog’s own implementation not only after calling 0611 // QColorDialog::setOption(QColorDialog::DontUseNativeDialog, true); 0612 // but yet on QColorDialog’s constructor call. 0613 void testConformanceWithQColorDialogNoButtons_data() 0614 { 0615 QTest::addColumn<bool>("showAlphaChannel"); 0616 QTest::addColumn<bool>("noButtons"); 0617 0618 QTest::newRow("/ShowAlphaChannel/NoButtons") << true << true; 0619 QTest::newRow("/ShowAlphaChannel") << true << false; 0620 QTest::newRow("/NoButtons") << false << true; 0621 QTest::newRow("") << false << false; 0622 } 0623 void testConformanceWithQColorDialogNoButtons() 0624 { 0625 // Some conformance tests (without a particular systematic approach) 0626 QColor initialColor = Qt::red; 0627 QColor secondColor = Qt::green; 0628 QFETCH(bool, showAlphaChannel); 0629 QFETCH(bool, noButtons); 0630 0631 m_perceptualDialog.reset( // 0632 new ColorDialog(m_srgbBuildinColorSpace, initialColor)); 0633 m_qDialog.reset(new QColorDialog(initialColor)); 0634 helperCompareDialog(m_perceptualDialog.data(), m_qDialog.data()); 0635 0636 m_perceptualDialog->setOption( // 0637 QColorDialog::ShowAlphaChannel, // 0638 showAlphaChannel); 0639 m_qDialog->setOption( // 0640 QColorDialog::ShowAlphaChannel, 0641 showAlphaChannel); 0642 0643 m_perceptualDialog->setOption(QColorDialog::NoButtons, noButtons); 0644 m_qDialog->setOption(QColorDialog::NoButtons, noButtons); 0645 helperCompareDialog(m_perceptualDialog.data(), m_qDialog.data()); 0646 0647 m_perceptualDialog->setCurrentColor(secondColor); 0648 m_qDialog->setCurrentColor(secondColor); 0649 helperCompareDialog(m_perceptualDialog.data(), m_qDialog.data()); 0650 0651 QTest::keyClick(m_perceptualDialog.data(), Qt::Key_Return); 0652 QTest::keyClick(m_qDialog.data(), Qt::Key_Return); 0653 helperCompareDialog(m_perceptualDialog.data(), m_qDialog.data()); 0654 0655 m_perceptualDialog->setCurrentColor(secondColor); 0656 m_qDialog->setCurrentColor(secondColor); 0657 helperCompareDialog(m_perceptualDialog.data(), m_qDialog.data()); 0658 0659 QTest::keyClick(m_perceptualDialog.data(), Qt::Key_Escape); 0660 QTest::keyClick(m_qDialog.data(), Qt::Key_Escape); 0661 helperCompareDialog(m_perceptualDialog.data(), m_qDialog.data()); 0662 } 0663 #endif 0664 0665 void testColorSelectedSignal() 0666 { 0667 m_perceptualDialog.reset( // 0668 new ColorDialog(m_srgbBuildinColorSpace)); 0669 m_perceptualDialog->show(); 0670 m_qDialog.reset(new QColorDialog()); 0671 m_qDialog->setOption(QColorDialog::DontUseNativeDialog, true); 0672 m_qDialog->show(); 0673 QSignalSpy spyPerceptualDialog( // 0674 m_perceptualDialog.data(), // 0675 &ColorDialog::colorSelected); 0676 QSignalSpy spyQDialog(m_qDialog.data(), &QColorDialog::colorSelected); 0677 QTest::keyClick(m_perceptualDialog.data(), Qt::Key_Return); 0678 QTest::keyClick(m_qDialog.data(), Qt::Key_Return); 0679 QCOMPARE(spyPerceptualDialog.count(), 1); 0680 QCOMPARE(spyPerceptualDialog.count(), spyQDialog.count()); 0681 m_perceptualDialog->show(); 0682 m_qDialog->show(); 0683 QTest::keyClick(m_perceptualDialog.data(), Qt::Key_Escape); 0684 QTest::keyClick(m_qDialog.data(), Qt::Key_Escape); 0685 QCOMPARE(spyPerceptualDialog.count(), 1); 0686 QCOMPARE(spyPerceptualDialog.count(), spyQDialog.count()); 0687 m_perceptualDialog->show(); 0688 m_qDialog->show(); 0689 QTest::keyClick(m_perceptualDialog.data(), Qt::Key_Return); 0690 QTest::keyClick(m_qDialog.data(), Qt::Key_Return); 0691 QCOMPARE(spyPerceptualDialog.count(), 2); 0692 QCOMPARE(spyPerceptualDialog.count(), spyQDialog.count()); 0693 } 0694 0695 void testPropertyConformance_data() 0696 { 0697 // We provide the property names as data. To get the property names, 0698 // this function is used: 0699 // const char *QMetaProperty::name() const 0700 // Now, the type “const char *” cannot be used with QTest::addColumn<> 0701 // because it is not known to Qt’s meta object system. The 0702 // meta object system requires copy constructors for its known types. 0703 // This might get wired with pointer types that might go out of scope. 0704 // Therefore, we create a QByteArray from the data, which can be passed 0705 // without problems through the meta object system. The good thing 0706 // is that for the conversion we do not need to know anything 0707 // about the actual encoding of “const char *”. 0708 QTest::addColumn<QByteArray>("propertyName"); 0709 QMetaObject referenceClass = QColorDialog::staticMetaObject; 0710 for (int i = 0; i < referenceClass.propertyCount(); ++i) { 0711 QTest::newRow(referenceClass.property(i).name()) // 0712 << QByteArray(referenceClass.property(i).name()); 0713 } 0714 } 0715 0716 void testPropertyConformance() 0717 { 0718 QFETCH(QByteArray, propertyName); 0719 QMetaObject testClass = ColorDialog::staticMetaObject; 0720 QMetaObject referenceClass = QColorDialog::staticMetaObject; 0721 int testClassIndex = // 0722 testClass.indexOfProperty(propertyName.constData()); 0723 int referenceClassIndex = // 0724 referenceClass.indexOfProperty(propertyName.constData()); 0725 QMetaProperty referenceClassProperty = // 0726 referenceClass.property(referenceClassIndex); 0727 // cppcheck-suppress unreadVariable // false positive 0728 QByteArray message = // 0729 QByteArrayLiteral("Test if property \"") // 0730 + QByteArray(referenceClassProperty.name()) // 0731 + QByteArrayLiteral("\" of class \"") // 0732 + QByteArray(referenceClass.className()) // 0733 + QByteArrayLiteral("\" is also available in \"") // 0734 + QByteArray(testClass.className()) // 0735 + QByteArrayLiteral("\"."); 0736 QVERIFY2(testClassIndex >= 0, message.constData()); 0737 QMetaProperty testClassProperty = testClass.property(testClassIndex); 0738 if (referenceClassProperty.hasNotifySignal()) { 0739 QVERIFY2(testClassProperty.hasNotifySignal(), 0740 "If the reference class has a notify signal, " 0741 "the test class must have also a notify signal."); 0742 } 0743 QCOMPARE(testClassProperty.isConstant(), // 0744 referenceClassProperty.isConstant()); 0745 QCOMPARE(testClassProperty.isDesignable(), // 0746 referenceClassProperty.isDesignable()); 0747 QCOMPARE(testClassProperty.isEnumType(), // 0748 referenceClassProperty.isEnumType()); 0749 if (referenceClassProperty.isEnumType()) { 0750 QCOMPARE(testClassProperty.enumerator().enumName(), // 0751 referenceClassProperty.enumerator().enumName()); 0752 QCOMPARE(testClassProperty.enumerator().isFlag(), // 0753 referenceClassProperty.enumerator().isFlag()); 0754 QCOMPARE(testClassProperty.enumerator().isScoped(), // 0755 referenceClassProperty.enumerator().isScoped()); 0756 QCOMPARE(testClassProperty.enumerator().isValid(), // 0757 referenceClassProperty.enumerator().isValid()); 0758 QCOMPARE(testClassProperty.enumerator().keyCount(), // 0759 referenceClassProperty.enumerator().keyCount()); 0760 QCOMPARE(testClassProperty.enumerator().name(), // 0761 referenceClassProperty.enumerator().name()); 0762 QCOMPARE(testClassProperty.enumerator().scope(), // 0763 referenceClassProperty.enumerator().scope()); 0764 } 0765 QCOMPARE(testClassProperty.isFinal(), // 0766 referenceClassProperty.isFinal()); 0767 QCOMPARE(testClassProperty.isFlagType(), // 0768 referenceClassProperty.isFlagType()); 0769 QCOMPARE(testClassProperty.isReadable(), // 0770 referenceClassProperty.isReadable()); 0771 QCOMPARE(testClassProperty.isResettable(), // 0772 referenceClassProperty.isResettable()); 0773 QCOMPARE(testClassProperty.isScriptable(), // 0774 referenceClassProperty.isScriptable()); 0775 QCOMPARE(testClassProperty.isStored(), // 0776 referenceClassProperty.isStored()); 0777 QCOMPARE(testClassProperty.isUser(), // 0778 referenceClassProperty.isUser()); 0779 QCOMPARE(testClassProperty.isValid(), // 0780 referenceClassProperty.isValid()); 0781 QCOMPARE(testClassProperty.isWritable(), // 0782 referenceClassProperty.isWritable()); 0783 QCOMPARE(testClassProperty.isWritable(), // 0784 referenceClassProperty.isWritable()); 0785 QCOMPARE(testClassProperty.name(), // 0786 referenceClassProperty.name()); 0787 if (referenceClassProperty.hasNotifySignal()) { 0788 QCOMPARE(testClassProperty.notifySignal().methodSignature(), // 0789 referenceClassProperty.notifySignal().methodSignature()); 0790 QCOMPARE(testClassProperty.notifySignal().methodType(), // 0791 referenceClassProperty.notifySignal().methodType()); 0792 QCOMPARE(testClassProperty.notifySignal().name(), // 0793 referenceClassProperty.notifySignal().name()); 0794 QCOMPARE(testClassProperty.notifySignal().parameterCount(), // 0795 referenceClassProperty.notifySignal().parameterCount()); 0796 QCOMPARE(testClassProperty.notifySignal().parameterNames(), // 0797 referenceClassProperty.notifySignal().parameterNames()); 0798 QCOMPARE(testClassProperty.notifySignal().parameterTypes(), // 0799 referenceClassProperty.notifySignal().parameterTypes()); 0800 QCOMPARE(testClassProperty.notifySignal().returnType(), // 0801 referenceClassProperty.notifySignal().returnType()); 0802 QCOMPARE(testClassProperty.notifySignal().revision(), // 0803 referenceClassProperty.notifySignal().revision()); 0804 QCOMPARE(testClassProperty.notifySignal().tag(), // 0805 referenceClassProperty.notifySignal().tag()); 0806 QCOMPARE(testClassProperty.notifySignal().typeName(), // 0807 referenceClassProperty.notifySignal().typeName()); 0808 } 0809 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0810 QCOMPARE(testClassProperty.metaType(), // 0811 referenceClassProperty.metaType()); 0812 #else 0813 QCOMPARE(testClassProperty.type(), referenceClassProperty.type()); 0814 #endif 0815 QCOMPARE(testClassProperty.typeName(), // 0816 referenceClassProperty.typeName()); 0817 QCOMPARE(testClassProperty.userType(), // 0818 referenceClassProperty.userType()); 0819 } 0820 0821 void testMethodConformance_data() 0822 { 0823 QTest::addColumn<QByteArray>("methodSignature"); 0824 QTest::addColumn<int>("referenceClassIndex"); 0825 QMetaObject referenceClass = QColorDialog::staticMetaObject; 0826 for (int i = 0; i < referenceClass.methodCount(); ++i) { 0827 if (referenceClass.method(i).access() != QMetaMethod::Private) { 0828 // Exclude private methods from conformance check 0829 QTest::newRow(referenceClass.method(i).name().data()) // 0830 << QMetaObject::normalizedSignature( // 0831 referenceClass.method(i).methodSignature().data()) // 0832 << i; 0833 } 0834 } 0835 } 0836 0837 void testMethodConformance() 0838 { 0839 // We do only check QMetaObject::method() and 0840 // not QMetaObject::constructor because QColorDialog 0841 // does not provide its constructors to the 0842 // meta-object system. 0843 QFETCH(QByteArray, methodSignature); 0844 QFETCH(int, referenceClassIndex); 0845 QMetaObject testClass = ColorDialog::staticMetaObject; 0846 QMetaObject referenceClass = QColorDialog::staticMetaObject; 0847 int testClassIndex = testClass.indexOfMethod(methodSignature.data()); 0848 QMetaMethod referenceClassMethod = // 0849 referenceClass.method(referenceClassIndex); 0850 // cppcheck-suppress unreadVariable // false positive 0851 QByteArray message = // 0852 QByteArrayLiteral("Test if method \"") // 0853 + QByteArray(referenceClassMethod.methodSignature()) // 0854 + QByteArrayLiteral("\" of class \"") // 0855 + QByteArray(referenceClass.className()) // 0856 + QByteArrayLiteral("\" is also available in \"") // 0857 + QByteArray(testClass.className()) // 0858 + QByteArrayLiteral("\"."); 0859 QVERIFY2(testClassIndex >= 0, message.constData()); 0860 QMetaMethod testClassMethod = testClass.method(testClassIndex); 0861 QCOMPARE(testClassMethod.access(), // 0862 referenceClassMethod.access()); 0863 QCOMPARE(testClassMethod.isValid(), // 0864 referenceClassMethod.isValid()); 0865 QCOMPARE(testClassMethod.methodSignature(), // 0866 referenceClassMethod.methodSignature()); 0867 QCOMPARE(testClassMethod.methodType(), // 0868 referenceClassMethod.methodType()); 0869 QCOMPARE(testClassMethod.name(), // 0870 referenceClassMethod.name()); 0871 QCOMPARE(testClassMethod.parameterCount(), // 0872 referenceClassMethod.parameterCount()); 0873 QCOMPARE(testClassMethod.parameterNames(), // 0874 referenceClassMethod.parameterNames()); 0875 QCOMPARE(testClassMethod.parameterTypes(), // 0876 referenceClassMethod.parameterTypes()); 0877 QCOMPARE(testClassMethod.returnType(), // 0878 referenceClassMethod.returnType()); 0879 QCOMPARE(testClassMethod.revision(), // 0880 referenceClassMethod.revision()); 0881 QCOMPARE(testClassMethod.tag(), // 0882 referenceClassMethod.tag()); 0883 QCOMPARE(testClassMethod.typeName(), // 0884 referenceClassMethod.typeName()); 0885 } 0886 0887 void testRttiConformance() 0888 { 0889 QMetaObject testClass = ColorDialog::staticMetaObject; 0890 QMetaObject referenceClass = QColorDialog::staticMetaObject; 0891 QVERIFY2(testClass.inherits(referenceClass.superClass()), 0892 "Test that ColorDialog inherits " 0893 "from QColorDialog’s superclass."); 0894 } 0895 0896 void testCurrentColorChangedSignal() 0897 { 0898 m_perceptualDialog.reset( // 0899 new ColorDialog(m_srgbBuildinColorSpace)); 0900 m_qDialog.reset(new QColorDialog()); 0901 m_perceptualDialog->show(); 0902 m_qDialog->show(); 0903 QSignalSpy spyPerceptualDialog( // 0904 m_perceptualDialog.data(), // 0905 &ColorDialog::currentColorChanged); 0906 QSignalSpy spyQDialog(m_qDialog.data(), // 0907 &QColorDialog::currentColorChanged); 0908 0909 // Test that a simple “return key” click by the user 0910 // does not call this signal 0911 QTest::keyClick(m_perceptualDialog.data(), Qt::Key_Return); 0912 QTest::keyClick(m_qDialog.data(), Qt::Key_Return); 0913 QCOMPARE(spyPerceptualDialog.count(), 0); 0914 QCOMPARE(spyPerceptualDialog.count(), spyQDialog.count()); 0915 0916 // A different color should call the signal 0917 m_perceptualDialog->setCurrentColor(QColor(1, 2, 3)); 0918 m_qDialog->setCurrentColor(QColor(1, 2, 3)); 0919 QCOMPARE(spyPerceptualDialog.count(), 1); 0920 QCOMPARE(spyPerceptualDialog.count(), spyQDialog.count()); 0921 0922 // The same color again should not call again the signal 0923 m_perceptualDialog->setCurrentColor(QColor(1, 2, 3)); 0924 m_qDialog->setCurrentColor(QColor(1, 2, 3)); 0925 QCOMPARE(spyPerceptualDialog.count(), 1); 0926 QCOMPARE(spyPerceptualDialog.count(), spyQDialog.count()); 0927 0928 // The same RGB values, but defined in another color model, should not 0929 // emit a signal either. 0930 m_perceptualDialog->setCurrentColor(QColor(1, 2, 3).toHsl()); 0931 m_qDialog->setCurrentColor(QColor(1, 2, 3).toHsl()); 0932 QCOMPARE(spyPerceptualDialog.count(), 1); 0933 QCOMPARE(spyPerceptualDialog.count(), spyQDialog.count()); 0934 0935 // Changing QColorDialog::ShowAlphaChannel should 0936 // not emit a signal either 0937 m_perceptualDialog->setOption( // 0938 QColorDialog::ShowAlphaChannel, // 0939 false); 0940 m_qDialog->setOption( // 0941 QColorDialog::ShowAlphaChannel, // 0942 false); 0943 QCOMPARE(spyPerceptualDialog.count(), 1); 0944 QCOMPARE(spyPerceptualDialog.count(), spyQDialog.count()); 0945 } 0946 0947 void testCurrentColorProperty_data() 0948 { 0949 helperProvideQColors(); 0950 } 0951 0952 void testCurrentColorProperty() 0953 { 0954 QFETCH(QColor, color); 0955 QColor correctedColor; 0956 if (color.isValid()) { 0957 correctedColor = color.toRgb(); 0958 } else { 0959 correctedColor = Qt::black; 0960 } 0961 QColor opaqueColor = correctedColor; 0962 opaqueColor.setAlpha(255); 0963 0964 m_perceptualDialog.reset( // 0965 new ColorDialog(m_srgbBuildinColorSpace)); 0966 m_qDialog.reset(new QColorDialog); 0967 m_qDialog->setOption(QColorDialog::DontUseNativeDialog, true); 0968 m_perceptualDialog->setOption( // 0969 QColorDialog::ShowAlphaChannel, // 0970 true); 0971 m_qDialog->setOption( // 0972 QColorDialog::ShowAlphaChannel, // 0973 true); 0974 m_perceptualDialog->setCurrentColor(color); 0975 m_qDialog->setCurrentColor(color); 0976 // Test conformance (but only integer precision) 0977 QCOMPARE(m_perceptualDialog->currentColor().rgb(), // 0978 m_qDialog->currentColor().rgb()); 0979 if (color.isValid()) { 0980 // Testing alpha value conformance only for valid QColor inputs, 0981 // because QColorDialog has here some surprising behaviour that 0982 // we won’t imitate. 0983 QCOMPARE(m_perceptualDialog->currentColor().alpha(), // 0984 m_qDialog->currentColor().alpha()); 0985 } 0986 QCOMPARE(static_cast<int>(m_perceptualDialog->currentColor().spec()), // 0987 static_cast<int>(m_qDialog->currentColor().spec())); 0988 // Test post condition (but only integer precision) 0989 QCOMPARE(m_perceptualDialog->currentColor().rgb(), // 0990 correctedColor.rgb()); 0991 QCOMPARE(m_perceptualDialog->currentColor().alpha(), // 0992 correctedColor.alpha()); 0993 QCOMPARE(static_cast<int>(m_perceptualDialog->currentColor().spec()), // 0994 static_cast<int>(correctedColor.spec())); 0995 0996 // Test that changing QColorDialog::ShowAlphaChannel 0997 // alone does not change the currentColor property 0998 m_perceptualDialog->setOption( // 0999 QColorDialog::ShowAlphaChannel, // 1000 false); 1001 m_qDialog->setOption( // 1002 QColorDialog::ShowAlphaChannel, // 1003 false); 1004 // Test conformance (but only integer precision) 1005 QCOMPARE(m_perceptualDialog->currentColor().rgb(), // 1006 m_qDialog->currentColor().rgb()); 1007 if (color.isValid()) { 1008 // Testing alpha value conformance only for valid QColor inputs, 1009 // because QColorDialog has here some surprising behaviour that 1010 // we won’t imitate. 1011 QCOMPARE(m_perceptualDialog->currentColor().alpha(), // 1012 m_qDialog->currentColor().alpha()); 1013 } 1014 QCOMPARE(static_cast<int>(m_perceptualDialog->currentColor().spec()), // 1015 static_cast<int>(m_qDialog->currentColor().spec())); 1016 // Test post condition (but only integer precision) 1017 QCOMPARE(m_perceptualDialog->currentColor().rgb(), // 1018 correctedColor.rgb()); 1019 QCOMPARE(m_perceptualDialog->currentColor().alpha(), // 1020 correctedColor.alpha()); 1021 QCOMPARE(static_cast<int>(m_perceptualDialog->currentColor().spec()), // 1022 static_cast<int>(correctedColor.spec())); 1023 1024 m_perceptualDialog->setOption(QColorDialog::ShowAlphaChannel, false); 1025 m_qDialog->setOption( // 1026 QColorDialog::ShowAlphaChannel, // 1027 false); 1028 m_perceptualDialog->setCurrentColor(color); 1029 m_qDialog->setCurrentColor(color); 1030 // Test conformance (but only integer precision) 1031 QCOMPARE(m_perceptualDialog->currentColor().rgb(), // 1032 m_qDialog->currentColor().rgb()); 1033 QCOMPARE(m_perceptualDialog->currentColor().alpha(), // 1034 m_qDialog->currentColor().alpha()); 1035 QCOMPARE(static_cast<int>(m_perceptualDialog->currentColor().spec()), // 1036 static_cast<int>(m_qDialog->currentColor().spec())); 1037 // Test post condition (but only integer precision) 1038 QCOMPARE(m_perceptualDialog->currentColor().rgb(), opaqueColor.rgb()); 1039 QCOMPARE(m_perceptualDialog->currentColor().alpha(), // 1040 opaqueColor.alpha()); 1041 QCOMPARE(static_cast<int>(m_perceptualDialog->currentColor().spec()), // 1042 static_cast<int>(opaqueColor.spec())); 1043 1044 // Test that changing QColorDialog::ShowAlphaChannel 1045 // alone does not change the currentColor property 1046 m_perceptualDialog->setOption( // 1047 QColorDialog::ShowAlphaChannel, // 1048 true); 1049 m_qDialog->setOption( // 1050 QColorDialog::ShowAlphaChannel, // 1051 true); 1052 // Test conformance (but only integer precision) 1053 QCOMPARE(m_perceptualDialog->currentColor().rgb(), // 1054 m_qDialog->currentColor().rgb()); 1055 QCOMPARE(m_perceptualDialog->currentColor().alpha(), // 1056 m_qDialog->currentColor().alpha()); 1057 QCOMPARE(static_cast<int>(m_perceptualDialog->currentColor().spec()), // 1058 static_cast<int>(m_qDialog->currentColor().spec())); 1059 // Test post condition (but only integer precision) 1060 QCOMPARE(m_perceptualDialog->currentColor().rgb(), opaqueColor.rgb()); 1061 QCOMPARE(m_perceptualDialog->currentColor().alpha(), // 1062 opaqueColor.alpha()); 1063 QCOMPARE(static_cast<int>(m_perceptualDialog->currentColor().spec()), // 1064 static_cast<int>(opaqueColor.spec())); 1065 } 1066 1067 #ifndef MSVC_DLL 1068 void testSetCurrentColor() 1069 { 1070 m_perceptualDialog.reset( // 1071 new ColorDialog(m_srgbBuildinColorSpace)); 1072 m_perceptualDialog->show(); 1073 constexpr auto testColor = Qt::yellow; 1074 m_perceptualDialog->setCurrentColor(testColor); 1075 1076 // Get internal LCH value 1077 const auto tmp = m_perceptualDialog->d_pointer->m_currentOpaqueColorAbs; 1078 const LchDouble color = // 1079 tmp.value(ColorModel::CielchD50).reinterpretAsLchToLchDouble(); 1080 1081 // The very same LCH value has to be found in all widgets using it. 1082 // (This is not trivial, because even coming from RGB, because of 1083 // rounding errors, you can get out-of-gamut LCH values when the 1084 // original RGB value was near to the border. And the child 1085 // widgets may change the LCH value that is given to them 1086 // to fit it into the gamut – each widget with a different 1087 // algorithm.) 1088 QVERIFY( // 1089 color.hasSameCoordinates( // 1090 m_perceptualDialog // 1091 ->d_pointer // 1092 ->m_wheelColorPicker // 1093 ->currentColor())); 1094 QVERIFY( // 1095 color.hasSameCoordinates( // 1096 m_perceptualDialog // 1097 ->d_pointer // 1098 ->m_chromaHueDiagram // 1099 ->currentColor())); 1100 // We do not also control this here for 1101 // m_perceptualDialog->d_pointer->m_ciehlcD50SpinBox because this 1102 // widget rounds the given value to the current decimal precision 1103 // it’s using. Therefore, it’s pointless to control here 1104 // for rounding errors. 1105 1106 const auto sliderColor = // 1107 m_perceptualDialog->d_pointer->m_alphaGradientSlider->secondColor(); 1108 QCOMPARE(sliderColor.l, color.l); 1109 QCOMPARE(sliderColor.c, color.c); 1110 QCOMPARE(sliderColor.h, color.h); 1111 } 1112 #endif 1113 1114 void testOpen() 1115 { 1116 // Test our reference (QColorDialog) 1117 m_color = Qt::black; 1118 m_qDialog.reset(new QColorDialog); 1119 m_qDialog->setOption(QColorDialog::DontUseNativeDialog, true); 1120 m_qDialog->setCurrentColor(Qt::white); 1121 m_qDialog->open(this, SLOT(helperReceiveSignals(QColor))); 1122 m_qDialog->setCurrentColor(Qt::red); 1123 // Changing the current color does not emit the signal 1124 QCOMPARE(m_color, Qt::black); 1125 QTest::keyClick(m_qDialog.data(), Qt::Key_Return); 1126 // Return key really emits a signal 1127 QCOMPARE(m_color, Qt::red); 1128 m_qDialog->show(); 1129 m_qDialog->setCurrentColor(Qt::green); 1130 QTest::keyClick(m_qDialog.data(), Qt::Key_Return); 1131 // The signal is really disconnected after the dialog has been closed. 1132 QCOMPARE(m_color, Qt::red); 1133 1134 // Now test if ColorDialog does the same 1135 // thing as our reference 1136 m_color = Qt::black; 1137 m_perceptualDialog.reset( // 1138 new ColorDialog(m_srgbBuildinColorSpace)); 1139 m_perceptualDialog->setCurrentColor(Qt::white); 1140 m_perceptualDialog->open(this, SLOT(helperReceiveSignals(QColor))); 1141 m_perceptualDialog->setCurrentColor(Qt::red); 1142 // Changing the current color does not emit the signal 1143 QCOMPARE(m_color, Qt::black); 1144 QTest::keyClick(m_perceptualDialog.data(), Qt::Key_Return); 1145 // Return key really emits a signal 1146 QCOMPARE(m_color, Qt::red); 1147 m_perceptualDialog->show(); 1148 m_perceptualDialog->setCurrentColor(Qt::green); 1149 QTest::keyClick(m_perceptualDialog.data(), Qt::Key_Return); 1150 // The signal is really disconnected after the dialog has been closed. 1151 QCOMPARE(m_color, Qt::red); 1152 } 1153 1154 void testDefaultOptions() 1155 { 1156 m_perceptualDialog.reset( // 1157 new ColorDialog(m_srgbBuildinColorSpace)); 1158 m_qDialog.reset(new QColorDialog); 1159 QCOMPARE( // 1160 m_perceptualDialog->testOption( // 1161 QColorDialog::DontUseNativeDialog), // 1162 true); 1163 QCOMPARE( // 1164 m_perceptualDialog->testOption(QColorDialog::NoButtons), // 1165 false); 1166 QCOMPARE( // 1167 m_perceptualDialog->testOption(QColorDialog::NoButtons), // 1168 m_qDialog->testOption(QColorDialog::NoButtons)); 1169 QCOMPARE( // 1170 m_perceptualDialog->testOption(QColorDialog::ShowAlphaChannel), // 1171 false); 1172 QCOMPARE( // 1173 m_perceptualDialog->testOption(QColorDialog::ShowAlphaChannel), // 1174 m_qDialog->testOption(QColorDialog::ShowAlphaChannel)); 1175 QCOMPARE( // 1176 m_perceptualDialog->options().testFlag( // 1177 QColorDialog::DontUseNativeDialog), // 1178 true); 1179 QCOMPARE( // 1180 m_perceptualDialog->options().testFlag(QColorDialog::NoButtons), // 1181 false); 1182 QCOMPARE( // 1183 m_perceptualDialog->options().testFlag(QColorDialog::NoButtons), // 1184 m_qDialog->options().testFlag(QColorDialog::NoButtons)); 1185 QCOMPARE( // 1186 m_perceptualDialog->options().testFlag( // 1187 QColorDialog::ShowAlphaChannel), // 1188 false); 1189 QCOMPARE( // 1190 m_perceptualDialog->options().testFlag( // 1191 QColorDialog::ShowAlphaChannel), // 1192 m_qDialog->options().testFlag(QColorDialog::ShowAlphaChannel)); 1193 } 1194 1195 void testOptionDontUseNativeDialogAlwaysTrue() 1196 { 1197 m_perceptualDialog.reset( // 1198 new ColorDialog(m_srgbBuildinColorSpace)); 1199 m_perceptualDialog->setOption(QColorDialog::DontUseNativeDialog); 1200 QCOMPARE( // 1201 m_perceptualDialog->testOption( // 1202 QColorDialog::DontUseNativeDialog), // 1203 true); 1204 QCOMPARE( // 1205 m_perceptualDialog->options().testFlag( // 1206 QColorDialog::DontUseNativeDialog), // 1207 true); 1208 m_perceptualDialog->setOptions(QColorDialog::DontUseNativeDialog); 1209 QCOMPARE( // 1210 m_perceptualDialog->testOption( // 1211 QColorDialog::DontUseNativeDialog), // 1212 true); 1213 QCOMPARE( // 1214 m_perceptualDialog->options().testFlag( // 1215 QColorDialog::DontUseNativeDialog), 1216 true); 1217 m_perceptualDialog->setOptions( // 1218 QColorDialog::DontUseNativeDialog | QColorDialog::NoButtons); 1219 QCOMPARE( // 1220 m_perceptualDialog->testOption( // 1221 QColorDialog::DontUseNativeDialog), // 1222 true); 1223 QCOMPARE( // 1224 m_perceptualDialog->options().testFlag( // 1225 QColorDialog::DontUseNativeDialog), // 1226 true); 1227 m_perceptualDialog->setOptions( // 1228 QColorDialog::DontUseNativeDialog | QColorDialog::ShowAlphaChannel); 1229 QCOMPARE( // 1230 m_perceptualDialog->testOption( // 1231 QColorDialog::DontUseNativeDialog), // 1232 true); 1233 QCOMPARE( // 1234 m_perceptualDialog->options().testFlag( // 1235 QColorDialog::DontUseNativeDialog), // 1236 true); 1237 m_perceptualDialog->setOptions( // 1238 QColorDialog::DontUseNativeDialog // 1239 | QColorDialog::ShowAlphaChannel // 1240 | QColorDialog::NoButtons); 1241 QCOMPARE( // 1242 m_perceptualDialog->testOption( // 1243 QColorDialog::DontUseNativeDialog), // 1244 true); 1245 QCOMPARE( // 1246 m_perceptualDialog->options().testFlag( // 1247 QColorDialog::DontUseNativeDialog), // 1248 true); 1249 } 1250 1251 #ifdef Q_OS_LINUX 1252 // Linux has no native color dialog, so it is the only system guaranteed 1253 // to use QColorDialog’s own implementation not only after calling 1254 // QColorDialog::setOption(QColorDialog::DontUseNativeDialog, true); 1255 // but yet on QColorDialog’s constructor call. 1256 void testOptionShowAlpha() 1257 { 1258 m_perceptualDialog.reset( // 1259 new ColorDialog(m_srgbBuildinColorSpace, QColor(Qt::white))); 1260 m_qDialog.reset(new QColorDialog); 1261 m_perceptualDialog->setOption( // 1262 QColorDialog::ShowAlphaChannel); 1263 QVERIFY2( // 1264 m_perceptualDialog->testOption(QColorDialog::ShowAlphaChannel), // 1265 "ShowAlphaChannel successfully set."); 1266 m_qDialog->setOption(QColorDialog::ShowAlphaChannel); 1267 m_perceptualDialog->show(); 1268 m_qDialog->show(); 1269 helperCompareDialog(m_perceptualDialog.data(), m_qDialog.data()); 1270 QColor tempColor = QColor(1, 101, 201, 155); 1271 m_perceptualDialog->setCurrentColor(tempColor); 1272 m_qDialog->setCurrentColor(tempColor); 1273 helperCompareDialog(m_perceptualDialog.data(), m_qDialog.data()); 1274 m_perceptualDialog->setOption( // 1275 QColorDialog::ShowAlphaChannel, // 1276 false); 1277 QVERIFY2( // 1278 !m_perceptualDialog->testOption(QColorDialog::ShowAlphaChannel), // 1279 "ShowAlphaChannel successfully set."); 1280 m_qDialog->setOption(QColorDialog::ShowAlphaChannel, false); 1281 helperCompareDialog(m_perceptualDialog.data(), m_qDialog.data()); 1282 tempColor = QColor(5, 105, 205, 133); 1283 m_perceptualDialog->setCurrentColor(tempColor); 1284 m_qDialog->setCurrentColor(tempColor); 1285 helperCompareDialog(m_perceptualDialog.data(), m_qDialog.data()); 1286 } 1287 #endif 1288 1289 #ifdef Q_OS_LINUX 1290 // Linux has no native color dialog, so it is the only system guaranteed 1291 // to use QColorDialog’s own implementation not only after calling 1292 // QColorDialog::setOption(QColorDialog::DontUseNativeDialog, true); 1293 // but yet on QColorDialog’s constructor call. 1294 void testOptionNoButtons() 1295 { 1296 m_perceptualDialog.reset( // 1297 new ColorDialog( // 1298 m_srgbBuildinColorSpace, // 1299 QColor(Qt::white) // 1300 ) // 1301 ); 1302 m_qDialog.reset(new QColorDialog); 1303 m_perceptualDialog->setOption( // 1304 QColorDialog::NoButtons); 1305 QVERIFY2( // 1306 m_perceptualDialog->testOption(QColorDialog::NoButtons), // 1307 "NoButtons successfully set to true."); 1308 m_qDialog->setOption(QColorDialog::NoButtons); 1309 m_perceptualDialog->show(); 1310 m_qDialog->show(); 1311 helperCompareDialog(m_perceptualDialog.data(), m_qDialog.data()); 1312 QTest::keyClick(m_perceptualDialog.data(), Qt::Key_Return); 1313 QTest::keyClick(m_qDialog.data(), Qt::Key_Return); 1314 QCOMPARE(m_perceptualDialog->isVisible(), m_qDialog->isVisible()); 1315 QVERIFY2(m_perceptualDialog->isVisible(), // 1316 "Should still visible after Return key pressed."); 1317 helperCompareDialog(m_perceptualDialog.data(), m_qDialog.data()); 1318 QTest::keyClick(m_perceptualDialog.data(), Qt::Key_Escape); 1319 QTest::keyClick(m_qDialog.data(), Qt::Key_Escape); 1320 QCOMPARE(m_perceptualDialog->isVisible(), m_qDialog->isVisible()); 1321 QVERIFY2(!m_perceptualDialog->isVisible(), // 1322 "Should no longer be visible after Escape key pressed."); 1323 helperCompareDialog(m_perceptualDialog.data(), m_qDialog.data()); 1324 1325 m_perceptualDialog->setOption(QColorDialog::NoButtons, false); 1326 QVERIFY2(!m_perceptualDialog->testOption(QColorDialog::NoButtons), // 1327 "NoButtons successfully set to false."); 1328 m_qDialog->setOption(QColorDialog::NoButtons, false); 1329 m_perceptualDialog->show(); 1330 m_qDialog->show(); 1331 helperCompareDialog(m_perceptualDialog.data(), m_qDialog.data()); 1332 QTest::keyClick(m_perceptualDialog.data(), Qt::Key_Return); 1333 QTest::keyClick(m_qDialog.data(), Qt::Key_Return); 1334 QCOMPARE(m_perceptualDialog->isVisible(), m_qDialog->isVisible()); 1335 QVERIFY2(!m_perceptualDialog->isVisible(), // 1336 "Should no longer be visible after Return key pressed."); 1337 helperCompareDialog(m_perceptualDialog.data(), m_qDialog.data()); 1338 } 1339 #endif 1340 1341 void testSetOptionAndTestOptionInteraction() 1342 { 1343 m_perceptualDialog.reset( // 1344 new ColorDialog(m_srgbBuildinColorSpace)); 1345 // Test if the option changes as expected 1346 m_perceptualDialog->setOption(QColorDialog::ShowAlphaChannel, // 1347 true); 1348 QCOMPARE( // 1349 m_perceptualDialog->testOption(QColorDialog::ShowAlphaChannel), // 1350 true); 1351 m_perceptualDialog->setOption(QColorDialog::ShowAlphaChannel, // 1352 false); 1353 QCOMPARE( // 1354 m_perceptualDialog->testOption(QColorDialog::ShowAlphaChannel), // 1355 false); 1356 m_perceptualDialog->setOption(QColorDialog::ShowAlphaChannel, // 1357 true); 1358 QCOMPARE( // 1359 m_perceptualDialog->testOption(QColorDialog::ShowAlphaChannel), // 1360 true); 1361 m_perceptualDialog->setOption(QColorDialog::ShowAlphaChannel, // 1362 false); 1363 QCOMPARE( // 1364 m_perceptualDialog->testOption(QColorDialog::ShowAlphaChannel), // 1365 false); 1366 m_perceptualDialog.reset(nullptr); 1367 1368 m_perceptualDialog.reset( // 1369 new ColorDialog(m_srgbBuildinColorSpace)); 1370 // Test if the option changes as expected 1371 m_perceptualDialog->setOption(QColorDialog::ShowAlphaChannel, // 1372 false); 1373 QCOMPARE( // 1374 m_perceptualDialog->testOption(QColorDialog::ShowAlphaChannel), // 1375 false); 1376 m_perceptualDialog->setOption(QColorDialog::ShowAlphaChannel, // 1377 true); 1378 QCOMPARE( // 1379 m_perceptualDialog->testOption(QColorDialog::ShowAlphaChannel), // 1380 true); 1381 m_perceptualDialog->setOption(QColorDialog::ShowAlphaChannel, // 1382 false); 1383 QCOMPARE( // 1384 m_perceptualDialog->testOption(QColorDialog::ShowAlphaChannel), // 1385 false); 1386 m_perceptualDialog->setOption(QColorDialog::ShowAlphaChannel, // 1387 true); 1388 QCOMPARE( // 1389 m_perceptualDialog->testOption(QColorDialog::ShowAlphaChannel), // 1390 true); 1391 m_perceptualDialog.reset(nullptr); 1392 1393 m_perceptualDialog.reset( // 1394 new ColorDialog(m_srgbBuildinColorSpace)); 1395 // Test if the option changes as expected 1396 m_perceptualDialog->setOption( // 1397 QColorDialog::NoButtons, // 1398 true); 1399 QCOMPARE( // 1400 m_perceptualDialog->testOption(QColorDialog::NoButtons), // 1401 true); 1402 m_perceptualDialog->setOption( // 1403 QColorDialog::NoButtons, // 1404 false); 1405 QCOMPARE(m_perceptualDialog->testOption(QColorDialog::NoButtons), // 1406 false); 1407 m_perceptualDialog->setOption( // 1408 QColorDialog::NoButtons, // 1409 true); 1410 QCOMPARE(m_perceptualDialog->testOption(QColorDialog::NoButtons), // 1411 true); 1412 m_perceptualDialog->setOption( // 1413 QColorDialog::NoButtons, // 1414 false); 1415 QCOMPARE(m_perceptualDialog->testOption(QColorDialog::NoButtons), // 1416 false); 1417 m_perceptualDialog.reset(nullptr); 1418 1419 m_perceptualDialog.reset( // 1420 new ColorDialog(m_srgbBuildinColorSpace)); 1421 // Test if the option changes as expected 1422 m_perceptualDialog->setOption( // 1423 QColorDialog::NoButtons, // 1424 false); 1425 QCOMPARE( // 1426 m_perceptualDialog->testOption(QColorDialog::NoButtons), // 1427 false); 1428 m_perceptualDialog->setOption(QColorDialog::NoButtons, true); 1429 QCOMPARE( // 1430 m_perceptualDialog->testOption(QColorDialog::NoButtons), // 1431 true); 1432 m_perceptualDialog->setOption( // 1433 QColorDialog::NoButtons, // 1434 false); 1435 QCOMPARE( // 1436 m_perceptualDialog->testOption(QColorDialog::NoButtons), // 1437 false); 1438 m_perceptualDialog->setOption( // 1439 QColorDialog::NoButtons, // 1440 true); 1441 QCOMPARE( // 1442 m_perceptualDialog->testOption(QColorDialog::NoButtons), // 1443 true); 1444 m_perceptualDialog.reset(nullptr); 1445 1446 m_perceptualDialog.reset( // 1447 new ColorDialog(m_srgbBuildinColorSpace)); 1448 // define an option 1449 m_perceptualDialog->setOption( // 1450 QColorDialog::ShowAlphaChannel, // 1451 true); 1452 // change some other option 1453 m_perceptualDialog->setOption( // 1454 QColorDialog::NoButtons, // 1455 true); 1456 // test if first option is still unchanged 1457 QCOMPARE( // 1458 m_perceptualDialog->testOption(QColorDialog::ShowAlphaChannel), // 1459 true); 1460 m_perceptualDialog.reset(nullptr); 1461 1462 m_perceptualDialog.reset( // 1463 new ColorDialog(m_srgbBuildinColorSpace)); 1464 // define an option 1465 m_perceptualDialog->setOption( // 1466 QColorDialog::ShowAlphaChannel, // 1467 false); 1468 // change some other option 1469 m_perceptualDialog->setOption( // 1470 QColorDialog::NoButtons, // 1471 true); 1472 // test if first option is still unchanged 1473 QCOMPARE( // 1474 m_perceptualDialog->testOption(QColorDialog::ShowAlphaChannel), // 1475 false); 1476 m_perceptualDialog.reset(nullptr); 1477 1478 m_perceptualDialog.reset( // 1479 new ColorDialog(m_srgbBuildinColorSpace)); 1480 // define an option 1481 m_perceptualDialog->setOption( // 1482 QColorDialog::ShowAlphaChannel, // 1483 true); 1484 // change some other option 1485 m_perceptualDialog->setOption( // 1486 QColorDialog::NoButtons, // 1487 false); 1488 // test if first option is still unchanged 1489 QCOMPARE( // 1490 m_perceptualDialog->testOption(QColorDialog::ShowAlphaChannel), // 1491 true); 1492 m_perceptualDialog.reset(nullptr); 1493 1494 m_perceptualDialog.reset( // 1495 new ColorDialog(m_srgbBuildinColorSpace)); 1496 // define an option 1497 m_perceptualDialog->setOption( // 1498 QColorDialog::ShowAlphaChannel, // 1499 false); 1500 // change some other option 1501 m_perceptualDialog->setOption( // 1502 QColorDialog::NoButtons, // 1503 false); 1504 // test if first option is still unchanged 1505 QCOMPARE( // 1506 m_perceptualDialog->testOption(QColorDialog::ShowAlphaChannel), // 1507 false); 1508 m_perceptualDialog.reset(nullptr); 1509 } 1510 1511 void testRgbInput() 1512 { 1513 m_perceptualDialog.reset( // 1514 new ColorDialog(m_srgbBuildinColorSpace)); 1515 m_perceptualDialog->setOption( // 1516 QColorDialog::ShowAlphaChannel, // 1517 true); 1518 } 1519 1520 void testAlphaSpinbox() 1521 { 1522 m_perceptualDialog.reset( // 1523 new ColorDialog(m_srgbBuildinColorSpace)); 1524 m_perceptualDialog->setOption( // 1525 QColorDialog::ShowAlphaChannel, // 1526 true); 1527 m_perceptualDialog->d_pointer->m_alphaGradientSlider->setValue(0.504); 1528 QCOMPARE( // 1529 m_perceptualDialog->d_pointer->m_alphaGradientSlider->value(), // 1530 0.504); 1531 QCOMPARE(m_perceptualDialog->d_pointer->m_alphaSpinBox->value(), 50); 1532 QTest::keyClick(m_perceptualDialog->d_pointer->m_alphaSpinBox, // 1533 Qt::Key_Up); 1534 QCOMPARE( // 1535 m_perceptualDialog->d_pointer->m_alphaGradientSlider->value(), // 1536 0.51); 1537 QCOMPARE(m_perceptualDialog->d_pointer->m_alphaSpinBox->value(), 51); 1538 } 1539 1540 #ifdef Q_OS_LINUX 1541 // Linux has no native color dialog, so it is the only system guaranteed 1542 // to use QColorDialog’s own implementation not only after calling 1543 // QColorDialog::setOption(QColorDialog::DontUseNativeDialog, true); 1544 // but yet on QColorDialog’s constructor call. 1545 void testSelectedColorAndSetVisible() 1546 { 1547 m_perceptualDialog.reset( // 1548 new ColorDialog(m_srgbBuildinColorSpace)); 1549 m_qDialog.reset(new QColorDialog); 1550 QCOMPARE(m_perceptualDialog->selectedColor(), // 1551 m_qDialog->selectedColor()); 1552 QCOMPARE(m_perceptualDialog->selectedColor(), QColor()); 1553 m_perceptualDialog->setCurrentColor(QColor(Qt::blue)); 1554 m_qDialog->setCurrentColor(QColor(Qt::blue)); 1555 QTest::keyClick(m_perceptualDialog.data(), Qt::Key_Return); 1556 QTest::keyClick(m_qDialog.data(), Qt::Key_Return); 1557 // Still no valid selectedColor() because the dialog still wasn't shown 1558 QCOMPARE(m_perceptualDialog->selectedColor(), // 1559 m_qDialog->selectedColor()); 1560 QCOMPARE(m_perceptualDialog->selectedColor(), QColor()); 1561 m_perceptualDialog->show(); 1562 m_qDialog->show(); 1563 QCOMPARE(m_perceptualDialog->selectedColor(), // 1564 m_qDialog->selectedColor()); 1565 QCOMPARE(m_perceptualDialog->selectedColor(), QColor()); 1566 QTest::keyClick(m_perceptualDialog.data(), Qt::Key_Return); 1567 QTest::keyClick(m_qDialog.data(), Qt::Key_Return); 1568 QCOMPARE(m_perceptualDialog->selectedColor(), // 1569 m_qDialog->selectedColor()); 1570 QCOMPARE(m_perceptualDialog->selectedColor(), QColor(Qt::blue)); 1571 m_perceptualDialog->show(); 1572 m_qDialog->show(); 1573 QCOMPARE(m_perceptualDialog->selectedColor(), // 1574 m_qDialog->selectedColor()); 1575 QCOMPARE(m_perceptualDialog->selectedColor(), QColor()); 1576 QTest::keyClick(m_perceptualDialog.data(), Qt::Key_Escape); 1577 QTest::keyClick(m_qDialog.data(), Qt::Key_Escape); 1578 QCOMPARE(m_perceptualDialog->selectedColor(), // 1579 m_qDialog->selectedColor()); 1580 QCOMPARE(m_perceptualDialog->selectedColor(), QColor()); 1581 m_perceptualDialog->setVisible(true); 1582 m_qDialog->setVisible(true); 1583 QCOMPARE(m_perceptualDialog->selectedColor(), // 1584 m_qDialog->selectedColor()); 1585 QCOMPARE(m_perceptualDialog->selectedColor(), QColor()); 1586 QTest::keyClick(m_perceptualDialog.data(), Qt::Key_Return); 1587 QTest::keyClick(m_qDialog.data(), Qt::Key_Return); 1588 QCOMPARE(m_perceptualDialog->selectedColor(), // 1589 m_qDialog->selectedColor()); 1590 QCOMPARE(m_perceptualDialog->selectedColor(), QColor(Qt::blue)); 1591 m_perceptualDialog->show(); 1592 m_qDialog->show(); 1593 QCOMPARE(m_perceptualDialog->selectedColor(), // 1594 m_qDialog->selectedColor()); 1595 QCOMPARE(m_perceptualDialog->selectedColor(), QColor()); 1596 m_perceptualDialog->hide(); 1597 m_qDialog->hide(); 1598 QCOMPARE(m_perceptualDialog->selectedColor(), // 1599 m_qDialog->selectedColor()); 1600 QCOMPARE(m_perceptualDialog->selectedColor(), QColor()); 1601 } 1602 #endif 1603 1604 void testAliases() 1605 { 1606 m_perceptualDialog.reset( // 1607 new ColorDialog(m_srgbBuildinColorSpace)); 1608 m_qDialog.reset(new QColorDialog); 1609 1610 // Test setting QColorDialog syntax 1611 m_perceptualDialog->setOption(QColorDialog::ShowAlphaChannel); 1612 QCOMPARE( // 1613 m_perceptualDialog->testOption(QColorDialog::ShowAlphaChannel), // 1614 true); 1615 QCOMPARE( // 1616 m_perceptualDialog->testOption // 1617 (ColorDialog::ColorDialogOption::ShowAlphaChannel), // 1618 true); 1619 m_qDialog->setOption( // 1620 QColorDialog::ShowAlphaChannel); 1621 QCOMPARE(m_qDialog->testOption(QColorDialog::ShowAlphaChannel), // 1622 true); 1623 QCOMPARE( // 1624 m_qDialog->testOption( // 1625 ColorDialog::ColorDialogOption::ShowAlphaChannel), // 1626 true); 1627 1628 // Test setting our alias syntax 1629 m_perceptualDialog->setOption( // 1630 ColorDialog::ColorDialogOption::NoButtons); 1631 QCOMPARE( // 1632 m_perceptualDialog->testOption(QColorDialog::NoButtons), 1633 true); 1634 QCOMPARE( // 1635 m_perceptualDialog->testOption( // 1636 ColorDialog::ColorDialogOption::NoButtons), // 1637 true); 1638 m_qDialog->setOption( // 1639 ColorDialog::ColorDialogOption::NoButtons); 1640 QCOMPARE(m_qDialog->testOption(QColorDialog::NoButtons), // 1641 true); 1642 QCOMPARE( // 1643 m_qDialog->testOption(ColorDialog::ColorDialogOption::NoButtons), // 1644 true); 1645 1646 // Test if ColorDialogOptions is compatible (at least for == operator) 1647 // Configure conformance with our dialog: 1648 m_qDialog->setOption(QColorDialog::DontUseNativeDialog); 1649 QCOMPARE(m_perceptualDialog->options(), m_qDialog->options()); 1650 } 1651 1652 #ifndef MSVC_DLL 1653 void testReadLightnessValues() 1654 { 1655 QScopedPointer<ColorDialog> myDialog( // 1656 new ColorDialog(m_srgbBuildinColorSpace)); 1657 myDialog->d_pointer->m_lchLightnessSelector->setValue(0.6); 1658 myDialog->d_pointer->readLightnessValue(); 1659 QCOMPARE(myDialog->d_pointer->m_currentOpaqueColorAbs.value(ColorModel::CielchD50).first, 60); 1660 } 1661 #endif 1662 1663 void testGamutIconCiehlcD50() 1664 { 1665 QScopedPointer<ColorDialog> myDialog( // 1666 new ColorDialog(m_srgbBuildinColorSpace)); 1667 1668 // On startup, the current color should be in-gamut, so no gamut action 1669 // should be visible. 1670 QCOMPARE( // 1671 myDialog->d_pointer->m_ciehlcD50SpinBoxGamutAction->isVisible(), // 1672 false); 1673 QCOMPARE( // 1674 myDialog->d_pointer->m_oklchSpinBoxGamutAction->isVisible(), // 1675 false); 1676 1677 constexpr int iterations = 15; 1678 1679 auto &myCiehlcD50SpinBox = myDialog->d_pointer->m_ciehlcD50SpinBox; 1680 myCiehlcD50SpinBox->setFocus(); 1681 QTest::keyClick(myCiehlcD50SpinBox, Qt::Key_Tab); 1682 QTest::keyClick(myCiehlcD50SpinBox, Qt::Key_Tab); 1683 // Now, the focus should be on the chroma value. 1684 for (int i = 0; i < iterations; ++i) { 1685 QTest::keyClick(myCiehlcD50SpinBox, Qt::Key_PageUp); 1686 } 1687 QCOMPARE( // 1688 myDialog->d_pointer->m_ciehlcD50SpinBoxGamutAction->isVisible(), // 1689 true); 1690 for (int i = 0; i < iterations; ++i) { 1691 QTest::keyClick(myCiehlcD50SpinBox, Qt::Key_PageDown); 1692 } 1693 QCOMPARE( // 1694 myDialog->d_pointer->m_ciehlcD50SpinBoxGamutAction->isVisible(), // 1695 false); 1696 } 1697 1698 void testGamutIconOklch() 1699 { 1700 QScopedPointer<ColorDialog> myDialog( // 1701 new ColorDialog(m_srgbBuildinColorSpace)); 1702 1703 // On startup, the current color should be in-gamut, so no gamut action 1704 // should be visible. 1705 QCOMPARE( // 1706 myDialog->d_pointer->m_oklchSpinBoxGamutAction->isVisible(), // 1707 false); 1708 QCOMPARE( // 1709 myDialog->d_pointer->m_oklchSpinBoxGamutAction->isVisible(), // 1710 false); 1711 1712 constexpr int iterations = 15; 1713 1714 auto &myOklchSpinBox = myDialog->d_pointer->m_oklchSpinBox; 1715 myOklchSpinBox->setFocus(); 1716 QTest::keyClick(myOklchSpinBox, Qt::Key_Tab); 1717 // Now, the focus should be on the chroma value. 1718 for (int i = 0; i < iterations; ++i) { 1719 QTest::keyClick(myOklchSpinBox, Qt::Key_PageUp); 1720 } 1721 QCOMPARE( // 1722 myDialog->d_pointer->m_oklchSpinBoxGamutAction->isVisible(), // 1723 true); 1724 for (int i = 0; i < iterations; ++i) { 1725 QTest::keyClick(myOklchSpinBox, Qt::Key_PageDown); 1726 } 1727 QCOMPARE( // 1728 myDialog->d_pointer->m_oklchSpinBoxGamutAction->isVisible(), // 1729 false); 1730 } 1731 1732 #ifndef MSVC_DLL 1733 void testReadHlcNumericValues() 1734 { 1735 QScopedPointer<ColorDialog> myDialog( // 1736 new ColorDialog(m_srgbBuildinColorSpace)); 1737 QList<double> myValues = // 1738 myDialog->d_pointer->m_ciehlcD50SpinBox->sectionValues(); 1739 1740 // Test with a normal value 1741 myValues[0] = 10; 1742 myValues[1] = 11; 1743 myValues[2] = 12; 1744 myDialog->d_pointer->m_ciehlcD50SpinBox->setSectionValues(myValues); 1745 myDialog->d_pointer->readHlcNumericValues(); 1746 QCOMPARE(myDialog->d_pointer->m_currentOpaqueColorAbs.value(ColorModel::CielchD50).third, 10); 1747 QCOMPARE(myDialog->d_pointer->m_currentOpaqueColorAbs.value(ColorModel::CielchD50).first, 11); 1748 QCOMPARE(myDialog->d_pointer->m_currentOpaqueColorAbs.value(ColorModel::CielchD50).second, 12); 1749 1750 // Test with an out-of-gamut value. Hue and lightness should not change. 1751 myValues[0] = 10; 1752 myValues[1] = 11; 1753 myValues[2] = 50; 1754 myDialog->d_pointer->m_ciehlcD50SpinBox->setSectionValues(myValues); 1755 myDialog->d_pointer->readHlcNumericValues(); 1756 QCOMPARE(myDialog->d_pointer->m_currentOpaqueColorAbs.value(ColorModel::CielchD50).third, 10); 1757 QCOMPARE(myDialog->d_pointer->m_currentOpaqueColorAbs.value(ColorModel::CielchD50).first, 11); 1758 } 1759 #endif 1760 1761 #ifndef MSVC_DLL 1762 void testReadOklchNumericValues() 1763 { 1764 QScopedPointer<ColorDialog> myDialog( // 1765 new ColorDialog(m_srgbBuildinColorSpace)); 1766 QList<double> myValues = // 1767 myDialog->d_pointer->m_oklchSpinBox->sectionValues(); 1768 1769 // Test with a normal value 1770 myValues[0] = 0.25; 1771 myValues[1] = 0.05; 1772 myValues[2] = 3; 1773 myDialog->d_pointer->m_oklchSpinBox->setSectionValues(myValues); 1774 myDialog->d_pointer->readOklchNumericValues(); 1775 QCOMPARE(myDialog->d_pointer->m_currentOpaqueColorAbs.value(ColorModel::OklchD65).first, 0.25); 1776 QCOMPARE(myDialog->d_pointer->m_currentOpaqueColorAbs.value(ColorModel::OklchD65).second, 0.05); 1777 QCOMPARE(myDialog->d_pointer->m_currentOpaqueColorAbs.value(ColorModel::OklchD65).third, 3); 1778 1779 // Test with an out-of-gamut value. Hue and lightness should not change. 1780 myValues[0] = 0.25; 1781 myValues[1] = 0.2; 1782 myValues[2] = 3; 1783 myDialog->d_pointer->m_oklchSpinBox->setSectionValues(myValues); 1784 myDialog->d_pointer->readOklchNumericValues(); 1785 QCOMPARE(myDialog->d_pointer->m_currentOpaqueColorAbs.value(ColorModel::OklchD65).first, 0.25); 1786 QCOMPARE(myDialog->d_pointer->m_currentOpaqueColorAbs.value(ColorModel::OklchD65).third, 3); 1787 } 1788 #endif 1789 1790 void testReadHsvNumericValues() 1791 { 1792 QScopedPointer<ColorDialog> myDialog( // 1793 new ColorDialog(m_srgbBuildinColorSpace)); 1794 QList<double> myValues = // 1795 myDialog->d_pointer->m_hsvSpinBox->sectionValues(); 1796 myValues[0] = 10; 1797 myValues[1] = 11; 1798 myValues[2] = 12; 1799 myDialog->d_pointer->m_hsvSpinBox->setSectionValues(myValues); 1800 myDialog->d_pointer->readHsvNumericValues(); 1801 QCOMPARE(qRound(myDialog->currentColor().hueF() * 360), 10); 1802 QCOMPARE(qRound(myDialog->currentColor().saturationF() * 100), 11); 1803 QCOMPARE(qRound(myDialog->currentColor().valueF() * 100), 12); 1804 } 1805 1806 void testReadRgbHexValues() 1807 { 1808 QScopedPointer<ColorDialog> myDialog( // 1809 new ColorDialog(m_srgbBuildinColorSpace)); 1810 1811 // Test some value 1812 myDialog->d_pointer->m_rgbLineEdit->setText(QStringLiteral("#010203")); 1813 myDialog->d_pointer->readRgbHexValues(); 1814 QCOMPARE(myDialog->currentColor().red(), 1); 1815 QCOMPARE(myDialog->currentColor().green(), 2); 1816 QCOMPARE(myDialog->currentColor().blue(), 3); 1817 QCOMPARE(myDialog->d_pointer->m_rgbLineEdit->text(), // 1818 QStringLiteral("#010203")); 1819 1820 // Test this value which is known to have triggered yet rounding errors! 1821 myDialog->d_pointer->m_rgbLineEdit->setText(QStringLiteral("#ff0000")); 1822 myDialog->d_pointer->readRgbHexValues(); 1823 QCOMPARE(myDialog->currentColor().red(), 255); 1824 QCOMPARE(myDialog->currentColor().green(), 0); 1825 QCOMPARE(myDialog->currentColor().blue(), 0); 1826 QCOMPARE(myDialog->d_pointer->m_rgbLineEdit->text(), // 1827 QStringLiteral("#ff0000")); 1828 1829 // Test this value which is known to have triggered yet rounding errors! 1830 myDialog->d_pointer->m_rgbLineEdit->setText(QStringLiteral("#ef6c00")); 1831 myDialog->d_pointer->readRgbHexValues(); 1832 QCOMPARE(myDialog->currentColor().red(), 239); 1833 QCOMPARE(myDialog->currentColor().green(), 108); 1834 QCOMPARE(myDialog->currentColor().blue(), 0); 1835 QCOMPARE(myDialog->d_pointer->m_rgbLineEdit->text(), // 1836 QStringLiteral("#ef6c00")); 1837 1838 // Test this value which is known to have triggered yet rounding errors! 1839 myDialog->d_pointer->m_rgbLineEdit->setText(QStringLiteral("#ffff00")); 1840 myDialog->d_pointer->readRgbHexValues(); 1841 QCOMPARE(myDialog->currentColor().red(), 255); 1842 QCOMPARE(myDialog->currentColor().green(), 255); 1843 QCOMPARE(myDialog->currentColor().blue(), 0); 1844 QCOMPARE(myDialog->d_pointer->m_rgbLineEdit->text(), // 1845 QStringLiteral("#ffff00")); 1846 } 1847 1848 void testReadRgbNumericValues() 1849 { 1850 QScopedPointer<ColorDialog> myDialog( // 1851 new ColorDialog(m_srgbBuildinColorSpace)); 1852 QList<double> myValues = // 1853 myDialog->d_pointer->m_rgbSpinBox->sectionValues(); 1854 myValues[0] = 10; 1855 myValues[1] = 11; 1856 myValues[2] = 12; 1857 myDialog->d_pointer->m_rgbSpinBox->setSectionValues(myValues); 1858 myDialog->d_pointer->readRgbNumericValues(); 1859 QCOMPARE(myDialog->currentColor().red(), 10); 1860 QCOMPARE(myDialog->currentColor().green(), 11); 1861 QCOMPARE(myDialog->currentColor().blue(), 12); 1862 } 1863 1864 #ifndef MSVC_DLL 1865 void testSetCurrentOpaqueColor() 1866 { 1867 QScopedPointer<ColorDialog> myDialog( // 1868 new ColorDialog(m_srgbBuildinColorSpace)); 1869 const auto myMultiColor = AbsoluteColor::allConversions( // 1870 ColorModel::CielchD50, 1871 GenericColor(30, 40, 50)); 1872 myDialog->d_pointer->setCurrentOpaqueColor(myMultiColor, nullptr); 1873 QCOMPARE(myDialog->d_pointer->m_currentOpaqueColorAbs, myMultiColor); 1874 QList<double> myValues = // 1875 myDialog->d_pointer->m_rgbSpinBox->sectionValues(); 1876 QCOMPARE(qRound(myValues.at(0)), 113); 1877 QCOMPARE(qRound(myValues.at(1)), 53); 1878 QCOMPARE(qRound(myValues.at(2)), 23); 1879 } 1880 #endif 1881 1882 void testUpdateColorPatch() 1883 { 1884 QScopedPointer<ColorDialog> myDialog( // 1885 new ColorDialog(m_srgbBuildinColorSpace)); 1886 myDialog->d_pointer->m_currentOpaqueColorRgb = // 1887 RgbColor::fromRgbQColor(QColor(1, 2, 3)); 1888 myDialog->d_pointer->updateColorPatch(); 1889 QCOMPARE(myDialog->d_pointer->m_colorPatch->color().red(), 1); 1890 QCOMPARE(myDialog->d_pointer->m_colorPatch->color().green(), 2); 1891 QCOMPARE(myDialog->d_pointer->m_colorPatch->color().blue(), 3); 1892 QCOMPARE(myDialog->d_pointer->m_colorPatch->color().alphaF(), // 1893 myDialog->d_pointer->m_alphaGradientSlider->value()); 1894 } 1895 1896 void testSizeGrip() 1897 { 1898 // As this dialog can indeed be resized, the size grip should 1899 // be enabled. So, users can see the little triangle at the 1900 // right bottom of the dialog (or the left bottom on a 1901 // right-to-left layout). So, the user will be aware 1902 // that he can indeed resize this dialog, which is 1903 // important as the users are used to the default 1904 // platform dialog, which often does not allow resizing. Therefore, 1905 // by default, QDialog::isSizeGripEnabled() should be true. 1906 // NOTE: Some widget styles like Oxygen or Breeze leave the size grip 1907 // widget invisible; nevertheless it reacts on mouse events. Other 1908 // widget styles indeed show the size grip widget, like Fusion or 1909 // QtCurve. 1910 m_perceptualDialog.reset( // 1911 new ColorDialog(m_srgbBuildinColorSpace)); 1912 QCOMPARE(m_perceptualDialog->isSizeGripEnabled(), true); 1913 m_perceptualDialog->show(); 1914 QCOMPARE(m_perceptualDialog->isSizeGripEnabled(), true); 1915 m_perceptualDialog->hide(); 1916 QCOMPARE(m_perceptualDialog->isSizeGripEnabled(), true); 1917 } 1918 1919 void testLayoutDimensions() 1920 { 1921 m_perceptualDialog.reset( // 1922 new ColorDialog(m_srgbBuildinColorSpace)); 1923 // Test default value 1924 QCOMPARE( // 1925 m_perceptualDialog->layoutDimensions(), // 1926 ColorDialog::DialogLayoutDimensions::Collapsed); 1927 1928 // Test if values are correctly stored before showing 1929 m_perceptualDialog->setLayoutDimensions( // 1930 ColorDialog::DialogLayoutDimensions::Collapsed); 1931 QCOMPARE( // 1932 m_perceptualDialog->layoutDimensions(), // 1933 ColorDialog::DialogLayoutDimensions::Collapsed); 1934 m_perceptualDialog->setLayoutDimensions( // 1935 ColorDialog::DialogLayoutDimensions::Expanded); 1936 QCOMPARE( // 1937 m_perceptualDialog->layoutDimensions(), // 1938 ColorDialog::DialogLayoutDimensions::Expanded); 1939 m_perceptualDialog->setLayoutDimensions( // 1940 ColorDialog::DialogLayoutDimensions::ScreenSizeDependent); 1941 QCOMPARE( // 1942 m_perceptualDialog->layoutDimensions(), // 1943 ColorDialog::DialogLayoutDimensions::ScreenSizeDependent); 1944 1945 // Test if values are correctly stored after showing 1946 m_perceptualDialog->show(); 1947 m_perceptualDialog->setLayoutDimensions( // 1948 ColorDialog::DialogLayoutDimensions::Collapsed); 1949 QCOMPARE( // 1950 m_perceptualDialog->layoutDimensions(), // 1951 ColorDialog::DialogLayoutDimensions::Collapsed); 1952 m_perceptualDialog->setLayoutDimensions( // 1953 ColorDialog::DialogLayoutDimensions::Expanded); 1954 QCOMPARE( // 1955 m_perceptualDialog->layoutDimensions(), // 1956 ColorDialog::DialogLayoutDimensions::Expanded); 1957 m_perceptualDialog->setLayoutDimensions( // 1958 ColorDialog::DialogLayoutDimensions::ScreenSizeDependent); 1959 QCOMPARE( // 1960 m_perceptualDialog->layoutDimensions(), // 1961 ColorDialog::DialogLayoutDimensions::ScreenSizeDependent); 1962 } 1963 1964 void testApplyLayoutDimensions() 1965 { 1966 m_perceptualDialog.reset( // 1967 new ColorDialog(m_srgbBuildinColorSpace)); 1968 // Test default value 1969 QCOMPARE( // 1970 m_perceptualDialog->layoutDimensions(), // 1971 ColorDialog::DialogLayoutDimensions::Collapsed); 1972 1973 m_perceptualDialog->d_pointer->m_layoutDimensions = // 1974 ColorDialog::DialogLayoutDimensions::Collapsed; 1975 m_perceptualDialog->d_pointer->applyLayoutDimensions(); 1976 int collapsedWidth = m_perceptualDialog->width(); 1977 1978 m_perceptualDialog->d_pointer->m_layoutDimensions = // 1979 ColorDialog::DialogLayoutDimensions::Expanded; 1980 m_perceptualDialog->d_pointer->applyLayoutDimensions(); 1981 int expandedWidth = m_perceptualDialog->width(); 1982 1983 QVERIFY2(collapsedWidth < expandedWidth, 1984 "Verify that collapsed width of the dialog is smaller than " 1985 "the expanded width."); 1986 } 1987 1988 void testLayoutDimensionsChanged() 1989 { 1990 m_perceptualDialog.reset( // 1991 new ColorDialog(m_srgbBuildinColorSpace)); 1992 m_perceptualDialog->setLayoutDimensions( // 1993 ColorDialog::DialogLayoutDimensions::Collapsed); 1994 QSignalSpy spyPerceptualDialog( 1995 // QObject to spy: 1996 m_perceptualDialog.data(), 1997 // Signal to spy: 1998 &ColorDialog::layoutDimensionsChanged); 1999 // Setting a different DialogLayoutDimensions will emit a signal 2000 m_perceptualDialog->setLayoutDimensions( // 2001 ColorDialog::DialogLayoutDimensions::Expanded); 2002 QCOMPARE(spyPerceptualDialog.count(), 1); 2003 // Setting the same DialogLayoutDimensions will not emit a signal again 2004 m_perceptualDialog->setLayoutDimensions( // 2005 ColorDialog::DialogLayoutDimensions::Expanded); 2006 QCOMPARE(spyPerceptualDialog.count(), 1); 2007 } 2008 2009 void testRoundingErrors_data() 2010 { 2011 QTest::addColumn<QColor>("color"); 2012 QTest::newRow("Qt::yellow") << QColor(Qt::yellow); 2013 QColorFloatType red = 1; 2014 QColorFloatType green = 1; 2015 QColorFloatType blue = 0; 2016 while (blue < 1) { 2017 QTest::newRow( // 2018 QStringLiteral("RGB %1 %2 %3") // 2019 .arg(red) // 2020 .arg(green) // 2021 .arg(blue) // 2022 .toUtf8() // 2023 .data()) // 2024 << QColor::fromRgbF(red, green, blue); 2025 blue += 0.1f; 2026 } 2027 } 2028 2029 void testRoundingErrors() 2030 { 2031 QFETCH(QColor, color); 2032 2033 // Moving around between the widgets with the Tab key should 2034 // never trigger a value change. (There could be a value 2035 // change because of rounding errors if the value gets updated 2036 // after the focus leaves, even though no editing has been 2037 // done. This would not be correct, and this test controls this.) 2038 2039 m_perceptualDialog.reset( // 2040 new ColorDialog(m_srgbBuildinColorSpace)); 2041 m_perceptualDialog->setCurrentColor(color); 2042 m_perceptualDialog->show(); 2043 QApplication::setActiveWindow(m_perceptualDialog.data()); 2044 // Using a QList instead of a simple QWidget* to make sure 2045 // not to have infinite loops even is focus passing might be 2046 // broken and never returns to the original focus. 2047 QList<QWidget *> oldFocusWidgets; 2048 for (int i = 0; // 2049 i < m_perceptualDialog->d_pointer->m_tabWidget->count(); // 2050 i++ // 2051 ) { 2052 m_perceptualDialog->d_pointer->m_tabWidget->setCurrentIndex(i); 2053 oldFocusWidgets.clear(); 2054 const QColor oldColor = m_perceptualDialog->currentColor(); 2055 const auto oldOpaqueColorAbs = // 2056 m_perceptualDialog->d_pointer->m_currentOpaqueColorAbs; 2057 const auto oldOpaqueColorRgb = // 2058 m_perceptualDialog->d_pointer->m_currentOpaqueColorRgb; 2059 bool focusPassingIsWorking = true; 2060 while ( // 2061 focusPassingIsWorking // 2062 && (!oldFocusWidgets.contains(QApplication::focusWidget())) // 2063 ) { 2064 oldFocusWidgets.append(QApplication::focusWidget()); 2065 focusPassingIsWorking = m_perceptualDialog->focusNextChild(); 2066 QCOMPARE(oldColor, m_perceptualDialog->currentColor()); 2067 QVERIFY( // 2068 oldOpaqueColorAbs // 2069 == m_perceptualDialog->d_pointer->m_currentOpaqueColorAbs); 2070 QVERIFY( // 2071 oldOpaqueColorRgb // 2072 == m_perceptualDialog->d_pointer->m_currentOpaqueColorRgb); 2073 } 2074 }; 2075 } 2076 2077 void testYellowRounding() 2078 { 2079 // During development was observed a particular bug for which 2080 // we test here. 2081 2082 // As we expect rounding errors, we define a tolerance range, 2083 // which is used both for the assertions and for the actual test. 2084 // This is necessary to guarantee that this test does not produce 2085 // false-positives just because the rounding behaviour of the 2086 // library has changed. 2087 const int toleranceRange = 1; 2088 2089 // Create a ColorDialog 2090 m_perceptualDialog.reset( // 2091 new ColorDialog(m_srgbBuildinColorSpace)); 2092 2093 // Start with Qt::yellow as initial color. 2094 // If this RGB value is interpreted in the sRGB (LittleCMS build-in) 2095 // profile, it has a particular property. Because of the irregular 2096 // shape of the sRGB color space at this position, thinking in 2097 // LCH values, when reducing (!) the chroma step-by-step, we run 2098 // out-of-gamut, before going again in-gamut at even lower chroma 2099 // values. 2100 m_perceptualDialog->setCurrentColor(QColor(Qt::yellow)); 2101 // The value is also converted to HLC 100°, 98%, 95 (rounded) 2102 // visible in the HLC spin box. 2103 QList<double> hlc = // 2104 m_perceptualDialog->d_pointer->m_ciehlcD50SpinBox->sectionValues(); 2105 QVERIFY(hlc.at(0) >= 100 - toleranceRange); // assertion 2106 QVERIFY(hlc.at(0) <= 100 + toleranceRange); // assertion 2107 QVERIFY(hlc.at(1) >= 98 - toleranceRange); // assertion 2108 QVERIFY(hlc.at(1) <= 98 + toleranceRange); // assertion 2109 QVERIFY(hlc.at(2) >= 95 - toleranceRange); // assertion 2110 QVERIFY(hlc.at(2) <= 95 + toleranceRange); // assertion 2111 // Now, the user clicks on the “Apply” button within the HLC spin box. 2112 // We simulate this by simply calling the slot that is connected 2113 // to this action: 2114 m_perceptualDialog->d_pointer->readHlcNumericValues(); 2115 // Now, during development there was a bug observed: The buggy 2116 // behaviour was that the chroma value was changed from 95 to 24. 2117 // The expected result was that the chroma value only changes 2118 // slightly because of rounding (or ideally not at all). 2119 hlc = m_perceptualDialog->d_pointer->m_ciehlcD50SpinBox->sectionValues(); 2120 QVERIFY(hlc.at(2) >= 95 - toleranceRange); 2121 QVERIFY(hlc.at(2) <= 95 + toleranceRange); 2122 } 2123 2124 void testBlackHSV() 2125 { 2126 // In the HSV color space, if V is 0 then the color is black. 2127 // Both, H and S are meaningless. When converting from other 2128 // color spaces, they get probably a default value. However, 2129 // when the user is editing the HSV spin box, we does not expect 2130 // that H or S change when switching from one section to another 2131 // or when the focus leaves. Make sure that H and S are preserved 2132 // during editing even if V becomes 0: 2133 2134 // Create a ColorDialog 2135 m_perceptualDialog.reset( // 2136 new ColorDialog(m_srgbBuildinColorSpace)); 2137 2138 const QList<double> hsvTestData{201, 33, 0}; 2139 m_perceptualDialog->d_pointer->m_hsvSpinBox->setSectionValues( // 2140 hsvTestData); 2141 QCOMPARE( // 2142 m_perceptualDialog->d_pointer->m_hsvSpinBox->sectionValues(), // 2143 hsvTestData); 2144 m_perceptualDialog->d_pointer->readHsvNumericValues(); 2145 QCOMPARE( // 2146 m_perceptualDialog->d_pointer->m_hsvSpinBox->sectionValues(), // 2147 hsvTestData); 2148 } 2149 2150 void testRoundingMultipleError() 2151 { 2152 // This is a test for a bug discovered during development. 2153 2154 // Create a ColorDialog: 2155 m_perceptualDialog.reset( // 2156 new ColorDialog(m_srgbBuildinColorSpace)); 2157 2158 // The user puts into the HLC spin box the value 100° 98% 94: 2159 m_perceptualDialog->d_pointer->m_ciehlcD50SpinBox->setSectionValues( // 2160 QList<double>{100, 98, 94}); 2161 // This is an out-of-gamut color which is not corrected until 2162 // the focus will leave the widget or the Return key is pressed. 2163 // A nearby in-gamut color is around 100° 98% 24; this color 2164 // is used internally to perform the conversion to RGB and other 2165 // color spaces. (It is however still not visible in the HLC 2166 // spin box.) 2167 // 2168 // The RGB spin box becomes: 2169 const QList<double> expectedRgbValues{255, 251, 202}; 2170 QCOMPARE( // 2171 m_perceptualDialog->d_pointer->m_rgbSpinBox->sectionValues(), // 2172 expectedRgbValues); 2173 // Now, the user finishes the editing process (the focus leaves 2174 // the widget or the Return key is pressed or the action button 2175 // is clicked): 2176 m_perceptualDialog->d_pointer->updateHlcButBlockSignals(); 2177 // The buggy result during development phase was an RGB value 2178 // of 252 254 4. Why? 2179 // - The internal value was around 100° 97% 94, but not exactly. 2180 // - Now, the exact (!) value of 100° 97% 94 is applied, and this 2181 // one, converted to RGB, triggers a different rounding. 2182 // The expected result is however still the very same RGB value 2183 // as above: 2184 QCOMPARE( // 2185 m_perceptualDialog->d_pointer->m_rgbSpinBox->sectionValues(), // 2186 expectedRgbValues); 2187 } 2188 2189 #ifndef MSVC_DLL 2190 void testRgbHexRounding() 2191 { 2192 // This is a test for a bug discovered during development. 2193 // QColor can produce a QString that contains a hexadecimal 2194 // (integer) representation of the color, just as used in 2195 // HTML. Example: #0000FF is blue. When rounding to 2196 // integers, apparently it does not use round(), but floor(). 2197 // That is not useful and not inconsistent with the rest of our 2198 // dialog. We want correct rounding! 2199 2200 // Create a ColorDialog: 2201 m_perceptualDialog.reset( // 2202 new ColorDialog(m_srgbBuildinColorSpace)); 2203 2204 // Set a color that triggers the rounding error: 2205 GenericColor testColorLch{97, 94, 100}; 2206 m_perceptualDialog->d_pointer->setCurrentOpaqueColor( 2207 // Color: 2208 AbsoluteColor::allConversions( // 2209 ColorModel::CielchD50, // 2210 testColorLch), 2211 // Widget to ignore: 2212 nullptr); 2213 2214 // Get the actual result 2215 QColor actualHex; 2216 actualHex.setNamedColor( // 2217 m_perceptualDialog->d_pointer->m_rgbLineEdit->text()); 2218 2219 // Get the expected result (We assume our own RGB spin box rounds 2220 // correctly.) 2221 const QList<double> rgbList = 2222 // The the values from the MultiSpinBox: 2223 m_perceptualDialog->d_pointer->m_rgbSpinBox->sectionValues(); 2224 QColor expectedHex = QColor::fromRgb( 2225 // The MultiSpinBox might have decimal places, so we round 2226 // here again. 2227 qRound(rgbList.at(0)), 2228 qRound(rgbList.at(1)), 2229 qRound(rgbList.at(2))); 2230 2231 // Compare 2232 QCOMPARE(actualHex, expectedHex); 2233 } 2234 #endif 2235 2236 #ifndef MSVC_DLL 2237 void testBugMaximumLightness() 2238 { 2239 QScopedPointer<QTemporaryFile> wideGamutProfile( 2240 // Create a temporary actual file… 2241 QTemporaryFile::createNativeFile( 2242 // …from the content of this resource: 2243 QStringLiteral(":/testbed/Compact-ICC-Profiles/Compact-ICC-Profiles/profiles/WideGamutCompat-v4.icc"))); 2244 if (wideGamutProfile.isNull()) { 2245 throw 0; 2246 } 2247 // This test looks for a bug that was seen during development 2248 // phase. When using WideGamutRGB and raising the lightness 2249 // slider up to 100%: Bug behaviour: the color switches 2250 // to 0% lightness. Expected behaviour: the color has almost 2251 // 100% lightness. 2252 auto myColorSpace = RgbColorSpace::createFromFile( // 2253 wideGamutProfile->fileName()); 2254 QCOMPARE(myColorSpace.isNull(), false); // assertion 2255 m_perceptualDialog.reset( // 2256 new ColorDialog(myColorSpace)); 2257 QTest::keyClick( // 2258 m_perceptualDialog->d_pointer->m_lchLightnessSelector, // 2259 Qt::Key_End); 2260 QVERIFY( // 2261 m_perceptualDialog->d_pointer->m_currentOpaqueColorAbs.value(ColorModel::CielchD50).first > 95); 2262 } 2263 #endif 2264 2265 void testExplicitShortcutsExpanded() 2266 { 2267 // Make sure to have mnemonics (like Qt::ALT+Qt::Key_X for "E&xit") 2268 // enabled, also on platforms that disable it by default. 2269 qt_set_sequence_auto_mnemonic(true); 2270 2271 setTranslation(QCoreApplication::instance(), // 2272 QLocale(QLocale::English).uiLanguages()); 2273 // Create a ColorDialog: 2274 m_perceptualDialog.reset( // 2275 new ColorDialog(m_srgbBuildinColorSpace)); 2276 m_perceptualDialog->setLayoutDimensions( // 2277 ColorDialog::DialogLayoutDimensions::Expanded); 2278 m_perceptualDialog->show(); 2279 QApplication::setActiveWindow(m_perceptualDialog.data()); 2280 auto &d = m_perceptualDialog->d_pointer; 2281 2282 d->m_tabWidget->setFocus(); 2283 QTest::keyClick(QApplication::focusWidget(), // 2284 Qt::Key_B, // 2285 Qt::AltModifier); 2286 QCOMPARE(d->m_tabWidget->currentIndex(), // 2287 d->m_tabWidget->indexOf(d->m_swatchBookWrapperWidget)); 2288 2289 d->m_tabWidget->setFocus(); 2290 QTest::keyClick(QApplication::focusWidget(), // 2291 Qt::Key_H, // 2292 Qt::AltModifier); 2293 QCOMPARE(d->m_tabWidget->currentIndex(), // 2294 d->m_tabWidget->indexOf(d->m_hueFirstWrapperWidget)); 2295 2296 d->m_tabWidget->setFocus(); 2297 QTest::keyClick(QApplication::focusWidget(), // 2298 Qt::Key_L, // 2299 Qt::AltModifier); 2300 QCOMPARE(d->m_tabWidget->currentIndex(), // 2301 d->m_tabWidget->indexOf(d->m_lightnessFirstWrapperWidget)); 2302 2303 // Return to "Basic colors" tab 2304 d->m_tabWidget->setFocus(); 2305 QTest::keyClick(QApplication::focusWidget(), // 2306 Qt::Key_B, // 2307 Qt::AltModifier); 2308 QCOMPARE(d->m_tabWidget->currentIndex(), // 2309 d->m_tabWidget->indexOf(d->m_swatchBookWrapperWidget)); 2310 2311 // The shortcut for the "Numerical" works. 2312 d->m_tabWidget->setFocus(); 2313 QTest::keyClick(QApplication::focusWidget(), // 2314 Qt::Key_N, // 2315 Qt::AltModifier); 2316 QCOMPARE(d->m_tabWidget->currentIndex(), // 2317 d->m_tabWidget->indexOf(d->m_swatchBookWrapperWidget)); 2318 2319 const auto indexOfSwatchBookTab = // 2320 d->m_tabWidget->indexOf(d->m_swatchBookWrapperWidget); 2321 const auto toolTip = d->m_tabWidget->tabToolTip(indexOfSwatchBookTab); 2322 const auto toolTipContainsUnderline = // 2323 toolTip.contains(QStringLiteral("<u>")); 2324 QCOMPARE(toolTipContainsUnderline, true); 2325 } 2326 2327 void testExplicitShortcutsCollapsed() 2328 { 2329 // Make sure to have mnemonics (like Qt::ALT+Qt::Key_X for "E&xit") 2330 // enabled, also on platforms that disable it by default. 2331 qt_set_sequence_auto_mnemonic(true); 2332 2333 setTranslation(QCoreApplication::instance(), // 2334 QLocale(QLocale::English).uiLanguages()); 2335 // Create a ColorDialog: 2336 m_perceptualDialog.reset( // 2337 new ColorDialog(m_srgbBuildinColorSpace)); 2338 m_perceptualDialog->setLayoutDimensions( // 2339 ColorDialog::DialogLayoutDimensions::Collapsed); 2340 m_perceptualDialog->show(); 2341 QApplication::setActiveWindow(m_perceptualDialog.data()); 2342 auto &d = m_perceptualDialog->d_pointer; 2343 2344 d->m_tabWidget->setFocus(); 2345 QTest::keyClick(QApplication::focusWidget(), // 2346 Qt::Key_B, // 2347 Qt::AltModifier); 2348 QCOMPARE(d->m_tabWidget->currentIndex(), // 2349 d->m_tabWidget->indexOf(d->m_swatchBookWrapperWidget)); 2350 2351 d->m_tabWidget->setFocus(); 2352 QTest::keyClick(QApplication::focusWidget(), // 2353 Qt::Key_H, // 2354 Qt::AltModifier); 2355 QCOMPARE(d->m_tabWidget->currentIndex(), // 2356 d->m_tabWidget->indexOf(d->m_hueFirstWrapperWidget)); 2357 2358 d->m_tabWidget->setFocus(); 2359 QTest::keyClick(QApplication::focusWidget(), // 2360 Qt::Key_L, // 2361 Qt::AltModifier); 2362 QCOMPARE(d->m_tabWidget->currentIndex(), // 2363 d->m_tabWidget->indexOf(d->m_lightnessFirstWrapperWidget)); 2364 2365 // Return to "Basic colors" tab 2366 d->m_tabWidget->setFocus(); 2367 QTest::keyClick(QApplication::focusWidget(), // 2368 Qt::Key_B, // 2369 Qt::AltModifier); 2370 QCOMPARE(d->m_tabWidget->currentIndex(), // 2371 d->m_tabWidget->indexOf(d->m_swatchBookWrapperWidget)); 2372 2373 // The shortcut for the "Numerical" works. 2374 d->m_tabWidget->setFocus(); 2375 QTest::keyClick(QApplication::focusWidget(), // 2376 Qt::Key_N, // 2377 Qt::AltModifier); 2378 QCOMPARE(d->m_tabWidget->currentIndex(), // 2379 d->m_tabWidget->indexOf(d->m_numericalWidget)); 2380 2381 const auto indexOfSwatchBookTab = // 2382 d->m_tabWidget->indexOf(d->m_swatchBookWrapperWidget); 2383 const auto toolTip = d->m_tabWidget->tabToolTip(indexOfSwatchBookTab); 2384 const auto toolTipContainsUnderline = // 2385 toolTip.contains(QStringLiteral("<u>")); 2386 QCOMPARE(toolTipContainsUnderline, true); 2387 } 2388 2389 void testExplicitShortcutsExpandedDisabled() 2390 { 2391 // Make sure to have mnemonics (like Qt::ALT+Qt::Key_X for "E&xit") 2392 // disabled, also on platforms that enable it by default. 2393 qt_set_sequence_auto_mnemonic(false); 2394 2395 setTranslation(QCoreApplication::instance(), // 2396 QLocale(QLocale::English).uiLanguages()); 2397 // Create a ColorDialog: 2398 m_perceptualDialog.reset( // 2399 new ColorDialog(m_srgbBuildinColorSpace)); 2400 m_perceptualDialog->setLayoutDimensions( // 2401 ColorDialog::DialogLayoutDimensions::Expanded); 2402 m_perceptualDialog->show(); 2403 QApplication::setActiveWindow(m_perceptualDialog.data()); 2404 auto &d = m_perceptualDialog->d_pointer; 2405 2406 const auto originalIndex = d->m_tabWidget->currentIndex(); 2407 2408 // NOTE When mnemonics are disabled, all these key clicks should 2409 // not have any effect. 2410 2411 d->m_tabWidget->setFocus(); 2412 QTest::keyClick(QApplication::focusWidget(), // 2413 Qt::Key_B, // 2414 Qt::AltModifier); 2415 QCOMPARE(d->m_tabWidget->currentIndex(), // 2416 originalIndex); 2417 2418 d->m_tabWidget->setFocus(); 2419 QTest::keyClick(QApplication::focusWidget(), // 2420 Qt::Key_H, // 2421 Qt::AltModifier); 2422 QCOMPARE(d->m_tabWidget->currentIndex(), // 2423 originalIndex); 2424 2425 d->m_tabWidget->setFocus(); 2426 QTest::keyClick(QApplication::focusWidget(), // 2427 Qt::Key_L, // 2428 Qt::AltModifier); 2429 QCOMPARE(d->m_tabWidget->currentIndex(), // 2430 originalIndex); 2431 2432 d->m_tabWidget->setFocus(); 2433 QTest::keyClick(QApplication::focusWidget(), // 2434 Qt::Key_N, // 2435 Qt::AltModifier); 2436 QCOMPARE(d->m_tabWidget->currentIndex(), // 2437 originalIndex); 2438 2439 const auto indexOfSwatchBookTab = // 2440 d->m_tabWidget->indexOf(d->m_swatchBookWrapperWidget); 2441 const auto toolTip = d->m_tabWidget->tabToolTip(indexOfSwatchBookTab); 2442 const auto toolTipContainsUnderline = // 2443 toolTip.contains(QStringLiteral("<u>")); 2444 QCOMPARE(toolTipContainsUnderline, false); 2445 } 2446 2447 void testExplicitShortcutsCollapsedDisabled() 2448 { 2449 // Make sure to have mnemonics (like Qt::ALT+Qt::Key_X for "E&xit") 2450 // disabled, also on platforms that enable it by default. 2451 qt_set_sequence_auto_mnemonic(false); 2452 2453 setTranslation(QCoreApplication::instance(), // 2454 QLocale(QLocale::English).uiLanguages()); 2455 // Create a ColorDialog: 2456 m_perceptualDialog.reset( // 2457 new ColorDialog(m_srgbBuildinColorSpace)); 2458 m_perceptualDialog->setLayoutDimensions( // 2459 ColorDialog::DialogLayoutDimensions::Collapsed); 2460 m_perceptualDialog->show(); 2461 QApplication::setActiveWindow(m_perceptualDialog.data()); 2462 auto &d = m_perceptualDialog->d_pointer; 2463 2464 const auto originalIndex = d->m_tabWidget->currentIndex(); 2465 2466 // NOTE When mnemonics are disabled, all these key clicks should 2467 // not have any effect. 2468 2469 d->m_tabWidget->setFocus(); 2470 QTest::keyClick(QApplication::focusWidget(), // 2471 Qt::Key_B, // 2472 Qt::AltModifier); 2473 QCOMPARE(d->m_tabWidget->currentIndex(), // 2474 originalIndex); 2475 2476 d->m_tabWidget->setFocus(); 2477 QTest::keyClick(QApplication::focusWidget(), // 2478 Qt::Key_H, // 2479 Qt::AltModifier); 2480 QCOMPARE(d->m_tabWidget->currentIndex(), // 2481 originalIndex); 2482 2483 d->m_tabWidget->setFocus(); 2484 QTest::keyClick(QApplication::focusWidget(), // 2485 Qt::Key_L, // 2486 Qt::AltModifier); 2487 QCOMPARE(d->m_tabWidget->currentIndex(), // 2488 originalIndex); 2489 2490 d->m_tabWidget->setFocus(); 2491 QTest::keyClick(QApplication::focusWidget(), // 2492 Qt::Key_N, // 2493 Qt::AltModifier); 2494 QCOMPARE(d->m_tabWidget->currentIndex(), // 2495 originalIndex); 2496 2497 const auto indexOfSwatchBookTab = // 2498 d->m_tabWidget->indexOf(d->m_swatchBookWrapperWidget); 2499 const auto toolTip = d->m_tabWidget->tabToolTip(indexOfSwatchBookTab); 2500 const auto toolTipContainsUnderline = // 2501 toolTip.contains(QStringLiteral("<u>")); 2502 QCOMPARE(toolTipContainsUnderline, false); 2503 } 2504 2505 void testSnippet02() 2506 { 2507 snippet02(); 2508 } 2509 2510 void testSnippet03() 2511 { 2512 snippet03(); 2513 } 2514 2515 void testSnippet05() 2516 { 2517 TestColorDialogSnippetClass mySnippets; 2518 mySnippets.testSnippet05(); 2519 } 2520 2521 void benchmarkCreateAndShowPerceptualDialog() 2522 { 2523 m_perceptualDialog.reset(nullptr); 2524 QBENCHMARK { 2525 m_perceptualDialog.reset( // 2526 new ColorDialog(m_srgbBuildinColorSpace)); 2527 m_perceptualDialog->show(); 2528 m_perceptualDialog->repaint(); 2529 m_perceptualDialog.reset(nullptr); 2530 } 2531 } 2532 2533 void benchmarkCreateAndShowMaximizedPerceptualDialog() 2534 { 2535 m_perceptualDialog.reset(nullptr); 2536 QBENCHMARK { 2537 m_perceptualDialog.reset( // 2538 new ColorDialog(m_srgbBuildinColorSpace)); 2539 m_perceptualDialog->showMaximized(); 2540 m_perceptualDialog->repaint(); 2541 m_perceptualDialog.reset(nullptr); 2542 } 2543 } 2544 2545 void benchmarkCreateAndShowQColorDialog() 2546 { 2547 m_qDialog.reset(nullptr); 2548 QBENCHMARK { 2549 m_qDialog.reset(new QColorDialog); 2550 m_qDialog->show(); 2551 m_qDialog->repaint(); 2552 m_perceptualDialog.reset(nullptr); 2553 } 2554 } 2555 2556 void benchmarkChangeColorPerceptualHueBased() 2557 { 2558 setTranslation(QCoreApplication::instance(), // 2559 QLocale(QLocale::English).uiLanguages()); 2560 m_perceptualDialog.reset( // 2561 new ColorDialog(m_srgbBuildinColorSpace)); 2562 m_perceptualDialog->show(); 2563 2564 QTabWidget *theTabWidget = // 2565 m_perceptualDialog->findChild<QTabWidget *>(); 2566 QVERIFY2(theTabWidget != nullptr, // 2567 "Assert that theTabWidget has actually been found."); 2568 constexpr int myIndex = 1; 2569 // Assert that we got the correct tab widget: 2570 QCOMPARE(theTabWidget->tabToolTip(myIndex), // 2571 QStringLiteral("<a/><u>H</u>ue-based")); 2572 theTabWidget->setCurrentIndex(myIndex); 2573 2574 QBENCHMARK { 2575 m_perceptualDialog->setCurrentColor(Qt::green); 2576 m_perceptualDialog->repaint(); 2577 m_perceptualDialog->setCurrentColor(Qt::blue); 2578 m_perceptualDialog->repaint(); 2579 m_perceptualDialog->setCurrentColor(Qt::yellow); 2580 m_perceptualDialog->repaint(); 2581 } 2582 } 2583 2584 void benchmarkChangeColorPerceptualLightnessBased() 2585 { 2586 setTranslation(QCoreApplication::instance(), // 2587 QLocale(QLocale::English).uiLanguages()); 2588 m_perceptualDialog.reset( // 2589 new ColorDialog(m_srgbBuildinColorSpace)); 2590 m_perceptualDialog->show(); 2591 2592 QTabWidget *theTabWidget = // 2593 m_perceptualDialog->findChild<QTabWidget *>(); 2594 QVERIFY2(theTabWidget != nullptr, // 2595 "Assert that theTabWidget has actually been found."); 2596 constexpr int myIndex = 2; 2597 // Assert that we got the correct tab widget: 2598 QCOMPARE(theTabWidget->tabToolTip(myIndex), // 2599 QStringLiteral("<a/><u>L</u>ightness-based")); 2600 theTabWidget->setCurrentIndex(myIndex); 2601 2602 QBENCHMARK { 2603 m_perceptualDialog->setCurrentColor(Qt::green); 2604 m_perceptualDialog->repaint(); 2605 m_perceptualDialog->setCurrentColor(Qt::blue); 2606 m_perceptualDialog->repaint(); 2607 m_perceptualDialog->setCurrentColor(Qt::yellow); 2608 m_perceptualDialog->repaint(); 2609 } 2610 } 2611 2612 void benchmarkChangeColorQColorDialog() 2613 { 2614 m_qDialog.reset(new QColorDialog); 2615 m_qDialog->show(); 2616 QBENCHMARK { 2617 m_qDialog->setCurrentColor(Qt::green); 2618 m_qDialog->repaint(); 2619 m_qDialog->setCurrentColor(Qt::blue); 2620 m_qDialog->repaint(); 2621 m_qDialog->setCurrentColor(Qt::yellow); 2622 m_qDialog->repaint(); 2623 } 2624 } 2625 2626 // The last unit tests are those who need to change the locale. 2627 // To avoid side-effects, these unit tests are the last ones. 2628 2629 void testChangeEventRetranslate() 2630 { 2631 initializeTranslation(QCoreApplication::instance(), // 2632 QLocale(QLocale::English).uiLanguages()); 2633 m_perceptualDialog.reset( // 2634 new ColorDialog(m_srgbBuildinColorSpace)); 2635 2636 // We test various translations, because we do not know the locale 2637 // of the system on which this unit test will run. As there might 2638 // be some coincidence between QLocale::system() and QLocale(), 2639 // we want to be sure and therefore test three translations. 2640 2641 initializeTranslation(QCoreApplication::instance(), // 2642 QLocale(QLocale::Dutch).uiLanguages()); 2643 { 2644 QEvent temp(QEvent::LanguageChange); 2645 QCoreApplication::sendEvent(m_perceptualDialog.data(), &temp); 2646 } 2647 QCOMPARE(m_perceptualDialog->d_pointer->m_buttonCancel->text(), // 2648 QStringLiteral("&Annuleren")); 2649 2650 initializeTranslation(QCoreApplication::instance(), // 2651 QLocale(QLocale::Catalan).uiLanguages()); 2652 { 2653 QEvent temp(QEvent::LanguageChange); 2654 QCoreApplication::sendEvent(m_perceptualDialog.data(), &temp); 2655 } 2656 QCOMPARE(m_perceptualDialog->d_pointer->m_buttonCancel->text(), // 2657 QStringLiteral("&Cancel·la")); 2658 2659 initializeTranslation(QCoreApplication::instance(), // 2660 QLocale(QLocale::Spanish).uiLanguages()); 2661 { 2662 QEvent temp(QEvent::LanguageChange); 2663 QCoreApplication::sendEvent(m_perceptualDialog.data(), &temp); 2664 } 2665 QCOMPARE(m_perceptualDialog->d_pointer->m_buttonCancel->text(), // 2666 QStringLiteral("&Cancelar")); 2667 } 2668 2669 void testChangeEventRetranslateButtons() 2670 { 2671 initializeTranslation(QCoreApplication::instance(), // 2672 QLocale(QLocale::English).uiLanguages()); 2673 m_perceptualDialog.reset( // 2674 new ColorDialog(m_srgbBuildinColorSpace)); 2675 2676 // There is a particular reason for testing the translation of 2677 // the dialog buttons. We are using standard-buttons generated 2678 // by QDialogButtonBox. These standard-buttons apparently are 2679 // re-translated by QDialogButtonBox, which hooks into LanuageChange 2680 // events of its parent widgets. (LanuageChange events originally 2681 // only go to the top-level widgets.) This is a problem, because 2682 // it might change the text of the buttons from our own translation 2683 // to the Qt translation. Furthermore, QDialogButtonBox uses 2684 // QLocale::system() while we use QLocale(), which means we could 2685 // end up with two different languages after calling retranslate() 2686 // if the implementation would not prevent this problem. Therefore, 2687 // here we test if the implementation actually prevents this problem. 2688 2689 initializeTranslation(QCoreApplication::instance(), // 2690 QLocale(QLocale::Dutch).uiLanguages()); 2691 { 2692 QEvent temp(QEvent::LanguageChange); 2693 QCoreApplication::sendEvent(m_perceptualDialog.data(), &temp); 2694 } 2695 QCOMPARE(m_perceptualDialog->d_pointer->m_buttonCancel->text(), // 2696 QStringLiteral("&Annuleren")); 2697 2698 initializeTranslation(QCoreApplication::instance(), // 2699 QLocale(QLocale::Catalan).uiLanguages()); 2700 { 2701 QEvent temp(QEvent::LanguageChange); 2702 QCoreApplication::sendEvent(m_perceptualDialog.data(), &temp); 2703 } 2704 QCOMPARE(m_perceptualDialog->d_pointer->m_buttonCancel->text(), // 2705 QStringLiteral("&Cancel·la")); 2706 2707 initializeTranslation(QCoreApplication::instance(), // 2708 QLocale(QLocale::Spanish).uiLanguages()); 2709 { 2710 QEvent temp(QEvent::LanguageChange); 2711 QCoreApplication::sendEvent(m_perceptualDialog.data(), &temp); 2712 } 2713 QCOMPARE(m_perceptualDialog->d_pointer->m_buttonCancel->text(), // 2714 QStringLiteral("&Cancelar")); 2715 } 2716 2717 void testRestoreTab_data() 2718 { 2719 QTest::addColumn<ColorDialog::DialogLayoutDimensions>("layout"); 2720 2721 QTest::newRow("Collapsed") // 2722 << ColorDialog::DialogLayoutDimensions::Collapsed; 2723 QTest::newRow("Expanded") // 2724 << ColorDialog::DialogLayoutDimensions::Expanded; 2725 QTest::newRow("ScreenSizeDependent") // 2726 << ColorDialog::DialogLayoutDimensions::ScreenSizeDependent; 2727 } 2728 2729 void testRestoreTab() 2730 { 2731 QFETCH(ColorDialog::DialogLayoutDimensions, layout); 2732 m_perceptualDialog.reset( // 2733 new ColorDialog(m_srgbBuildinColorSpace)); 2734 m_perceptualDialog->setLayoutDimensions(layout); 2735 m_perceptualDialog->show(); // Needed for correct m_tabWidget->count() 2736 2737 QList<int> testList; 2738 const auto tabCount = m_perceptualDialog->d_pointer->m_tabWidget->count(); 2739 testList.reserve(tabCount + 1); 2740 for (int i = 0; i < tabCount; ++i) { 2741 testList.append(i); 2742 } 2743 testList.append(0); // Finally return again to the first tab. 2744 2745 for (const auto i : std::as_const(testList)) { 2746 m_perceptualDialog->d_pointer->m_tabWidget->setCurrentIndex(i); 2747 m_perceptualDialog.reset( // 2748 new ColorDialog(m_srgbBuildinColorSpace)); 2749 // The last tab is only restored on show(). 2750 m_perceptualDialog->setLayoutDimensions(layout); 2751 m_perceptualDialog->show(); 2752 QCOMPARE(m_perceptualDialog->d_pointer->m_tabWidget->currentIndex(), i); 2753 } 2754 } 2755 2756 private: 2757 void unused() 2758 { 2759 // These will not be called in the unit tests because getColor() 2760 // does not return without user interaction! 2761 // They are noted here to avoid a warning about “unused function”. 2762 snippet01(); 2763 snippet04(); 2764 } 2765 }; 2766 2767 } // namespace PerceptualColor 2768 2769 QTEST_MAIN(PerceptualColor::TestColorDialog) 2770 // The following “include” is necessary because we do not use a header file: 2771 #include "testcolordialog.moc"