1 | /* |
2 | This file is part of libkabc. |
3 | Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> |
4 | |
5 | This library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Library General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2 of the License, or (at your option) any later version. |
9 | |
10 | This library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Library General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Library General Public License |
16 | along with this library; see the file COPYING.LIB. If not, write to |
17 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
18 | Boston, MA 02110-1301, USA. |
19 | */ |
20 | |
21 | #include "address.h" |
22 | |
23 | #include <krandom.h> |
24 | #include <kdebug.h> |
25 | #include <kglobal.h> |
26 | #include <klocale.h> |
27 | #include <klocalizedstring.h> |
28 | #include <kconfig.h> |
29 | #include <kstandarddirs.h> |
30 | #include <kconfiggroup.h> |
31 | |
32 | #include <QtCore/QFile> |
33 | #include <QtCore/QMap> |
34 | #include <QtCore/QTextStream> |
35 | #include <QtCore/QSharedData> |
36 | |
37 | using namespace KABC; |
38 | |
39 | // template tags for address formatting localization |
40 | #define KABC_FMTTAG_realname QString::fromLatin1("%n") |
41 | #define KABC_FMTTAG_REALNAME QString::fromLatin1("%N") |
42 | #define KABC_FMTTAG_company QString::fromLatin1("%cm") |
43 | #define KABC_FMTTAG_COMPANY QString::fromLatin1("%CM") |
44 | #define KABC_FMTTAG_pobox QString::fromLatin1("%p") |
45 | #define KABC_FMTTAG_street QString::fromLatin1("%s") |
46 | #define KABC_FMTTAG_STREET QString::fromLatin1("%S") |
47 | #define KABC_FMTTAG_zipcode QString::fromLatin1("%z") |
48 | #define KABC_FMTTAG_location QString::fromLatin1("%l") |
49 | #define KABC_FMTTAG_LOCATION QString::fromLatin1("%L") |
50 | #define KABC_FMTTAG_region QString::fromLatin1("%r") |
51 | #define KABC_FMTTAG_REGION QString::fromLatin1("%R") |
52 | #define KABC_FMTTAG_newline QString::fromLatin1("\\n") |
53 | #define KABC_FMTTAG_condcomma QString::fromLatin1("%,") |
54 | #define KABC_FMTTAG_condwhite QString::fromLatin1("%w") |
55 | #define KABC_FMTTAG_purgeempty QString::fromLatin1("%0") |
56 | |
57 | /** |
58 | Finds the balanced closing bracket starting from the opening bracket at |
59 | pos in tsection. |
60 | @return position of closing bracket, -1 for unbalanced brackets |
61 | */ |
62 | static int findBalancedBracket( const QString &tsection, int pos ) |
63 | { |
64 | int balancecounter = 0; |
65 | for ( int i = pos + 1; i < tsection.length(); ++i ) { |
66 | if ( QLatin1Char( ')' ) == tsection[i] && 0 == balancecounter ) { |
67 | // found end of brackets |
68 | return i; |
69 | } else { |
70 | if ( QLatin1Char( '(' ) == tsection[i] ) { |
71 | // nested brackets |
72 | balancecounter++; |
73 | } |
74 | } |
75 | } |
76 | return -1; |
77 | } |
78 | |
79 | /** |
80 | Parses a snippet of an address template |
81 | @param tsection the template string to be parsed |
82 | @param result QString reference in which the result will be stored |
83 | @return true if at least one tag evaluated positively, else false |
84 | */ |
85 | static bool parseAddressTemplateSection( const QString &tsection, QString &result, |
86 | const QString &realName, const QString &orgaName, |
87 | const KABC::Address &address ) |
88 | { |
89 | // This method first parses and substitutes any bracketed sections and |
90 | // after that replaces any tags with their values. If a bracketed section |
91 | // or a tag evaluate to zero, they are not just removed but replaced |
92 | // with a placeholder. This is because in the last step conditionals are |
93 | // resolved which depend on information about zero-evaluations. |
94 | result = tsection; |
95 | int stpos = 0; |
96 | bool ret = false; |
97 | |
98 | // first check for brackets that have to be evaluated first |
99 | int fpos = result.indexOf( KABC_FMTTAG_purgeempty, stpos ); |
100 | while ( -1 != fpos ) { |
101 | int bpos1 = fpos + KABC_FMTTAG_purgeempty.length(); |
102 | int bpos2; |
103 | // expect opening bracket and find next balanced closing bracket. If |
104 | // next char is no opening bracket, continue parsing (no valid tag) |
105 | if ( QLatin1Char( '(' ) == result[bpos1] ) { |
106 | bpos2 = findBalancedBracket( result, bpos1 ); |
107 | if ( -1 != bpos2 ) { |
108 | // we have balanced brackets, recursively parse: |
109 | QString rplstr; |
110 | bool purge = !parseAddressTemplateSection( result.mid( bpos1+1, |
111 | bpos2-bpos1-1 ), rplstr, |
112 | realName, orgaName, address ); |
113 | if ( purge ) { |
114 | // purge -> remove all |
115 | // replace with !_P_!, so conditional tags work later |
116 | result.replace( fpos, bpos2 - fpos + 1, QLatin1String( "!_P_!" ) ); |
117 | // leave stpos as it is |
118 | } else { |
119 | // no purge -> replace with recursively parsed string |
120 | result.replace( fpos, bpos2 - fpos + 1, rplstr ); |
121 | ret = true; |
122 | stpos = fpos + rplstr.length(); |
123 | } |
124 | } else { |
125 | // unbalanced brackets: keep on parsing (should not happen |
126 | // and will result in bad formatting) |
127 | stpos = bpos1; |
128 | } |
129 | } |
130 | fpos = result.indexOf( KABC_FMTTAG_purgeempty, stpos ); |
131 | } |
132 | |
133 | // after sorting out all purge tags, we just search'n'replace the rest, |
134 | // keeping track of whether at least one tag evaluates to something. |
135 | // The following macro needs QString for R_FIELD |
136 | // It substitutes !_P_! for empty fields so conditional tags work later |
137 | #define REPLTAG(R_TAG,R_FIELD) \ |
138 | if ( result.indexOf( R_TAG, false ) != -1 ) { \ |
139 | QString rpl = R_FIELD.isEmpty() ? QLatin1String( "!_P_!" ) : R_FIELD; \ |
140 | result.replace( R_TAG, rpl ); \ |
141 | if ( !R_FIELD.isEmpty() ) { \ |
142 | ret = true; \ |
143 | } \ |
144 | } |
145 | REPLTAG( KABC_FMTTAG_realname, realName ); |
146 | REPLTAG( KABC_FMTTAG_REALNAME, realName.toUpper() ); |
147 | REPLTAG( KABC_FMTTAG_company, orgaName ); |
148 | REPLTAG( KABC_FMTTAG_COMPANY, orgaName.toUpper() ); |
149 | REPLTAG( KABC_FMTTAG_pobox, address.postOfficeBox() ); |
150 | REPLTAG( KABC_FMTTAG_street, address.street() ); |
151 | REPLTAG( KABC_FMTTAG_STREET, address.street().toUpper() ); |
152 | REPLTAG( KABC_FMTTAG_zipcode, address.postalCode() ); |
153 | REPLTAG( KABC_FMTTAG_location, address.locality() ); |
154 | REPLTAG( KABC_FMTTAG_LOCATION, address.locality().toUpper() ); |
155 | REPLTAG( KABC_FMTTAG_region, address.region() ); |
156 | REPLTAG( KABC_FMTTAG_REGION, address.region().toUpper() ); |
157 | result.replace( KABC_FMTTAG_newline, QLatin1String( "\n" ) ); |
158 | #undef REPLTAG |
159 | |
160 | // conditional comma |
161 | fpos = result.indexOf( KABC_FMTTAG_condcomma, 0 ); |
162 | while ( -1 != fpos ) { |
163 | const QString str1 = result.mid( fpos - 5, 5 ); |
164 | const QString str2 = result.mid( fpos + 2, 5 ); |
165 | if ( str1 != QLatin1String( "!_P_!" ) && str2 != QLatin1String( "!_P_!" ) ) { |
166 | result.replace( fpos, 2, QLatin1String( ", " ) ); |
167 | } else { |
168 | result.remove( fpos, 2 ); |
169 | } |
170 | fpos = result.indexOf( KABC_FMTTAG_condcomma, fpos ); |
171 | } |
172 | // conditional whitespace |
173 | fpos = result.indexOf( KABC_FMTTAG_condwhite, 0 ); |
174 | while ( -1 != fpos ) { |
175 | const QString str1 = result.mid( fpos - 5, 5 ); |
176 | const QString str2 = result.mid( fpos + 2, 5 ); |
177 | if ( str1 != QLatin1String( "!_P_!" ) && str2 != QLatin1String( "!_P_!" ) ) { |
178 | result.replace( fpos, 2, QLatin1String( " " ) ); |
179 | } else { |
180 | result.remove( fpos, 2 ); |
181 | } |
182 | fpos = result.indexOf( KABC_FMTTAG_condwhite, fpos ); |
183 | } |
184 | |
185 | // remove purged: |
186 | result.remove( QLatin1String( "!_P_!" ) ); |
187 | |
188 | return ret; |
189 | } |
190 | |
191 | class Address::Private : public QSharedData |
192 | { |
193 | public: |
194 | Private() |
195 | : mEmpty( true ), mType( 0 ) |
196 | { |
197 | mId = KRandom::randomString( 10 ); |
198 | } |
199 | |
200 | Private( const Private &other ) |
201 | : QSharedData( other ) |
202 | { |
203 | mEmpty = other.mEmpty; |
204 | mId = other.mId; |
205 | mType = other.mType; |
206 | |
207 | mPostOfficeBox = other.mPostOfficeBox; |
208 | mExtended = other.mExtended; |
209 | mStreet = other.mStreet; |
210 | mLocality = other.mLocality; |
211 | mRegion = other.mRegion; |
212 | mPostalCode = other.mPostalCode; |
213 | mCountry = other.mCountry; |
214 | mLabel = other.mLabel; |
215 | } |
216 | |
217 | bool mEmpty; |
218 | QString mId; |
219 | Type mType; |
220 | |
221 | QString mPostOfficeBox; |
222 | QString mExtended; |
223 | QString mStreet; |
224 | QString mLocality; |
225 | QString mRegion; |
226 | QString mPostalCode; |
227 | QString mCountry; |
228 | QString mLabel; |
229 | }; |
230 | |
231 | Address::Address() |
232 | : d( new Private ) |
233 | { |
234 | } |
235 | |
236 | Address::Address( Type type ) |
237 | : d( new Private ) |
238 | { |
239 | d->mType = type; |
240 | } |
241 | |
242 | Address::Address( const Address &other ) |
243 | : d( other.d ) |
244 | { |
245 | } |
246 | |
247 | Address::~Address() |
248 | { |
249 | } |
250 | |
251 | Address &Address::operator=( const Address &other ) |
252 | { |
253 | if ( this != &other ) { |
254 | d = other.d; |
255 | } |
256 | |
257 | return *this; |
258 | } |
259 | |
260 | bool Address::operator==( const Address &other ) const |
261 | { |
262 | if ( d->mId != other.d->mId ) { |
263 | return false; |
264 | } |
265 | if ( d->mType != other.d->mType ) { |
266 | return false; |
267 | } |
268 | if ( d->mPostOfficeBox != other.d->mPostOfficeBox ) { |
269 | return false; |
270 | } |
271 | if ( d->mExtended != other.d->mExtended ) { |
272 | return false; |
273 | } |
274 | if ( d->mStreet != other.d->mStreet ) { |
275 | return false; |
276 | } |
277 | if ( d->mLocality != other.d->mLocality ) { |
278 | return false; |
279 | } |
280 | if ( d->mRegion != other.d->mRegion ) { |
281 | return false; |
282 | } |
283 | if ( d->mPostalCode != other.d->mPostalCode ) { |
284 | return false; |
285 | } |
286 | if ( d->mCountry != other.d->mCountry ) { |
287 | return false; |
288 | } |
289 | if ( d->mLabel != other.d->mLabel ) { |
290 | return false; |
291 | } |
292 | |
293 | return true; |
294 | } |
295 | |
296 | bool Address::operator!=( const Address &a ) const |
297 | { |
298 | return !( a == *this ); |
299 | } |
300 | |
301 | bool Address::isEmpty() const |
302 | { |
303 | return d->mEmpty; |
304 | } |
305 | |
306 | void Address::clear() |
307 | { |
308 | *this = Address(); |
309 | } |
310 | |
311 | void Address::setId( const QString &id ) |
312 | { |
313 | d->mEmpty = false; |
314 | d->mId = id; |
315 | } |
316 | |
317 | QString Address::id() const |
318 | { |
319 | return d->mId; |
320 | } |
321 | |
322 | void Address::setType( Type type ) |
323 | { |
324 | d->mEmpty = false; |
325 | d->mType = type; |
326 | } |
327 | |
328 | Address::Type Address::type() const |
329 | { |
330 | return d->mType; |
331 | } |
332 | |
333 | QString Address::typeLabel() const |
334 | { |
335 | QString label; |
336 | bool first = true; |
337 | |
338 | const TypeList list = typeList(); |
339 | |
340 | TypeList::ConstIterator it; |
341 | for ( it = list.begin(); it != list.end(); ++it ) { |
342 | if ( ( type() & ( *it ) ) && ( ( *it ) != Pref ) ) { |
343 | if ( !first ) { |
344 | label.append( QLatin1Char( '/' ) ); |
345 | } |
346 | label.append( typeLabel( *it ) ); |
347 | if ( first ) { |
348 | first = false; |
349 | } |
350 | } |
351 | } |
352 | |
353 | return label; |
354 | } |
355 | |
356 | void Address::setPostOfficeBox( const QString &postOfficeBox ) |
357 | { |
358 | d->mEmpty = false; |
359 | d->mPostOfficeBox = postOfficeBox; |
360 | } |
361 | |
362 | QString Address::postOfficeBox() const |
363 | { |
364 | return d->mPostOfficeBox; |
365 | } |
366 | |
367 | QString Address::postOfficeBoxLabel() |
368 | { |
369 | return i18n( "Post Office Box" ); |
370 | } |
371 | |
372 | void Address::setExtended( const QString &extended ) |
373 | { |
374 | d->mEmpty = false; |
375 | d->mExtended = extended; |
376 | } |
377 | |
378 | QString Address::extended() const |
379 | { |
380 | return d->mExtended; |
381 | } |
382 | |
383 | QString Address::extendedLabel() |
384 | { |
385 | return i18n( "Extended Address Information" ); |
386 | } |
387 | |
388 | void Address::setStreet( const QString &street ) |
389 | { |
390 | d->mEmpty = false; |
391 | d->mStreet = street; |
392 | } |
393 | |
394 | QString Address::street() const |
395 | { |
396 | return d->mStreet; |
397 | } |
398 | |
399 | QString Address::streetLabel() |
400 | { |
401 | return i18n( "Street" ); |
402 | } |
403 | |
404 | void Address::setLocality( const QString &locality ) |
405 | { |
406 | d->mEmpty = false; |
407 | d->mLocality = locality; |
408 | } |
409 | |
410 | QString Address::locality() const |
411 | { |
412 | return d->mLocality; |
413 | } |
414 | |
415 | QString Address::localityLabel() |
416 | { |
417 | return i18n( "Locality" ); |
418 | } |
419 | |
420 | void Address::setRegion( const QString ®ion ) |
421 | { |
422 | d->mEmpty = false; |
423 | d->mRegion = region; |
424 | } |
425 | |
426 | QString Address::region() const |
427 | { |
428 | return d->mRegion; |
429 | } |
430 | |
431 | QString Address::regionLabel() |
432 | { |
433 | return i18n( "Region" ); |
434 | } |
435 | |
436 | void Address::setPostalCode( const QString &postalCode ) |
437 | { |
438 | d->mEmpty = false; |
439 | d->mPostalCode = postalCode; |
440 | } |
441 | |
442 | QString Address::postalCode() const |
443 | { |
444 | return d->mPostalCode; |
445 | } |
446 | |
447 | QString Address::postalCodeLabel() |
448 | { |
449 | return i18n( "Postal Code" ); |
450 | } |
451 | |
452 | void Address::setCountry( const QString &country ) |
453 | { |
454 | d->mEmpty = false; |
455 | d->mCountry = country; |
456 | } |
457 | |
458 | QString Address::country() const |
459 | { |
460 | return d->mCountry; |
461 | } |
462 | |
463 | QString Address::countryLabel() |
464 | { |
465 | return i18n( "Country" ); |
466 | } |
467 | |
468 | void Address::setLabel( const QString &label ) |
469 | { |
470 | d->mEmpty = false; |
471 | d->mLabel = label; |
472 | } |
473 | |
474 | QString Address::label() const |
475 | { |
476 | return d->mLabel; |
477 | } |
478 | |
479 | QString Address::labelLabel() |
480 | { |
481 | return i18n( "Delivery Label" ); |
482 | } |
483 | |
484 | Address::TypeList Address::typeList() |
485 | { |
486 | static TypeList list; |
487 | |
488 | if ( list.isEmpty() ) { |
489 | list << Dom << Intl << Postal << Parcel << Home << Work << Pref; |
490 | } |
491 | |
492 | return list; |
493 | } |
494 | |
495 | QString Address::typeLabel( Type type ) |
496 | { |
497 | if ( type & Pref ) { |
498 | return i18nc( "Preferred address" , "Preferred" ); |
499 | } |
500 | |
501 | switch ( type ) { |
502 | case Dom: |
503 | return i18nc( "Address is in home country" , "Domestic" ); |
504 | break; |
505 | case Intl: |
506 | return i18nc( "Address is not in home country" , "International" ); |
507 | break; |
508 | case Postal: |
509 | return i18nc( "Address for delivering letters" , "Postal" ); |
510 | break; |
511 | case Parcel: |
512 | return i18nc( "Address for delivering packages" , "Parcel" ); |
513 | break; |
514 | case Home: |
515 | return i18nc( "Home Address" , "Home" ); |
516 | break; |
517 | case Work: |
518 | return i18nc( "Work Address" , "Work" ); |
519 | break; |
520 | case Pref: |
521 | return i18n( "Preferred Address" ); |
522 | break; |
523 | default: |
524 | return i18nc( "another type of address" , "Other" ); |
525 | break; |
526 | } |
527 | } |
528 | |
529 | QString Address::toString() const |
530 | { |
531 | QString str; |
532 | |
533 | str += QLatin1String( "Address {\n" ); |
534 | str += QString::fromLatin1( " IsEmpty: %1\n" ). |
535 | arg( d->mEmpty ? QLatin1String( "true" ) : QLatin1String( "false" ) ); |
536 | str += QString::fromLatin1( " Id: %1\n" ).arg( d->mId ); |
537 | str += QString::fromLatin1( " Type: %1\n" ).arg( typeLabel( d->mType ) ); |
538 | str += QString::fromLatin1( " Post office box: %1\n" ).arg( d->mPostOfficeBox ); |
539 | str += QString::fromLatin1( " Extended: %1\n" ).arg( d->mExtended ); |
540 | str += QString::fromLatin1( " Street: %1\n" ).arg( d->mStreet ); |
541 | str += QString::fromLatin1( " Locality: %1\n" ).arg( d->mLocality ); |
542 | str += QString::fromLatin1( " Region: %1\n" ).arg( d->mRegion ); |
543 | str += QString::fromLatin1( " Postal code: %1\n" ).arg( d->mPostalCode ); |
544 | str += QString::fromLatin1( " Country: %1\n" ).arg( d->mCountry ); |
545 | str += QString::fromLatin1( " Label: %1\n" ).arg( d->mLabel ); |
546 | str += QLatin1String( "}\n" ); |
547 | |
548 | return str; |
549 | } |
550 | |
551 | QString Address::formattedAddress( const QString &realName, |
552 | const QString &orgaName ) const |
553 | { |
554 | QString ciso; |
555 | QString addrTemplate; |
556 | QString ret; |
557 | |
558 | // FIXME: first check for iso-country-field and prefer that one |
559 | if ( !country().isEmpty() ) { |
560 | ciso = countryToISO( country() ); |
561 | } else { |
562 | // fall back to our own country |
563 | ciso = KGlobal::locale()->country(); |
564 | } |
565 | KConfig entry( KStandardDirs::locate( "locale" , |
566 | QLatin1String( "l10n/" ) + ciso + QLatin1String( "/entry.desktop" ) ) ); |
567 | |
568 | KConfigGroup group = entry.group( "KCM Locale" ); |
569 | // decide whether this needs special business address formatting |
570 | if ( orgaName.isEmpty() ) { |
571 | addrTemplate = group.readEntry( "AddressFormat" ); |
572 | } else { |
573 | addrTemplate = group.readEntry( "BusinessAddressFormat" ); |
574 | if ( addrTemplate.isEmpty() ) { |
575 | addrTemplate = group.readEntry( "AddressFormat" ); |
576 | } |
577 | } |
578 | |
579 | // in the case there's no format found at all, default to what we've always |
580 | // used: |
581 | if ( addrTemplate.isEmpty() ) { |
582 | kWarning( 5700 ) << "address format database incomplete" |
583 | << "(no format for locale" << ciso |
584 | << "found). Using default address formatting." ; |
585 | addrTemplate = QLatin1String( "%0(%n\\n)%0(%cm\\n)%0(%s\\n)%0(PO BOX %p\\n)%0(%l%w%r)%,%z" ); |
586 | } |
587 | |
588 | // scan |
589 | parseAddressTemplateSection( addrTemplate, ret, realName, orgaName, *this ); |
590 | |
591 | // now add the country line if needed (formatting this time according to |
592 | // the rules of our own system country ) |
593 | if ( !country().isEmpty() ) { |
594 | KConfig entry( KStandardDirs::locate( "locale" , QLatin1String( "l10n/" ) + |
595 | KGlobal::locale()->country() + |
596 | QLatin1String( "/entry.desktop" ) ) ); |
597 | KConfigGroup group = entry.group( "KCM Locale" ); |
598 | QString cpos = group.readEntry( "AddressCountryPosition" ); |
599 | if ( QLatin1String( "BELOW" ) == cpos || cpos.isEmpty() ) { |
600 | ret = ret + QLatin1String( "\n\n" ) + country().toUpper(); |
601 | } else if ( QLatin1String( "below" ) == cpos ) { |
602 | ret = ret + QLatin1String( "\n\n" ) + country(); |
603 | } else if ( QLatin1String( "ABOVE" ) == cpos ) { |
604 | ret = country().toUpper() + QLatin1String( "\n\n" ) + ret; |
605 | } else if ( QLatin1String( "above" ) == cpos ) { |
606 | ret = country() + QLatin1String( "\n\n" ) + ret; |
607 | } |
608 | } |
609 | |
610 | return ret; |
611 | } |
612 | |
613 | QString Address::countryToISO( const QString &cname ) |
614 | { |
615 | // we search a map file for translations from country names to |
616 | // iso codes, storing caching things in a QMap for faster future |
617 | // access. |
618 | typedef QMap<QString, QString> stringMap; |
619 | K_GLOBAL_STATIC( stringMap, sISOMap ) |
620 | |
621 | QMap<QString, QString>::ConstIterator it; |
622 | it = sISOMap->constFind( cname ); |
623 | if ( it != sISOMap->constEnd() ) { |
624 | return it.value(); |
625 | } |
626 | |
627 | QString mapfile = KGlobal::dirs()->findResource( "data" , |
628 | QLatin1String( "kabc/countrytransl.map" ) ); |
629 | |
630 | QFile file( mapfile ); |
631 | if ( file.open( QIODevice::ReadOnly ) ) { |
632 | QTextStream s( &file ); |
633 | QString strbuf = s.readLine(); |
634 | while ( !strbuf.isEmpty() ) { |
635 | QStringList countryInfo = strbuf.split( QLatin1Char( '\t' ), QString::KeepEmptyParts ); |
636 | if ( countryInfo[ 0 ] == cname ) { |
637 | file.close(); |
638 | sISOMap->insert( cname, countryInfo[ 1 ] ); |
639 | return countryInfo[ 1 ]; |
640 | } |
641 | strbuf = s.readLine(); |
642 | } |
643 | file.close(); |
644 | } |
645 | |
646 | // fall back to system country |
647 | sISOMap->insert( cname, KGlobal::locale()->country() ); |
648 | return KGlobal::locale()->country(); |
649 | } |
650 | |
651 | QString Address::ISOtoCountry( const QString &ISOname ) |
652 | { |
653 | // get country name from ISO country code (e.g. "no" -> i18n("Norway")) |
654 | if ( ISOname.simplified().isEmpty() ) { |
655 | return QString(); |
656 | } |
657 | |
658 | QString mapfile = KGlobal::dirs()->findResource( "data" , |
659 | QLatin1String( "kabc/countrytransl.map" ) ); |
660 | |
661 | QFile file( mapfile ); |
662 | if ( file.open( QIODevice::ReadOnly ) ) { |
663 | QTextStream s( &file ); |
664 | QString searchStr = QLatin1Char( '\t' ) + ISOname.simplified().toLower(); |
665 | QString strbuf = s.readLine(); |
666 | int pos; |
667 | while ( !strbuf.isEmpty() ) { |
668 | if ( ( pos = strbuf.indexOf( searchStr ) ) != -1 ) { |
669 | file.close(); |
670 | return i18n( strbuf.left( pos ).toUtf8() ); |
671 | } |
672 | strbuf = s.readLine(); |
673 | } |
674 | file.close(); |
675 | } |
676 | |
677 | return ISOname; |
678 | } |
679 | |
680 | QDataStream &KABC::operator<<( QDataStream &s, const Address &addr ) |
681 | { |
682 | return s << addr.d->mId << (uint)addr.d->mType << addr.d->mPostOfficeBox |
683 | << addr.d->mExtended << addr.d->mStreet << addr.d->mLocality |
684 | << addr.d->mRegion << addr.d->mPostalCode << addr.d->mCountry |
685 | << addr.d->mLabel << addr.d->mEmpty; |
686 | } |
687 | |
688 | QDataStream &KABC::operator>>( QDataStream &s, Address &addr ) |
689 | { |
690 | uint type; |
691 | s >> addr.d->mId >> type >> addr.d->mPostOfficeBox >> addr.d->mExtended |
692 | >> addr.d->mStreet >> addr.d->mLocality >> addr.d->mRegion |
693 | >> addr.d->mPostalCode >> addr.d->mCountry >> addr.d->mLabel |
694 | >> addr.d->mEmpty; |
695 | |
696 | addr.d->mType = Address::Type( type ); |
697 | |
698 | return s; |
699 | } |
700 | |