File indexing completed on 2025-07-13 03:32:32
0001 /* 0002 File : AsciiOptionsWidget.h 0003 Project : LabPlot 0004 Description : widget providing options for the import of ascii data 0005 -------------------------------------------------------------------- 0006 SPDX-FileCopyrightText: 2009-2017 Stefan Gerlach <stefan.gerlach@uni.kn> 0007 SPDX-FileCopyrightText: 2009-2019 Alexander Semke <alexander.semke@web.de> 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 #include "AsciiOptionsWidget.h" 0012 #include "backend/core/Settings.h" 0013 #include "backend/datasources/filters/AbstractFileFilter.h" 0014 #include "backend/datasources/filters/AsciiFilter.h" 0015 #include "backend/lib/macros.h" 0016 0017 #include <KConfigGroup> 0018 #include <KLocalizedString> 0019 0020 /*! 0021 \class AsciiOptionsWidget 0022 \brief Widget providing options for the import of ascii data 0023 0024 \ingroup kdefrontend 0025 */ 0026 AsciiOptionsWidget::AsciiOptionsWidget(QWidget* parent) 0027 : QWidget(parent) { 0028 ui.setupUi(parent); 0029 0030 ui.cbSeparatingCharacter->addItems(AsciiFilter::separatorCharacters()); 0031 ui.cbCommentCharacter->addItems(AsciiFilter::commentCharacters()); 0032 ui.cbDecimalSeparator->addItem(i18n("Point '.'")); 0033 ui.cbDecimalSeparator->addItem(i18n("Comma ','")); 0034 ui.cbDateTimeFormat->addItems(AbstractColumn::dateTimeFormats()); 0035 0036 const QString textNumberFormatShort = i18n("This option determines how the imported strings have to be converted to numbers."); 0037 const QString textNumberFormat = textNumberFormatShort + QStringLiteral("<br><br>") 0038 + i18n("When point character is used for the decimal separator, the valid number representations are:" 0039 "<ul>" 0040 "<li>1234.56</li>" 0041 "<li>1,234.56</li>" 0042 "<li>etc.</li>" 0043 "</ul>" 0044 "For comma as the decimal separator, the valid number representations are:" 0045 "<ul>" 0046 "<li>1234,56</li>" 0047 "<li>1.234,56</li>" 0048 "<li>etc.</li>" 0049 "</ul>"); 0050 0051 ui.lDecimalSeparator->setToolTip(textNumberFormatShort); 0052 ui.lDecimalSeparator->setWhatsThis(textNumberFormat); 0053 ui.cbDecimalSeparator->setToolTip(textNumberFormatShort); 0054 ui.cbDecimalSeparator->setWhatsThis(textNumberFormat); 0055 0056 // only available for live data, will be activated explicitly 0057 ui.chbCreateTimestamp->setVisible(false); 0058 0059 const QString textDateTimeFormatShort = i18n( 0060 "This option determines how the imported strings have to be converted to calendar date, i.e. year, month, and day numbers in the Gregorian calendar " 0061 "and to time."); 0062 const QString textDateTimeFormat = textDateTimeFormatShort + QStringLiteral("<br><br>") 0063 + i18n("Expressions that may be used for the date part of format string:" 0064 "<table>" 0065 "<tr><td>d</td><td>the day as number without a leading zero (1 to 31).</td></tr>" 0066 "<tr><td>dd</td><td>the day as number with a leading zero (01 to 31).</td></tr>" 0067 "<tr><td>ddd</td><td>the abbreviated localized day name (e.g. 'Mon' to 'Sun'). Uses the system locale to localize the name.</td></tr>" 0068 "<tr><td>dddd</td><td>the long localized day name (e.g. 'Monday' to 'Sunday'). Uses the system locale to localize the name.</td></tr>" 0069 "<tr><td>M</td><td>the month as number without a leading zero (1 to 12).</td></tr>" 0070 "<tr><td>MM</td><td>the month as number with a leading zero (01 to 12).</td></tr>" 0071 "<tr><td>MMM</td><td>the abbreviated localized month name (e.g. 'Jan' to 'Dec'). Uses the system locale to localize the name.</td></tr>" 0072 "<tr><td>MMMM</td><td>the long localized month name (e.g. 'January' to 'December'). Uses the system locale to localize the name.</td></tr>" 0073 "<tr><td>yy</td><td>the year as two digit number (00 to 99).</td></tr>" 0074 "<tr><td>yyyy</td><td>the year as four digit number. If the year is negative, a minus sign is prepended in addition.</td></tr>" 0075 "</table><br><br>" 0076 "Expressions that may be used for the time part of the format string:" 0077 "<table>" 0078 "<tr><td>h</td><td>the hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display)</td></tr>" 0079 "<tr><td>hh</td><td>the hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display)</td></tr>" 0080 "<tr><td>H</td><td>the hour without a leading zero (0 to 23, even with AM/PM display)</td></tr>" 0081 "<tr><td>HH</td><td>the hour with a leading zero (00 to 23, even with AM/PM display)</td></tr>" 0082 "<tr><td>m</td><td>the minute without a leading zero (0 to 59)</td></tr>" 0083 "<tr><td>mm</td><td>the minute with a leading zero (00 to 59)</td></tr>" 0084 "<tr><td>s</td><td>the second without a leading zero (0 to 59)</td></tr>" 0085 "<tr><td>ss</td><td>the second with a leading zero (00 to 59)</td></tr>" 0086 "<tr><td>z</td><td>the milliseconds without leading zeroes (0 to 999)</td></tr>" 0087 "<tr><td>zzz</td><td>the milliseconds with leading zeroes (000 to 999)</td></tr>" 0088 "<tr><td>AP or A</td><td>interpret as an AM/PM time. AP must be either 'AM' or 'PM'.</td></tr>" 0089 "<tr><td>ap or a</td><td>Interpret as an AM/PM time. ap must be either 'am' or 'pm'.</td></tr>" 0090 "</table><br><br>" 0091 "Examples are:" 0092 "<table>" 0093 "<tr><td>dd.MM.yyyy</td><td>20.07.1969</td></tr>" 0094 "<tr><td>ddd MMMM d yy</td><td>Sun July 20 69</td></tr>" 0095 "<tr><td>'The day is' dddd</td><td>The day is Sunday</td></tr>" 0096 "</table>" 0097 "<br><br>" 0098 "In case the provided expression is empty, the format will be auto-detected."); 0099 0100 ui.lDateTimeFormat->setToolTip(textDateTimeFormatShort); 0101 ui.lDateTimeFormat->setWhatsThis(textDateTimeFormat); 0102 ui.cbDateTimeFormat->setToolTip(textDateTimeFormatShort); 0103 ui.cbDateTimeFormat->setWhatsThis(textDateTimeFormat); 0104 0105 QString info = i18n("If checked, the specified line in the file will be used to determine the column names."); 0106 ui.chbHeader->setToolTip(info); 0107 0108 info = i18n("Line in the file that should be used to determine the column names."); 0109 ui.sbHeaderLine->setToolTip(info); 0110 0111 info = i18n("Custom column names, space separated. E.g. \"x y\""); 0112 ui.lVectorNames->setToolTip(info); 0113 ui.kleVectorNames->setToolTip(info); 0114 0115 connect(ui.chbHeader, &QCheckBox::toggled, this, &AsciiOptionsWidget::headerChanged); 0116 connect(ui.sbHeaderLine, QOverload<int>::of(&QSpinBox::valueChanged), this, &AsciiOptionsWidget::headerLineChanged); 0117 } 0118 0119 void AsciiOptionsWidget::showAsciiHeaderOptions(bool visible) { 0120 DEBUG(Q_FUNC_INFO); 0121 ui.chbHeader->setVisible(visible); 0122 ui.sbHeaderLine->setVisible(visible); 0123 if (visible) { 0124 ui.lVectorNames->setVisible(!ui.chbHeader->isChecked()); 0125 ui.kleVectorNames->setVisible(!ui.chbHeader->isChecked()); 0126 } else { 0127 ui.lVectorNames->setVisible(false); 0128 ui.kleVectorNames->setVisible(false); 0129 } 0130 } 0131 0132 void AsciiOptionsWidget::showTimestampOptions(bool visible) { 0133 ui.chbCreateTimestamp->setVisible(visible); 0134 m_createTimeStampAvailable = visible; 0135 } 0136 0137 /*! 0138 Shows a text field for the vector names if the option "Use the first row..." was not selected. 0139 Hides it otherwise. 0140 */ 0141 void AsciiOptionsWidget::headerChanged(bool state) const { 0142 ui.sbHeaderLine->setEnabled(state); 0143 ui.kleVectorNames->setVisible(!state); 0144 ui.lVectorNames->setVisible(!state); 0145 } 0146 0147 void AsciiOptionsWidget::applyFilterSettings(AsciiFilter* filter) const { 0148 DEBUG(Q_FUNC_INFO) 0149 Q_ASSERT(filter); 0150 filter->setCommentCharacter(ui.cbCommentCharacter->currentText()); 0151 filter->setSeparatingCharacter(ui.cbSeparatingCharacter->currentText()); 0152 0153 // TODO: use general setting for decimal separator? 0154 QLocale::Language lang; 0155 if (ui.cbDecimalSeparator->currentIndex() == 0) 0156 lang = QLocale::Language::C; 0157 else 0158 lang = QLocale::Language::German; 0159 filter->setNumberFormat(lang); 0160 filter->setDateTimeFormat(ui.cbDateTimeFormat->currentText()); 0161 filter->setCreateIndexEnabled(ui.chbCreateIndex->isChecked()); 0162 0163 // save the timestamp option only if it's visible, i.e. live source is used. 0164 // use the default setting in the filter (false) otherwise for non-live source 0165 if (m_createTimeStampAvailable) 0166 filter->setCreateTimestampEnabled(ui.chbCreateTimestamp->isChecked()); 0167 0168 filter->setSimplifyWhitespacesEnabled(ui.chbSimplifyWhitespaces->isChecked()); 0169 filter->setNaNValueToZero(ui.chbConvertNaNToZero->isChecked()); 0170 filter->setRemoveQuotesEnabled(ui.chbRemoveQuotes->isChecked()); 0171 filter->setSkipEmptyParts(ui.chbSkipEmptyParts->isChecked()); 0172 filter->setVectorNames(ui.kleVectorNames->text()); 0173 filter->setHeaderEnabled(ui.chbHeader->isChecked()); 0174 filter->setHeaderLine(ui.sbHeaderLine->value()); 0175 } 0176 0177 void AsciiOptionsWidget::setSeparatingCharacter(QLatin1Char character) { 0178 ui.cbSeparatingCharacter->setCurrentItem(QString(character)); 0179 } 0180 0181 // ############################################################################## 0182 // ########################## Template handling ############################## 0183 // ############################################################################## 0184 void AsciiOptionsWidget::loadSettings() const { 0185 auto config = KConfig(); 0186 loadConfigFromTemplate(config); 0187 } 0188 0189 void AsciiOptionsWidget::saveSettings() const { 0190 auto config = KConfig(); 0191 saveConfigAsTemplate(config); 0192 } 0193 0194 void AsciiOptionsWidget::loadConfigFromTemplate(KConfig& config) const { 0195 auto group = config.group(QStringLiteral("ImportAscii")); 0196 0197 ui.cbCommentCharacter->setCurrentText(group.readEntry("CommentCharacter", "#")); 0198 ui.cbSeparatingCharacter->setCurrentText(group.readEntry("SeparatingCharacter", "auto")); 0199 0200 const auto decimalSeparator = QLocale().decimalPoint(); 0201 int index = (decimalSeparator == QLatin1Char('.')) ? 0 : 1; 0202 ui.cbDecimalSeparator->setCurrentIndex(group.readEntry("DecimalSeparator", index)); 0203 0204 ui.cbDateTimeFormat->setCurrentText(group.readEntry("DateTimeFormat", "yyyy-MM-dd hh:mm:ss.zzz")); 0205 ui.chbCreateIndex->setChecked(group.readEntry("CreateIndex", false)); 0206 ui.chbCreateTimestamp->setChecked(group.readEntry("CreateTimestamp", true)); 0207 ui.chbSimplifyWhitespaces->setChecked(group.readEntry("SimplifyWhitespaces", true)); 0208 ui.chbConvertNaNToZero->setChecked(group.readEntry("ConvertNaNToZero", false)); 0209 ui.chbRemoveQuotes->setChecked(group.readEntry("RemoveQuotes", false)); 0210 ui.chbSkipEmptyParts->setChecked(group.readEntry("SkipEmptyParts", false)); 0211 ui.chbHeader->setChecked(group.readEntry("UseFirstRow", true)); // header enabled - yes/no 0212 headerChanged(ui.chbHeader->isChecked()); // call this to update the status of the SpinBox for the header line 0213 ui.sbHeaderLine->setValue(group.readEntry(QLatin1String("HeaderLine"), 1)); 0214 ui.kleVectorNames->setText(group.readEntry("Names", "")); 0215 } 0216 0217 void AsciiOptionsWidget::saveConfigAsTemplate(KConfig& config) const { 0218 auto group = config.group(QStringLiteral("ImportAscii")); 0219 0220 group.writeEntry("CommentCharacter", ui.cbCommentCharacter->currentText()); 0221 group.writeEntry("SeparatingCharacter", ui.cbSeparatingCharacter->currentText()); 0222 group.writeEntry("DecimalSeparator", ui.cbDecimalSeparator->currentIndex()); 0223 group.writeEntry("DateTimeFormat", ui.cbDateTimeFormat->currentText()); 0224 group.writeEntry("CreateIndex", ui.chbCreateIndex->isChecked()); 0225 group.writeEntry("CreateTimestamp", ui.chbCreateTimestamp->isChecked()); 0226 group.writeEntry("SimplifyWhitespaces", ui.chbSimplifyWhitespaces->isChecked()); 0227 group.writeEntry("ConvertNaNToZero", ui.chbConvertNaNToZero->isChecked()); 0228 group.writeEntry("RemoveQuotes", ui.chbRemoveQuotes->isChecked()); 0229 group.writeEntry("SkipEmptyParts", ui.chbSkipEmptyParts->isChecked()); 0230 group.writeEntry("UseFirstRow", ui.chbHeader->isChecked()); // header enabled - yes/no 0231 group.writeEntry(QLatin1String("HeaderLine"), ui.sbHeaderLine->value()); 0232 group.writeEntry("Names", ui.kleVectorNames->text()); 0233 }