1/*
2 * SPDX-FileCopyrightText: 2007-2009 Petri Damstén <damu@iki.fi>
3 * SPDX-FileCopyrightText: 2014 John Layt <jlayt@kde.org>
4 *
5 * SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7
8#include "unitcategory.h"
9#include "unit_p.h"
10#include "unitcategory_p.h"
11
12#include <KLocalizedString>
13
14#include <QNetworkReply>
15
16#include <QNetworkAccessManager>
17#include <QStandardPaths>
18
19namespace KUnitConversion
20{
21UnitCategoryPrivate::UnitCategoryPrivate()
22 : m_id(InvalidCategory)
23{
24}
25
26UnitCategoryPrivate::UnitCategoryPrivate(CategoryId id, const QString &name, const QString &description)
27 : m_id(id)
28 , m_name(name)
29 , m_description(description)
30{
31}
32
33UnitCategoryPrivate::~UnitCategoryPrivate()
34{
35}
36
37UnitCategoryPrivate *UnitCategoryPrivate::clone()
38{
39 return new UnitCategoryPrivate(*this);
40}
41
42bool UnitCategoryPrivate::operator==(const UnitCategoryPrivate &other) const
43{
44 return (m_id == other.m_id);
45}
46
47bool UnitCategoryPrivate::operator!=(const UnitCategoryPrivate &other) const
48{
49 return !(*this == other);
50}
51
52QNetworkAccessManager *UnitCategoryPrivate::nam()
53{
54 static std::unique_ptr<QNetworkAccessManager> s_nam;
55 if (!s_nam) {
56 s_nam = std::make_unique<QNetworkAccessManager>();
57 s_nam->setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy);
58 s_nam->setStrictTransportSecurityEnabled(true);
59 s_nam->enableStrictTransportSecurityStore(enabled: true, storeDir: QStandardPaths::writableLocation(type: QStandardPaths::GenericCacheLocation) + QLatin1String("/org.kde.unitconversion/hsts/"));
60 }
61 return s_nam.get();
62}
63
64Value UnitCategoryPrivate::convert(const Value &value, const Unit &toUnit)
65{
66 qreal v = value.unit().toDefault(value: value.number());
67 return Value(toUnit.fromDefault(value: v), toUnit);
68}
69
70UnitCategory::UnitCategory()
71 : d(nullptr)
72{
73}
74
75UnitCategory::UnitCategory(UnitCategoryPrivate *dd)
76 : d(dd)
77{
78}
79
80UnitCategory::UnitCategory(const UnitCategory &other)
81 : d(other.d)
82{
83}
84
85UnitCategory::~UnitCategory()
86{
87}
88
89UnitCategory &UnitCategory::operator=(const UnitCategory &other)
90{
91 d = other.d;
92 return *this;
93}
94
95UnitCategory &UnitCategory::operator=(UnitCategory &&other)
96{
97 d.swap(other&: other.d);
98 return *this;
99}
100
101bool UnitCategory::operator==(const UnitCategory &other) const
102{
103 if (d && other.d) {
104 return (*d == *other.d);
105 } else {
106 return (d == other.d);
107 }
108}
109
110bool UnitCategory::operator!=(const UnitCategory &other) const
111{
112 if (d && other.d) {
113 return (*d != *other.d);
114 } else {
115 return (d != other.d);
116 }
117}
118
119bool UnitCategory::isNull() const
120{
121 return !d;
122}
123
124CategoryId UnitCategory::id() const
125{
126 if (d) {
127 return d->m_id;
128 }
129 return InvalidCategory;
130}
131
132QList<Unit> UnitCategory::units() const
133{
134 if (d) {
135 return d->m_units;
136 }
137 return QList<Unit>();
138}
139
140QList<Unit> UnitCategory::mostCommonUnits() const
141{
142 if (d) {
143 return d->m_mostCommonUnits;
144 }
145 return QList<Unit>();
146}
147
148QStringList UnitCategory::allUnits() const
149{
150 if (d) {
151 return d->m_unitMap.keys();
152 }
153 return QStringList();
154}
155
156bool UnitCategory::hasUnit(const QString &unit) const
157{
158 if (d) {
159 return d->m_unitMap.contains(key: unit);
160 }
161 return false;
162}
163
164Value UnitCategory::convert(const Value &value, const QString &toUnit) const
165{
166 if (d && (toUnit.isEmpty() || d->m_unitMap.contains(key: toUnit)) && value.unit().isValid()) {
167 Unit to = toUnit.isEmpty() ? defaultUnit() : d->m_unitMap[toUnit];
168 return convert(value, toUnit: to);
169 }
170 return Value();
171}
172
173Value UnitCategory::convert(const Value &value, UnitId toUnit) const
174{
175 if (d && d->m_idMap.contains(key: toUnit) && value.unit().isValid()) {
176 return convert(value, toUnit: d->m_idMap[toUnit]);
177 }
178 return Value();
179}
180
181Value UnitCategory::convert(const Value &value, const Unit &toUnit) const
182{
183 if (d && !toUnit.isNull()) {
184 return d->convert(value, toUnit);
185 }
186 return Value();
187}
188
189Unit UnitCategory::unit(const QString &s) const
190{
191 if (d) {
192 return d->m_unitMap.value(key: s);
193 }
194 return Unit();
195}
196
197Unit UnitCategory::unit(UnitId unitId) const
198{
199 if (d && d->m_idMap.contains(key: unitId)) {
200 return d->m_idMap[unitId];
201 }
202 return Unit();
203}
204
205QString UnitCategory::name() const
206{
207 if (d) {
208 return d->m_name;
209 }
210 return QString();
211}
212
213Unit UnitCategory::defaultUnit() const
214{
215 if (d) {
216 return d->m_defaultUnit;
217 }
218 return Unit();
219}
220
221QString UnitCategory::description() const
222{
223 if (d) {
224 return d->m_description;
225 }
226 return QString();
227}
228
229void UnitCategoryPrivate::addDefaultUnit(const Unit &unit)
230{
231 addCommonUnit(unit);
232 m_defaultUnit = unit;
233}
234
235void UnitCategoryPrivate::addCommonUnit(const Unit &unit)
236{
237 addUnit(unit);
238 m_mostCommonUnits.append(t: unit);
239}
240
241void UnitCategoryPrivate::addUnit(const Unit &unit)
242{
243 // ### this is emulating a weak_ptr to break a reference cycle between Unit and UnitCategory
244 // ### even without that, this is slicing the polymorphic part of UnitCategory
245 // this only works by chance as apart from the ctors those parts contain no logic or data it seems
246 unit.d->m_category = this;
247 const QStringList list = unit.d->m_matchString.split(sep: QLatin1Char(';'), behavior: Qt::SkipEmptyParts);
248 Q_ASSERT_X(!list.isEmpty(),
249 "UnitCategoryPrivate::addUnit",
250 QLatin1String("Empty match string for unit symbol: '%1' '%2' - fix translation?").arg(unit.symbol(), unit.description()).toUtf8().constData());
251
252 for (const QString &name : list) {
253 m_unitMap[name] = unit;
254 }
255 m_idMap[unit.id()] = unit;
256 m_units.append(t: unit);
257}
258
259bool UnitCategory::hasOnlineConversionTable() const
260{
261 return d->hasOnlineConversionTable();
262}
263
264UpdateJob* UnitCategory::syncConversionTable(std::chrono::seconds updateSkipPeriod)
265{
266 return d->syncConversionTable(updateSkipPeriod);
267}
268
269
270UpdateJob::UpdateJob(QNetworkReply *reply)
271 : d(reply)
272{
273 connect(sender: d, signal: &QNetworkReply::finished, context: this, slot: &UpdateJob::finished);
274 connect(sender: d, signal: &QNetworkReply::finished, context: this, slot: &QObject::deleteLater);
275}
276
277UpdateJob::~UpdateJob() = default;
278
279}
280
281#include "moc_unitcategory.cpp"
282

source code of kunitconversion/src/unitcategory.cpp