1 | /* |
2 | This file is part of the KContacts framework. |
3 | SPDX-FileCopyrightText: 2001 Cornelius Schumacher <schumacher@kde.org> |
4 | |
5 | SPDX-License-Identifier: LGPL-2.0-or-later |
6 | */ |
7 | |
8 | #include "address.h" |
9 | #include "addressformat.h" |
10 | #include "addressformatter_p.h" |
11 | |
12 | #include "kcontacts_debug.h" |
13 | #include <KConfig> |
14 | #include <KCountry> |
15 | #include <KLocalizedString> |
16 | #include <krandom.h> |
17 | |
18 | #include <KConfigGroup> |
19 | |
20 | #include <QDataStream> |
21 | #include <QSharedData> |
22 | #include <QUrlQuery> |
23 | |
24 | using namespace KContacts; |
25 | |
26 | class Q_DECL_HIDDEN Address::Private : public QSharedData |
27 | { |
28 | public: |
29 | Private() |
30 | : mEmpty(true) |
31 | { |
32 | mId = KRandom::randomString(length: 10); |
33 | } |
34 | |
35 | Private(const Private &other) |
36 | : QSharedData(other) |
37 | { |
38 | mEmpty = other.mEmpty; |
39 | mId = other.mId; |
40 | mType = other.mType; |
41 | |
42 | mPostOfficeBox = other.mPostOfficeBox; |
43 | mExtended = other.mExtended; |
44 | mStreet = other.mStreet; |
45 | mLocality = other.mLocality; |
46 | mRegion = other.mRegion; |
47 | mPostalCode = other.mPostalCode; |
48 | mCountry = other.mCountry; |
49 | mLabel = other.mLabel; |
50 | } |
51 | |
52 | bool mEmpty; |
53 | QString mId; |
54 | Type mType; |
55 | Geo mGeo; |
56 | |
57 | QString mPostOfficeBox; |
58 | QString mExtended; |
59 | QString mStreet; |
60 | QString mLocality; |
61 | QString mRegion; |
62 | QString mPostalCode; |
63 | QString mCountry; |
64 | QString mLabel; |
65 | }; |
66 | |
67 | Address::Address() |
68 | : d(new Private) |
69 | { |
70 | } |
71 | |
72 | Address::Address(Type type) |
73 | : d(new Private) |
74 | { |
75 | d->mType = type; |
76 | } |
77 | |
78 | Address::Address(const Address &other) |
79 | : d(other.d) |
80 | { |
81 | } |
82 | |
83 | Address::~Address() |
84 | { |
85 | } |
86 | |
87 | Address &Address::operator=(const Address &other) |
88 | { |
89 | if (this != &other) { |
90 | d = other.d; |
91 | } |
92 | |
93 | return *this; |
94 | } |
95 | |
96 | bool Address::operator==(const Address &other) const |
97 | { |
98 | if (d->mId != other.d->mId) { |
99 | return false; |
100 | } |
101 | if (d->mType != other.d->mType) { |
102 | return false; |
103 | } |
104 | if (d->mPostOfficeBox != other.d->mPostOfficeBox) { |
105 | return false; |
106 | } |
107 | if (d->mExtended != other.d->mExtended) { |
108 | return false; |
109 | } |
110 | if (d->mStreet != other.d->mStreet) { |
111 | return false; |
112 | } |
113 | if (d->mLocality != other.d->mLocality) { |
114 | return false; |
115 | } |
116 | if (d->mRegion != other.d->mRegion) { |
117 | return false; |
118 | } |
119 | if (d->mPostalCode != other.d->mPostalCode) { |
120 | return false; |
121 | } |
122 | if (d->mCountry != other.d->mCountry) { |
123 | return false; |
124 | } |
125 | if (d->mLabel != other.d->mLabel) { |
126 | return false; |
127 | } |
128 | |
129 | if (d->mGeo != other.d->mGeo) { |
130 | return false; |
131 | } |
132 | |
133 | return true; |
134 | } |
135 | |
136 | bool Address::operator!=(const Address &a) const |
137 | { |
138 | return !(a == *this); |
139 | } |
140 | |
141 | bool Address::isEmpty() const |
142 | { |
143 | return d->mEmpty; |
144 | } |
145 | |
146 | void Address::clear() |
147 | { |
148 | *this = Address(); |
149 | } |
150 | |
151 | void Address::setId(const QString &id) |
152 | { |
153 | d->mEmpty = false; |
154 | d->mId = id; |
155 | } |
156 | |
157 | QString Address::id() const |
158 | { |
159 | return d->mId; |
160 | } |
161 | |
162 | void Address::setType(Type type) |
163 | { |
164 | d->mEmpty = false; |
165 | d->mType = type; |
166 | } |
167 | |
168 | Address::Type Address::type() const |
169 | { |
170 | return d->mType; |
171 | } |
172 | |
173 | QString Address::typeLabel(Type type) |
174 | { |
175 | QString label; |
176 | const TypeList list = typeList(); |
177 | |
178 | for (const auto typeFlag : list) { |
179 | // these are actually flags |
180 | const TypeFlag flag = static_cast<TypeFlag>(static_cast<int>(typeFlag)); |
181 | if (type & flag) { |
182 | label.append(s: QLatin1Char('/') + typeFlagLabel(type: flag)); |
183 | } |
184 | } |
185 | |
186 | // Remove the first '/' |
187 | if (!label.isEmpty()) { |
188 | label.remove(i: 0, len: 1); |
189 | } |
190 | |
191 | return label; |
192 | } |
193 | |
194 | QString Address::typeLabel() const |
195 | { |
196 | QString label; |
197 | const TypeList list = typeList(); |
198 | |
199 | for (const auto f : list) { |
200 | if ((type() & f) && (f != Pref)) { |
201 | label.append(s: QLatin1Char('/') + typeLabel(type: f)); |
202 | } |
203 | } |
204 | // Remove the first '/' |
205 | if (!label.isEmpty()) { |
206 | label.remove(i: 0, len: 1); |
207 | } |
208 | return label; |
209 | } |
210 | |
211 | void Address::setPostOfficeBox(const QString &postOfficeBox) |
212 | { |
213 | d->mEmpty = false; |
214 | d->mPostOfficeBox = postOfficeBox; |
215 | } |
216 | |
217 | QString Address::postOfficeBox() const |
218 | { |
219 | return d->mPostOfficeBox; |
220 | } |
221 | |
222 | QString Address::postOfficeBoxLabel() |
223 | { |
224 | return i18n("Post Office Box" ); |
225 | } |
226 | |
227 | void Address::setExtended(const QString &extended) |
228 | { |
229 | d->mEmpty = false; |
230 | d->mExtended = extended; |
231 | } |
232 | |
233 | QString Address::extended() const |
234 | { |
235 | return d->mExtended; |
236 | } |
237 | |
238 | QString Address::extendedLabel() |
239 | { |
240 | return i18n("Extended Address Information" ); |
241 | } |
242 | |
243 | void Address::setStreet(const QString &street) |
244 | { |
245 | d->mEmpty = false; |
246 | d->mStreet = street; |
247 | } |
248 | |
249 | QString Address::street() const |
250 | { |
251 | return d->mStreet; |
252 | } |
253 | |
254 | QString Address::streetLabel() |
255 | { |
256 | return i18n("Street" ); |
257 | } |
258 | |
259 | void Address::setLocality(const QString &locality) |
260 | { |
261 | d->mEmpty = false; |
262 | d->mLocality = locality; |
263 | } |
264 | |
265 | QString Address::locality() const |
266 | { |
267 | return d->mLocality; |
268 | } |
269 | |
270 | QString Address::localityLabel() |
271 | { |
272 | return i18n("Locality" ); |
273 | } |
274 | |
275 | void Address::setRegion(const QString ®ion) |
276 | { |
277 | d->mEmpty = false; |
278 | d->mRegion = region; |
279 | } |
280 | |
281 | QString Address::region() const |
282 | { |
283 | return d->mRegion; |
284 | } |
285 | |
286 | QString Address::regionLabel() |
287 | { |
288 | return i18n("Region" ); |
289 | } |
290 | |
291 | void Address::setPostalCode(const QString &postalCode) |
292 | { |
293 | d->mEmpty = false; |
294 | d->mPostalCode = postalCode; |
295 | } |
296 | |
297 | QString Address::postalCode() const |
298 | { |
299 | return d->mPostalCode; |
300 | } |
301 | |
302 | QString Address::postalCodeLabel() |
303 | { |
304 | return i18n("Postal Code" ); |
305 | } |
306 | |
307 | void Address::setCountry(const QString &country) |
308 | { |
309 | d->mEmpty = false; |
310 | d->mCountry = country; |
311 | } |
312 | |
313 | QString Address::country() const |
314 | { |
315 | return d->mCountry; |
316 | } |
317 | |
318 | QString Address::countryLabel() |
319 | { |
320 | return i18n("Country" ); |
321 | } |
322 | |
323 | void Address::setLabel(const QString &label) |
324 | { |
325 | d->mEmpty = false; |
326 | d->mLabel = label; |
327 | } |
328 | |
329 | QString Address::label() const |
330 | { |
331 | return d->mLabel; |
332 | } |
333 | |
334 | QString Address::labelLabel() |
335 | { |
336 | return i18n("Delivery Label" ); |
337 | } |
338 | |
339 | Address::TypeList Address::typeList() |
340 | { |
341 | static TypeList list; |
342 | |
343 | if (list.isEmpty()) { |
344 | list << Dom << Intl << Postal << Parcel << Home << Work << Pref; |
345 | } |
346 | |
347 | return list; |
348 | } |
349 | |
350 | QString Address::typeFlagLabel(TypeFlag type) |
351 | { |
352 | switch (type) { |
353 | case Dom: |
354 | return i18nc("Address is in home country" , "Domestic" ); |
355 | case Intl: |
356 | return i18nc("Address is not in home country" , "International" ); |
357 | case Postal: |
358 | return i18nc("Address for delivering letters" , "Postal" ); |
359 | case Parcel: |
360 | return i18nc("Address for delivering packages" , "Parcel" ); |
361 | case Home: |
362 | return i18nc("Home Address" , "Home" ); |
363 | case Work: |
364 | return i18nc("Work Address" , "Work" ); |
365 | case Pref: |
366 | return i18n("Preferred Address" ); |
367 | } |
368 | return i18nc("another type of address" , "Other" ); |
369 | } |
370 | |
371 | void Address::setGeo(const Geo &geo) |
372 | { |
373 | d->mEmpty = false; |
374 | d->mGeo = geo; |
375 | } |
376 | |
377 | Geo Address::geo() const |
378 | { |
379 | return d->mGeo; |
380 | } |
381 | |
382 | QString Address::toString() const |
383 | { |
384 | QString str = QLatin1String("Address {\n" ); |
385 | str += QStringLiteral(" IsEmpty: %1\n" ).arg(a: d->mEmpty ? QStringLiteral("true" ) : QStringLiteral("false" )); |
386 | str += QStringLiteral(" Id: %1\n" ).arg(a: d->mId); |
387 | str += QStringLiteral(" Type: %1\n" ).arg(a: typeLabel(type: d->mType)); |
388 | str += QStringLiteral(" Post office box: %1\n" ).arg(a: d->mPostOfficeBox); |
389 | str += QStringLiteral(" Extended: %1\n" ).arg(a: d->mExtended); |
390 | str += QStringLiteral(" Street: %1\n" ).arg(a: d->mStreet); |
391 | str += QStringLiteral(" Locality: %1\n" ).arg(a: d->mLocality); |
392 | str += QStringLiteral(" Region: %1\n" ).arg(a: d->mRegion); |
393 | str += QStringLiteral(" Postal code: %1\n" ).arg(a: d->mPostalCode); |
394 | str += QStringLiteral(" Country: %1\n" ).arg(a: d->mCountry); |
395 | str += QStringLiteral(" Label: %1\n" ).arg(a: d->mLabel); |
396 | str += QStringLiteral(" Geo: %1\n" ).arg(a: d->mGeo.toString()); |
397 | str += QLatin1String("}\n" ); |
398 | |
399 | return str; |
400 | } |
401 | |
402 | QString Address::formatted(AddressFormatStyle style, const QString &realName, const QString &orgaName) const |
403 | { |
404 | const auto formatPref = (orgaName.isEmpty() || style != AddressFormatStyle::Postal) ? AddressFormatPreference::Generic : AddressFormatPreference::Business; |
405 | const auto format = AddressFormatRepository::formatForAddress(address: *this, formatPref); |
406 | return AddressFormatter::format(address: *this, name: realName, organization: orgaName, format, style); |
407 | } |
408 | |
409 | QString Address::formattedPostalAddress() const |
410 | { |
411 | return formatted(style: AddressFormatStyle::Postal); |
412 | } |
413 | |
414 | QUrl Address::geoUri() const |
415 | { |
416 | QUrl url; |
417 | url.setScheme(QStringLiteral("geo" )); |
418 | |
419 | if (geo().isValid()) { |
420 | url.setPath(path: QString::number(geo().latitude()) + QLatin1Char(',') + QString::number(geo().longitude())); |
421 | return url; |
422 | } |
423 | |
424 | if (!isEmpty()) { |
425 | url.setPath(QStringLiteral("0,0" )); |
426 | QUrlQuery query; |
427 | query.addQueryItem(QStringLiteral("q" ), value: formatted(style: KContacts::AddressFormatStyle::GeoUriQuery)); |
428 | url.setQuery(query); |
429 | return url; |
430 | } |
431 | |
432 | return {}; |
433 | } |
434 | |
435 | // clang-format off |
436 | QDataStream &KContacts::operator<<(QDataStream &s, const Address &addr) |
437 | { |
438 | return s << addr.d->mId << (uint)addr.d->mType << addr.d->mPostOfficeBox |
439 | << addr.d->mExtended << addr.d->mStreet << addr.d->mLocality |
440 | << addr.d->mRegion << addr.d->mPostalCode << addr.d->mCountry |
441 | << addr.d->mLabel << addr.d->mEmpty << addr.d->mGeo; |
442 | } |
443 | |
444 | QDataStream &KContacts::operator>>(QDataStream &s, Address &addr) |
445 | { |
446 | uint type; |
447 | s >> addr.d->mId >> type >> addr.d->mPostOfficeBox >> addr.d->mExtended |
448 | >> addr.d->mStreet >> addr.d->mLocality >> addr.d->mRegion |
449 | >> addr.d->mPostalCode >> addr.d->mCountry >> addr.d->mLabel |
450 | >> addr.d->mEmpty >> addr.d->mGeo; |
451 | |
452 | addr.d->mType = Address::Type(type); |
453 | |
454 | return s; |
455 | } |
456 | // clang-format on |
457 | |
458 | #include "moc_address.cpp" |
459 | |