File indexing completed on 2025-07-13 03:32:45

0001 /*
0002     File                 : MAtrixDock.cpp
0003     Project              : LabPlot
0004     Description          : widget for matrix properties
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2015 Alexander Semke <alexander.semke@web.de>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "MatrixDock.h"
0012 #include "commonfrontend/matrix/MatrixView.h"
0013 #include "kdefrontend/TemplateHandler.h"
0014 
0015 #include <KConfig>
0016 #include <KConfigGroup>
0017 
0018 #include <QDir>
0019 
0020 /*!
0021  \class MatrixDock
0022  \brief Provides a widget for editing the properties of the matrices currently selected in the project explorer.
0023 
0024  \ingroup kdefrontend
0025 */
0026 MatrixDock::MatrixDock(QWidget* parent)
0027     : BaseDock(parent) {
0028     ui.setupUi(this);
0029     setBaseWidgets(ui.leName, ui.teComment);
0030 
0031     ui.cbFormat->addItem(i18n("Decimal"), QVariant('f'));
0032     ui.cbFormat->addItem(i18n("Scientific (e)"), QVariant('e'));
0033     ui.cbFormat->addItem(i18n("Scientific (E)"), QVariant('E'));
0034     ui.cbFormat->addItem(i18n("Automatic (g)"), QVariant('g'));
0035     ui.cbFormat->addItem(i18n("Automatic (G)"), QVariant('G'));
0036 
0037     ui.cbHeader->addItem(i18n("Rows and Columns"));
0038     ui.cbHeader->addItem(i18n("xy-Values"));
0039     ui.cbHeader->addItem(i18n("Rows, Columns and xy-Values"));
0040 
0041     // Validators
0042     ui.leXStart->setValidator(new QDoubleValidator(ui.leXStart));
0043     ui.leXEnd->setValidator(new QDoubleValidator(ui.leXEnd));
0044     ui.leYStart->setValidator(new QDoubleValidator(ui.leYStart));
0045     ui.leYEnd->setValidator(new QDoubleValidator(ui.leYEnd));
0046 
0047     connect(ui.sbColumnCount, QOverload<int>::of(&QSpinBox::valueChanged), this, &MatrixDock::columnCountChanged);
0048     connect(ui.sbRowCount, QOverload<int>::of(&QSpinBox::valueChanged), this, &MatrixDock::rowCountChanged);
0049     connect(ui.leXStart, &QLineEdit::textChanged, this, &MatrixDock::xStartChanged);
0050     connect(ui.leXEnd, &QLineEdit::textChanged, this, &MatrixDock::xEndChanged);
0051     connect(ui.leYStart, &QLineEdit::textChanged, this, &MatrixDock::yStartChanged);
0052     connect(ui.leYEnd, &QLineEdit::textChanged, this, &MatrixDock::yEndChanged);
0053     connect(ui.cbFormat, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &MatrixDock::numericFormatChanged);
0054     connect(ui.sbPrecision, QOverload<int>::of(&QSpinBox::valueChanged), this, &MatrixDock::precisionChanged);
0055     connect(ui.cbHeader, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &MatrixDock::headerFormatChanged);
0056 
0057     auto* templateHandler = new TemplateHandler(this, QLatin1String("Matrix"));
0058     ui.gridLayout->addWidget(templateHandler, 22, 0, 1, 4);
0059     // templateHandler->show();
0060     connect(templateHandler, &TemplateHandler::loadConfigRequested, this, &MatrixDock::loadConfigFromTemplate);
0061     connect(templateHandler, &TemplateHandler::saveConfigRequested, this, &MatrixDock::saveConfigAsTemplate);
0062     connect(templateHandler, &TemplateHandler::info, this, &MatrixDock::info);
0063 }
0064 
0065 void MatrixDock::setMatrices(QList<Matrix*> list) {
0066     CONDITIONAL_LOCK_RETURN;
0067     m_matrixList = list;
0068     m_matrix = list.first();
0069     setAspects(list);
0070 
0071     // show the properties of the first Matrix in the list, if there are >1 matrixs
0072     this->load();
0073 
0074     // undo functions
0075 
0076     connect(m_matrix, &Matrix::rowCountChanged, this, &MatrixDock::matrixRowCountChanged);
0077     connect(m_matrix, &Matrix::columnCountChanged, this, &MatrixDock::matrixColumnCountChanged);
0078 
0079     connect(m_matrix, &Matrix::xStartChanged, this, &MatrixDock::matrixXStartChanged);
0080     connect(m_matrix, &Matrix::xEndChanged, this, &MatrixDock::matrixXEndChanged);
0081     connect(m_matrix, &Matrix::yStartChanged, this, &MatrixDock::matrixYStartChanged);
0082     connect(m_matrix, &Matrix::yEndChanged, this, &MatrixDock::matrixYEndChanged);
0083 
0084     connect(m_matrix, &Matrix::numericFormatChanged, this, &MatrixDock::matrixNumericFormatChanged);
0085     connect(m_matrix, &Matrix::precisionChanged, this, &MatrixDock::matrixPrecisionChanged);
0086     connect(m_matrix, &Matrix::headerFormatChanged, this, &MatrixDock::matrixHeaderFormatChanged);
0087 }
0088 
0089 //*************************************************************
0090 //****** SLOTs for changes triggered in MatrixDock *******
0091 //*************************************************************
0092 // mapping to the logical coordinates
0093 void MatrixDock::xStartChanged(const QString& text) {
0094     CONDITIONAL_LOCK_RETURN;
0095 
0096     QString str = text.trimmed();
0097     if (str.isEmpty())
0098         return;
0099     bool ok;
0100     const double value{QLocale().toDouble(str, &ok)};
0101     if (ok) {
0102         for (auto* matrix : m_matrixList)
0103             matrix->setXStart(value);
0104     }
0105 }
0106 
0107 void MatrixDock::xEndChanged(const QString& text) {
0108     CONDITIONAL_LOCK_RETURN;
0109 
0110     QString str = text.trimmed();
0111     if (str.isEmpty())
0112         return;
0113     bool ok;
0114     const double value{QLocale().toDouble(str, &ok)};
0115     if (ok) {
0116         for (auto* matrix : m_matrixList)
0117             matrix->setXEnd(value);
0118     }
0119 }
0120 
0121 void MatrixDock::yStartChanged(const QString& text) {
0122     CONDITIONAL_LOCK_RETURN;
0123 
0124     QString str = text.trimmed();
0125     if (str.isEmpty())
0126         return;
0127     bool ok;
0128     const double value{QLocale().toDouble(str, &ok)};
0129     if (ok) {
0130         for (auto* matrix : m_matrixList)
0131             matrix->setYStart(value);
0132     }
0133 }
0134 
0135 void MatrixDock::yEndChanged(const QString& text) {
0136     CONDITIONAL_LOCK_RETURN;
0137 
0138     QString str = text.trimmed();
0139     if (str.isEmpty())
0140         return;
0141     bool ok;
0142     const double value{QLocale().toDouble(str, &ok)};
0143     if (ok) {
0144         for (auto* matrix : m_matrixList)
0145             matrix->setYEnd(value);
0146     }
0147 }
0148 
0149 // format
0150 void MatrixDock::numericFormatChanged(int index) {
0151     CONDITIONAL_LOCK_RETURN;
0152 
0153     char format = ui.cbFormat->itemData(index).toChar().toLatin1();
0154     for (auto* matrix : m_matrixList)
0155         matrix->setNumericFormat(format);
0156 }
0157 
0158 void MatrixDock::precisionChanged(int precision) {
0159     CONDITIONAL_LOCK_RETURN;
0160 
0161     for (auto* matrix : m_matrixList)
0162         matrix->setPrecision(precision);
0163 }
0164 
0165 void MatrixDock::headerFormatChanged(int value) {
0166     CONDITIONAL_LOCK_RETURN;
0167 
0168     auto format = static_cast<Matrix::HeaderFormat>(value);
0169     for (auto* matrix : m_matrixList)
0170         matrix->setHeaderFormat(format);
0171 }
0172 
0173 void MatrixDock::rowCountChanged(int rows) {
0174     CONDITIONAL_LOCK_RETURN;
0175 
0176     for (auto* matrix : m_matrixList)
0177         matrix->setRowCount(rows);
0178 }
0179 
0180 void MatrixDock::columnCountChanged(int columns) {
0181     CONDITIONAL_LOCK_RETURN;
0182 
0183     for (auto* matrix : m_matrixList)
0184         matrix->setColumnCount(columns);
0185 }
0186 
0187 //*************************************************************
0188 //******** SLOTs for changes triggered in Matrix *********
0189 //*************************************************************
0190 // matrix dimensions
0191 void MatrixDock::matrixRowCountChanged(int count) {
0192     CONDITIONAL_LOCK_RETURN;
0193     ui.sbRowCount->setValue(count);
0194 }
0195 
0196 void MatrixDock::matrixColumnCountChanged(int count) {
0197     CONDITIONAL_LOCK_RETURN;
0198     ui.sbColumnCount->setValue(count);
0199 }
0200 
0201 // mapping to the logical coordinates
0202 void MatrixDock::matrixXStartChanged(double value) {
0203     CONDITIONAL_LOCK_RETURN;
0204     ui.leXStart->setText(QLocale().toString(value));
0205 }
0206 
0207 void MatrixDock::matrixXEndChanged(double value) {
0208     CONDITIONAL_LOCK_RETURN;
0209     ui.leXEnd->setText(QLocale().toString(value));
0210 }
0211 
0212 void MatrixDock::matrixYStartChanged(double value) {
0213     CONDITIONAL_LOCK_RETURN;
0214     ui.leYStart->setText(QLocale().toString(value));
0215 }
0216 
0217 void MatrixDock::matrixYEndChanged(double value) {
0218     CONDITIONAL_LOCK_RETURN;
0219     ui.leYEnd->setText(QLocale().toString(value));
0220 }
0221 
0222 // format
0223 void MatrixDock::matrixNumericFormatChanged(char format) {
0224     CONDITIONAL_LOCK_RETURN;
0225     int index = ui.cbFormat->findData((int)format);
0226     ui.cbFormat->setCurrentIndex(index);
0227 }
0228 
0229 void MatrixDock::matrixPrecisionChanged(int precision) {
0230     CONDITIONAL_LOCK_RETURN;
0231     ui.sbPrecision->setValue(precision);
0232 }
0233 
0234 void MatrixDock::matrixHeaderFormatChanged(Matrix::HeaderFormat format) {
0235     CONDITIONAL_LOCK_RETURN;
0236     ui.cbHeader->setCurrentIndex((int)format);
0237 }
0238 
0239 //*************************************************************
0240 //******************** SETTINGS *******************************
0241 //*************************************************************
0242 void MatrixDock::load() {
0243     // matrix dimensions
0244     ui.sbRowCount->setValue(m_matrix->rowCount());
0245     ui.sbColumnCount->setValue(m_matrix->columnCount());
0246 
0247     // mapping to the logical coordinates
0248     const auto numberLocale = QLocale();
0249     ui.leXStart->setText(numberLocale.toString(m_matrix->xStart()));
0250     ui.leXEnd->setText(numberLocale.toString(m_matrix->xEnd()));
0251     ui.leYStart->setText(numberLocale.toString(m_matrix->yStart()));
0252     ui.leYEnd->setText(numberLocale.toString(m_matrix->yEnd()));
0253 
0254     // format
0255     ui.cbFormat->setCurrentIndex(ui.cbFormat->findData((int)m_matrix->numericFormat()));
0256     ui.sbPrecision->setValue(m_matrix->precision());
0257     ui.cbHeader->setCurrentIndex(static_cast<int>(m_matrix->headerFormat()));
0258 }
0259 
0260 void MatrixDock::loadConfigFromTemplate(KConfig& config) {
0261     auto name = TemplateHandler::templateName(config);
0262     const int size = m_matrixList.size();
0263     if (size > 1)
0264         m_matrix->beginMacro(i18n("%1 matrices: template \"%2\" loaded", size, name));
0265     else
0266         m_matrix->beginMacro(i18n("%1: template \"%2\" loaded", m_matrix->name(), name));
0267 
0268     this->loadConfig(config);
0269 
0270     m_matrix->endMacro();
0271 }
0272 
0273 /*!
0274     loads saved matrix properties from \c config.
0275  */
0276 void MatrixDock::loadConfig(KConfig& config) {
0277     KConfigGroup group = config.group(QStringLiteral("Matrix"));
0278 
0279     // matrix dimensions
0280     ui.sbRowCount->setValue(group.readEntry(QStringLiteral("RowCount"), m_matrix->rowCount()));
0281     ui.sbColumnCount->setValue(group.readEntry(QStringLiteral("ColumnCount"), m_matrix->columnCount()));
0282 
0283     // mapping to the logical coordinates
0284     const auto numberLocale = QLocale();
0285     ui.leXStart->setText(numberLocale.toString(group.readEntry(QStringLiteral("XStart"), m_matrix->xStart())));
0286     ui.leXEnd->setText(numberLocale.toString(group.readEntry(QStringLiteral("XEnd"), m_matrix->xEnd())));
0287     ui.leYStart->setText(numberLocale.toString(group.readEntry(QStringLiteral("YStart"), m_matrix->yStart())));
0288     ui.leYEnd->setText(numberLocale.toString(group.readEntry(QStringLiteral("YEnd"), m_matrix->yEnd())));
0289 
0290     // format
0291     ui.cbFormat->setCurrentIndex(ui.cbFormat->findData(group.readEntry(QStringLiteral("NumericFormat"), (int)(m_matrix->numericFormat()))));
0292     ui.sbPrecision->setValue(group.readEntry(QStringLiteral("Precision"), m_matrix->precision()));
0293     ui.cbHeader->setCurrentIndex(group.readEntry(QStringLiteral("HeaderFormat"), (int)m_matrix->headerFormat()));
0294 }
0295 
0296 /*!
0297     saves matrix properties to \c config.
0298  */
0299 void MatrixDock::saveConfigAsTemplate(KConfig& config) {
0300     KConfigGroup group = config.group(QStringLiteral("Matrix"));
0301 
0302     // matrix dimensions
0303     group.writeEntry(QStringLiteral("RowCount"), ui.sbRowCount->value());
0304     group.writeEntry(QStringLiteral("ColumnCount"), ui.sbColumnCount->value());
0305 
0306     // mapping to the logical coordinates
0307     const auto numberLocale = QLocale();
0308     group.writeEntry(QStringLiteral("XStart"), numberLocale.toDouble(ui.leXStart->text()));
0309     group.writeEntry(QStringLiteral("XEnd"), numberLocale.toDouble(ui.leXEnd->text()));
0310     group.writeEntry(QStringLiteral("YStart"), numberLocale.toDouble(ui.leYStart->text()));
0311     group.writeEntry(QStringLiteral("YEnd"), numberLocale.toDouble(ui.leYEnd->text()));
0312 
0313     // format
0314     group.writeEntry(QStringLiteral("NumericFormat"), ui.cbFormat->itemData(ui.cbFormat->currentIndex()));
0315     group.writeEntry(QStringLiteral("Precision"), ui.sbPrecision->value());
0316     group.writeEntry(QStringLiteral("HeaderFormat"), ui.cbHeader->currentIndex());
0317 
0318     config.sync();
0319 }