File indexing completed on 2025-02-09 04:28:36

0001 /*
0002  * This file is part of the KTextTemplate library
0003  *
0004  * SPDX-FileCopyrightText: 2020 Matthias Fehring <mf@huessenbergnetz.de>
0005  *
0006  * SPDX-License-Identifier: LGPL-2.0-or-later
0007  */
0008 
0009 #include "l10n_filesize.h"
0010 
0011 #include "abstractlocalizer.h"
0012 #include "exception.h"
0013 #include "parser.h"
0014 #include "util.h"
0015 
0016 #include <limits>
0017 
0018 L10nFileSizeNodeFactory::L10nFileSizeNodeFactory() = default;
0019 
0020 Node *L10nFileSizeNodeFactory::getNode(const QString &tagContent, Parser *p) const
0021 {
0022     QStringList parts = smartSplit(tagContent);
0023     parts.removeFirst(); // not interested in the name of the tag
0024     if (parts.isEmpty()) {
0025         throw Exception(TagSyntaxError,
0026                         QStringLiteral("Error: l10n_filesize requires at least the "
0027                                        "file size as first parameter"));
0028     }
0029 
0030     FilterExpression size(parts.at(0), p);
0031 
0032     FilterExpression unitSystem;
0033     if (parts.size() > 1) {
0034         unitSystem = FilterExpression(parts.at(1), p);
0035     }
0036 
0037     FilterExpression precision;
0038     if (parts.size() > 2) {
0039         precision = FilterExpression(parts.at(2), p);
0040     }
0041 
0042     FilterExpression multiplier;
0043     if (parts.size() > 3) {
0044         multiplier = FilterExpression(parts.at(3), p);
0045     }
0046 
0047     return new L10nFileSizeNode(size, unitSystem, precision, multiplier, p);
0048 }
0049 
0050 L10nFileSizeVarNodeFactory::L10nFileSizeVarNodeFactory() = default;
0051 
0052 Node *L10nFileSizeVarNodeFactory::getNode(const QString &tagContent, Parser *p) const
0053 {
0054     QStringList parts = smartSplit(tagContent);
0055     parts.removeFirst(); // not interested in the name of the tag
0056     if (parts.size() < 2) {
0057         throw Exception(TagSyntaxError,
0058                         QStringLiteral("Error: l10n_filesize_var tag takes at least 2 "
0059                                        "arguments, the file size and the variable name"));
0060     }
0061 
0062     FilterExpression size(parts.at(0), p);
0063 
0064     FilterExpression unitSystem;
0065     if (parts.size() > 2) {
0066         unitSystem = FilterExpression(parts.at(1), p);
0067     }
0068 
0069     FilterExpression precision;
0070     if (parts.size() > 3) {
0071         precision = FilterExpression(parts.at(2), p);
0072     }
0073 
0074     FilterExpression multiplier;
0075     if (parts.size() > 4) {
0076         multiplier = FilterExpression(parts.at(3), p);
0077     }
0078 
0079     const auto resultName = parts.last();
0080 
0081     return new L10nFileSizeVarNode(size, unitSystem, precision, multiplier, resultName, p);
0082 }
0083 
0084 L10nFileSizeNode::L10nFileSizeNode(const FilterExpression &size,
0085                                    const FilterExpression &unitSystem,
0086                                    const FilterExpression &precision,
0087                                    const FilterExpression &multiplier,
0088                                    QObject *parent)
0089     : Node(parent)
0090     , m_size(size)
0091     , m_unitSystem(unitSystem)
0092     , m_precision(precision)
0093     , m_multiplier(multiplier)
0094 {
0095 }
0096 
0097 void L10nFileSizeNode::render(OutputStream *stream, Context *c) const
0098 {
0099     bool convertNumbers = true;
0100 
0101     qreal size = 0.0F;
0102     if (m_size.resolve(c).canConvert<qreal>()) {
0103         size = m_size.resolve(c).toReal(&convertNumbers);
0104     } else {
0105         size = getSafeString(m_size.resolve(c)).get().toDouble(&convertNumbers);
0106     }
0107     if (!convertNumbers) {
0108         qWarning("%s", "Failed to convert input file size into a floating point number.");
0109         return;
0110     }
0111 
0112     int unitSystem = m_unitSystem.isValid() ? m_unitSystem.resolve(c).toInt(&convertNumbers) : 10;
0113     if (!convertNumbers) {
0114         qWarning("%s",
0115                  "Failed to convert unit system for file size into integer "
0116                  "value. Using default decimal system as default.");
0117         unitSystem = 10;
0118     }
0119 
0120     int precision = m_precision.isValid() ? m_precision.resolve(c).toInt(&convertNumbers) : 2;
0121     if (!convertNumbers) {
0122         qWarning("%s",
0123                  "Failed to convert decimal precision for file size into an "
0124                  "integer value. Using default value 2.");
0125         precision = 2;
0126     }
0127 
0128     qreal multiplier = m_multiplier.isValid() ? m_multiplier.resolve(c).toReal(&convertNumbers) : 1.0F;
0129     if (!convertNumbers) {
0130         qWarning("%s",
0131                  "Failed to convert multiplier file size into a floating "
0132                  "point number. Using default value 1.0.");
0133         multiplier = 1.0F;
0134     }
0135 
0136     if (multiplier == 0.0F) {
0137         qWarning("%s",
0138                  "It makes no sense to multiply the file size by zero. Using "
0139                  "default value 1.0.");
0140         multiplier = 1.0F;
0141     }
0142 
0143     const qreal sizeMult = size * multiplier;
0144 
0145     if (unitSystem == 10) {
0146         if ((sizeMult > -1000) && (sizeMult < 1000)) {
0147             precision = 0;
0148         }
0149     } else if (unitSystem == 2) {
0150         if ((sizeMult > -1024) && (sizeMult < 1024)) {
0151             precision = 0;
0152         }
0153     }
0154 
0155     QString resultString;
0156 
0157     if (sizeMult > static_cast<qreal>(std::numeric_limits<qint64>::min()) && sizeMult < static_cast<qreal>(std::numeric_limits<qint64>::max())) {
0158         QLocale l(c->localizer()->currentLocale());
0159         QLocale::DataSizeFormats format = unitSystem == 10 ? QLocale::DataSizeSIFormat : QLocale::DataSizeIecFormat;
0160 
0161         resultString = l.formattedDataSize(static_cast<qint64>(sizeMult), precision, format);
0162 
0163     } else {
0164         const std::pair<qreal, QString> fspair = calcFileSize(size, unitSystem, multiplier);
0165 
0166         if (precision == 2) {
0167             resultString = c->localizer()->localizeNumber(fspair.first) + QChar(QChar::Space) + fspair.second;
0168         } else {
0169             QLocale l(c->localizer()->currentLocale());
0170             resultString = l.toString(fspair.first, 'f', precision) + QChar(QChar::Space) + fspair.second;
0171         }
0172     }
0173 
0174     streamValueInContext(stream, resultString, c);
0175 }
0176 
0177 L10nFileSizeVarNode::L10nFileSizeVarNode(const FilterExpression &size,
0178                                          const FilterExpression &unitSystem,
0179                                          const FilterExpression &precision,
0180                                          const FilterExpression &multiplier,
0181                                          const QString &resultName,
0182                                          QObject *parent)
0183     : Node(parent)
0184     , m_size(size)
0185     , m_unitSystem(unitSystem)
0186     , m_precision(precision)
0187     , m_multiplier(multiplier)
0188     , m_resultName(resultName)
0189 {
0190 }
0191 
0192 void L10nFileSizeVarNode::render(OutputStream *stream, Context *c) const
0193 {
0194     Q_UNUSED(stream)
0195     bool convertNumbers = true;
0196 
0197     qreal size = 0.0F;
0198     if (m_size.resolve(c).canConvert<qreal>()) {
0199         size = m_size.resolve(c).toReal(&convertNumbers);
0200     } else {
0201         size = getSafeString(m_size.resolve(c)).get().toDouble(&convertNumbers);
0202     }
0203     if (!convertNumbers) {
0204         qWarning("%s", "Failed to convert input file size into a floating point number.");
0205         return;
0206     }
0207 
0208     int unitSystem = m_unitSystem.isValid() ? m_unitSystem.resolve(c).toInt(&convertNumbers) : 10;
0209     if (!convertNumbers) {
0210         qWarning("%s",
0211                  "Failed to convert unit system for file size into integer "
0212                  "value. Using default decimal system.");
0213         unitSystem = 10;
0214     }
0215 
0216     int precision = m_precision.isValid() ? m_precision.resolve(c).toInt(&convertNumbers) : 2;
0217     if (!convertNumbers) {
0218         qWarning("%s",
0219                  "Failed to convert decimal precision for file size into an "
0220                  "integer value. Using default value 2.");
0221         precision = 2;
0222     }
0223 
0224     qreal multiplier = m_multiplier.isValid() ? m_multiplier.resolve(c).toReal(&convertNumbers) : 1.0F;
0225     if (!convertNumbers) {
0226         qWarning("%s",
0227                  "Failed to convert multiplier file size into a floating "
0228                  "point number. Using default value 1.0.");
0229         multiplier = 1.0F;
0230     }
0231 
0232     if (multiplier == 0.0F) {
0233         qWarning("%s",
0234                  "It makes no sense to mulitply the file size by zero. Using "
0235                  "default value 1.0.");
0236         multiplier = 1.0F;
0237     }
0238 
0239     const double sizeMult = size * multiplier;
0240 
0241     if (unitSystem == 10) {
0242         if ((sizeMult > -1000) && (sizeMult < 1000)) {
0243             precision = 0;
0244         }
0245     } else if (unitSystem == 2) {
0246         if ((sizeMult > -1024) && (sizeMult < 1024)) {
0247             precision = 0;
0248         }
0249     }
0250 
0251     QString resultString;
0252 
0253     if (sizeMult > static_cast<qreal>(std::numeric_limits<qint64>::min()) && sizeMult < static_cast<qreal>(std::numeric_limits<qint64>::max())) {
0254         QLocale l(c->localizer()->currentLocale());
0255         QLocale::DataSizeFormats format = unitSystem == 10 ? QLocale::DataSizeSIFormat : QLocale::DataSizeIecFormat;
0256 
0257         resultString = l.formattedDataSize(static_cast<qint64>(sizeMult), precision, format);
0258 
0259     } else {
0260         const std::pair<qreal, QString> fspair = calcFileSize(size, unitSystem, multiplier);
0261 
0262         if (precision == 2) {
0263             resultString = c->localizer()->localizeNumber(fspair.first) + QChar(QChar::Space) + fspair.second;
0264         } else {
0265             QLocale l(c->localizer()->currentLocale());
0266             resultString = l.toString(fspair.first, 'f', precision) + QChar(QChar::Space) + fspair.second;
0267         }
0268     }
0269 
0270     c->insert(m_resultName, resultString);
0271 }
0272 
0273 #include "moc_l10n_filesize.cpp"