File indexing completed on 2024-05-12 15:27:58
0001 /*************************************************************************** 0002 File : ColumnDock.cpp 0003 Project : LabPlot 0004 -------------------------------------------------------------------- 0005 Copyright : (C) 2011-2020 by Alexander Semke (alexander.semke@web.de) 0006 Copyright : (C) 2013-2017 by Stefan Gerlach (stefan.gerlach@uni.kn) 0007 Description : widget for column properties 0008 0009 ***************************************************************************/ 0010 0011 /*************************************************************************** 0012 * * 0013 * This program is free software; you can redistribute it and/or modify * 0014 * it under the terms of the GNU General Public License as published by * 0015 * the Free Software Foundation; either version 2 of the License, or * 0016 * (at your option) any later version. * 0017 * * 0018 * This program is distributed in the hope that it will be useful, * 0019 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0021 * GNU General Public License for more details. * 0022 * * 0023 * You should have received a copy of the GNU General Public License * 0024 * along with this program; if not, write to the Free Software * 0025 * Foundation, Inc., 51 Franklin Street, Fifth Floor, * 0026 * Boston, MA 02110-1301 USA * 0027 * * 0028 ***************************************************************************/ 0029 0030 #include "ColumnDock.h" 0031 0032 #include "backend/core/AbstractFilter.h" 0033 #include "backend/core/datatypes/SimpleCopyThroughFilter.h" 0034 #include "backend/core/datatypes/Double2StringFilter.h" 0035 #include "backend/core/datatypes/String2DoubleFilter.h" 0036 #include "backend/core/datatypes/DateTime2StringFilter.h" 0037 #include "backend/core/datatypes/String2DateTimeFilter.h" 0038 #include "backend/spreadsheet/Spreadsheet.h" 0039 0040 #include <KLocalizedString> 0041 0042 /*! 0043 \class ColumnDock 0044 \brief Provides a widget for editing the properties of the spreadsheet columns currently selected in the project explorer. 0045 0046 \ingroup kdefrontend 0047 */ 0048 0049 ColumnDock::ColumnDock(QWidget* parent) : BaseDock(parent) { 0050 ui.setupUi(this); 0051 m_leName = ui.leName; 0052 m_leComment = ui.leComment; 0053 0054 //add formats for numeric values 0055 ui.cbNumericFormat->addItem(i18n("Decimal"), QVariant('f')); 0056 ui.cbNumericFormat->addItem(i18n("Scientific (e)"), QVariant('e')); 0057 ui.cbNumericFormat->addItem(i18n("Scientific (E)"), QVariant('E')); 0058 ui.cbNumericFormat->addItem(i18n("Automatic (e)"), QVariant('g')); 0059 ui.cbNumericFormat->addItem(i18n("Automatic (E)"), QVariant('G')); 0060 0061 //add format for date, time and datetime values 0062 for (const auto& s : AbstractColumn::dateTimeFormats()) 0063 ui.cbDateTimeFormat->addItem(s, QVariant(s)); 0064 0065 ui.cbDateTimeFormat->setEditable(true); 0066 0067 connect(ui.leName, &QLineEdit::textChanged, this, &ColumnDock::nameChanged); 0068 connect(ui.leComment, &QLineEdit::textChanged, this, &ColumnDock::commentChanged); 0069 connect(ui.cbType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ColumnDock::typeChanged); 0070 connect(ui.cbNumericFormat, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ColumnDock::numericFormatChanged); 0071 connect(ui.sbPrecision, QOverload<int>::of(&QSpinBox::valueChanged), this, &ColumnDock::precisionChanged); 0072 connect(ui.cbDateTimeFormat, &QComboBox::currentTextChanged, this, &ColumnDock::dateTimeFormatChanged); 0073 connect(ui.cbPlotDesignation, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ColumnDock::plotDesignationChanged); 0074 0075 retranslateUi(); 0076 } 0077 0078 void ColumnDock::setColumns(QList<Column*> list) { 0079 m_initializing = true; 0080 m_columnsList = list; 0081 m_column = list.first(); 0082 m_aspect = list.first(); 0083 0084 //check whether we have non-editable columns: 0085 //1. columns in a LiveDataSource 0086 //2. columns in the spreadsheet of a datapicker curve 0087 //3. columns for residuals calculated in XYFitCurve) 0088 bool nonEditable = false; 0089 for (auto* col : m_columnsList) { 0090 auto* s = dynamic_cast<Spreadsheet*>(col->parentAspect()); 0091 if (s) { 0092 if (s->type() == AspectType::LiveDataSource || s->parentAspect()->type() == AspectType::DatapickerCurve) { 0093 nonEditable = true; 0094 break; 0095 } 0096 } else { 0097 nonEditable = true; 0098 break; 0099 } 0100 } 0101 0102 //if columns of different modes are selected, change of the mode is not possible 0103 bool sameMode = true; 0104 0105 if (list.size() == 1) { 0106 //names and comments of non-editable columns in a file data source can be changed. 0107 if (!nonEditable && m_column->parentAspect()->type() == AspectType::LiveDataSource) { 0108 ui.leName->setEnabled(false); 0109 ui.leComment->setEnabled(false); 0110 } else { 0111 ui.leName->setEnabled(true); 0112 ui.leComment->setEnabled(true); 0113 } 0114 0115 ui.leName->setText(m_column->name()); 0116 ui.leComment->setText(m_column->comment()); 0117 } else { 0118 ui.leName->setEnabled(false); 0119 ui.leComment->setEnabled(false); 0120 0121 ui.leName->setText(QString()); 0122 ui.leComment->setText(QString()); 0123 0124 auto mode = m_column->columnMode(); 0125 for (auto* col : m_columnsList) { 0126 if (col->columnMode() != mode) { 0127 sameMode = false; 0128 break; 0129 } 0130 } 0131 } 0132 0133 ui.lType->setEnabled(sameMode); 0134 ui.cbType->setEnabled(sameMode); 0135 ui.lNumericFormat->setEnabled(sameMode); 0136 ui.cbNumericFormat->setEnabled(sameMode); 0137 ui.lPrecision->setEnabled(sameMode); 0138 ui.sbPrecision->setEnabled(sameMode); 0139 ui.lDateTimeFormat->setEnabled(sameMode); 0140 ui.cbDateTimeFormat->setEnabled(sameMode); 0141 0142 ui.leName->setStyleSheet(""); 0143 ui.leName->setToolTip(""); 0144 0145 //show the properties of the first column 0146 updateTypeWidgets(m_column->columnMode()); 0147 ui.cbPlotDesignation->setCurrentIndex( int(m_column->plotDesignation()) ); 0148 0149 // slots 0150 connect(m_column, &AbstractColumn::aspectDescriptionChanged, this, &ColumnDock::columnDescriptionChanged); 0151 connect(m_column, &AbstractColumn::modeChanged, this, &ColumnDock::columnModeChanged); 0152 connect(m_column->outputFilter(), &AbstractSimpleFilter::formatChanged, this, &ColumnDock::columnFormatChanged); 0153 connect(m_column->outputFilter(), &AbstractSimpleFilter::digitsChanged, this, &ColumnDock::columnPrecisionChanged); 0154 connect(m_column, &AbstractColumn::plotDesignationChanged, this, &ColumnDock::columnPlotDesignationChanged); 0155 0156 //don't allow to change the column type at least one non-editable column 0157 if (sameMode) 0158 ui.cbType->setEnabled(!nonEditable); 0159 0160 m_initializing = false; 0161 } 0162 0163 /*! 0164 depending on the currently selected column type (column mode) updates the widgets for the column format, 0165 shows/hides the allowed widgets, fills the corresponding combobox with the possible entries. 0166 Called when the type (column mode) is changed. 0167 */ 0168 void ColumnDock::updateTypeWidgets(AbstractColumn::ColumnMode mode) { 0169 const Lock lock(m_initializing); 0170 ui.cbType->setCurrentIndex(ui.cbType->findData((int)mode)); 0171 switch (mode) { 0172 case AbstractColumn::ColumnMode::Numeric: { 0173 auto* filter = static_cast<Double2StringFilter*>(m_column->outputFilter()); 0174 ui.cbNumericFormat->setCurrentIndex(ui.cbNumericFormat->findData(filter->numericFormat())); 0175 ui.sbPrecision->setValue(filter->numDigits()); 0176 break; 0177 } 0178 case AbstractColumn::ColumnMode::Month: 0179 case AbstractColumn::ColumnMode::Day: 0180 case AbstractColumn::ColumnMode::DateTime: { 0181 auto* filter = static_cast<DateTime2StringFilter*>(m_column->outputFilter()); 0182 // DEBUG(" set column format: " << STDSTRING(filter->format())); 0183 ui.cbDateTimeFormat->setCurrentIndex(ui.cbDateTimeFormat->findData(filter->format())); 0184 break; 0185 } 0186 case AbstractColumn::ColumnMode::Integer: // nothing to set 0187 case AbstractColumn::ColumnMode::BigInt: 0188 case AbstractColumn::ColumnMode::Text: 0189 break; 0190 } 0191 0192 //hide all the format related widgets first and 0193 //then show only what is required depending of the column mode(s) 0194 ui.lNumericFormat->hide(); 0195 ui.cbNumericFormat->hide(); 0196 ui.lPrecision->hide(); 0197 ui.sbPrecision->hide(); 0198 ui.lDateTimeFormat->hide(); 0199 ui.cbDateTimeFormat->hide(); 0200 0201 if (mode == AbstractColumn::ColumnMode::Numeric) { 0202 ui.lNumericFormat->show(); 0203 ui.cbNumericFormat->show(); 0204 } 0205 0206 //precision is only available for Numeric 0207 if (mode == AbstractColumn::ColumnMode::Numeric) { 0208 ui.lPrecision->show(); 0209 ui.sbPrecision->show(); 0210 } 0211 0212 if (mode == AbstractColumn::ColumnMode::DateTime) { 0213 ui.lDateTimeFormat->show(); 0214 ui.cbDateTimeFormat->show(); 0215 } 0216 } 0217 0218 //************************************************************* 0219 //******** SLOTs for changes triggered in ColumnDock ********** 0220 //************************************************************* 0221 void ColumnDock::retranslateUi() { 0222 m_initializing = true; 0223 0224 ui.cbType->clear(); 0225 ui.cbType->addItem(i18n("Numeric"), QVariant(static_cast<int>(AbstractColumn::ColumnMode::Numeric))); 0226 ui.cbType->addItem(i18n("Integer"), QVariant(static_cast<int>(AbstractColumn::ColumnMode::Integer))); 0227 ui.cbType->addItem(i18n("Big Integer"), QVariant(static_cast<int>(AbstractColumn::ColumnMode::BigInt))); 0228 ui.cbType->addItem(i18n("Text"), QVariant(static_cast<int>(AbstractColumn::ColumnMode::Text))); 0229 ui.cbType->addItem(i18n("Month Names"), QVariant(static_cast<int>(AbstractColumn::ColumnMode::Month))); 0230 ui.cbType->addItem(i18n("Day Names"), QVariant(static_cast<int>(AbstractColumn::ColumnMode::Day))); 0231 ui.cbType->addItem(i18n("Date and Time"), QVariant(static_cast<int>(AbstractColumn::ColumnMode::DateTime))); 0232 0233 ui.cbPlotDesignation->clear(); 0234 ui.cbPlotDesignation->addItem(i18n("None")); 0235 ui.cbPlotDesignation->addItem(i18n("X")); 0236 ui.cbPlotDesignation->addItem(i18n("Y")); 0237 ui.cbPlotDesignation->addItem(i18n("Z")); 0238 ui.cbPlotDesignation->addItem(i18n("X-error")); 0239 ui.cbPlotDesignation->addItem(i18n("X-error -")); 0240 ui.cbPlotDesignation->addItem(i18n("X-error +")); 0241 ui.cbPlotDesignation->addItem(i18n("Y-error")); 0242 ui.cbPlotDesignation->addItem(i18n("Y-error -")); 0243 ui.cbPlotDesignation->addItem(i18n("Y-error +")); 0244 0245 m_initializing = false; 0246 } 0247 0248 /*! 0249 called when the type (column mode - numeric, text etc.) of the column was changed. 0250 */ 0251 void ColumnDock::typeChanged(int index) { 0252 DEBUG("ColumnDock::typeChanged()"); 0253 if (m_initializing) 0254 return; 0255 0256 auto columnMode = (AbstractColumn::ColumnMode)ui.cbType->itemData(index).toInt(); 0257 0258 switch (columnMode) { 0259 case AbstractColumn::ColumnMode::Numeric: { 0260 int digits = ui.sbPrecision->value(); 0261 for (auto* col : m_columnsList) { 0262 col->beginMacro(i18n("%1: change column type", col->name())); 0263 col->setColumnMode(columnMode); 0264 auto* filter = static_cast<Double2StringFilter*>(col->outputFilter()); 0265 0266 //TODO: using 0267 //char format = ui.cbFormat->itemData(ui.cbFormat->currentIndex()).toChar().toLatin1(); 0268 //outside of the for-loop and 0269 //filter->setNumericFormat(format); 0270 //inside the loop leads to wrong results when converting from integer to numeric -> 'f' is set instead of 'e' 0271 filter->setNumericFormat(ui.cbNumericFormat->itemData(ui.cbNumericFormat->currentIndex()).toChar().toLatin1()); 0272 filter->setNumDigits(digits); 0273 col->endMacro(); 0274 } 0275 break; 0276 } 0277 case AbstractColumn::ColumnMode::Integer: 0278 case AbstractColumn::ColumnMode::BigInt: 0279 case AbstractColumn::ColumnMode::Text: 0280 for (auto* col : m_columnsList) 0281 col->setColumnMode(columnMode); 0282 break; 0283 case AbstractColumn::ColumnMode::Month: 0284 case AbstractColumn::ColumnMode::Day: 0285 for (auto* col : m_columnsList) { 0286 col->beginMacro(i18n("%1: change column type", col->name())); 0287 // the format is saved as item data 0288 QString format = ui.cbDateTimeFormat->itemData(ui.cbDateTimeFormat->currentIndex()).toString(); 0289 col->setColumnMode(columnMode); 0290 auto* filter = static_cast<DateTime2StringFilter*>(col->outputFilter()); 0291 filter->setFormat(format); 0292 col->endMacro(); 0293 } 0294 break; 0295 case AbstractColumn::ColumnMode::DateTime: 0296 for (auto* col : m_columnsList) { 0297 col->beginMacro(i18n("%1: change column type", col->name())); 0298 // the format is the current text 0299 QString format = ui.cbDateTimeFormat->currentText(); 0300 col->setColumnMode(columnMode); 0301 auto* filter = static_cast<DateTime2StringFilter*>(col->outputFilter()); 0302 filter->setFormat(format); 0303 col->endMacro(); 0304 } 0305 break; 0306 } 0307 0308 updateTypeWidgets(columnMode); 0309 0310 DEBUG("ColumnDock::typeChanged() DONE"); 0311 } 0312 0313 void ColumnDock::numericFormatChanged(int index) { 0314 if (m_initializing) 0315 return; 0316 0317 char format = ui.cbNumericFormat->itemData(index).toChar().toLatin1(); 0318 for (auto* col : m_columnsList) { 0319 auto* filter = static_cast<Double2StringFilter*>(col->outputFilter()); 0320 filter->setNumericFormat(format); 0321 } 0322 } 0323 0324 void ColumnDock::precisionChanged(int digits) { 0325 if (m_initializing) 0326 return; 0327 0328 for (auto* col : m_columnsList) { 0329 auto* filter = static_cast<Double2StringFilter*>(col->outputFilter()); 0330 filter->setNumDigits(digits); 0331 } 0332 } 0333 0334 void ColumnDock::dateTimeFormatChanged(const QString& format) { 0335 if (m_initializing) 0336 return; 0337 0338 for (auto* col : m_columnsList) { 0339 auto* filter = static_cast<DateTime2StringFilter*>(col->outputFilter()); 0340 filter->setFormat(format); 0341 } 0342 } 0343 0344 void ColumnDock::plotDesignationChanged(int index) { 0345 if (m_initializing) 0346 return; 0347 0348 auto pd = AbstractColumn::PlotDesignation(index); 0349 for (auto* col : m_columnsList) 0350 col->setPlotDesignation(pd); 0351 } 0352 0353 //************************************************************* 0354 //********* SLOTs for changes triggered in Column ************* 0355 //************************************************************* 0356 void ColumnDock::columnDescriptionChanged(const AbstractAspect* aspect) { 0357 if (m_column != aspect) 0358 return; 0359 0360 m_initializing = true; 0361 if (aspect->name() != ui.leName->text()) 0362 ui.leName->setText(aspect->name()); 0363 else if (aspect->comment() != ui.leComment->text()) 0364 ui.leComment->setText(aspect->comment()); 0365 m_initializing = false; 0366 } 0367 0368 void ColumnDock::columnModeChanged(const AbstractAspect* aspect) { 0369 if (m_column != aspect) 0370 return; 0371 0372 updateTypeWidgets(m_column->columnMode()); 0373 } 0374 0375 void ColumnDock::columnFormatChanged() { 0376 DEBUG("ColumnDock::columnFormatChanged()"); 0377 const Lock lock(m_initializing); 0378 auto columnMode = m_column->columnMode(); 0379 switch (columnMode) { 0380 case AbstractColumn::ColumnMode::Numeric: { 0381 auto* filter = static_cast<Double2StringFilter*>(m_column->outputFilter()); 0382 ui.cbNumericFormat->setCurrentIndex(ui.cbNumericFormat->findData(filter->numericFormat())); 0383 break; 0384 } 0385 case AbstractColumn::ColumnMode::Integer: 0386 case AbstractColumn::ColumnMode::BigInt: 0387 case AbstractColumn::ColumnMode::Text: 0388 break; 0389 case AbstractColumn::ColumnMode::Month: 0390 case AbstractColumn::ColumnMode::Day: 0391 case AbstractColumn::ColumnMode::DateTime: { 0392 auto* filter = static_cast<DateTime2StringFilter*>(m_column->outputFilter()); 0393 ui.cbDateTimeFormat->setCurrentText(filter->format()); 0394 break; 0395 } 0396 } 0397 } 0398 0399 void ColumnDock::columnPrecisionChanged() { 0400 const Lock lock(m_initializing); 0401 auto* filter = static_cast<Double2StringFilter*>(m_column->outputFilter()); 0402 ui.sbPrecision->setValue(filter->numDigits()); 0403 } 0404 0405 void ColumnDock::columnPlotDesignationChanged(const AbstractColumn* col) { 0406 const Lock lock(m_initializing); 0407 ui.cbPlotDesignation->setCurrentIndex(int(col->plotDesignation())); 0408 }