Cutelee  6.2.0
l10n_filesize.cpp
1 /*
2  * This file is part of the Cutelee template system.
3  *
4  * Copyright (c) 2020 Matthias Fehring <mf@huessenbergnetz.de>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either version
9  * 2 of the Licence, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "l10n_filesize.h"
21 
22 #include "abstractlocalizer.h"
23 #include "engine.h"
24 #include "exception.h"
25 #include "parser.h"
26 #include "template.h"
27 #include "util.h"
28 
29 #include <limits>
30 
31 L10nFileSizeNodeFactory::L10nFileSizeNodeFactory() {}
32 
33 Node *L10nFileSizeNodeFactory::getNode(const QString &tagContent, Parser *p) const
34 {
35  QStringList parts = smartSplit(tagContent);
36  parts.removeFirst(); // not interested in the name of the tag
37  if (parts.isEmpty()) {
38  throw Exception(TagSyntaxError, QStringLiteral("Error: l10n_filesize requires at least the file size as first parameter"));
39  }
40 
41  FilterExpression size(parts.at(0), p);
42 
43  FilterExpression unitSystem;
44  if (parts.size() > 1) {
45  unitSystem = FilterExpression(parts.at(1), p);
46  }
47 
48  FilterExpression precision;
49  if (parts.size() > 2) {
50  precision = FilterExpression(parts.at(2), p);
51  }
52 
53  FilterExpression multiplier;
54  if (parts.size() > 3) {
55  multiplier = FilterExpression(parts.at(3), p);
56  }
57 
58  return new L10nFileSizeNode(size, unitSystem, precision, multiplier, p);
59 }
60 
61 L10nFileSizeVarNodeFactory::L10nFileSizeVarNodeFactory() {}
62 
64 {
65  QStringList parts = smartSplit(tagContent);
66  parts.removeFirst(); // not interested in the name of the tag
67  if (parts.size() < 2) {
68  throw Exception(TagSyntaxError, QStringLiteral("Error: l10n_filesize_var tag takes at least 2 arguments, the file size and the variable name"));
69  }
70 
71  FilterExpression size(parts.at(0), p);
72 
73  FilterExpression unitSystem;
74  if (parts.size() > 2) {
75  unitSystem = FilterExpression(parts.at(1), p);
76  }
77 
78  FilterExpression precision;
79  if (parts.size() > 3) {
80  precision = FilterExpression(parts.at(2), p);
81  }
82 
83  FilterExpression multiplier;
84  if (parts.size() > 4) {
85  multiplier = FilterExpression(parts.at(3), p);
86  }
87 
88  auto resultName = parts.last();
89 
90  return new L10nFileSizeVarNode(size, unitSystem, precision, multiplier, resultName, p);
91 }
92 
93 L10nFileSizeNode::L10nFileSizeNode(const FilterExpression &size,
94  const FilterExpression &unitSystem,
95  const FilterExpression &precision,
96  const FilterExpression &multiplier,
97  QObject *parent)
98  : Node(parent), m_size(size), m_unitSystem(unitSystem), m_precision(precision), m_multiplier(multiplier)
99 {
100 }
101 
103 {
104  bool convertNumbers = true;
105 
106  qreal size = 0.0f;
107  if (m_size.resolve(c).canConvert<qreal>()) {
108  size = m_size.resolve(c).toReal(&convertNumbers);
109  } else {
110  size = getSafeString(m_size.resolve(c)).get().toDouble(&convertNumbers);
111  }
112  if (!convertNumbers) {
113  qWarning("%s", "Failed to convert input file size into a floating point number.");
114  return;
115  }
116 
117  int unitSystem = m_unitSystem.isValid() ? m_unitSystem.resolve(c).toInt(&convertNumbers) : 10;
118  if (!convertNumbers) {
119  qWarning("%s", "Failed to convert unit system for file size into integer value. Using default decimal system as default.");
120  unitSystem = 10;
121  }
122 
123  int precision = m_precision.isValid() ? m_precision.resolve(c).toInt(&convertNumbers) : 2;
124  if (!convertNumbers) {
125  qWarning("%s", "Failed to convert decimal precision for file size into an integer value. Using default value 2.");
126  precision = 2;
127  }
128 
129  qreal multiplier = m_multiplier.isValid() ? m_multiplier.resolve(c).toReal(&convertNumbers) : 1.0f;
130  if (!convertNumbers) {
131  qWarning("%s", "Failed to convert multiplier file size into a floating point number. Using default value 1.0.");
132  multiplier = 1.0f;
133  }
134 
135  if (multiplier == 0.0f) {
136  qWarning("%s", "It makes no sense to multiply the file size by zero. Using default value 1.0.");
137  multiplier = 1.0f;
138  }
139 
140  const qreal sizeMult = size * multiplier;
141 
142  if (unitSystem == 10) {
143  if ((sizeMult > -1000) && (sizeMult < 1000)) {
144  precision = 0;
145  }
146  } else if (unitSystem == 2) {
147  if ((sizeMult > - 1024) && (sizeMult < 1024)) {
148  precision = 0;
149  }
150  }
151 
152  QString resultString;
153 
154  if (sizeMult > static_cast<qreal>(std::numeric_limits<qint64>::min()) && sizeMult < static_cast<qreal>(std::numeric_limits<qint64>::max())) {
155 
156  QLocale l(c->localizer()->currentLocale());
158 
159  resultString = l.formattedDataSize(static_cast<qint64>(sizeMult), precision, format);
160 
161  } else {
162  const std::pair<qreal,QString> fspair = calcFileSize(size, unitSystem, multiplier);
163 
164  if (precision == 2) {
165  resultString = c->localizer()->localizeNumber(fspair.first) + QChar(QChar::Space) + fspair.second;
166  } else {
167  QLocale l(c->localizer()->currentLocale());
168  resultString = l.toString(fspair.first, 'f', precision) + QChar(QChar::Space) + fspair.second;
169  }
170  }
171 
172  streamValueInContext(stream, resultString, c);
173 }
174 
175 L10nFileSizeVarNode::L10nFileSizeVarNode(const FilterExpression &size,
176  const FilterExpression &unitSystem,
177  const FilterExpression &precision,
178  const FilterExpression &multiplier,
179  const QString &resultName, QObject *parent)
180  : Node(parent), m_size(size), m_unitSystem(unitSystem), m_precision(precision), m_multiplier(multiplier),
181  m_resultName(resultName)
182 {
183 }
184 
186 {
187  Q_UNUSED(stream)
188  bool convertNumbers = true;
189 
190  qreal size = 0.0f;
191  if (m_size.resolve(c).canConvert<qreal>()) {
192  size = m_size.resolve(c).toReal(&convertNumbers);
193  } else {
194  size = getSafeString(m_size.resolve(c)).get().toDouble(&convertNumbers);
195  }
196  if (!convertNumbers) {
197  qWarning("%s", "Failed to convert input file size into a floating point number.");
198  return;
199  }
200 
201  int unitSystem = m_unitSystem.isValid() ? m_unitSystem.resolve(c).toInt(&convertNumbers) : 10;
202  if (!convertNumbers) {
203  qWarning("%s", "Failed to convert unit system for file size into integer value. Using default decimal system.");
204  unitSystem = 10;
205  }
206 
207  int precision = m_precision.isValid() ? m_precision.resolve(c).toInt(&convertNumbers) : 2;
208  if (!convertNumbers) {
209  qWarning("%s", "Failed to convert decimal precision for file size into an integer value. Using default value 2.");
210  precision = 2;
211  }
212 
213  qreal multiplier = m_multiplier.isValid() ? m_multiplier.resolve(c).toReal(&convertNumbers) : 1.0f;
214  if (!convertNumbers) {
215  qWarning("%s", "Failed to convert multiplier file size into a floating point number. Using default value 1.0.");
216  multiplier = 1.0f;
217  }
218 
219  if (multiplier == 0.0f) {
220  qWarning("%s", "It makes no sense to mulitply the file size by zero. Using default value 1.0.");
221  multiplier = 1.0f;
222  }
223 
224  const double sizeMult = size * multiplier;
225 
226  if (unitSystem == 10) {
227  if ((sizeMult > -1000) && (sizeMult < 1000)) {
228  precision = 0;
229  }
230  } else if (unitSystem == 2) {
231  if ((sizeMult > - 1024) && (sizeMult < 1024)) {
232  precision = 0;
233  }
234  }
235 
236  QString resultString;
237 
238  if (sizeMult > static_cast<qreal>(std::numeric_limits<qint64>::min()) && sizeMult < static_cast<qreal>(std::numeric_limits<qint64>::max())) {
239 
240  QLocale l(c->localizer()->currentLocale());
242 
243  resultString = l.formattedDataSize(static_cast<qint64>(sizeMult), precision, format);
244 
245  } else {
246  const std::pair<qreal,QString> fspair = calcFileSize(size, unitSystem, multiplier);
247 
248  if (precision == 2) {
249  resultString = c->localizer()->localizeNumber(fspair.first) + QChar(QChar::Space) + fspair.second;
250  } else {
251  QLocale l(c->localizer()->currentLocale());
252  resultString = l.toString(fspair.first, 'f', precision) + QChar(QChar::Space) + fspair.second;
253  }
254  }
255 
256  c->insert(m_resultName, resultString);
257 }
The Context class holds the context to render a Template with.
Definition: context.h:118
Node * getNode(const QString &tagContent, Parser *p) const override
Node * getNode(const QString &tagContent, Parser *p) const override
void removeFirst()
const_reference at(qsizetype i) const const
void render(OutputStream *stream, Context *c) const override
qsizetype size() const const
bool canConvert() const const
int toInt(bool *ok) const const
bool isEmpty() const const
typedef DataSizeFormats
Base class for all nodes.
Definition: node.h:77
Utility functions used throughout Cutelee.
The OutputStream class is used to render templates to a QTextStream.
Definition: outputstream.h:80
QVariant resolve(OutputStream *stream, Context *c) const
std::shared_ptr< AbstractLocalizer > localizer() const
Definition: context.cpp:230
T & last()
The Parser class processes a string template into a tree of nodes.
Definition: parser.h:48
void render(OutputStream *stream, Context *c) const override
std::pair< qreal, QString > calcFileSize(qreal size, int unitSystem=10, qreal multiplier=1.0)
Definition: util.cpp:196
A FilterExpression object represents a filter expression in a template.
Q_INVOKABLE QStringList smartSplit(const QString &str) const
Definition: node.cpp:202
qreal toReal(bool *ok) const const
void streamValueInContext(OutputStream *stream, const QVariant &input, Cutelee::Context *c) const
Definition: node.cpp:88
void insert(const QString &name, QObject *object)
Definition: context.cpp:145
Cutelee::SafeString getSafeString(const QVariant &input)
Definition: util.cpp:111
An exception for use when implementing template tags.
Definition: exception.h:84