File indexing completed on 2024-05-12 11:41:21

0001 /*
0002     File                 : SettingsGeneralPage.cpp
0003     Project              : LabPlot
0004     Description          : general settings page
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2008-2023 Alexander Semke <alexander.semke@web.de>
0007     SPDX-FileCopyrightText: 2020-2022 Stefan Gerlach <stefan.gerlach@uni.kn>
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "SettingsGeneralPage.h"
0012 #ifdef HAVE_CANTOR_LIBS
0013 #include <cantor/backend.h>
0014 #endif
0015 #include "backend/core/Settings.h"
0016 #include "backend/lib/macros.h"
0017 #include "kdefrontend/MainWin.h" // LoadOnStart
0018 
0019 #include <KConfigGroup>
0020 #include <KLocalizedString>
0021 
0022 /**
0023  * \brief Page for the 'General' settings of the Labplot settings dialog.
0024  */
0025 SettingsGeneralPage::SettingsGeneralPage(QWidget* parent)
0026     : SettingsPage(parent) {
0027     ui.setupUi(this);
0028     ui.sbAutoSaveInterval->setSuffix(i18n("min."));
0029     retranslateUi();
0030 
0031     connect(ui.cbLoadOnStart, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &SettingsGeneralPage::loadOnStartChanged);
0032     connect(ui.cbNewProject, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &SettingsGeneralPage::newProjectChanged);
0033     connect(ui.cbNewProjectNotebook, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &SettingsGeneralPage::changed);
0034     connect(ui.cbDockWindowPositionReopen, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &SettingsGeneralPage::changed);
0035     connect(ui.cbLoadOnStart, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &SettingsGeneralPage::changed);
0036     connect(ui.cbTitleBar, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &SettingsGeneralPage::changed);
0037     connect(ui.cbUnits, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &SettingsGeneralPage::changed);
0038     connect(ui.cbDecimalSeparator, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &SettingsGeneralPage::changed);
0039     connect(ui.chkGUMTerms, &QCheckBox::toggled, this, &SettingsGeneralPage::changed);
0040     connect(ui.chkOmitGroupSeparator, &QCheckBox::toggled, this, &SettingsGeneralPage::changed);
0041     connect(ui.chkOmitLeadingZeroInExponent, &QCheckBox::toggled, this, &SettingsGeneralPage::changed);
0042     connect(ui.chkIncludeTrailingZeroesAfterDot, &QCheckBox::toggled, this, &SettingsGeneralPage::changed);
0043     connect(ui.chkAutoSave, &QCheckBox::toggled, this, &SettingsGeneralPage::autoSaveChanged);
0044     connect(ui.chkCompatible, &QCheckBox::toggled, this, &SettingsGeneralPage::changed);
0045 
0046 #ifdef HAVE_CANTOR_LIBS
0047     for (auto* backend : Cantor::Backend::availableBackends()) {
0048         if (backend->isEnabled())
0049             ui.cbNewProjectNotebook->addItem(QIcon::fromTheme(backend->icon()), backend->name());
0050     }
0051 #endif
0052 
0053     loadSettings();
0054     autoSaveChanged(ui.chkAutoSave->isChecked());
0055 }
0056 
0057 /* returns decimal separator (as SettingsGeneralPage::DecimalSeparator) of given locale (default: system setting) */
0058 SettingsGeneralPage::DecimalSeparator SettingsGeneralPage::decimalSeparator(QLocale locale) {
0059     DEBUG(Q_FUNC_INFO << ", LOCALE: " << STDSTRING(locale.name()) << ", " << locale.language())
0060     const auto decimalPoint = locale.decimalPoint();
0061     DEBUG(Q_FUNC_INFO << ", SEPARATING CHAR: " << STDSTRING(QString(decimalPoint)))
0062     if (decimalPoint == QLatin1Char('.'))
0063         return DecimalSeparator::Dot;
0064     else if (decimalPoint == QLatin1Char(','))
0065         return DecimalSeparator::Comma;
0066 
0067     return DecimalSeparator::Arabic;
0068 }
0069 
0070 QLocale::Language SettingsGeneralPage::decimalSeparatorLocale() const {
0071     int currentIndex = ui.cbDecimalSeparator->currentIndex();
0072     DEBUG(Q_FUNC_INFO << ", SYSTEM LOCALE: " << STDSTRING(QLocale().name()) << ':' << QLocale().language())
0073     DEBUG(Q_FUNC_INFO << ", SYSTEM SEPARATING CHAR: " << STDSTRING(QString(QLocale().decimalPoint())))
0074 
0075     const auto groupSeparator = QLocale().groupSeparator();
0076     switch (currentIndex) {
0077     case static_cast<int>(DecimalSeparator::Dot):
0078         if (groupSeparator == QLocale(QLocale::Language::Zarma).groupSeparator()) // \u00a0
0079             return QLocale::Language::Zarma; // . \u00a0
0080         else if (groupSeparator == QLocale(QLocale::Language::SwissGerman).groupSeparator()) // \u2019
0081             return QLocale::Language::SwissGerman; // . \u2019
0082         else
0083             return QLocale::Language::C; // . ,
0084     case static_cast<int>(DecimalSeparator::Comma):
0085         if (groupSeparator == QLocale(QLocale::Language::French).groupSeparator()) // \u00a0
0086             return QLocale::Language::French; // , \u00a0
0087         else if (groupSeparator == QLocale(QLocale::Language::Walser).groupSeparator()) // \u2019
0088             return QLocale::Language::Walser; // , \u2019
0089         else
0090             return QLocale::Language::German; // , .
0091     case static_cast<int>(DecimalSeparator::Arabic):
0092         return QLocale::Language::Arabic; // \u066b \u066c
0093     default: // automatic
0094         return QLocale::Language::AnyLanguage;
0095     }
0096 }
0097 
0098 void SettingsGeneralPage::applySettings() {
0099     DEBUG(Q_FUNC_INFO)
0100     if (!m_changed)
0101         return;
0102 
0103     KConfigGroup group = Settings::settingsGeneral();
0104     group.writeEntry(QLatin1String("LoadOnStart"), ui.cbLoadOnStart->currentData().toInt());
0105     group.writeEntry(QLatin1String("NewProject"), ui.cbNewProject->currentData().toInt());
0106     group.writeEntry(QLatin1String("NewProjectNotebook"), ui.cbNewProjectNotebook->currentText());
0107     group.writeEntry(QLatin1String("TitleBar"), ui.cbTitleBar->currentIndex());
0108     group.writeEntry(QLatin1String("Units"), ui.cbUnits->currentIndex());
0109     if (ui.cbDecimalSeparator->currentIndex() == static_cast<int>(DecimalSeparator::Automatic)) // need to overwrite previous setting
0110         group.writeEntry(QLatin1String("DecimalSeparatorLocale"), static_cast<int>(QLocale::Language::AnyLanguage));
0111     else
0112         group.writeEntry(QLatin1String("DecimalSeparatorLocale"), static_cast<int>(decimalSeparatorLocale()));
0113     QLocale::NumberOptions numberOptions{QLocale::DefaultNumberOptions};
0114     if (ui.chkOmitGroupSeparator->isChecked())
0115         numberOptions |= QLocale::OmitGroupSeparator;
0116     if (ui.chkOmitLeadingZeroInExponent->isChecked())
0117         numberOptions |= QLocale::OmitLeadingZeroInExponent;
0118     if (ui.chkIncludeTrailingZeroesAfterDot->isChecked())
0119         numberOptions |= QLocale::IncludeTrailingZeroesAfterDot;
0120     group.writeEntry(QLatin1String("GUMTerms"), ui.chkGUMTerms->isChecked());
0121     group.writeEntry(QLatin1String("NumberOptions"), static_cast<int>(numberOptions));
0122     group.writeEntry(QLatin1String("AutoSave"), ui.chkAutoSave->isChecked());
0123     group.writeEntry(QLatin1String("AutoSaveInterval"), ui.sbAutoSaveInterval->value());
0124     group.writeEntry(QLatin1String("CompatibleSave"), ui.chkCompatible->isChecked());
0125     Settings::writeDockPosBehaviour(static_cast<Settings::DockPosBehaviour>(ui.cbDockWindowPositionReopen->currentData().toInt()));
0126 }
0127 
0128 void SettingsGeneralPage::restoreDefaults() {
0129     ui.cbLoadOnStart->setCurrentIndex(ui.cbLoadOnStart->findData(static_cast<int>(MainWin::LoadOnStart::NewProject)));
0130     ui.cbNewProject->setCurrentIndex(ui.cbNewProject->findData(static_cast<int>(MainWin::NewProject::WithWorksheet)));
0131     ui.cbTitleBar->setCurrentIndex(0);
0132     ui.cbUnits->setCurrentIndex(0);
0133     ui.cbDecimalSeparator->setCurrentIndex(static_cast<int>(DecimalSeparator::Automatic));
0134     ui.chkGUMTerms->setChecked(false);
0135     ui.chkOmitGroupSeparator->setChecked(true);
0136     ui.chkOmitLeadingZeroInExponent->setChecked(true);
0137     ui.chkIncludeTrailingZeroesAfterDot->setChecked(false);
0138     ui.chkAutoSave->setChecked(false);
0139     ui.sbAutoSaveInterval->setValue(5);
0140     ui.chkCompatible->setChecked(false);
0141     ui.cbDockWindowPositionReopen->setCurrentIndex(ui.cbDockWindowPositionReopen->findData(static_cast<int>(Settings::DockPosBehaviour::AboveLastActive)));
0142 }
0143 
0144 void SettingsGeneralPage::loadSettings() {
0145     const auto group = Settings::group(QStringLiteral("Settings_General"));
0146 
0147     const auto loadOnStart = group.readEntry(QLatin1String("LoadOnStart"), static_cast<int>(MainWin::LoadOnStart::NewProject));
0148     ui.cbLoadOnStart->setCurrentIndex(ui.cbLoadOnStart->findData(loadOnStart));
0149     loadOnStartChanged();
0150 
0151     const auto newProject = group.readEntry(QLatin1String("NewProject"), static_cast<int>(MainWin::NewProject::WithWorksheet));
0152     ui.cbNewProject->setCurrentIndex(ui.cbNewProject->findData(newProject));
0153     newProjectChanged(); // call it to update notebook related widgets also if the current index above was not changed (true for index=0)
0154 
0155 #ifdef HAVE_CANTOR_LIBS
0156     const auto& backendName = group.readEntry(QLatin1String("LoadOnStartNotebook"), QString());
0157     int index = ui.cbNewProjectNotebook->findText(backendName);
0158     if (index == -1 && ui.cbNewProjectNotebook->count() > 0)
0159         ui.cbNewProjectNotebook->setCurrentIndex(0); // select the first available backend if not backend was select yet
0160     else
0161         ui.cbNewProjectNotebook->setCurrentIndex(index);
0162 #endif
0163 
0164     ui.cbTitleBar->setCurrentIndex(group.readEntry(QLatin1String("TitleBar"), 0));
0165     ui.cbDockWindowPositionReopen->setCurrentIndex(ui.cbDockWindowPositionReopen->findData(static_cast<int>(Settings::readDockPosBehaviour())));
0166 
0167     ui.cbUnits->setCurrentIndex(group.readEntry(QLatin1String("Units"), 0));
0168     // must be done, because locale.language() will return the default locale if AnyLanguage is passed
0169     const auto l = static_cast<QLocale::Language>(group.readEntry(QLatin1String("DecimalSeparatorLocale"), static_cast<int>(QLocale::Language::AnyLanguage)));
0170     QLocale locale(l);
0171     if (l == QLocale::Language::AnyLanguage) // no or default setting
0172         ui.cbDecimalSeparator->setCurrentIndex(static_cast<int>(DecimalSeparator::Automatic));
0173     else
0174         ui.cbDecimalSeparator->setCurrentIndex(static_cast<int>(decimalSeparator(locale)));
0175     ui.chkGUMTerms->setChecked(group.readEntry<bool>(QLatin1String("GUMTerms"), false));
0176     QLocale::NumberOptions numberOptions{
0177         static_cast<QLocale::NumberOptions>(group.readEntry(QLatin1String("NumberOptions"), static_cast<int>(QLocale::DefaultNumberOptions)))};
0178     if (numberOptions & QLocale::OmitGroupSeparator)
0179         ui.chkOmitGroupSeparator->setChecked(true);
0180     if (numberOptions & QLocale::OmitLeadingZeroInExponent)
0181         ui.chkOmitLeadingZeroInExponent->setChecked(true);
0182     if (numberOptions & QLocale::IncludeTrailingZeroesAfterDot)
0183         ui.chkIncludeTrailingZeroesAfterDot->setChecked(true);
0184 
0185     ui.chkAutoSave->setChecked(group.readEntry<bool>(QLatin1String("AutoSave"), false));
0186     ui.sbAutoSaveInterval->setValue(group.readEntry(QLatin1String("AutoSaveInterval"), 0));
0187     ui.chkCompatible->setChecked(group.readEntry<bool>(QLatin1String("CompatibleSave"), false));
0188 }
0189 
0190 void SettingsGeneralPage::retranslateUi() {
0191     ui.cbLoadOnStart->clear();
0192     ui.cbLoadOnStart->addItem(i18n("Create New Project"), static_cast<int>(MainWin::LoadOnStart::NewProject));
0193     ui.cbLoadOnStart->addItem(i18n("Load Last Used Project"), static_cast<int>(MainWin::LoadOnStart::LastProject));
0194     // ui.cbLoadOnStart->addItem(i18n("Show Welcome Screen"), static_cast<int>(MainWin::LoadOnStart::WelcomeScreen));
0195 
0196     ui.cbNewProject->clear();
0197     ui.cbNewProject->addItem(i18n("With Worksheet"), static_cast<int>(MainWin::NewProject::WithWorksheet));
0198     ui.cbNewProject->addItem(i18n("With Spreadsheet"), static_cast<int>(MainWin::NewProject::WithSpreadsheet));
0199     ui.cbNewProject->addItem(i18n("With Worksheet and Spreadsheet"), static_cast<int>(MainWin::NewProject::WithWorksheetSpreadsheet));
0200 #ifdef HAVE_CANTOR_LIBS
0201     ui.cbNewProject->addItem(i18n("With Notebook"), static_cast<int>(MainWin::NewProject::WithNotebook));
0202 #endif
0203 
0204     QString msg = i18n("Notebook type to create automatically on startup");
0205     ui.lNewProjectNotebook->setToolTip(msg);
0206     ui.cbNewProjectNotebook->setToolTip(msg);
0207 
0208     msg = i18n("Controls the behavior of where the dock widgets are placed after being re-opened");
0209     ui.lDockWindowPositionReopen->setToolTip(msg);
0210     ui.cbDockWindowPositionReopen->setToolTip(msg);
0211     ui.cbDockWindowPositionReopen->clear();
0212     ui.cbDockWindowPositionReopen->addItem(i18n("Original Position"), static_cast<int>(Settings::DockPosBehaviour::OriginalPos));
0213     ui.cbDockWindowPositionReopen->addItem(i18n("On top of the last active Dock Widget"), static_cast<int>(Settings::DockPosBehaviour::AboveLastActive));
0214 
0215     ui.cbTitleBar->clear();
0216     ui.cbTitleBar->addItem(i18n("Show File Path"));
0217     ui.cbTitleBar->addItem(i18n("Show File Name"));
0218     ui.cbTitleBar->addItem(i18n("Show Project Name"));
0219 
0220     ui.cbUnits->addItem(i18n("Metric"));
0221     ui.cbUnits->addItem(i18n("Imperial"));
0222 
0223     ui.cbDecimalSeparator->addItem(i18n("Dot (.)"));
0224     ui.cbDecimalSeparator->addItem(i18n("Comma (,)"));
0225     ui.cbDecimalSeparator->addItem(i18n("Arabic (٫)"));
0226     ui.cbDecimalSeparator->addItem(i18n("Automatic"));
0227 
0228     msg = i18n(
0229         "Use terms compliant with the <a href=\"http://www.bipm.org/utils/common/documents/jcgm/JCGM_100_2008_E.pdf\">Guide to the Expression of Uncertainty "
0230         "in Measurement (GUM)</a>");
0231     ui.chkGUMTerms->setWhatsThis(msg);
0232 }
0233 
0234 void SettingsGeneralPage::loadOnStartChanged() {
0235     const auto loadOnStart = static_cast<MainWin::LoadOnStart>(ui.cbLoadOnStart->currentData().toInt());
0236     const bool visible = (loadOnStart == MainWin::LoadOnStart::NewProject);
0237     ui.lNewProject->setVisible(visible);
0238     ui.cbNewProject->setVisible(visible);
0239     newProjectChanged();
0240 }
0241 
0242 void SettingsGeneralPage::newProjectChanged() {
0243     const auto newProject = static_cast<MainWin::NewProject>(ui.cbNewProject->currentData().toInt());
0244     const bool visible = (newProject == MainWin::NewProject::WithNotebook);
0245     ui.lNewProjectNotebook->setVisible(visible);
0246     ui.cbNewProjectNotebook->setVisible(visible);
0247     changed();
0248 }
0249 
0250 void SettingsGeneralPage::autoSaveChanged(bool state) {
0251     ui.lAutoSaveInterval->setVisible(state);
0252     ui.sbAutoSaveInterval->setVisible(state);
0253     changed();
0254 }
0255 
0256 void SettingsGeneralPage::changed() {
0257     m_changed = true;
0258     Q_EMIT settingsChanged();
0259 }