diff --git a/src/Gui/PreferencePages/DlgSettingsGeneral.cpp b/src/Gui/PreferencePages/DlgSettingsGeneral.cpp index 0e93f92b1..732457a64 100644 --- a/src/Gui/PreferencePages/DlgSettingsGeneral.cpp +++ b/src/Gui/PreferencePages/DlgSettingsGeneral.cpp @@ -150,7 +150,9 @@ void DlgSettingsGeneral::saveUnitSystemSettings() ParameterGrp::handle hGrpu = App::GetApplication().GetParameterGroupByPath( "User parameter:BaseApp/Preferences/Units" ); - hGrpu->SetInt("UserSchema", ui->comboBox_UnitSystem->currentIndex()); + const int selectedSchema = ui->comboBox_UnitSystem->currentIndex(); + const bool schemaChanged = selectedSchema != hGrpu->GetInt("UserSchema", 0); + hGrpu->SetInt("UserSchema", selectedSchema); hGrpu->SetInt("Decimals", ui->spinBoxDecimals->value()); hGrpu->SetBool("IgnoreProjectSchema", ui->checkBox_projectUnitSystemIgnore->isChecked()); @@ -171,20 +173,26 @@ void DlgSettingsGeneral::saveUnitSystemSettings() // Set the actual format value UnitsApi::setDenominator(FracInch); - // Set and save the Unit System - if (ui->checkBox_projectUnitSystemIgnore->isChecked()) { - // currently selected View System (unit system) - int viewSystemIndex = ui->comboBox_UnitSystem->currentIndex(); - UnitsApi::setSchema(viewSystemIndex); - } - else if (App::Document* doc = App::GetApplication().getActiveDocument()) { - UnitsApi::setSchema(doc->UnitSystem.getValue()); - } - else { - // if there is no existing document then the unit must still be set - int viewSystemIndex = ui->comboBox_UnitSystem->currentIndex(); - UnitsApi::setSchema(viewSystemIndex); - } + // Set and save the Unit System + if (ui->checkBox_projectUnitSystemIgnore->isChecked()) { + // Use the preference for the current view without changing the + // document's own unit system. + UnitsApi::setSchema(selectedSchema); + } + else if (App::Document* doc = App::GetApplication().getActiveDocument()) { + if (schemaChanged) { + getMainWindow()->setUserSchema(selectedSchema); + } + else { + // Applying unrelated preferences or restoring project units must + // preserve the document's own schema. + UnitsApi::setSchema(doc->UnitSystem.getValue()); + } + } + else { + // if there is no existing document then the unit must still be set + UnitsApi::setSchema(selectedSchema); + } ui->SubstituteDecimal->onSave(); ui->UseLocaleFormatting->onSave(); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index edf27339e..56c7f67d0 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -109,6 +109,12 @@ if(WIN32) elseif(EXISTS "${CMAKE_PREFIX_PATH}/bin") list(APPEND _test_env_mod "PATH=path_list_prepend:${CMAKE_PREFIX_PATH}/bin") endif() + set(_qt_platform_plugin_path "${CMAKE_PREFIX_PATH}/lib/qt6/plugins/platforms") + if(EXISTS "${_qt_platform_plugin_path}") + list(APPEND _test_env_mod + "QT_QPA_PLATFORM_PLUGIN_PATH=set:${_qt_platform_plugin_path}" + ) + endif() file(GLOB _mod_dirs LIST_DIRECTORIES true "${CMAKE_BINARY_DIR}/Mod/*") foreach(_mod_dir ${_mod_dirs}) if(IS_DIRECTORY "${_mod_dir}") diff --git a/tests/src/Gui/CMakeLists.txt b/tests/src/Gui/CMakeLists.txt index 78a7dc055..b914eb61d 100644 --- a/tests/src/Gui/CMakeLists.txt +++ b/tests/src/Gui/CMakeLists.txt @@ -29,6 +29,11 @@ setup_qt_test(MacroTaskAcceptance) setup_qt_test(QuantitySpinBox) set(RenderMeshController_LIBS PartGui Part) setup_qt_test(RenderMeshController) +setup_qt_test(UnitSettings) + +target_sources(UnitSettings_Tests_run PRIVATE + ${CMAKE_SOURCE_DIR}/src/Gui/PreferencePages/DlgSettingsGeneral.cpp +) target_link_libraries(Gui_tests_run PRIVATE GTest::gmock_main diff --git a/tests/src/Gui/UnitSettings.cpp b/tests/src/Gui/UnitSettings.cpp new file mode 100644 index 000000000..de898e5d8 --- /dev/null +++ b/tests/src/Gui/UnitSettings.cpp @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +class UnitSettingsTest: public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase() + { + tests::initApplication(); + Gui::Application::initApplication(); + Gui::Application::initOpenInventor(); + guiApplication = std::make_unique(true); + mainWindow = std::make_unique(); + } + + void cleanup() + { + if (!documentName.empty() + && App::GetApplication().getDocument(documentName.c_str())) { + App::GetApplication().closeDocument(documentName.c_str()); + documentName.clear(); + } + preferences()->SetInt("UserSchema", originalSchema); + preferences()->SetBool("IgnoreProjectSchema", originalIgnoreProjectSchema); + Base::UnitsApi::setSchema(originalSchema); + } + + void cleanupTestCase() + { + // FreeCAD's GUI singleton is process-scoped; leave it alive until the + // test process exits rather than tearing it down after QTest. + mainWindow.release(); + guiApplication.release(); + } + + void savingUnitPreferences_data() + { + QTest::addColumn("projectSchema"); + QTest::addColumn("selectedSchema"); + QTest::addColumn("initialIgnore"); + QTest::addColumn("ignoreProject"); + QTest::addColumn("expectedProjectSchema"); + QTest::addColumn("expectedViewSchema"); + + QTest::newRow("change-open-document") << 0 << 3 << false << false << 3 << 3; + QTest::newRow("unchanged-preference") << 3 << 0 << false << false << 3 << 3; + QTest::newRow("ignore-project") << 0 << 3 << false << true << 0 << 3; + QTest::newRow("ignore-project-unchanged") << 3 << 0 << true << true << 3 << 0; + QTest::newRow("restore-project-units") << 3 << 0 << true << false << 3 << 3; + QTest::newRow("change-and-restore-project-units") << 0 << 3 << true << false << 3 << 3; + QTest::newRow("no-document") << -1 << 3 << false << false << -1 << 3; + } + + void savingUnitPreferences() + { + QFETCH(int, projectSchema); + QFETCH(int, selectedSchema); + QFETCH(bool, initialIgnore); + QFETCH(bool, ignoreProject); + QFETCH(int, expectedProjectSchema); + QFETCH(int, expectedViewSchema); + auto units = preferences(); + originalSchema = units->GetInt("UserSchema", 0); + originalIgnoreProjectSchema = units->GetBool("IgnoreProjectSchema", false); + units->SetInt("UserSchema", 0); + units->SetBool("IgnoreProjectSchema", initialIgnore); + Base::UnitsApi::setSchema(0); + + App::Document* document = nullptr; + if (projectSchema >= 0) { + documentName = App::GetApplication().getUniqueDocumentName("unit_settings_test"); + document = App::GetApplication().newDocument(documentName.c_str()); + QVERIFY(document != nullptr); + document->UnitSystem.setValue(static_cast(projectSchema)); + + auto* guiDocument = guiApplication->getDocument(document); + QVERIFY(guiDocument != nullptr); + guiApplication->setActiveDocument(guiDocument); + } + + Gui::Dialog::DlgSettingsGeneral dialog; + dialog.loadSettings(); + auto* unitSystem = dialog.findChild(QStringLiteral("comboBox_UnitSystem")); + QVERIFY(unitSystem != nullptr); + QVERIFY(unitSystem->count() > selectedSchema); + unitSystem->setCurrentIndex(selectedSchema); + auto* ignore = dialog.findChild( + QStringLiteral("checkBox_projectUnitSystemIgnore") + ); + QVERIFY(ignore != nullptr); + ignore->setChecked(ignoreProject); + + dialog.saveSettings(); + + if (document) { + QCOMPARE(document->UnitSystem.getValue(), expectedProjectSchema); + } + QCOMPARE(units->GetInt("UserSchema", 0), selectedSchema); + QCOMPARE(units->GetBool("IgnoreProjectSchema", false), ignoreProject); + const auto translated = Base::UnitsApi::schemaTranslate(Base::Quantity(25.4, "mm")); + QCOMPARE( + QString::fromStdString(translated).contains(QStringLiteral("in")), + expectedViewSchema == 3 + ); + } + +private: + ParameterGrp::handle preferences() const + { + return App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Units" + ); + } + + std::unique_ptr guiApplication; + std::unique_ptr mainWindow; + std::string documentName; + int originalSchema {0}; + bool originalIgnoreProjectSchema {false}; +}; + +QTEST_MAIN(UnitSettingsTest) + +#include "UnitSettings.moc"