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 }