| 1 | /* |
| 2 | SPDX-FileCopyrightText: 2022 Volker Krause <vkrause@kde.org> |
| 3 | SPDX-License-Identifier: LGPL-2.0-or-later |
| 4 | */ |
| 5 | |
| 6 | #include "addressformat.h" |
| 7 | #include "address.h" |
| 8 | #include "addressformat_p.h" |
| 9 | #include "addressformatparser_p.h" |
| 10 | #include "addressformatscript_p.h" |
| 11 | |
| 12 | #include <KConfig> |
| 13 | #include <KConfigGroup> |
| 14 | #include <KCountry> |
| 15 | |
| 16 | #include <QDebug> |
| 17 | #include <QLocale> |
| 18 | |
| 19 | using namespace KContacts; |
| 20 | |
| 21 | AddressFormatElement::AddressFormatElement() |
| 22 | : d(new AddressFormatElementPrivate) |
| 23 | { |
| 24 | } |
| 25 | |
| 26 | AddressFormatElement::AddressFormatElement(const AddressFormatElement &) = default; |
| 27 | AddressFormatElement::~AddressFormatElement() = default; |
| 28 | AddressFormatElement &AddressFormatElement::operator=(const AddressFormatElement &) = default; |
| 29 | |
| 30 | bool AddressFormatElement::isField() const |
| 31 | { |
| 32 | return d->field != AddressFormatField::NoField; |
| 33 | } |
| 34 | |
| 35 | AddressFormatField AddressFormatElement::field() const |
| 36 | { |
| 37 | return d->field; |
| 38 | } |
| 39 | |
| 40 | bool AddressFormatElement::isLiteral() const |
| 41 | { |
| 42 | return !d->literal.isEmpty(); |
| 43 | } |
| 44 | |
| 45 | QString AddressFormatElement::literal() const |
| 46 | { |
| 47 | return d->literal; |
| 48 | } |
| 49 | |
| 50 | bool AddressFormatElement::isSeparator() const |
| 51 | { |
| 52 | return !isField() && !isLiteral(); |
| 53 | } |
| 54 | |
| 55 | AddressFormat::AddressFormat() |
| 56 | : d(new AddressFormatPrivate) |
| 57 | { |
| 58 | } |
| 59 | |
| 60 | AddressFormat::AddressFormat(const AddressFormat &) = default; |
| 61 | AddressFormat::~AddressFormat() = default; |
| 62 | AddressFormat &AddressFormat::operator=(const AddressFormat &) = default; |
| 63 | |
| 64 | const std::vector<AddressFormatElement> &AddressFormat::elements() const |
| 65 | { |
| 66 | return d->elements; |
| 67 | } |
| 68 | |
| 69 | AddressFormatFields AddressFormat::requiredFields() const |
| 70 | { |
| 71 | return d->required; |
| 72 | } |
| 73 | |
| 74 | AddressFormatFields AddressFormat::usedFields() const |
| 75 | { |
| 76 | return std::accumulate(first: d->elements.begin(), last: d->elements.end(), init: AddressFormatFields(AddressFormatField::NoField), binary_op: [](auto lhs, const auto &rhs) { |
| 77 | return lhs | rhs.field(); |
| 78 | }); |
| 79 | } |
| 80 | |
| 81 | AddressFormatFields AddressFormat::upperCaseFields() const |
| 82 | { |
| 83 | return d->upper; |
| 84 | } |
| 85 | |
| 86 | QString AddressFormat::postalCodeRegularExpression() const |
| 87 | { |
| 88 | return d->postalCodeFormat; |
| 89 | } |
| 90 | |
| 91 | QString AddressFormat::country() const |
| 92 | { |
| 93 | return d->country; |
| 94 | } |
| 95 | |
| 96 | QList<AddressFormatElement> AddressFormat::elementsForQml() const |
| 97 | { |
| 98 | QList<AddressFormatElement> l; |
| 99 | l.reserve(asize: d->elements.size()); |
| 100 | std::copy(first: d->elements.begin(), last: d->elements.end(), result: std::back_inserter(x&: l)); |
| 101 | return l; |
| 102 | } |
| 103 | |
| 104 | static QString addressFormatRc() |
| 105 | { |
| 106 | Q_INIT_RESOURCE(kcontacts); // must be called outside of a namespace |
| 107 | return QStringLiteral(":/org.kde.kcontacts/addressformatrc" ); |
| 108 | } |
| 109 | |
| 110 | AddressFormat |
| 111 | AddressFormatRepository::formatForCountry(const QString &countryCode, AddressFormatScriptPreference scriptPref, AddressFormatPreference formatPref) |
| 112 | { |
| 113 | static const KConfig entry(addressFormatRc(), KConfig::SimpleConfig); |
| 114 | KConfigGroup group = entry.group(group: countryCode); |
| 115 | |
| 116 | AddressFormat format; |
| 117 | auto fmt = AddressFormatPrivate::get(format); |
| 118 | fmt->required = AddressFormatParser::parseFields(s: group.readEntry(key: "Required" , aDefault: QString())); |
| 119 | fmt->upper = AddressFormatParser::parseFields(s: group.readEntry(key: "Upper" , aDefault: QString())); |
| 120 | |
| 121 | QString formatString; |
| 122 | if (scriptPref == AddressFormatScriptPreference::Latin && formatPref == AddressFormatPreference::Business) { |
| 123 | formatString = group.readEntry(key: "LatinBusinessAddressFormat" , aDefault: QString()); |
| 124 | } |
| 125 | if (formatString.isEmpty() && scriptPref == AddressFormatScriptPreference::Latin) { |
| 126 | formatString = group.readEntry(key: "LatinAddressFormat" , aDefault: QString()); |
| 127 | } |
| 128 | if (formatString.isEmpty() && formatPref == AddressFormatPreference::Business) { |
| 129 | formatString = group.readEntry(key: "BusinessAddressFormat" , aDefault: QString()); |
| 130 | } |
| 131 | if (formatString.isEmpty()) { |
| 132 | formatString = group.readEntry(key: "AddressFormat" , QStringLiteral("%N%n%O%n%A%nPO BOX %P%n%C %S %Z" )); |
| 133 | } |
| 134 | fmt->elements = AddressFormatParser::parseElements(s: formatString); |
| 135 | fmt->postalCodeFormat = group.readEntry(key: "PostalCodeFormat" , aDefault: QString()); |
| 136 | fmt->country = countryCode; |
| 137 | return format; |
| 138 | } |
| 139 | |
| 140 | AddressFormat AddressFormatRepository::formatForAddress(const Address &address, AddressFormatPreference formatPref) |
| 141 | { |
| 142 | KCountry c; |
| 143 | if (address.country().size() == 2) { |
| 144 | c = KCountry::fromAlpha2(alpha2Code: address.country()); |
| 145 | } |
| 146 | if (!c.isValid()) { |
| 147 | c = KCountry::fromName(name: address.country()); |
| 148 | } |
| 149 | // fall back to our own country |
| 150 | if (!c.isValid()) { |
| 151 | c = KCountry::fromQLocale(country: QLocale().territory()); |
| 152 | } |
| 153 | |
| 154 | const auto scriptPref = AddressFormatScript::detect(addr: address) == AddressFormatScript::LatinLikeScript ? AddressFormatScriptPreference::Latin |
| 155 | : AddressFormatScriptPreference::Local; |
| 156 | return formatForCountry(countryCode: c.alpha2(), scriptPref, formatPref); |
| 157 | } |
| 158 | |
| 159 | #include "moc_addressformat.cpp" |
| 160 | |