1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtPositioning module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qgeoaddress.h"
41#include "qgeoaddress_p.h"
42
43#include <QtCore/QStringList>
44
45#ifdef QGEOADDRESS_DEBUG
46#include <QDebug>
47#endif
48
49QT_BEGIN_NAMESPACE
50
51/*
52 Combines a list of address parts into a single line.
53
54 The parts parameter contains both address elements such as city, state and so on
55 as well as separators such as spaces and commas.
56
57 It is expected that an element is always followed by a separator and the last
58 sepator is usually a new line delimeter.
59
60 For example: Springfield, 8900
61 would have four parts
62 ["Springfield", ", ", "8900", "<br>"]
63
64 The addressLine takes care of putting in separators appropriately or leaving
65 them out depending on whether the adjacent elements are present or not.
66 For example if city were empty in the above scenario the returned string is "8900<br>"
67 If the postal code was empty, returned string is "Springfield<br>"
68 If both city and postal code were empty, the returned string is "".
69*/
70static QString addressLine(const QStringList &parts)
71{
72 QString line;
73 Q_ASSERT(parts.count() % 2 == 0);
74
75 //iterate until just before the last pair
76 QString penultimateSeparator;
77 for (int i = 0; i < parts.count() - 2; i += 2) {
78 if (!parts.at(i).isEmpty()) {
79 line.append(s: parts.at(i) + parts.at(i: i + 1));
80 penultimateSeparator = parts.at(i: i + 1);
81 }
82 }
83
84 if (parts.at(i: parts.count() - 2).isEmpty()) {
85 line.chop(n: penultimateSeparator.length());
86
87 if (!line.isEmpty())
88 line.append(s: parts.at(i: parts.count() - 1));
89 } else {
90 line.append(s: parts.at(i: parts.count() - 2));
91 line.append(s: parts.at(i: parts.count() - 1));
92 }
93
94 return line;
95}
96
97/*
98 Returns a single formatted string representing the \a address. Lines of the address
99 are delimited by \a newLine. By default lines are delimited by <br/>. The \l
100 {QGeoAddress::countryCode} {countryCode} of the \a address determines the format of
101 the resultant string.
102*/
103static QString formattedAddress(const QGeoAddress &address,
104 const QString &newLine = QLatin1String("<br/>"))
105{
106 const QString Comma(QStringLiteral(", "));
107 const QString Dash(QStringLiteral("-"));
108 const QString Space(QStringLiteral(" "));
109
110 QString text;
111
112 if (address.countryCode() == QLatin1String("ALB")
113 || address.countryCode() == QLatin1String("MTQ")) {
114 text += addressLine(parts: QStringList() << address.street() << newLine);
115 text += addressLine(parts: QStringList() << address.postalCode() << Comma
116 << address.city() << newLine);
117 text += addressLine(parts: QStringList() << address.country() << newLine);
118 } else if (address.countryCode() == QLatin1String("AND")
119 || address.countryCode() == QLatin1String("AUT")
120 || address.countryCode() == QLatin1String("FRA")
121 || address.countryCode() == QLatin1String("GLP")
122 || address.countryCode() == QLatin1String("GUF")
123 || address.countryCode() == QLatin1String("ITA")
124 || address.countryCode() == QLatin1String("LUX")
125 || address.countryCode() == QLatin1String("MCO")
126 || address.countryCode() == QLatin1String("REU")
127 || address.countryCode() == QLatin1String("RUS")
128 || address.countryCode() == QLatin1String("SMR")
129 || address.countryCode() == QLatin1String("VAT")) {
130 text += addressLine(parts: QStringList() << address.street() << newLine);
131 text += addressLine(parts: QStringList() << address.postalCode() << Space
132 << address.city() << newLine);
133 text += addressLine(parts: QStringList() << address.country() << newLine);
134 } else if (address.countryCode() == QLatin1String("ARE")
135 || address.countryCode() == QLatin1String("BHS")) {
136 text += addressLine(parts: QStringList() << address.street() << newLine);
137 text += addressLine(parts: QStringList() << address.district() << Space
138 << address.city() << newLine);
139 text += addressLine(parts: QStringList() << address.country() << newLine);
140 } else if (address.countryCode() == QLatin1String("AUS")) {
141 text += addressLine(parts: QStringList() << address.street() << newLine);
142 text += addressLine(parts: QStringList() << (address.district().isEmpty() ? address.city() : address.district())
143 << Space << address.state() << Space << address.postalCode() << newLine);
144 text += addressLine(parts: QStringList() << address.country() << newLine);
145 } else if (address.countryCode() == QLatin1String("BHR")) {
146 text += addressLine(parts: QStringList() << address.street() << newLine);
147 text += addressLine(parts: QStringList() << address.district() << Comma
148 << address.city() << Comma << address.state() << newLine);
149 text += addressLine(parts: QStringList() << address.country() << newLine);
150 } else if (address.countryCode() == QLatin1String("BRA")) {
151 text += addressLine(parts: QStringList() << address.street() << newLine);
152 text += addressLine(parts: QStringList() << address.district() << Space
153 << address.city() << Dash << address.state() << Space << address.postalCode() << newLine);
154 text += addressLine(parts: QStringList() << address.country() << newLine);
155 } else if (address.countryCode() == QLatin1String("BRN")
156 || address.countryCode() == QLatin1String("JOR")
157 || address.countryCode() == QLatin1String("LBN")
158 || address.countryCode() == QLatin1String("NZL")) {
159 text += addressLine(parts: QStringList() << address.street() << newLine);
160 text += addressLine(parts: QStringList() << address.district() << Space
161 << address.city() << Space << address.postalCode() << newLine);
162 text += addressLine(parts: QStringList() << address.country() << newLine);
163 } else if (address.countryCode() == QLatin1String("CAN")
164 || address.countryCode() == QLatin1String("USA")
165 || address.countryCode() == QLatin1String("VIR")) {
166 text += addressLine(parts: QStringList() << address.street() << newLine);
167 text += addressLine(parts: QStringList() << address.city() << Comma << address.state() << Space
168 << address.postalCode() << newLine);
169 text += addressLine(parts: QStringList() << address.country() << newLine);
170 } else if (address.countryCode() == QLatin1String("CHN")) {
171 text += addressLine(parts: QStringList() << address.street() << Comma << address.city() << newLine);
172 text += addressLine(parts: QStringList() << address.postalCode() << Space << address.state() << newLine);
173 text += addressLine(parts: QStringList() << address.country() << newLine);
174 } else if (address.countryCode() == QLatin1String("CHL")) {
175 text += addressLine(parts: QStringList() << address.street() << newLine);
176 text += addressLine(parts: QStringList() << address.postalCode() << Space
177 << address.district() << Comma << address.city() << Comma
178 << address.state() << newLine);
179 text += addressLine(parts: QStringList() << address.country() << newLine);
180 } else if (address.countryCode() == QLatin1String("CYM")) {
181 text += addressLine(parts: QStringList() << address.street() << newLine);
182 text += addressLine(parts: QStringList() << address.state() << Space
183 << address.postalCode() << newLine);
184 text += addressLine(parts: QStringList() << address.country() << newLine);
185 } else if (address.countryCode() == QLatin1String("GBR")) {
186 text += addressLine(parts: QStringList() << address.street() << newLine);
187 text += addressLine(parts: QStringList() << address.district() << Comma
188 << address.city() << Comma << address.postalCode() << newLine);
189 text += addressLine(parts: QStringList() << address.country() << newLine);
190 } else if (address.countryCode() == QLatin1String("GIB")) {
191 text += addressLine(parts: QStringList() << address.street() << newLine);
192 text += addressLine(parts: QStringList() << address.city() << newLine);
193 text += addressLine(parts: QStringList() << address.country() << newLine);
194 } else if (address.countryCode() == QLatin1String("HKG")) {
195 text += addressLine(parts: QStringList() << address.street() << newLine);
196 text += addressLine(parts: QStringList() << address.district() << newLine);
197 text += addressLine(parts: QStringList() << address.city() << newLine);
198 } else if (address.countryCode() == QLatin1String("IND")) {
199 text += addressLine(parts: QStringList() << address.street() << newLine);
200 text += addressLine(parts: QStringList() << address.city() << Space << address.postalCode() << Space
201 << address.state() << newLine);
202 text += addressLine(parts: QStringList() << address.country() << newLine);
203 } else if (address.countryCode() == QLatin1String("IDN")
204 || address.countryCode() == QLatin1String("JEY")
205 || address.countryCode() == QLatin1String("LVA")) {
206 text += addressLine(parts: QStringList() << address.street() << newLine);
207 text += addressLine(parts: QStringList() << address.city() << Comma << address.postalCode() << newLine);
208 text += addressLine(parts: QStringList() << address.country() << newLine);
209 } else if (address.countryCode() == QLatin1String("IRL")) {
210 text += addressLine(parts: QStringList() << address.street() << newLine);
211 text += addressLine(parts: QStringList() << address.district() << Comma << address.state() << newLine);
212 text += addressLine(parts: QStringList() << address.country() << newLine);
213 } else if (address.countryCode() == QLatin1String("KWT")) {
214 text += addressLine(parts: QStringList() << address.street() << newLine);
215 text += addressLine(parts: QStringList() << address.postalCode() << Comma
216 << address.district() << Comma << address.city() << newLine);
217 text += addressLine(parts: QStringList() << address.country() << newLine);
218 } else if (address.countryCode() == QLatin1String("MLT")
219 || address.countryCode() == QLatin1String("SGP")
220 || address.countryCode() == QLatin1String("UKR")) {
221 text += addressLine(parts: QStringList() << address.street() << newLine);
222 text += addressLine(parts: QStringList() << address.city() << Space << address.postalCode() << newLine);
223 text += addressLine(parts: QStringList() << address.country() << newLine);
224 } else if (address.countryCode() == QLatin1String("MEX")) {
225 text += addressLine(parts: QStringList() << address.street() << newLine);
226 text += addressLine(parts: QStringList() << address.district() << newLine);
227 text += addressLine(parts: QStringList() << address.postalCode() << Space << address.city() << Comma
228 << address.state() << newLine);
229 text += addressLine(parts: QStringList() << address.country() << newLine);
230 } else if (address.countryCode() == QLatin1String("MYS")) {
231 text += addressLine(parts: QStringList() << address.street() << newLine);
232 text += addressLine(parts: QStringList() << address.postalCode() << Space << address.city() << newLine);
233 text += addressLine(parts: QStringList() << address.state() << newLine);
234 text += addressLine(parts: QStringList() << address.country() << newLine);
235 } else if (address.countryCode() == QLatin1String("OMN")) {
236 text += addressLine(parts: QStringList() << address.street() << newLine);
237 text += addressLine(parts: QStringList() << address.district() << Comma
238 << address.postalCode() << Comma
239 << address.city() << Comma
240 << address.country() << newLine);
241 } else if (address.countryCode() == QLatin1String("PRI")) {
242 text += addressLine(parts: QStringList() << address.street() << newLine);
243 text += addressLine(parts: QStringList() << address.district() << Comma << address.city() << Comma
244 << address.state() << Comma << address.postalCode() << newLine);
245 text += addressLine(parts: QStringList() << address.country() << newLine);
246 } else if (address.countryCode() == QLatin1String("QAT")) {
247 text += addressLine(parts: QStringList() << address.street() << newLine);
248 text += addressLine(parts: QStringList() << address.district() << Space << address.city() << Comma
249 << address.country() << newLine);
250 } else if (address.countryCode() == QLatin1String("SAU")) {
251 text += addressLine(parts: QStringList() << address.street() << Space << address.district() << newLine);
252 text += addressLine(parts: QStringList() << address.city() << Space << address.postalCode() << newLine);
253 text += addressLine(parts: QStringList() << address.country() << newLine);
254 } else if (address.countryCode() == QLatin1String("TWN")) {
255 text += addressLine(parts: QStringList() << address.street() << Comma
256 << address.district() << Comma << address.city() << newLine);
257 text += addressLine(parts: QStringList() << address.country() << newLine);
258 } else if (address.countryCode() == QLatin1String("THA")) {
259 text += addressLine(parts: QStringList() << address.street() << newLine);
260 text += addressLine(parts: QStringList() << address.district() << Comma << address.city() << Space
261 << address.postalCode() << newLine);
262 text += addressLine(parts: QStringList() << address.country() << newLine);
263 } else if (address.countryCode() == QLatin1String("TUR")) {
264 text += addressLine(parts: QStringList() << address.street() << newLine);
265 text += addressLine(parts: QStringList() << address.postalCode() << Space << address.district() << Comma
266 << address.city() << newLine);
267 text += addressLine(parts: QStringList() << address.country() << newLine);
268 } else if (address.countryCode() == QLatin1String("VEN")) {
269 text += addressLine(parts: QStringList() << address.street() << newLine);
270 text += addressLine(parts: QStringList() << address.city() << Space << address.postalCode() << Comma
271 << address.state() << newLine);
272 text += addressLine(parts: QStringList() << address.country() << newLine);
273 } else if (address.countryCode() == QLatin1String("ZAF")) {
274 text += addressLine(parts: QStringList() << address.street() << newLine);
275 text += addressLine(parts: QStringList() << address.district() << Comma << address.city() << newLine);
276 text += addressLine(parts: QStringList() << address.country() << newLine);
277 } else {
278 text += addressLine(parts: QStringList() << address.street() << newLine);
279 text += addressLine(parts: QStringList() << address.postalCode() << Space << address.city() << newLine);
280 text += addressLine(parts: QStringList() << address.country() << newLine);
281 }
282
283 text.chop(n: newLine.length());
284 return text;
285}
286
287QGeoAddressPrivate::QGeoAddressPrivate()
288 : QSharedData(),
289 m_autoGeneratedText(false)
290{
291}
292
293QGeoAddressPrivate::QGeoAddressPrivate(const QGeoAddressPrivate &other)
294 : QSharedData(other),
295 sCountry(other.sCountry),
296 sCountryCode(other.sCountryCode),
297 sState(other.sState),
298 sCounty(other.sCounty),
299 sCity(other.sCity),
300 sDistrict(other.sDistrict),
301 sStreet(other.sStreet),
302 sPostalCode(other.sPostalCode),
303 sText(other.sText),
304 m_autoGeneratedText(false)
305{
306}
307
308QGeoAddressPrivate::~QGeoAddressPrivate()
309{
310}
311
312/*!
313 \class QGeoAddress
314 \inmodule QtPositioning
315 \ingroup QtPositioning-positioning
316 \ingroup QtLocation-places-data
317 \ingroup QtLocation-places
318 \since 5.2
319
320 \brief The QGeoAddress class represents an address of a \l QGeoLocation.
321
322 The address' attributes are normalized to US feature names and can be mapped
323 to the local feature levels (for example State matches "Bundesland" in Germany).
324
325 The address contains a \l text() for displaying purposes and additional
326 properties to access the components of an address:
327
328 \list
329 \li QGeoAddress::country()
330 \li QGeoAddress::countryCode()
331 \li QGeoAddress::state()
332 \li QGeoAddress::city()
333 \li QGeoAddress::district()
334 \li QGeoAddress::street()
335 \li QGeoAddress::postalCode()
336 \endlist
337*/
338
339/*!
340 Default constructor.
341*/
342QGeoAddress::QGeoAddress()
343 : d(new QGeoAddressPrivate)
344{
345}
346
347/*!
348 Constructs a copy of \a other.
349*/
350QGeoAddress::QGeoAddress(const QGeoAddress &other)
351 : d(other.d)
352{
353}
354
355/*!
356 Destroys this address.
357*/
358QGeoAddress::~QGeoAddress()
359{
360}
361
362/*!
363 Assigns the given \a address to this address and
364 returns a reference to this address.
365*/
366QGeoAddress &QGeoAddress::operator=(const QGeoAddress & address)
367{
368 if (this == &address)
369 return *this;
370
371 d = address.d;
372 return *this;
373}
374
375/*!
376 Returns true if this address is equal to \a other,
377 otherwise returns false.
378*/
379bool QGeoAddress::operator==(const QGeoAddress &other) const
380{
381#ifdef QGEOADDRESS_DEBUG
382 qDebug() << "country" << (d->sCountry == other.country());
383 qDebug() << "countryCode" << (d->sCountryCode == other.countryCode());
384 qDebug() << "state:" << (d->sState == other.state());
385 qDebug() << "county:" << (d->sCounty == other.county());
386 qDebug() << "city:" << (d->sCity == other.city());
387 qDebug() << "district:" << (d->sDistrict == other.district());
388 qDebug() << "street:" << (d->sStreet == other.street());
389 qDebug() << "postalCode:" << (d->sPostalCode == other.postalCode());
390 qDebug() << "text:" << (text() == other.text());
391#endif
392
393 return d->sCountry == other.country() &&
394 d->sCountryCode == other.countryCode() &&
395 d->sState == other.state() &&
396 d->sCounty == other.county() &&
397 d->sCity == other.city() &&
398 d->sDistrict == other.district() &&
399 d->sStreet == other.street() &&
400 d->sPostalCode == other.postalCode() &&
401 this->text() == other.text();
402}
403
404/*!
405 \fn bool QGeoAddress::operator!=(const QGeoAddress &other) const
406
407 Returns true if this address is not equal to \a other,
408 otherwise returns false.
409*/
410
411/*!
412 Returns the address as a single formatted string. It is the recommended string
413 to use to display the address to the user. It typically takes the format of
414 an address as found on an envelope, but this is not always necessarily the case.
415
416 The address text is either automatically generated or explicitly assigned.
417 This can be determined by checking \l {QGeoAddress::isTextGenerated()} {isTextGenerated}.
418
419 If an empty string is provided to setText(), then isTextGenerated() will be set
420 to true and text() will return a string which is locally formatted according to
421 countryCode() and based on the elements of the address such as street, city and so on.
422 Because the text string is generated from the address elements, a sequence
423 of calls such as text(), setStreet(), text() may return different strings for each
424 invocation of text().
425
426 If a non-empty string is provided to setText(), then isTextGenerated() will be
427 set to false and text() will always return the explicitly assigned string.
428 Calls to modify other elements such as setStreet(), setCity() and so on will not
429 affect the resultant string from text().
430*/
431QString QGeoAddress::text() const
432{
433 if (d->sText.isEmpty())
434 return formattedAddress(address: *this);
435 else
436 return d->sText;
437}
438
439/*!
440 If \a text is not empty, explicitly assigns \a text as the string to be returned by
441 text(). isTextGenerated() will return false.
442
443 If \a text is empty, indicates that text() should be automatically generated
444 from the address elements. isTextGenerated() will return true.
445*/
446void QGeoAddress::setText(const QString &text)
447{
448 d->sText = text;
449}
450
451/*!
452 Returns the country name.
453*/
454QString QGeoAddress::country() const
455{
456 return d->sCountry;
457}
458
459/*!
460 Sets the \a country name.
461*/
462void QGeoAddress::setCountry(const QString &country)
463{
464 d->sCountry = country;
465}
466
467/*!
468 Returns the country code according to ISO 3166-1 alpha-3
469*/
470QString QGeoAddress::countryCode() const
471{
472 return d->sCountryCode;
473}
474
475/*!
476 Sets the \a countryCode according to ISO 3166-1 alpha-3
477*/
478void QGeoAddress::setCountryCode(const QString &countryCode)
479{
480 d->sCountryCode = countryCode;
481}
482
483/*!
484 Returns the state. The state is considered the first subdivision below country.
485*/
486QString QGeoAddress::state() const
487{
488 return d->sState;
489}
490
491/*!
492 Sets the \a state.
493*/
494void QGeoAddress::setState(const QString &state)
495{
496 d->sState = state;
497}
498
499/*!
500 Returns the county. The county is considered the second subdivision below country.
501*/
502QString QGeoAddress::county() const
503{
504 return d->sCounty;
505}
506
507/*!
508 Sets the \a county.
509*/
510void QGeoAddress::setCounty(const QString &county)
511{
512 d->sCounty = county;
513}
514
515/*!
516 Returns the city.
517*/
518QString QGeoAddress::city() const
519{
520 return d->sCity;
521}
522
523/*!
524 Sets the \a city.
525*/
526void QGeoAddress::setCity(const QString &city)
527{
528 d->sCity = city;
529}
530
531/*!
532 Returns the district. The district is considered the subdivison below city.
533*/
534QString QGeoAddress::district() const
535{
536 return d->sDistrict;
537}
538
539/*!
540 Sets the \a district.
541*/
542void QGeoAddress::setDistrict(const QString &district)
543{
544 d->sDistrict = district;
545}
546
547/*!
548 Returns the street-level component of the address.
549
550 This typically includes a street number and street name
551 but may also contain things like a unit number, a building
552 name, or anything else that might be used to
553 distinguish one address from another.
554*/
555QString QGeoAddress::street() const
556{
557 return d->sStreet;
558}
559
560/*!
561 Sets the street-level component of the address to \a street.
562
563 This typically includes a street number and street name
564 but may also contain things like a unit number, a building
565 name, or anything else that might be used to
566 distinguish one address from another.
567*/
568void QGeoAddress::setStreet(const QString &street)
569{
570 d->sStreet = street;
571}
572
573/*!
574 Returns the postal code.
575*/
576QString QGeoAddress::postalCode() const
577{
578 return d->sPostalCode;
579}
580
581/*!
582 Sets the \a postalCode.
583*/
584void QGeoAddress::setPostalCode(const QString &postalCode)
585{
586 d->sPostalCode = postalCode;
587}
588
589/*!
590 Returns whether this address is empty. An address is considered empty
591 if \e all of its fields are empty.
592*/
593bool QGeoAddress::isEmpty() const
594{
595 return d->sCountry.isEmpty() &&
596 d->sCountryCode.isEmpty() &&
597 d->sState.isEmpty() &&
598 d->sCounty.isEmpty() &&
599 d->sCity.isEmpty() &&
600 d->sDistrict.isEmpty() &&
601 d->sStreet.isEmpty() &&
602 d->sPostalCode.isEmpty() &&
603 d->sText.isEmpty();
604
605}
606
607/*!
608 Clears all of the address' data fields.
609*/
610void QGeoAddress::clear()
611{
612 d->sCountry.clear();
613 d->sCountryCode.clear();
614 d->sState.clear();
615 d->sCounty.clear();
616 d->sCity.clear();
617 d->sDistrict.clear();
618 d->sStreet.clear();
619 d->sPostalCode.clear();
620 d->sText.clear();
621}
622
623/*!
624 Returns true if QGeoAddress::text() is automatically generated from address elements,
625 otherwise returns false if text() has been explicitly assigned.
626
627 \sa text(), setText()
628*/
629bool QGeoAddress::isTextGenerated() const
630{
631 return d->sText.isEmpty();
632}
633
634QT_END_NAMESPACE
635
636

source code of qtlocation/src/positioning/qgeoaddress.cpp