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
24using namespace KContacts;
25
26class Q_DECL_HIDDEN Address::Private : public QSharedData
27{
28public:
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
67Address::Address()
68 : d(new Private)
69{
70}
71
72Address::Address(Type type)
73 : d(new Private)
74{
75 d->mType = type;
76}
77
78Address::Address(const Address &other)
79 : d(other.d)
80{
81}
82
83Address::~Address()
84{
85}
86
87Address &Address::operator=(const Address &other)
88{
89 if (this != &other) {
90 d = other.d;
91 }
92
93 return *this;
94}
95
96bool 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
136bool Address::operator!=(const Address &a) const
137{
138 return !(a == *this);
139}
140
141bool Address::isEmpty() const
142{
143 return d->mEmpty;
144}
145
146void Address::clear()
147{
148 *this = Address();
149}
150
151void Address::setId(const QString &id)
152{
153 d->mEmpty = false;
154 d->mId = id;
155}
156
157QString Address::id() const
158{
159 return d->mId;
160}
161
162void Address::setType(Type type)
163{
164 d->mEmpty = false;
165 d->mType = type;
166}
167
168Address::Type Address::type() const
169{
170 return d->mType;
171}
172
173QString 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
194QString 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
211void Address::setPostOfficeBox(const QString &postOfficeBox)
212{
213 d->mEmpty = false;
214 d->mPostOfficeBox = postOfficeBox;
215}
216
217QString Address::postOfficeBox() const
218{
219 return d->mPostOfficeBox;
220}
221
222QString Address::postOfficeBoxLabel()
223{
224 return i18n("Post Office Box");
225}
226
227void Address::setExtended(const QString &extended)
228{
229 d->mEmpty = false;
230 d->mExtended = extended;
231}
232
233QString Address::extended() const
234{
235 return d->mExtended;
236}
237
238QString Address::extendedLabel()
239{
240 return i18n("Extended Address Information");
241}
242
243void Address::setStreet(const QString &street)
244{
245 d->mEmpty = false;
246 d->mStreet = street;
247}
248
249QString Address::street() const
250{
251 return d->mStreet;
252}
253
254QString Address::streetLabel()
255{
256 return i18n("Street");
257}
258
259void Address::setLocality(const QString &locality)
260{
261 d->mEmpty = false;
262 d->mLocality = locality;
263}
264
265QString Address::locality() const
266{
267 return d->mLocality;
268}
269
270QString Address::localityLabel()
271{
272 return i18n("Locality");
273}
274
275void Address::setRegion(const QString &region)
276{
277 d->mEmpty = false;
278 d->mRegion = region;
279}
280
281QString Address::region() const
282{
283 return d->mRegion;
284}
285
286QString Address::regionLabel()
287{
288 return i18n("Region");
289}
290
291void Address::setPostalCode(const QString &postalCode)
292{
293 d->mEmpty = false;
294 d->mPostalCode = postalCode;
295}
296
297QString Address::postalCode() const
298{
299 return d->mPostalCode;
300}
301
302QString Address::postalCodeLabel()
303{
304 return i18n("Postal Code");
305}
306
307void Address::setCountry(const QString &country)
308{
309 d->mEmpty = false;
310 d->mCountry = country;
311}
312
313QString Address::country() const
314{
315 return d->mCountry;
316}
317
318QString Address::countryLabel()
319{
320 return i18n("Country");
321}
322
323void Address::setLabel(const QString &label)
324{
325 d->mEmpty = false;
326 d->mLabel = label;
327}
328
329QString Address::label() const
330{
331 return d->mLabel;
332}
333
334QString Address::labelLabel()
335{
336 return i18n("Delivery Label");
337}
338
339Address::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
350QString 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
371void Address::setGeo(const Geo &geo)
372{
373 d->mEmpty = false;
374 d->mGeo = geo;
375}
376
377Geo Address::geo() const
378{
379 return d->mGeo;
380}
381
382QString 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
402QString 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
409QString Address::formattedPostalAddress() const
410{
411 return formatted(style: AddressFormatStyle::Postal);
412}
413
414QUrl 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
436QDataStream &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
444QDataStream &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

source code of kcontacts/src/address.cpp