File indexing completed on 2024-06-16 03:42:36

0001 /*
0002     File                 : String2DateTimeFilter.cpp
0003     Project              : LabPlot
0004     Description          : Conversion filter QString -> QDateTime.
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2007 Tilman Benkert <thzs@gmx.net>
0007     SPDX-FileCopyrightText: 2007 Knut Franke <knut.franke@gmx.de>
0008     SPDX-FileCopyrightText: 2017 Stefan Gerlach <stefan.gerlach@uni.kn>
0009     SPDX-License-Identifier: GPL-2.0-or-later
0010 */
0011 
0012 #include "String2DateTimeFilter.h"
0013 #include "backend/lib/XmlStreamReader.h"
0014 #include <QDate>
0015 #include <QDateTime>
0016 #include <QStringList>
0017 #include <QTime>
0018 #include <QUndoCommand>
0019 
0020 #include <KLocalizedString>
0021 
0022 class String2DateTimeFilterSetFormatCmd : public QUndoCommand {
0023 public:
0024     String2DateTimeFilterSetFormatCmd(String2DateTimeFilter* target, const QString& new_format);
0025 
0026     void redo() override;
0027     void undo() override;
0028 
0029 private:
0030     String2DateTimeFilter* m_target;
0031     QString m_other_format;
0032 };
0033 
0034 AbstractColumn::ColumnMode String2DateTimeFilter::columnMode() const {
0035     return AbstractColumn::ColumnMode::DateTime;
0036 }
0037 
0038 QDateTime String2DateTimeFilter::dateTimeAt(int row) const {
0039     if (!m_inputs.value(0))
0040         return {};
0041     QString input_value = m_inputs.value(0)->textAt(row);
0042     if (input_value.isEmpty())
0043         return {};
0044 
0045     // first try the selected format string m_format
0046     QDateTime result = QDateTime::fromString(input_value, m_format);
0047     result.setTimeSpec(Qt::UTC);
0048     if (result.isValid())
0049         return result;
0050 
0051         // fallback:
0052         // try other format strings built from date_formats and time_formats
0053         // comma and space are valid separators between date and time
0054 #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
0055     QStringList strings = input_value.simplified().split(QLatin1Char(','), Qt::SkipEmptyParts);
0056     if (strings.size() == 1)
0057         strings = strings.at(0).split(QLatin1Char(' '), Qt::SkipEmptyParts);
0058 #else
0059     QStringList strings = input_value.simplified().split(QLatin1Char(','), QString::SkipEmptyParts);
0060     if (strings.size() == 1)
0061         strings = strings.at(0).split(QLatin1Char(' '), QString::SkipEmptyParts);
0062 #endif
0063 
0064     if (strings.size() < 1)
0065         return result; // invalid date/time from first attempt
0066 
0067     QDate date_result;
0068     QTime time_result;
0069 
0070     QString date_string = strings.at(0).trimmed();
0071     QString time_string;
0072     if (strings.size() > 1)
0073         time_string = strings.at(1).trimmed();
0074     else
0075         time_string = date_string;
0076 
0077     // try to find a valid date
0078     for (const auto& format : AbstractColumn::dateFormats()) {
0079         date_result = QDate::fromString(date_string, format);
0080         if (date_result.isValid())
0081             break;
0082     }
0083     // try to find a valid time
0084     for (const auto& format : AbstractColumn::timeFormats()) {
0085         time_result = QTime::fromString(time_string, format);
0086         if (time_result.isValid())
0087             break;
0088     }
0089 
0090     if (!date_result.isValid() && time_result.isValid())
0091         date_result.setDate(1900, 1, 1); // this is what QDateTime does e.g. for QDateTime::fromString("00:00","hh:mm");
0092     else if (date_result.isValid() && !time_result.isValid())
0093         time_result = QTime(0, 0, 0, 0);
0094 
0095     return {date_result, time_result};
0096 }
0097 
0098 QDate String2DateTimeFilter::dateAt(int row) const {
0099     return dateTimeAt(row).date();
0100 }
0101 
0102 QTime String2DateTimeFilter::timeAt(int row) const {
0103     return dateTimeAt(row).time();
0104 }
0105 
0106 bool String2DateTimeFilter::inputAcceptable(int, const AbstractColumn* source) {
0107     return source->columnMode() == AbstractColumn::ColumnMode::Text;
0108 }
0109 
0110 void String2DateTimeFilter::writeExtraAttributes(QXmlStreamWriter* writer) const {
0111     writer->writeAttribute(QStringLiteral("format"), format());
0112 }
0113 
0114 bool String2DateTimeFilter::load(XmlStreamReader* reader, bool preview) {
0115     if (preview)
0116         return true;
0117 
0118     QXmlStreamAttributes attribs = reader->attributes();
0119     QString str = attribs.value(reader->namespaceUri().toString(), QStringLiteral("format")).toString();
0120 
0121     if (AbstractSimpleFilter::load(reader, preview))
0122         setFormat(str);
0123     else
0124         return false;
0125 
0126     return !reader->hasError();
0127 }
0128 
0129 void String2DateTimeFilter::setFormat(const QString& format) {
0130     exec(new String2DateTimeFilterSetFormatCmd(this, format));
0131 }
0132 
0133 String2DateTimeFilterSetFormatCmd::String2DateTimeFilterSetFormatCmd(String2DateTimeFilter* target, const QString& new_format)
0134     : m_target(target)
0135     , m_other_format(new_format) {
0136     if (m_target->parentAspect())
0137         setText(i18n("%1: set date-time format to %2", m_target->parentAspect()->name(), new_format));
0138     else
0139         setText(i18n("set date-time format to %1", new_format));
0140 }
0141 
0142 void String2DateTimeFilterSetFormatCmd::redo() {
0143     QString tmp = m_target->m_format;
0144     m_target->m_format = m_other_format;
0145     m_other_format = tmp;
0146     Q_EMIT m_target->formatChanged();
0147 }
0148 
0149 void String2DateTimeFilterSetFormatCmd::undo() {
0150     redo();
0151 }