File indexing completed on 2024-04-21 03:58:32

0001 /*
0002  *   SPDX-FileCopyrightText: 2007-2009 Petri Damstén <damu@iki.fi>
0003  *   SPDX-FileCopyrightText: 2014 John Layt <jlayt@kde.org>
0004  *
0005  *   SPDX-License-Identifier: LGPL-2.0-or-later
0006  */
0007 
0008 #include "unitcategory.h"
0009 #include "unit_p.h"
0010 #include "unitcategory_p.h"
0011 
0012 #include <KLocalizedString>
0013 
0014 #include <QNetworkReply>
0015 
0016 #include <QNetworkAccessManager>
0017 #include <QStandardPaths>
0018 
0019 namespace KUnitConversion
0020 {
0021 UnitCategoryPrivate::UnitCategoryPrivate()
0022     : m_id(InvalidCategory)
0023 {
0024 }
0025 
0026 UnitCategoryPrivate::UnitCategoryPrivate(CategoryId id, const QString &name, const QString &description)
0027     : m_id(id)
0028     , m_name(name)
0029     , m_description(description)
0030 {
0031 }
0032 
0033 UnitCategoryPrivate::~UnitCategoryPrivate()
0034 {
0035 }
0036 
0037 UnitCategoryPrivate *UnitCategoryPrivate::clone()
0038 {
0039     return new UnitCategoryPrivate(*this);
0040 }
0041 
0042 bool UnitCategoryPrivate::operator==(const UnitCategoryPrivate &other) const
0043 {
0044     return (m_id == other.m_id);
0045 }
0046 
0047 bool UnitCategoryPrivate::operator!=(const UnitCategoryPrivate &other) const
0048 {
0049     return !(*this == other);
0050 }
0051 
0052 QNetworkAccessManager *UnitCategoryPrivate::nam()
0053 {
0054     static std::unique_ptr<QNetworkAccessManager> s_nam;
0055     if (!s_nam) {
0056         s_nam = std::make_unique<QNetworkAccessManager>();
0057         s_nam->setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy);
0058         s_nam->setStrictTransportSecurityEnabled(true);
0059         s_nam->enableStrictTransportSecurityStore(true, QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + QLatin1String("/org.kde.unitconversion/hsts/"));
0060     }
0061     return s_nam.get();
0062 }
0063 
0064 Value UnitCategoryPrivate::convert(const Value &value, const Unit &toUnit)
0065 {
0066     qreal v = value.unit().toDefault(value.number());
0067     return Value(toUnit.fromDefault(v), toUnit);
0068 }
0069 
0070 UnitCategory::UnitCategory()
0071     : d(nullptr)
0072 {
0073 }
0074 
0075 UnitCategory::UnitCategory(UnitCategoryPrivate *dd)
0076     : d(dd)
0077 {
0078 }
0079 
0080 UnitCategory::UnitCategory(const UnitCategory &other)
0081     : d(other.d)
0082 {
0083 }
0084 
0085 UnitCategory::~UnitCategory()
0086 {
0087 }
0088 
0089 UnitCategory &UnitCategory::operator=(const UnitCategory &other)
0090 {
0091     d = other.d;
0092     return *this;
0093 }
0094 
0095 UnitCategory &UnitCategory::operator=(UnitCategory &&other)
0096 {
0097     d.swap(other.d);
0098     return *this;
0099 }
0100 
0101 bool UnitCategory::operator==(const UnitCategory &other) const
0102 {
0103     if (d && other.d) {
0104         return (*d == *other.d);
0105     } else {
0106         return (d == other.d);
0107     }
0108 }
0109 
0110 bool UnitCategory::operator!=(const UnitCategory &other) const
0111 {
0112     if (d && other.d) {
0113         return (*d != *other.d);
0114     } else {
0115         return (d != other.d);
0116     }
0117 }
0118 
0119 bool UnitCategory::isNull() const
0120 {
0121     return !d;
0122 }
0123 
0124 CategoryId UnitCategory::id() const
0125 {
0126     if (d) {
0127         return d->m_id;
0128     }
0129     return InvalidCategory;
0130 }
0131 
0132 QList<Unit> UnitCategory::units() const
0133 {
0134     if (d) {
0135         return d->m_units;
0136     }
0137     return QList<Unit>();
0138 }
0139 
0140 QList<Unit> UnitCategory::mostCommonUnits() const
0141 {
0142     if (d) {
0143         return d->m_mostCommonUnits;
0144     }
0145     return QList<Unit>();
0146 }
0147 
0148 QStringList UnitCategory::allUnits() const
0149 {
0150     if (d) {
0151         return d->m_unitMap.keys();
0152     }
0153     return QStringList();
0154 }
0155 
0156 bool UnitCategory::hasUnit(const QString &unit) const
0157 {
0158     if (d) {
0159         return d->m_unitMap.contains(unit);
0160     }
0161     return false;
0162 }
0163 
0164 Value UnitCategory::convert(const Value &value, const QString &toUnit) const
0165 {
0166     if (d && (toUnit.isEmpty() || d->m_unitMap.contains(toUnit)) && value.unit().isValid()) {
0167         Unit to = toUnit.isEmpty() ? defaultUnit() : d->m_unitMap[toUnit];
0168         return convert(value, to);
0169     }
0170     return Value();
0171 }
0172 
0173 Value UnitCategory::convert(const Value &value, UnitId toUnit) const
0174 {
0175     if (d && d->m_idMap.contains(toUnit) && value.unit().isValid()) {
0176         return convert(value, d->m_idMap[toUnit]);
0177     }
0178     return Value();
0179 }
0180 
0181 Value UnitCategory::convert(const Value &value, const Unit &toUnit) const
0182 {
0183     if (d && !toUnit.isNull()) {
0184         return d->convert(value, toUnit);
0185     }
0186     return Value();
0187 }
0188 
0189 Unit UnitCategory::unit(const QString &s) const
0190 {
0191     if (d) {
0192         return d->m_unitMap.value(s);
0193     }
0194     return Unit();
0195 }
0196 
0197 Unit UnitCategory::unit(UnitId unitId) const
0198 {
0199     if (d && d->m_idMap.contains(unitId)) {
0200         return d->m_idMap[unitId];
0201     }
0202     return Unit();
0203 }
0204 
0205 QString UnitCategory::name() const
0206 {
0207     if (d) {
0208         return d->m_name;
0209     }
0210     return QString();
0211 }
0212 
0213 Unit UnitCategory::defaultUnit() const
0214 {
0215     if (d) {
0216         return d->m_defaultUnit;
0217     }
0218     return Unit();
0219 }
0220 
0221 QString UnitCategory::description() const
0222 {
0223     if (d) {
0224         return d->m_description;
0225     }
0226     return QString();
0227 }
0228 
0229 void UnitCategoryPrivate::addDefaultUnit(const Unit &unit)
0230 {
0231     addCommonUnit(unit);
0232     m_defaultUnit = unit;
0233 }
0234 
0235 void UnitCategoryPrivate::addCommonUnit(const Unit &unit)
0236 {
0237     addUnit(unit);
0238     m_mostCommonUnits.append(unit);
0239 }
0240 
0241 void UnitCategoryPrivate::addUnit(const Unit &unit)
0242 {
0243     // ### this is emulating a weak_ptr to break a reference cycle between Unit and UnitCategory
0244     // ### even without that, this is slicing the polymorphic part of UnitCategory
0245     // this only works by chance as apart from the ctors those parts contain no logic or data it seems
0246     unit.d->m_category = this;
0247     const QStringList list = unit.d->m_matchString.split(QLatin1Char(';'), Qt::SkipEmptyParts);
0248     Q_ASSERT_X(!list.isEmpty(),
0249                "UnitCategoryPrivate::addUnit",
0250                QLatin1String("Empty match string for unit symbol: '%1' '%2' - fix translation?").arg(unit.symbol(), unit.description()).toUtf8().constData());
0251 
0252     for (const QString &name : list) {
0253         m_unitMap[name] = unit;
0254     }
0255     m_idMap[unit.id()] = unit;
0256     m_units.append(unit);
0257 }
0258 
0259 bool UnitCategory::hasOnlineConversionTable() const
0260 {
0261     return d->hasOnlineConversionTable();
0262 }
0263 
0264 UpdateJob* UnitCategory::syncConversionTable(std::chrono::seconds updateSkipPeriod)
0265 {
0266     return d->syncConversionTable(updateSkipPeriod);
0267 }
0268 
0269 
0270 UpdateJob::UpdateJob(QNetworkReply *reply)
0271     : d(reply)
0272 {
0273     connect(d, &QNetworkReply::finished, this, &UpdateJob::finished);
0274     connect(d, &QNetworkReply::finished, this, &QObject::deleteLater);
0275 }
0276 
0277 UpdateJob::~UpdateJob() = default;
0278 
0279 }
0280 
0281 #include "moc_unitcategory.cpp"