File indexing completed on 2025-11-02 03:43:30

0001 /*
0002     File                 : ReferenceLineDock.cpp
0003     Project              : LabPlot
0004     Description          : Dock widget for the reference line on the plot
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2020-2023 Alexander Semke <alexander.semke@web.de>
0007     SPDX-FileCopyrightText: 2021 Stefan Gerlach <stefan.gerlach@uni.kn>
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "ReferenceLineDock.h"
0012 #include "backend/worksheet/plots/cartesian/ReferenceLine.h"
0013 #include "kdefrontend/TemplateHandler.h"
0014 #include "kdefrontend/widgets/LineWidget.h"
0015 
0016 #include <KConfig>
0017 #include <KConfigGroup>
0018 #include <KLocalizedString>
0019 
0020 ReferenceLineDock::ReferenceLineDock(QWidget* parent)
0021     : BaseDock(parent) {
0022     ui.setupUi(this);
0023     setPlotRangeCombobox(ui.cbPlotRanges);
0024     setBaseWidgets(ui.leName, ui.teComment);
0025     setVisibilityWidgets(ui.chkVisible);
0026 
0027     ui.cbOrientation->addItem(i18n("Horizontal"));
0028     ui.cbOrientation->addItem(i18n("Vertical"));
0029 
0030     auto* layout = static_cast<QHBoxLayout*>(ui.tabLine->layout());
0031     lineWidget = new LineWidget(ui.tabLine);
0032     layout->insertWidget(0, lineWidget);
0033 
0034     // SLOTS
0035     // General
0036     connect(ui.cbOrientation, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ReferenceLineDock::orientationChanged);
0037     connect(ui.sbPosition, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &ReferenceLineDock::positionLogicalChanged);
0038     connect(ui.dtePosition, &UTCDateTimeEdit::mSecsSinceEpochUTCChanged, this, &ReferenceLineDock::positionLogicalDateTimeChanged);
0039     connect(ui.chbLock, &QCheckBox::clicked, this, &ReferenceLineDock::lockChanged);
0040 
0041     // Template handler
0042     auto* frame = new QFrame(this);
0043     auto* hlayout = new QHBoxLayout(frame);
0044     hlayout->setContentsMargins(0, 11, 0, 11);
0045 
0046     auto* templateHandler = new TemplateHandler(this, QLatin1String("ReferenceLine"));
0047     hlayout->addWidget(templateHandler);
0048     connect(templateHandler, &TemplateHandler::loadConfigRequested, this, &ReferenceLineDock::loadConfigFromTemplate);
0049     connect(templateHandler, &TemplateHandler::saveConfigRequested, this, &ReferenceLineDock::saveConfigAsTemplate);
0050     connect(templateHandler, &TemplateHandler::info, this, &ReferenceLineDock::info);
0051 
0052     ui.verticalLayout->addWidget(frame);
0053 }
0054 
0055 void ReferenceLineDock::setReferenceLines(QList<ReferenceLine*> list) {
0056     CONDITIONAL_LOCK_RETURN;
0057     m_linesList = list;
0058     m_line = list.first();
0059     setAspects(list);
0060     Q_ASSERT(m_line);
0061 
0062     // show the properties of the first reference line
0063     this->load();
0064 
0065     QList<Line*> lines;
0066     for (auto* line : m_linesList)
0067         lines << line->line();
0068     lineWidget->setLines(lines);
0069 
0070     updatePlotRangeList();
0071 
0072     // SIGNALs/SLOTs
0073     connect(m_line, &ReferenceLine::lockChanged, this, &ReferenceLineDock::lineLockChanged);
0074     connect(m_line, &ReferenceLine::orientationChanged, this, &ReferenceLineDock::lineOrientationChanged);
0075     connect(m_line, &ReferenceLine::positionLogicalChanged, this, &ReferenceLineDock::linePositionLogicalChanged);
0076 }
0077 
0078 /*
0079  * updates the locale in the widgets. called when the application settings are changed.
0080  */
0081 void ReferenceLineDock::updateLocale() {
0082     CONDITIONAL_LOCK_RETURN;
0083     const auto* plot = static_cast<const CartesianPlot*>(m_line->plot());
0084     if (m_line->orientation() == ReferenceLine::Orientation::Horizontal) {
0085         if (plot->yRangeFormatDefault() == RangeT::Format::Numeric)
0086             ui.sbPosition->setValue(m_line->positionLogical().y());
0087     } else {
0088         if (plot->xRangeFormatDefault() == RangeT::Format::Numeric)
0089             ui.sbPosition->setValue(m_line->positionLogical().x());
0090     }
0091 
0092     lineWidget->updateLocale();
0093 }
0094 
0095 void ReferenceLineDock::updateWidgetsOrientation(ReferenceLine::Orientation orientation) {
0096     const auto* plot = static_cast<const CartesianPlot*>(m_line->plot());
0097     bool numeric;
0098     if (orientation == ReferenceLine::Orientation::Horizontal) {
0099         ui.lPosition->setText(QStringLiteral("y:"));
0100         ui.lPositionDateTime->setText(QStringLiteral("y:"));
0101         numeric = (plot->yRangeFormatDefault() == RangeT::Format::Numeric);
0102     } else {
0103         ui.lPosition->setText(QStringLiteral("x:"));
0104         ui.lPositionDateTime->setText(QStringLiteral("x:"));
0105         numeric = (plot->xRangeFormatDefault() == RangeT::Format::Numeric);
0106     }
0107 
0108     ui.lPosition->setVisible(numeric);
0109     ui.sbPosition->setVisible(numeric);
0110     ui.lPositionDateTime->setVisible(!numeric);
0111     ui.dtePosition->setVisible(!numeric);
0112 }
0113 
0114 //**********************************************************
0115 //*** SLOTs for changes triggered in ReferenceLineDock *****
0116 //**********************************************************
0117 // Position
0118 void ReferenceLineDock::orientationChanged(int index) {
0119     auto orientation{ReferenceLine::Orientation(index)};
0120     updateWidgetsOrientation(orientation);
0121 
0122     CONDITIONAL_LOCK_RETURN;
0123 
0124     for (auto* line : m_linesList)
0125         line->setOrientation(orientation);
0126 
0127     // call this slot to show the x or y value depending on the new orientation
0128     linePositionLogicalChanged(m_line->positionLogical());
0129 }
0130 
0131 void ReferenceLineDock::positionLogicalChanged(double pos) {
0132     CONDITIONAL_RETURN_NO_LOCK;
0133 
0134     for (auto* line : m_linesList) {
0135         auto positionLogical = line->positionLogical();
0136         if (line->orientation() == ReferenceLine::Orientation::Horizontal)
0137             positionLogical.setY(pos);
0138         else
0139             positionLogical.setX(pos);
0140         line->setPositionLogical(positionLogical);
0141     }
0142 }
0143 
0144 void ReferenceLineDock::positionLogicalDateTimeChanged(qint64 pos) {
0145     CONDITIONAL_LOCK_RETURN;
0146 
0147     for (auto* line : m_linesList) {
0148         auto positionLogical = line->positionLogical();
0149         if (line->orientation() == ReferenceLine::Orientation::Horizontal)
0150             positionLogical.setY(pos);
0151         else
0152             positionLogical.setX(pos);
0153         line->setPositionLogical(positionLogical);
0154     }
0155 }
0156 
0157 void ReferenceLineDock::lockChanged(bool locked) {
0158     CONDITIONAL_LOCK_RETURN;
0159 
0160     for (auto* line : m_linesList)
0161         line->setLock(locked);
0162 }
0163 
0164 //*************************************************************
0165 //******* SLOTs for changes triggered in ReferenceLine ********
0166 //*************************************************************
0167 void ReferenceLineDock::linePositionLogicalChanged(const QPointF& positionLogical) {
0168     CONDITIONAL_LOCK_RETURN;
0169     if (m_line->orientation() == ReferenceLine::Orientation::Horizontal) {
0170         ui.sbPosition->setValue(positionLogical.y());
0171         ui.dtePosition->setMSecsSinceEpochUTC(positionLogical.y());
0172     } else {
0173         ui.sbPosition->setValue(positionLogical.x());
0174         ui.dtePosition->setMSecsSinceEpochUTC(positionLogical.x());
0175     }
0176 }
0177 
0178 void ReferenceLineDock::lineOrientationChanged(ReferenceLine::Orientation orientation) {
0179     CONDITIONAL_LOCK_RETURN;
0180     ui.cbOrientation->setCurrentIndex(static_cast<int>(orientation));
0181 }
0182 
0183 void ReferenceLineDock::lineLockChanged(bool on) {
0184     CONDITIONAL_LOCK_RETURN;
0185     ui.chbLock->setChecked(on);
0186 }
0187 
0188 //**********************************************************
0189 //******************** SETTINGS ****************************
0190 //**********************************************************
0191 void ReferenceLineDock::load() {
0192     if (!m_line)
0193         return;
0194 
0195     // No lock!
0196 
0197     auto orientation = m_line->orientation();
0198     ui.cbOrientation->setCurrentIndex(static_cast<int>(orientation));
0199     updateWidgetsOrientation(orientation);
0200 
0201     // position
0202     const auto* plot = static_cast<const CartesianPlot*>(m_line->plot());
0203     if (orientation == ReferenceLine::Orientation::Horizontal) {
0204         if (plot->yRangeFormatDefault() == RangeT::Format::Numeric)
0205             ui.sbPosition->setValue(m_line->positionLogical().y());
0206         else { // DateTime
0207             ui.dtePosition->setDisplayFormat(plot->rangeDateTimeFormat(Dimension::Y));
0208             ui.dtePosition->setMSecsSinceEpochUTC(m_line->positionLogical().y());
0209         }
0210     } else {
0211         if (plot->xRangeFormatDefault() == RangeT::Format::Numeric)
0212             ui.sbPosition->setValue(m_line->positionLogical().x());
0213         else { // DateTime
0214             ui.dtePosition->setDisplayFormat(plot->rangeDateTimeFormat(Dimension::X));
0215             ui.dtePosition->setMSecsSinceEpochUTC(m_line->positionLogical().x());
0216         }
0217     }
0218 
0219     ui.chbLock->setChecked(m_line->isLocked());
0220     ui.chkVisible->setChecked(m_line->isVisible());
0221 }
0222 
0223 void ReferenceLineDock::loadConfigFromTemplate(KConfig& config) {
0224     auto name = TemplateHandler::templateName(config);
0225     int size = m_linesList.size();
0226     if (size > 1)
0227         m_line->beginMacro(i18n("%1 reference lines: template \"%2\" loaded", size, name));
0228     else
0229         m_line->beginMacro(i18n("%1: template \"%2\" loaded", m_line->name(), name));
0230 
0231     lineWidget->loadConfig(config.group(QStringLiteral("ReferenceLine")));
0232 
0233     m_line->endMacro();
0234 }
0235 
0236 void ReferenceLineDock::saveConfigAsTemplate(KConfig& config) {
0237     KConfigGroup group = config.group(QStringLiteral("ReferenceLine"));
0238     lineWidget->saveConfig(group);
0239 }