• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.10.5 API Reference
  • KDE Home
  • Contact Us
 

kabc

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

KDE's Doxygen guidelines are available online.

kabc

Skip menu "kabc"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Related Pages

kdepimlibs-4.10.5 API Reference

Skip menu "kdepimlibs-4.10.5 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal