File indexing completed on 2025-01-05 03:35:30
0001 /* 0002 File : InfoElement.cpp 0003 Project : LabPlot 0004 Description : Dock widget for InfoElemnt 0005 -------------------------------------------------------------------- 0006 SPDX-FileCopyrightText: 2020 Martin Marmsoler <martin.marmsoler@gmail.com> 0007 SPDX-FileCopyrightText: 2020-2022 Alexander Semke <alexander.semke@web.de> 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 #include "InfoElementDock.h" 0012 #include "backend/worksheet/InfoElement.h" 0013 #include "backend/worksheet/plots/cartesian/CartesianPlot.h" 0014 #include "backend/worksheet/plots/cartesian/XYCurve.h" 0015 #include "kdefrontend/GuiTools.h" 0016 #include "kdefrontend/widgets/LabelWidget.h" 0017 #include "kdefrontend/widgets/LineWidget.h" 0018 #include "ui_infoelementdock.h" 0019 0020 InfoElementDock::InfoElementDock(QWidget* parent) 0021 : BaseDock(parent) 0022 , ui(new Ui::InfoElementDock) { 0023 ui->setupUi(this); 0024 setPlotRangeCombobox(ui->cbPlotRanges); 0025 setBaseWidgets(ui->leName, ui->teComment); 0026 setVisibilityWidgets(ui->chbVisible); 0027 0028 //"Title"-tab 0029 auto* hboxLayout = new QHBoxLayout(ui->tabTitle); 0030 m_labelWidget = new LabelWidget(ui->tabTitle); 0031 hboxLayout->addWidget(m_labelWidget); 0032 hboxLayout->setContentsMargins(2, 2, 2, 2); 0033 hboxLayout->setSpacing(2); 0034 0035 // "Lines"-tab 0036 auto* layout = static_cast<QGridLayout*>(ui->tabLines->layout()); 0037 m_verticalLineWidget = new LineWidget(ui->tabLines); 0038 layout->addWidget(m_verticalLineWidget, 1, 0, 1, 3); 0039 0040 m_connectionLineWidget = new LineWidget(ui->tabLines); 0041 layout->addWidget(m_connectionLineWidget, 4, 0, 1, 3); 0042 0043 // set the current locale 0044 ui->sbPosition->setLocale(QLocale()); 0045 m_labelWidget->updateLocale(); 0046 m_verticalLineWidget->updateLocale(); 0047 m_connectionLineWidget->updateLocale(); 0048 0049 //********************************** Slots ********************************************** 0050 // general 0051 connect(ui->sbPosition, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &InfoElementDock::positionChanged); 0052 connect(ui->dateTimeEditPosition, &UTCDateTimeEdit::mSecsSinceEpochUTCChanged, this, &InfoElementDock::positionDateTimeChanged); 0053 connect(ui->cbConnectToCurve, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &InfoElementDock::curveChanged); 0054 connect(ui->cbConnectToAnchor, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &InfoElementDock::gluePointChanged); 0055 } 0056 0057 void InfoElementDock::setInfoElements(QList<InfoElement*> list) { 0058 CONDITIONAL_LOCK_RETURN; 0059 0060 m_elements = list; 0061 m_element = list.first(); 0062 setAspects(list); 0063 0064 // check if all InfoElements have the same CartesianPlot as Parent 0065 m_sameParent = true; 0066 if (!m_elements.isEmpty()) { 0067 const auto* parent = m_elements.constFirst()->parentAspect(); 0068 for (auto* element : m_elements) { 0069 if (element->parentAspect() != parent) { 0070 m_sameParent = false; 0071 break; 0072 } 0073 } 0074 } 0075 0076 QList<TextLabel*> labels; 0077 QList<Line*> verticalLines; 0078 QList<Line*> connectionLines; 0079 for (auto* element : list) { 0080 labels << element->title(); 0081 verticalLines << element->verticalLine(); 0082 connectionLines << element->connectionLine(); 0083 } 0084 0085 m_labelWidget->setLabels(labels); 0086 m_verticalLineWidget->setLines(verticalLines); 0087 m_connectionLineWidget->setLines(connectionLines); 0088 0089 ui->lwCurves->clear(); 0090 ui->cbConnectToCurve->clear(); 0091 0092 ui->chbVisible->setChecked(m_element->isVisible()); 0093 0094 // disable if not all worksheetelements do not have the same parent (different CartesianPlots), 0095 // because then the available curves are different 0096 if (m_sameParent) { 0097 ui->lwCurves->setEnabled(true); 0098 ui->cbConnectToCurve->setEnabled(true); 0099 0100 const auto& curves = m_element->plot()->children<XYCurve>(); 0101 for (const auto* curve : curves) { 0102 auto* item = new QListWidgetItem(); 0103 auto* checkBox = new QCheckBox(curve->name()); 0104 for (int i = 0; i < m_element->markerPointsCount(); i++) { 0105 if (curve->path() == m_element->markerPointAt(i).curvePath) { 0106 checkBox->setChecked(true); 0107 ui->cbConnectToCurve->addItem(curve->name()); 0108 break; 0109 } 0110 } 0111 connect(checkBox, &QCheckBox::toggled, this, &InfoElementDock::curveSelectionChanged); 0112 ui->lwCurves->addItem(item); 0113 ui->lwCurves->setItemWidget(item, checkBox); 0114 } 0115 } else { 0116 ui->lwCurves->setEnabled(false); 0117 ui->cbConnectToCurve->setEnabled(false); 0118 } 0119 0120 const QString& curveName = m_element->connectionLineCurveName(); 0121 for (int i = 0; i < ui->cbConnectToCurve->count(); i++) { 0122 if (ui->cbConnectToCurve->itemData(i, Qt::DisplayRole).toString().compare(curveName) == 0) { 0123 ui->cbConnectToCurve->setCurrentIndex(i); 0124 break; 0125 } 0126 } 0127 0128 // possible anchor points 0129 ui->cbConnectToAnchor->clear(); 0130 ui->cbConnectToAnchor->addItem(i18n("Auto")); 0131 for (int i = 0; i < m_element->gluePointsCount(); i++) 0132 ui->cbConnectToAnchor->addItem(m_element->gluePoint(i).name); 0133 ui->cbConnectToAnchor->setCurrentIndex(m_element->gluePointIndex() + 1); 0134 0135 if (m_element->plot()->xRangeFormatDefault() == RangeT::Format::Numeric) { 0136 ui->sbPosition->setValue(m_element->positionLogical()); 0137 ui->lPosition->show(); 0138 ui->sbPosition->show(); 0139 ui->lPositionDateTime->hide(); 0140 ui->dateTimeEditPosition->hide(); 0141 } else { 0142 ui->dateTimeEditPosition->setDisplayFormat(m_element->plot()->rangeDateTimeFormat(Dimension::X)); 0143 ui->dateTimeEditPosition->setMSecsSinceEpochUTC(m_element->positionLogical()); 0144 ui->lPosition->hide(); 0145 ui->sbPosition->hide(); 0146 ui->lPositionDateTime->show(); 0147 ui->dateTimeEditPosition->show(); 0148 } 0149 0150 updatePlotRangeList(); // needed when loading project 0151 0152 // general 0153 connect(m_element, &InfoElement::positionLogicalChanged, this, &InfoElementDock::elementPositionChanged); 0154 connect(m_element, &InfoElement::gluePointIndexChanged, this, &InfoElementDock::elementGluePointIndexChanged); 0155 connect(m_element, &InfoElement::connectionLineCurveNameChanged, this, &InfoElementDock::elementConnectionLineCurveChanged); 0156 connect(m_element, &InfoElement::labelBorderShapeChangedSignal, this, &InfoElementDock::elementLabelBorderShapeChanged); 0157 connect(m_element, &InfoElement::curveRemoved, this, &InfoElementDock::elementCurveRemoved); 0158 } 0159 0160 //************************************************************* 0161 //******* SLOTs for changes triggered in InfoElementDock ****** 0162 //************************************************************* 0163 InfoElementDock::~InfoElementDock() { 0164 delete ui; 0165 } 0166 0167 // general tab 0168 void InfoElementDock::positionChanged(double pos) { 0169 CONDITIONAL_RETURN_NO_LOCK; 0170 0171 for (auto* element : m_elements) 0172 element->setPositionLogical(pos); 0173 } 0174 0175 void InfoElementDock::positionDateTimeChanged(qint64 value) { 0176 CONDITIONAL_LOCK_RETURN; 0177 0178 for (auto* element : m_elements) 0179 element->setPositionLogical(value); 0180 } 0181 0182 void InfoElementDock::curveSelectionChanged(bool enabled) { 0183 CONDITIONAL_LOCK_RETURN; 0184 if (!m_sameParent) 0185 return; 0186 0187 // determine the curve for which the selection was changed 0188 auto* checkBox = static_cast<QCheckBox*>(QObject::sender()); 0189 QString curveName = checkBox->text().remove(QLatin1Char('&')); 0190 XYCurve* curve = nullptr; 0191 for (auto* c : m_elements[0]->plot()->children<XYCurve>()) { 0192 if (c->name() == curveName) { 0193 curve = c; 0194 break; 0195 } 0196 } 0197 0198 // add/remove the changed curve 0199 if (enabled && curve) { 0200 for (auto* element : m_elements) 0201 element->addCurve(curve); 0202 0203 // TODO: add the new curve at the proper index via insertItem(); 0204 ui->cbConnectToCurve->addItem(curveName); 0205 } else { 0206 bool macroStarted = false; 0207 0208 // update the "connect to" combobox 0209 for (int i = 0; ui->cbConnectToCurve->count(); ++i) { 0210 if (ui->cbConnectToCurve->itemText(i) == curveName) { 0211 // removing an entry from combo box automatically triggers 0212 // the selection of a new time which leads to a selection of 0213 // a new "connect to"-curve in the InfoElement. To make only 0214 // one single entry on the undo-stak we need to start a macro here: 0215 macroStarted = true; 0216 int size = m_elements.size(); 0217 if (size > 1) 0218 m_element->beginMacro(i18n("%1 info elements: curve \"%2\" removed", size, curveName)); 0219 else 0220 m_element->beginMacro(i18n("%1: curve \"%2\" removed", m_element->name(), curveName)); 0221 0222 ui->cbConnectToCurve->removeItem(i); 0223 break; 0224 } 0225 } 0226 0227 for (auto* element : m_elements) 0228 element->removeCurve(curve); 0229 0230 if (macroStarted) 0231 m_element->endMacro(); 0232 } 0233 } 0234 0235 void InfoElementDock::curveChanged() { 0236 CONDITIONAL_LOCK_RETURN; 0237 0238 const QString& name = ui->cbConnectToCurve->currentText(); 0239 for (auto* infoElement : m_elements) 0240 infoElement->setConnectionLineCurveName(name); 0241 } 0242 0243 void InfoElementDock::gluePointChanged(int index) { 0244 CONDITIONAL_LOCK_RETURN; 0245 0246 for (auto* infoElement : m_elements) 0247 infoElement->setGluePointIndex(index - 1); // index 0 means automatic, which is defined as -1 0248 } 0249 0250 //*********************************************************** 0251 //******* SLOTs for changes triggered in InfoElement ******** 0252 //*********************************************************** 0253 void InfoElementDock::elementGluePointIndexChanged(const int index) { 0254 CONDITIONAL_LOCK_RETURN; 0255 if (index < 0) 0256 ui->cbConnectToAnchor->setCurrentIndex(0); 0257 else 0258 ui->cbConnectToAnchor->setCurrentIndex(index + 1); // automatic label is in same combo box 0259 } 0260 0261 void InfoElementDock::elementConnectionLineCurveChanged(const QString& name) { 0262 CONDITIONAL_LOCK_RETURN; 0263 for (int i = 0; i < ui->cbConnectToCurve->count(); i++) { 0264 if (ui->cbConnectToCurve->itemData(i).toString().compare(name) == 0) { 0265 ui->cbConnectToCurve->setCurrentIndex(i); 0266 break; 0267 } 0268 } 0269 } 0270 0271 void InfoElementDock::elementLabelBorderShapeChanged() { 0272 CONDITIONAL_LOCK_RETURN; 0273 ui->cbConnectToAnchor->clear(); 0274 ui->cbConnectToAnchor->addItem(i18n("Auto")); 0275 for (int i = 0; i < m_element->gluePointsCount(); i++) 0276 ui->cbConnectToAnchor->addItem(m_element->gluePoint(i).name); 0277 } 0278 0279 void InfoElementDock::elementPositionChanged(double pos) { 0280 CONDITIONAL_LOCK_RETURN; 0281 ui->sbPosition->setValue(pos); 0282 ui->dateTimeEditPosition->setMSecsSinceEpochUTC(pos); 0283 } 0284 0285 void InfoElementDock::elementCurveRemoved(const QString& name) { 0286 CONDITIONAL_LOCK_RETURN; 0287 for (int i = 0; i < ui->lwCurves->count(); ++i) { 0288 auto* item = ui->lwCurves->item(i); 0289 auto* checkBox = static_cast<QCheckBox*>(ui->lwCurves->itemWidget(item)); 0290 if (checkBox->text() == name) { 0291 ui->lwCurves->takeItem(i); 0292 break; 0293 } 0294 } 0295 }