// SPDX-License-Identifier: LGPL-2.1-or-later /**************************************************************************** * Copyright (c) 2004 Werner Mayer * * Copyright (c) 2023 FreeCAD Project Association * * * * This file is part of FreeCAD. * * * * FreeCAD is free software: you can redistribute it and/or modify it * * under the terms of the GNU Lesser General Public License as * * published by the Free Software Foundation, either version 2.1 of the * * License, or (at your option) any later version. * * * * FreeCAD is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with FreeCAD. If not, see * * . * * * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "DlgSettingsGeneral.h" #include "ui_DlgSettingsGeneral.h" using namespace Gui; using namespace Gui::Dialog; namespace fs = std::filesystem; using Base::QuantityFormat; using Base::UnitsApi; /* TRANSLATOR Gui::Dialog::DlgSettingsGeneral */ /** * Constructs a DlgSettingsGeneral which is a child of 'parent', with the * name 'name' and widget flags set to 'f' * * The dialog will by default be modeless, unless you set 'modal' to * true to construct a modal dialog. */ DlgSettingsGeneral::DlgSettingsGeneral(QWidget* parent) : PreferencePage(parent) , localeIndex(0) , themeChanged(false) , ui(new Ui_DlgSettingsGeneral) { ui->setupUi(this); recreatePreferencePackMenu(); for (const char* option : Translator::formattingOptions) { ui->UseLocaleFormatting->addItem(QCoreApplication::translate("Gui::Translator", option)); } ui->themesCombobox->setEnabled(true); Gui::Document* doc = Gui::Application::Instance->activeDocument(); if (doc) { Gui::View3DInventor* view = qobject_cast(doc->getActiveView()); if (view) { Gui::View3DInventorViewer* viewer = view->getViewer(); if (viewer->isEditing()) { ui->ImportConfig->setEnabled(false); ui->SaveNewPreferencePack->setEnabled(false); ui->ManagePreferencePacks->setEnabled(false); ui->themesCombobox->setEnabled(false); ui->moreThemesLabel->setEnabled(false); } } } if (ui->themesCombobox->isEnabled()) { connect(ui->ImportConfig, &QPushButton::clicked, this, &DlgSettingsGeneral::onImportConfigClicked); connect( ui->SaveNewPreferencePack, &QPushButton::clicked, this, &DlgSettingsGeneral::saveAsNewPreferencePack ); ui->ManagePreferencePacks->setToolTip(tr("Manage preference packs")); connect( ui->ManagePreferencePacks, &QPushButton::clicked, this, &DlgSettingsGeneral::onManagePreferencePacksClicked ); connect( ui->themesCombobox, qOverload(&QComboBox::activated), this, &DlgSettingsGeneral::onThemeChanged ); connect(ui->moreThemesLabel, &QLabel::linkActivated, this, &DlgSettingsGeneral::onLinkActivated); } // If there are any saved config file backs, show the revert button, otherwise hide it: const auto& backups = Application::Instance->prefPackManager()->configBackups(); ui->RevertToSavedConfig->setEnabled(backups.empty()); connect(ui->RevertToSavedConfig, &QPushButton::clicked, this, &DlgSettingsGeneral::revertToSavedConfig); connect( ui->comboBox_UnitSystem, qOverload(&QComboBox::currentIndexChanged), this, &DlgSettingsGeneral::onUnitSystemIndexChanged ); ui->spinBoxDecimals->setMaximum(std::numeric_limits::digits10 + 1); auto addItem = [&, index {0}](const std::string& item) mutable { ui->comboBox_UnitSystem->addItem(QString::fromStdString(item), index++); }; auto descriptions = UnitsApi::getDescriptions(); std::for_each(descriptions.begin(), descriptions.end(), addItem); // Enable/disable the fractional inch option depending on system const auto visible = UnitsApi::isMultiUnitLength(); ui->comboBox_FracInch->setVisible(visible); ui->fractionalInchLabel->setVisible(visible); ui->moreThemesLabel->setEnabled( Application::Instance->commandManager().getCommandByName("Std_AddonMgr") != nullptr ); } /** * Destroys the object and frees any allocated resources */ DlgSettingsGeneral::~DlgSettingsGeneral() = default; /** Sets the size of the recent file list from the user parameters. * @see RecentFilesAction * @see StdCmdRecentFiles */ void DlgSettingsGeneral::setRecentFileSize() { auto recent = getMainWindow()->findChild(QLatin1String("recentFiles")); if (recent) { ParameterGrp::handle hGrp = WindowParameter::getDefaultParameter()->GetGroup("RecentFiles"); recent->resizeList(hGrp->GetInt("RecentFiles", 4)); } } bool DlgSettingsGeneral::setLanguage() { ParameterGrp::handle hGrp = WindowParameter::getDefaultParameter()->GetGroup("General"); QString lang = QLocale::languageToString(QLocale().language()); QByteArray language = hGrp->GetASCII("Language", (const char*)lang.toLatin1()).c_str(); QByteArray current = ui->Languages->itemData(ui->Languages->currentIndex()).toByteArray(); if (current != language) { hGrp->SetASCII("Language", current.constData()); Translator::instance()->activateLanguage(current.constData()); return true; } return false; } void DlgSettingsGeneral::setNumberLocale(bool force /* = false*/) { int localeFormat = ui->UseLocaleFormatting->currentIndex(); // Only make the change if locale setting has changed or if forced // Except if format is "OS" where we don't want to run setLocale if (localeIndex == localeFormat && (!force || localeFormat == 0)) { return; } localeIndex = localeFormat; } void DlgSettingsGeneral::saveUnitSystemSettings() { ParameterGrp::handle hGrpu = App::GetApplication().GetParameterGroupByPath( "User parameter:BaseApp/Preferences/Units" ); hGrpu->SetInt("UserSchema", ui->comboBox_UnitSystem->currentIndex()); hGrpu->SetInt("Decimals", ui->spinBoxDecimals->value()); hGrpu->SetBool("IgnoreProjectSchema", ui->checkBox_projectUnitSystemIgnore->isChecked()); // Set actual value UnitsApi::setDecimals(ui->spinBoxDecimals->value()); // Convert the combobox index to the its integer denominator. Currently // with 1/2, 1/4, through 1/128, this little equation directly computes the // denominator given the combobox integer. // // The inverse conversion is done when loaded. That way only one thing (the // numerical fractional inch value) needs to be stored. // minimum fractional inch to display int FracInch = std::pow(2, ui->comboBox_FracInch->currentIndex() + 1); hGrpu->SetInt("FracInch", FracInch); // 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); } ui->SubstituteDecimal->onSave(); ui->UseLocaleFormatting->onSave(); } void DlgSettingsGeneral::saveSettings() { saveUnitSystemSettings(); ui->RecentFiles->onSave(); ui->EnableCursorBlinking->onSave(); ui->SplashScreen->onSave(); ui->ActivateOverlay->onSave(); if (property("ActivateOverlay").toBool() != ui->ActivateOverlay->isChecked()) { requireRestart(); } setRecentFileSize(); bool force = setLanguage(); // In case type is "Selected language", we need to force locale change setNumberLocale(force); ParameterGrp::handle hGrp = WindowParameter::getDefaultParameter()->GetGroup("General"); QVariant size = ui->toolbarIconSize->itemData(ui->toolbarIconSize->currentIndex()); int pixel = size.toInt(); hGrp->SetInt("ToolbarIconSize", pixel); getMainWindow()->setIconSize(QSize(pixel, pixel)); int blinkTime {hGrp->GetBool("EnableCursorBlinking", true) ? -1 : 0}; qApp->setCursorFlashTime(blinkTime); saveDockWindowVisibility(); hGrp = App::GetApplication().GetParameterGroupByPath( "User parameter:BaseApp/Preferences/MainWindow" ); hGrp->SetBool("TiledBackground", ui->tiledBackground->isChecked()); if (themeChanged) { saveThemes(); } } void DlgSettingsGeneral::loadSettings() { int FracInch; int cbIndex; ParameterGrp::handle hGrpu = App::GetApplication().GetParameterGroupByPath( "User parameter:BaseApp/Preferences/Units" ); ui->comboBox_UnitSystem->setCurrentIndex(hGrpu->GetInt("UserSchema", 0)); ui->spinBoxDecimals->setValue(hGrpu->GetInt("Decimals", UnitsApi::getDecimals())); ui->checkBox_projectUnitSystemIgnore->setChecked(hGrpu->GetBool("IgnoreProjectSchema", false)); // Get the current user setting for the minimum fractional inch FracInch = hGrpu->GetInt("FracInch", UnitsApi::getDenominator()); // Convert fractional inch to the corresponding combobox index using this // handy little equation. cbIndex = std::log2(FracInch) - 1; ui->comboBox_FracInch->setCurrentIndex(cbIndex); ui->SubstituteDecimal->onRestore(); ui->UseLocaleFormatting->onRestore(); ui->RecentFiles->onRestore(); ui->EnableCursorBlinking->onRestore(); ui->SplashScreen->onRestore(); ui->ActivateOverlay->onRestore(); setProperty("ActivateOverlay", ui->ActivateOverlay->isChecked()); // search for the language files ParameterGrp::handle hGrp = WindowParameter::getDefaultParameter()->GetGroup("General"); auto langToStr = Translator::instance()->activeLanguage(); QByteArray language = hGrp->GetASCII("Language", langToStr.c_str()).c_str(); localeIndex = ui->UseLocaleFormatting->currentIndex(); int index = 1; TStringMap list = Translator::instance()->supportedLocales(); ui->Languages->clear(); ui->Languages->addItem(QStringLiteral("English"), QByteArray("English")); for (auto it = list.begin(); it != list.end(); ++it, index++) { QByteArray lang = it->first.c_str(); QString langname = QString::fromLatin1(lang.constData()); if (it->second == "sr-CS") { // Qt does not treat sr-CS (Serbian, Latin) as a Latin-script variant by default: this // forces it to do so. it->second = "sr_Latn"; } QLocale locale(QString::fromLatin1(it->second.c_str())); QString native = locale.nativeLanguageName(); if (!native.isEmpty()) { if (native[0].isLetter()) { native[0] = native[0].toUpper(); } langname = native; } ui->Languages->addItem(langname, lang); if (language == lang) { ui->Languages->setCurrentIndex(index); } } QAbstractItemModel* model = ui->Languages->model(); if (model) { model->sort(0); } addIconSizes(getCurrentIconSize()); // TreeMode combobox setup. loadDockWindowVisibility(); hGrp = App::GetApplication().GetParameterGroupByPath( "User parameter:BaseApp/Preferences/MainWindow" ); ui->tiledBackground->setChecked(hGrp->GetBool("TiledBackground", false)); loadThemes(); } void DlgSettingsGeneral::resetSettingsToDefaults() { ParameterGrp::handle hGrp; hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Units"); // reset "UserSchema" parameter hGrp->RemoveInt("UserSchema"); // reset "Decimals" parameter hGrp->RemoveInt("Decimals"); // reset "IgnoreProjectSchema" parameter hGrp->RemoveBool("IgnoreProjectSchema"); // reset "FracInch" parameter hGrp->RemoveInt("FracInch"); hGrp = App::GetApplication().GetParameterGroupByPath( "User parameter:BaseApp/Preferences/MainWindow" ); // reset "Theme" parameter hGrp->RemoveASCII("Theme"); // reset "TiledBackground" parameter hGrp->RemoveBool("TiledBackground"); hGrp = App::GetApplication().GetParameterGroupByPath( "User parameter:BaseApp/Preferences/DockWindows" ); // reset "ComboView" parameters hGrp->GetGroup("ComboView")->RemoveBool("Enabled"); // reset "TreeView" parameters hGrp->GetGroup("TreeView")->RemoveBool("Enabled"); // reset "PropertyView" parameters hGrp->GetGroup("PropertyView")->RemoveBool("Enabled"); hGrp = WindowParameter::getDefaultParameter()->GetGroup("General"); // reset "Language" parameter hGrp->RemoveASCII("Language"); // reset "ToolbarIconSize" parameter hGrp->RemoveInt("ToolbarIconSize"); // finally reset all the parameters associated to Gui::Pref* widgets PreferencePage::resetSettingsToDefaults(); } void DlgSettingsGeneral::saveThemes() { ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( "User parameter:BaseApp/Preferences/MainWindow" ); // First we check if the theme has actually changed. std::string previousTheme = hGrp->GetASCII("Theme", "").c_str(); std::string newTheme = ui->themesCombobox->currentText().toStdString(); if (previousTheme == newTheme) { themeChanged = false; return; } // Save the name of the theme hGrp->SetASCII("Theme", newTheme); // Then we apply the themepack. Application::Instance->prefPackManager()->rescan(); auto packs = Application::Instance->prefPackManager()->preferencePacks(); for (const auto& pack : packs) { if (pack.first == newTheme) { if (Application::Instance->prefPackManager()->apply(pack.first)) { auto parentDialog = qobject_cast(this->window()); if (parentDialog) { parentDialog->reload(); } } break; } } themeChanged = false; } void DlgSettingsGeneral::loadThemes() { ui->themesCombobox->clear(); ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath( "User parameter:BaseApp/Preferences/MainWindow" ); QString currentTheme = QString::fromLatin1(hGrp->GetASCII("Theme", "").c_str()); Application::Instance->prefPackManager()->rescan(); auto packs = Application::Instance->prefPackManager()->preferencePacks(); QString currentStyleSheet = QString::fromLatin1(hGrp->GetASCII("StyleSheet", "").c_str()); QFileInfo fi(currentStyleSheet); currentStyleSheet = fi.baseName(); QString themeClassic = QStringLiteral("classic"); // handle the upcoming name change QString similarTheme; QString packName; for (const auto& pack : packs) { if (pack.second.metadata().type() == "Theme") { packName = QString::fromStdString(pack.first); if (packName.contains(themeClassic, Qt::CaseInsensitive)) { themeClassic = QString::fromStdString(pack.first); } if (packName.contains(currentStyleSheet, Qt::CaseInsensitive)) { similarTheme = QString::fromStdString(pack.first); } ui->themesCombobox->addItem(QString::fromStdString(pack.first)); } } if (currentTheme.isEmpty()) { if (!currentStyleSheet.isEmpty() && !similarTheme.isEmpty()) { // a user upgrading from // 0.21 or earlier hGrp->SetASCII("Theme", similarTheme.toStdString()); currentTheme = QString::fromLatin1(hGrp->GetASCII("Theme", "").c_str()); } else { // a brand new user hGrp->SetASCII("Theme", themeClassic.toStdString()); currentTheme = QString::fromLatin1(hGrp->GetASCII("Theme", "").c_str()); } } int index = ui->themesCombobox->findText(currentTheme); if (index >= 0 && index < ui->themesCombobox->count()) { ui->themesCombobox->setCurrentIndex(index); } } int DlgSettingsGeneral::getCurrentIconSize() const { ParameterGrp::handle hGrp = WindowParameter::getDefaultParameter()->GetGroup("General"); int current = getMainWindow()->iconSize().width(); return hGrp->GetInt("ToolbarIconSize", current); } void DlgSettingsGeneral::addIconSizes(int current) { ui->toolbarIconSize->clear(); QList sizes {16, 24, 32, 48}; if (!sizes.contains(current)) { sizes.append(current); } for (int size : sizes) { ui->toolbarIconSize->addItem(QString(), QVariant(size)); } int index = ui->toolbarIconSize->findData(QVariant(current)); ui->toolbarIconSize->setCurrentIndex(index); translateIconSizes(); } void DlgSettingsGeneral::translateIconSizes() { auto getSize = [this](int index) { return ui->toolbarIconSize->itemData(index).toInt(); }; QStringList sizes; sizes << tr("Small (%1px)").arg(getSize(0)); sizes << tr("Medium (%1px)").arg(getSize(1)); sizes << tr("Large (%1px)").arg(getSize(2)); sizes << tr("Extra large (%1px)").arg(getSize(3)); if (ui->toolbarIconSize->count() > 4) { sizes << tr("Custom (%1px)").arg(getSize(4)); } for (int index = 0; index < sizes.size(); index++) { ui->toolbarIconSize->setItemText(index, sizes[index]); } } void DlgSettingsGeneral::retranslateUnits() { auto setItem = [&, index {0}](const std::string& item) mutable { ui->comboBox_UnitSystem->setItemText(index++, QString::fromStdString(item)); }; const auto descriptions = UnitsApi::getDescriptions(); std::for_each(descriptions.begin(), descriptions.end(), setItem); } void DlgSettingsGeneral::changeEvent(QEvent* event) { if (event->type() == QEvent::LanguageChange) { translateIconSizes(); retranslateUnits(); int index = ui->UseLocaleFormatting->currentIndex(); ui->retranslateUi(this); ui->UseLocaleFormatting->setCurrentIndex(index); } else { QWidget::changeEvent(event); } } void DlgSettingsGeneral::saveDockWindowVisibility() { auto hGrp = App::GetApplication().GetParameterGroupByPath( "User parameter:BaseApp/Preferences/DockWindows" ); bool treeView = hGrp->GetGroup("TreeView")->GetBool("Enabled", false); bool propertyView = hGrp->GetGroup("PropertyView")->GetBool("Enabled", false); bool comboView = hGrp->GetGroup("ComboView")->GetBool("Enabled", true); int index = -1; if (propertyView || treeView) { index = 1; } else if (comboView) { index = 0; } if (index != ui->treeMode->currentIndex()) { requireRestart(); } switch (ui->treeMode->currentIndex()) { case 0: comboView = true; treeView = propertyView = false; break; case 1: treeView = propertyView = true; comboView = false; break; } hGrp->GetGroup("ComboView")->SetBool("Enabled", comboView); hGrp->GetGroup("TreeView")->SetBool("Enabled", treeView); hGrp->GetGroup("PropertyView")->SetBool("Enabled", propertyView); } void DlgSettingsGeneral::loadDockWindowVisibility() { ui->treeMode->clear(); ui->treeMode->addItem(tr("Combined")); ui->treeMode->addItem(tr("Independent")); auto hGrp = App::GetApplication().GetParameterGroupByPath( "User parameter:BaseApp/Preferences/DockWindows" ); bool propertyView = hGrp->GetGroup("PropertyView")->GetBool("Enabled", false); bool treeView = hGrp->GetGroup("TreeView")->GetBool("Enabled", false); bool comboView = hGrp->GetGroup("ComboView")->GetBool("Enabled", true); int index = -1; if (propertyView || treeView) { index = 1; } else if (comboView) { index = 0; } ui->treeMode->setCurrentIndex(index); } void DlgSettingsGeneral::recreatePreferencePackMenu() { ui->PreferencePacks->setRowCount(0); // Begin by clearing whatever is there ui->PreferencePacks->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft); ui->PreferencePacks->setColumnCount(3); ui->PreferencePacks->setSelectionMode(QAbstractItemView::SelectionMode::NoSelection); ui->PreferencePacks->horizontalHeader()->setStretchLastSection(false); ui->PreferencePacks->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeMode::Stretch); ui->PreferencePacks->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeMode::Stretch); ui->PreferencePacks->horizontalHeader()->setSectionResizeMode( 2, QHeaderView::ResizeMode::ResizeToContents ); QStringList columnHeaders; columnHeaders << tr("Preference Pack Name") << tr("Tags") << QString(); // for the "Load" buttons ui->PreferencePacks->setHorizontalHeaderLabels(columnHeaders); // Populate the Preference Packs list Application::Instance->prefPackManager()->rescan(); auto packs = Application::Instance->prefPackManager()->preferencePacks(); // Remove the Themes. std::vector packsToRemove; for (const auto& pack : packs) { if (pack.second.metadata().type() == "Theme") { packsToRemove.push_back(pack.first); // Store the keys to remove later } } for (const auto& key : packsToRemove) { packs.erase(key); // Remove the elements from the map } ui->PreferencePacks->setRowCount(packs.size()); int row = 0; QIcon icon = style()->standardIcon(QStyle::SP_DialogApplyButton); for (const auto& pack : packs) { auto name = new QTableWidgetItem(QString::fromStdString(pack.first)); name->setToolTip(QString::fromStdString(pack.second.metadata().description())); ui->PreferencePacks->setItem(row, 0, name); auto tags = pack.second.metadata().tag(); QString tagString; for (const auto& tag : tags) { if (tagString.isEmpty()) { tagString.append(QString::fromStdString(tag)); } else { tagString.append(QStringLiteral(", ") + QString::fromStdString(tag)); } } auto kind = new QTableWidgetItem(tagString); ui->PreferencePacks->setItem(row, 1, kind); auto button = new QPushButton(icon, tr("Apply")); button->setEnabled(true); Gui::Document* doc = Gui::Application::Instance->activeDocument(); if (doc) { Gui::View3DInventor* view = qobject_cast(doc->getActiveView()); if (view) { Gui::View3DInventorViewer* viewer = view->getViewer(); if (viewer->isEditing()) { button->setEnabled(false); } } } if (button->isEnabled()) { button->setToolTip( tr("Applies the %1 preference pack").arg(QString::fromStdString(pack.first)) ); connect(button, &QPushButton::clicked, this, [this, pack]() { onLoadPreferencePackClicked(pack.first); }); } ui->PreferencePacks->setCellWidget(row, 2, button); ++row; } } void DlgSettingsGeneral::saveAsNewPreferencePack() { // Create and run a modal New PreferencePack dialog box auto packs = Application::Instance->prefPackManager()->preferencePackNames(); newPreferencePackDialog = std::make_unique(this); newPreferencePackDialog->setPreferencePackTemplates( Application::Instance->prefPackManager()->templateFiles() ); newPreferencePackDialog->setPreferencePackNames(packs); connect( newPreferencePackDialog.get(), &DlgCreateNewPreferencePackImp::accepted, this, &DlgSettingsGeneral::newPreferencePackDialogAccepted ); newPreferencePackDialog->open(); } void DlgSettingsGeneral::revertToSavedConfig() { revertToBackupConfigDialog = std::make_unique(this); connect(revertToBackupConfigDialog.get(), &DlgRevertToBackupConfigImp::accepted, this, [this]() { auto parentDialog = qobject_cast(this->window()); if (parentDialog) { parentDialog->reload(); } }); revertToBackupConfigDialog->open(); } void DlgSettingsGeneral::newPreferencePackDialogAccepted() { auto preferencePackTemplates = Application::Instance->prefPackManager()->templateFiles(); auto selection = newPreferencePackDialog->selectedTemplates(); std::vector selectedTemplates; std::copy_if( preferencePackTemplates.begin(), preferencePackTemplates.end(), std::back_inserter(selectedTemplates), [selection](PreferencePackManager::TemplateFile& tf) { for (const auto& item : selection) { if (item.group == tf.group && item.name == tf.name) { return true; } } return false; } ); auto preferencePackName = newPreferencePackDialog->preferencePackName(); auto preferencePackDirectory = newPreferencePackDialog->preferencePackDirectory(); Application::Instance->prefPackManager() ->save(preferencePackName, preferencePackDirectory, selectedTemplates); recreatePreferencePackMenu(); } void DlgSettingsGeneral::onManagePreferencePacksClicked() { if (!this->preferencePackManagementDialog) { this->preferencePackManagementDialog = std::make_unique(this); connect( this->preferencePackManagementDialog.get(), &DlgPreferencePackManagementImp::packVisibilityChanged, this, &DlgSettingsGeneral::recreatePreferencePackMenu ); } this->preferencePackManagementDialog->show(); } void DlgSettingsGeneral::onImportConfigClicked() { auto path = fs::path( QFileDialog::getOpenFileName( this, tr("Choose a FreeCAD config file to import"), QString(), QStringLiteral("*.cfg") ) .toStdString() ); if (!path.empty()) { // Create a name from the filename: auto packName = path.filename().stem().string(); std::replace(packName.begin(), packName.end(), '_', ' '); auto existingPacks = Application::Instance->prefPackManager()->preferencePackNames(); if (std::ranges::find(existingPacks, packName) != existingPacks.end()) { auto result = QMessageBox::question( this, tr("File exists"), tr("A preference pack with that name already exists. Overwrite?") ); if (result == QMessageBox::No) { // Maybe someday ask for a new name? return; } } Application::Instance->prefPackManager()->importConfig(packName, path); recreatePreferencePackMenu(); } } void DlgSettingsGeneral::onLoadPreferencePackClicked(const std::string& packName) { if (Application::Instance->prefPackManager()->apply(packName)) { auto parentDialog = qobject_cast(this->window()); if (parentDialog) { parentDialog->reload(); } } } void DlgSettingsGeneral::onUnitSystemIndexChanged(const int index) { if (index < 0) { return; // happens when clearing the combo box in retranslateUi() } // Enable/disable the fractional inch option depending on system const auto schema = UnitsApi::createSchema(index); const auto visible = schema->isMultiUnitLength(); ui->comboBox_FracInch->setVisible(visible); ui->fractionalInchLabel->setVisible(visible); } void DlgSettingsGeneral::onThemeChanged(int index) { Q_UNUSED(index); themeChanged = true; } void DlgSettingsGeneral::onLinkActivated(const QString& link) { auto const addonManagerLink = QStringLiteral("freecad:Std_AddonMgr"); if (link != addonManagerLink) { return; } // Set the user preferences to include only preference packs. // This is a quick and dirty way to open Addon Manager with only themes. auto pref = App::GetApplication().GetParameterGroupByPath( "User parameter:BaseApp/Preferences/Addons" ); pref->SetInt("PackageTypeSelection", 3); // 3 stands for Preference Packs pref->SetInt("StatusSelection", 0); // 0 stands for any installation status Gui::Application::Instance->commandManager().runCommandByName("Std_AddonMgr"); } /////////////////////////////////////////////////////////// namespace { class ApplyDockWidget: public ParamHandler { public: bool onChange(const ParamKey*) override { OverlayManager::instance()->reload(OverlayManager::ReloadMode::ReloadPause); return true; } void onTimer() override { getMainWindow()->initDockWindows(true); OverlayManager::instance()->reload(OverlayManager::ReloadMode::ReloadResume); } }; } // anonymous namespace void DlgSettingsGeneral::attachObserver() { static ParamHandlers handlers; auto hDockWindows = App::GetApplication().GetUserParameter().GetGroup( "BaseApp/Preferences/DockWindows" ); auto applyDockWidget = std::shared_ptr(new ApplyDockWidget); handlers.addHandler(ParamKey(hDockWindows->GetGroup("ComboView"), "Enabled"), applyDockWidget); handlers.addHandler(ParamKey(hDockWindows->GetGroup("TreeView"), "Enabled"), applyDockWidget); handlers.addHandler(ParamKey(hDockWindows->GetGroup("PropertyView"), "Enabled"), applyDockWidget); handlers.addHandler(ParamKey(hDockWindows->GetGroup("DAGView"), "Enabled"), applyDockWidget); } #include "moc_DlgSettingsGeneral.cpp"