File indexing completed on 2024-05-12 15:27:51

0001 /***************************************************************************
0002     File                 : JsonOptionsWidget.cpp
0003     Project              : LabPlot
0004     Description          : Widget providing options for the import of json data.
0005     --------------------------------------------------------------------
0006     --------------------------------------------------------------------
0007     Copyright            : (C) 2018 Andrey Cygankov (craftplace.ms@gmail.com)
0008     Copyright            : (C) 2018-2020 by Alexander Semke (alexander.semke@web.de)
0009 
0010  ***************************************************************************/
0011 
0012 /***************************************************************************
0013  *                                                                         *
0014  *  This program is free software; you can redistribute it and/or modify   *
0015  *  it under the terms of the GNU General Public License as published by   *
0016  *  the Free Software Foundation; either version 2 of the License, or      *
0017  *  (at your option) any later version.                                    *
0018  *                                                                         *
0019  *  This program is distributed in the hope that it will be useful,        *
0020  *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
0021  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
0022  *  GNU General Public License for more details.                           *
0023  *                                                                         *
0024  *   You should have received a copy of the GNU General Public License     *
0025  *   along with this program; if not, write to the Free Software           *
0026  *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
0027  *   Boston, MA  02110-1301  USA                                           *
0028  *                                                                         *
0029  ***************************************************************************/
0030 
0031 #include "JsonOptionsWidget.h"
0032 #include "ImportFileWidget.h"
0033 #include "backend/datasources/filters/QJsonModel.h"
0034 #include "backend/datasources/filters/AbstractFileFilter.h"
0035 #include "backend/datasources/filters/JsonFilter.h"
0036 #include "backend/lib/trace.h"
0037 
0038 #include <KLocalizedString>
0039 #include <KFilterDev>
0040 #include <KSharedConfig>
0041 #include <KConfigGroup>
0042 
0043 /*!
0044 \class JsonOptionsWidget
0045 \brief Widget providing options for the import of json data
0046 
0047 \ingroup kdefrontend
0048 */
0049 JsonOptionsWidget::JsonOptionsWidget(QWidget* parent, ImportFileWidget* fileWidget) : QWidget(parent),
0050     m_fileWidget(fileWidget),
0051     m_model(new QJsonModel()) {
0052 
0053     ui.setupUi(parent);
0054 
0055     ui.cbDecimalSeparator->addItem(i18n("Point '.'"));
0056     ui.cbDecimalSeparator->addItem(i18n("Comma ','"));
0057     ui.cbDateTimeFormat->addItems(AbstractColumn::dateTimeFormats());
0058 
0059     setTooltips();
0060 }
0061 
0062 void JsonOptionsWidget::applyFilterSettings(JsonFilter* filter, const QModelIndex& index) const {
0063     Q_ASSERT(filter);
0064 
0065     filter->setModel(m_model);
0066     filter->setModelRows(getIndexRows(index));
0067 
0068     QLocale::Language lang;
0069     if (ui.cbDecimalSeparator->currentIndex() == 0)
0070         lang = QLocale::Language::C;
0071     else
0072         lang = QLocale::Language::German;
0073     filter->setNumberFormat(lang);
0074 
0075     filter->setDateTimeFormat(ui.cbDateTimeFormat->currentText());
0076     filter->setCreateIndexEnabled(ui.chbCreateIndex->isChecked());
0077     filter->setNaNValueToZero(ui.chbConvertNaNToZero->isChecked());
0078     filter->setImportObjectNames(ui.chbImportObjectNames->isChecked());
0079 
0080     //TODO: change this after implementation other row types
0081     filter->setDataRowType(QJsonValue::Array);
0082     if (!index.isValid()) return;
0083     auto* item = static_cast<QJsonTreeItem*>(index.internalPointer());
0084     if (item->childCount() < 1) return;
0085     filter->setDataRowType(item->child(0)->type());
0086 }
0087 
0088 void JsonOptionsWidget::clearModel() {
0089     m_model->clear();
0090     m_filename.clear();
0091 }
0092 
0093 void JsonOptionsWidget::loadSettings() const {
0094     KConfigGroup conf(KSharedConfig::openConfig(), "ImportJson");
0095 
0096     const QChar decimalSeparator = QLocale().decimalPoint();
0097     int index = (decimalSeparator == '.') ? 0 : 1;
0098     ui.cbDecimalSeparator->setCurrentIndex(conf.readEntry("DecimalSeparator", index));
0099 
0100     ui.cbDateTimeFormat->setCurrentItem(conf.readEntry("DateTimeFormat", "yyyy-MM-dd hh:mm:ss.zzz"));
0101     ui.chbCreateIndex->setChecked(conf.readEntry("CreateIndex", false));
0102     ui.chbConvertNaNToZero->setChecked(conf.readEntry("ConvertNaNToZero", false));
0103     ui.chbImportObjectNames->setChecked(conf.readEntry("ParseRowsName", false));
0104 }
0105 
0106 void JsonOptionsWidget::saveSettings() {
0107     KConfigGroup conf(KSharedConfig::openConfig(), "ImportJson");
0108 
0109     conf.writeEntry("DecimalSeparator", ui.cbDecimalSeparator->currentIndex());
0110     conf.writeEntry("DateTimeFormat", ui.cbDateTimeFormat->currentText());
0111     conf.writeEntry("CreateIndex", ui.chbCreateIndex->isChecked());
0112     conf.writeEntry("ConvertNaNToZero", ui.chbConvertNaNToZero->isChecked());
0113     conf.writeEntry("ParseRowsName", ui.chbImportObjectNames->isChecked());
0114 }
0115 
0116 void JsonOptionsWidget::loadDocument(const QString& filename) {
0117     PERFTRACE("JsonOptionsWidget::loadDocument");
0118     if (m_filename == filename) return;
0119     else
0120         m_filename = filename;
0121 
0122     KFilterDev device(m_filename);
0123     m_model->clear();
0124     if (!device.open(QIODevice::ReadOnly) ||
0125         (device.atEnd() && !device.isSequential()) || // empty file
0126         !m_model->loadJson(device.readAll())
0127        )
0128         clearModel();
0129 }
0130 
0131 QAbstractItemModel* JsonOptionsWidget::model() {
0132     return m_model;
0133 }
0134 
0135 void JsonOptionsWidget::setTooltips() {
0136     const QString textNumberFormatShort = i18n("This option determines how the imported strings have to be converted to numbers.");
0137     const QString textNumberFormat = textNumberFormatShort + "<br><br>" + i18n(
0138             "For 'C Format', a period is used for the decimal point character and comma is used for the thousands group separator. "
0139             "Valid number representations are:"
0140             "<ul>"
0141             "<li>1234.56</li>"
0142             "<li>1,234.56</li>"
0143             "<li>etc.</li>"
0144             "</ul>"
0145             "When using 'System locale', the system settings will be used. "
0146             "E.g., for the German local the valid number representations are:"
0147             "<ul>"
0148             "<li>1234,56</li>"
0149             "<li>1.234,56</li>"
0150             "<li>etc.</li>"
0151             "</ul>"
0152     );
0153 
0154     ui.lDecimalSeparator->setToolTip(textNumberFormatShort);
0155     ui.lDecimalSeparator->setWhatsThis(textNumberFormat);
0156     ui.cbDecimalSeparator->setToolTip(textNumberFormatShort);
0157     ui.cbDecimalSeparator->setWhatsThis(textNumberFormat);
0158 
0159     const QString textDateTimeFormatShort = i18n("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 and to time.");
0160     const QString textDateTimeFormat = textDateTimeFormatShort + "<br><br>" + i18n(
0161             "Expressions that may be used for the date part of format string:"
0162             "<table>"
0163             "<tr><td>d</td><td>the day as number without a leading zero (1 to 31).</td></tr>"
0164             "<tr><td>dd</td><td>the day as number with a leading zero (01 to 31).</td></tr>"
0165             "<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>"
0166             "<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>"
0167             "<tr><td>M</td><td>the month as number without a leading zero (1 to 12).</td></tr>"
0168             "<tr><td>MM</td><td>the month as number with a leading zero (01 to 12).</td></tr>"
0169             "<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>"
0170             "<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>"
0171             "<tr><td>yy</td><td>the year as two digit number (00 to 99).</td></tr>"
0172             "<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>"
0173             "</table><br><br>"
0174             "Expressions that may be used for the time part of the format string:"
0175             "<table>"
0176             "<tr><td>h</td><td>the hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display)</td></tr>"
0177             "<tr><td>hh</td><td>the hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display)</td></tr>"
0178             "<tr><td>H</td><td>the hour without a leading zero (0 to 23, even with AM/PM display)</td></tr>"
0179             "<tr><td>HH</td><td>the hour with a leading zero (00 to 23, even with AM/PM display)</td></tr>"
0180             "<tr><td>m</td><td>the minute without a leading zero (0 to 59)</td></tr>"
0181             "<tr><td>mm</td><td>the minute with a leading zero (00 to 59)</td></tr>"
0182             "<tr><td>s</td><td>the second without a leading zero (0 to 59)</td></tr>"
0183             "<tr><td>ss</td><td>the second with a leading zero (00 to 59)</td></tr>"
0184             "<tr><td>z</td><td>the milliseconds without leading zeroes (0 to 999)</td></tr>"
0185             "<tr><td>zzz</td><td>the milliseconds with leading zeroes (000 to 999)</td></tr>"
0186             "<tr><td>AP or A</td><td>interpret as an AM/PM time. AP must be either 'AM' or 'PM'.</td></tr>"
0187             "<tr><td>ap or a</td><td>Interpret as an AM/PM time. ap must be either 'am' or 'pm'.</td></tr>"
0188             "</table><br><br>"
0189             "Examples are:"
0190             "<table>"
0191             "<tr><td>dd.MM.yyyy</td><td>20.07.1969</td></tr>"
0192             "<tr><td>ddd MMMM d yy</td><td>Sun July 20 69</td></tr>"
0193             "<tr><td>'The day is' dddd</td><td>The day is Sunday</td></tr>"
0194             "</table>");
0195 
0196     ui.lDateTimeFormat->setToolTip(textDateTimeFormatShort);
0197     ui.lDateTimeFormat->setWhatsThis(textDateTimeFormat);
0198     ui.cbDateTimeFormat->setToolTip(textDateTimeFormatShort);
0199     ui.cbDateTimeFormat->setWhatsThis(textDateTimeFormat);
0200 }
0201 
0202 QVector<int> JsonOptionsWidget::getIndexRows(const QModelIndex &index) const {
0203     QVector<int> rows;
0204     QModelIndex current = index;
0205     while (current.isValid()) {
0206         rows.prepend(current.row());
0207         current = current.parent();
0208     }
0209     return rows;
0210 }