Cutelee  6.1.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 (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
155  if (sizeMult > static_cast<qreal>(std::numeric_limits<qint64>::min()) && sizeMult < static_cast<qreal>(std::numeric_limits<qint64>::max())) {
156 
157  QLocale l(c->localizer()->currentLocale());
158  QLocale::DataSizeFormats format = unitSystem == 10 ? QLocale::DataSizeSIFormat : QLocale::DataSizeIecFormat;
159 
160  resultString = l.formattedDataSize(static_cast<qint64>(sizeMult), precision, format);
161 
162  } else {
163 #endif
164 
165  const std::pair<qreal,QString> fspair = calcFileSize(size, unitSystem, multiplier);
166 
167  if (precision == 2) {
168  resultString = c->localizer()->localizeNumber(fspair.first) + QChar(QChar::Space) + fspair.second;
169  } else {
170  QLocale l(c->localizer()->currentLocale());
171  resultString = l.toString(fspair.first, 'f', precision) + QChar(QChar::Space) + fspair.second;
172  }
173 
174 #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
175  }
176 #endif
177 
178  streamValueInContext(stream, resultString, c);
179 }
180 
181 L10nFileSizeVarNode::L10nFileSizeVarNode(const FilterExpression &size,
182  const FilterExpression &unitSystem,
183  const FilterExpression &precision,
184  const FilterExpression &multiplier,
185  const QString &resultName, QObject *parent)
186  : Node(parent), m_size(size), m_unitSystem(unitSystem), m_precision(precision), m_multiplier(multiplier),
187  m_resultName(resultName)
188 {
189 }
190 
192 {
193  Q_UNUSED(stream)
194  bool convertNumbers = true;
195 
196  qreal size = 0.0f;
197  if (m_size.resolve(c).canConvert<qreal>()) {
198  size = m_size.resolve(c).toReal(&convertNumbers);
199  } else {
200  size = getSafeString(m_size.resolve(c)).get().toDouble(&convertNumbers);
201  }
202  if (!convertNumbers) {
203  qWarning("%s", "Failed to convert input file size into a floating point number.");
204  return;
205  }
206 
207  int unitSystem = m_unitSystem.isValid() ? m_unitSystem.resolve(c).toInt(&convertNumbers) : 10;
208  if (!convertNumbers) {
209  qWarning("%s", "Failed to convert unit system for file size into integer value. Using default decimal system.");
210  unitSystem = 10;
211  }
212 
213  int precision = m_precision.isValid() ? m_precision.resolve(c).toInt(&convertNumbers) : 2;
214  if (!convertNumbers) {
215  qWarning("%s", "Failed to convert decimal precision for file size into an integer value. Using default value 2.");
216  precision = 2;
217  }
218 
219  qreal multiplier = m_multiplier.isValid() ? m_multiplier.resolve(c).toReal(&convertNumbers) : 1.0f;
220  if (!convertNumbers) {
221  qWarning("%s", "Failed to convert multiplier file size into a floating point number. Using default value 1.0.");
222  multiplier = 1.0f;
223  }
224 
225  if (multiplier == 0.0f) {
226  qWarning("%s", "It makes no sense to mulitply the file size by zero. Using default value 1.0.");
227  multiplier = 1.0f;
228  }
229 
230  const double sizeMult = size * multiplier;
231 
232  if (unitSystem == 10) {
233  if ((sizeMult > -1000) && (sizeMult < 1000)) {
234  precision = 0;
235  }
236  } else if (unitSystem == 2) {
237  if ((sizeMult > - 1024) && (sizeMult < 1024)) {
238  precision = 0;
239  }
240  }
241 
242  QString resultString;
243 
244 #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
245  if (sizeMult > static_cast<qreal>(std::numeric_limits<qint64>::min()) && sizeMult < static_cast<qreal>(std::numeric_limits<qint64>::max())) {
246 
247  QLocale l(c->localizer()->currentLocale());
248  QLocale::DataSizeFormats format = unitSystem == 10 ? QLocale::DataSizeSIFormat : QLocale::DataSizeIecFormat;
249 
250  resultString = l.formattedDataSize(static_cast<qint64>(sizeMult), precision, format);
251 
252  } else {
253 #endif
254 
255  const std::pair<qreal,QString> fspair = calcFileSize(size, unitSystem, multiplier);
256 
257  if (precision == 2) {
258  resultString = c->localizer()->localizeNumber(fspair.first) + QChar(QChar::Space) + fspair.second;
259  } else {
260  QLocale l(c->localizer()->currentLocale());
261  resultString = l.toString(fspair.first, 'f', precision) + QChar(QChar::Space) + fspair.second;
262  }
263 
264 #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
265  }
266 #endif
267 
268  c->insert(m_resultName, resultString);
269 }
Q_INVOKABLE QStringList smartSplit(const QString &str) const
Definition: node.cpp:202
The Context class holds the context to render a Template with.
Definition: context.h:119
std::shared_ptr< AbstractLocalizer > localizer() const
Definition: context.cpp:230
void insert(const QString &name, QObject *object)
Definition: context.cpp:145
An exception for use when implementing template tags.
Definition: exception.h:85
A FilterExpression object represents a filter expression in a template.
QVariant resolve(OutputStream *stream, Context *c) const
Base class for all nodes.
Definition: node.h:78
void streamValueInContext(OutputStream *stream, const QVariant &input, Cutelee::Context *c) const
Definition: node.cpp:88
The OutputStream class is used to render templates to a QTextStream.
Definition: outputstream.h:81
The Parser class processes a string template into a tree of nodes.
Definition: parser.h:49
const NestedString & get() const
Definition: safestring.h:340
Node * getNode(const QString &tagContent, Parser *p) const override
void render(OutputStream *stream, Context *c) const override
Node * getNode(const QString &tagContent, Parser *p) const override
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:215
Cutelee::SafeString getSafeString(const QVariant &input)
Definition: util.cpp:108
Utility functions used throughout Cutelee.