| # kabc Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# address.cpp

    00001 /*
    00002     This file is part of libkabc.
    00003     Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
    00004
    00005     This library is free software; you can redistribute it and/or
    00006     modify it under the terms of the GNU Library General Public
    00007     License as published by the Free Software Foundation; either
    00008     version 2 of the License, or (at your option) any later version.
    00009
    00010     This library is distributed in the hope that it will be useful,
    00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
    00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00013     Library General Public License for more details.
    00014
    00015     You should have received a copy of the GNU Library General Public License
    00016     along with this library; see the file COPYING.LIB.  If not, write to
    00017     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00018     Boston, MA 02111-1307, USA.
    00019 */
    00020
    00021 #include "address.h"
    00022
    00023 #include <kapplication.h>
    00024 #include <kdebug.h>
    00025 #include <klocale.h>
    00026 #include <ksimpleconfig.h>
    00027 #include <kstandarddirs.h>
    00028 #include <kstaticdeleter.h>
    00029
    00030 #include <qfile.h>
    00031
    00032 using namespace KABC;
    00033
    00034 QMap<QString, QString> *Address::mISOMap = 0;
    00035 static KStaticDeleter< QMap<QString, QString> > isoMapDeleter;
    00036
    00037 Address::Address() :
    00038   mEmpty( true ), mType( 0 )
    00039 {
    00040   mId = KApplication::randomString( 10 );
    00041 }
    00042
    00043 Address::Address( int type ) :
    00044   mEmpty( true ), mType( type )
    00045 {
    00046   mId = KApplication::randomString( 10 );
    00047 }
    00048
    00049 bool Address::operator==( const Address &a ) const
    00050 {
    00051   if ( mPostOfficeBox != a.mPostOfficeBox ) return false;
    00052   if ( mExtended != a.mExtended ) return false;
    00053   if ( mStreet != a.mStreet ) return false;
    00054   if ( mLocality != a.mLocality ) return false;
    00055   if ( mRegion != a.mRegion ) return false;
    00056   if ( mPostalCode != a.mPostalCode ) return false;
    00057   if ( mCountry != a.mCountry ) return false;
    00058   if ( mLabel != a.mLabel ) return false;
    00059
    00060   return true;
    00061 }
    00062
    00063 bool Address::operator!=( const Address &a ) const
    00064 {
    00065   return !( a == *this );
    00066 }
    00067
    00068 bool Address::isEmpty() const
    00069 {
    00070   if ( mPostOfficeBox.isEmpty() &&
    00071        mExtended.isEmpty() &&
    00072        mStreet.isEmpty() &&
    00073        mLocality.isEmpty() &&
    00074        mRegion.isEmpty() &&
    00075        mPostalCode.isEmpty() &&
    00076        mCountry.isEmpty() &&
    00077        mLabel.isEmpty() ) {
    00078     return true;
    00079   }
    00080   return false;
    00081 }
    00082
    00083 void Address::clear()
    00084 {
    00085   *this = Address();
    00086 }
    00087
    00088 void Address::setId( const QString &id )
    00089 {
    00090   mEmpty = false;
    00091
    00092   mId = id;
    00093 }
    00094
    00095 QString Address::id() const
    00096 {
    00097   return mId;
    00098 }
    00099
    00100 void Address::setType( int type )
    00101 {
    00102   mEmpty = false;
    00103
    00104   mType = type;
    00105 }
    00106
    00107 int Address::type() const
    00108 {
    00109   return mType;
    00110 }
    00111
    00112 QString Address::typeLabel() const
    00113 {
    00114   QString label;
    00115   bool first = true;
    00116
    00117   const TypeList list = typeList();
    00118
    00119   TypeList::ConstIterator it;
    00120   for ( it = list.begin(); it != list.end(); ++it ) {
    00121     if ( ( type() & (*it) ) && ( (*it) != Pref ) ) {
    00122       label.append( ( first ? "" : "/" ) + typeLabel( *it ) );
    00123       if ( first )
    00124         first = false;
    00125     }
    00126   }
    00127
    00128   return label;
    00129 }
    00130
    00131 void Address::setPostOfficeBox( const QString &s )
    00132 {
    00133   mEmpty = false;
    00134
    00135   mPostOfficeBox = s;
    00136 }
    00137
    00138 QString Address::postOfficeBox() const
    00139 {
    00140   return mPostOfficeBox;
    00141 }
    00142
    00143 QString Address::postOfficeBoxLabel()
    00144 {
    00145   return i18n("Post Office Box");
    00146 }
    00147
    00148
    00149 void Address::setExtended( const QString &s )
    00150 {
    00151   mEmpty = false;
    00152
    00153   mExtended = s;
    00154 }
    00155
    00156 QString Address::extended() const
    00157 {
    00158   return mExtended;
    00159 }
    00160
    00161 QString Address::extendedLabel()
    00162 {
    00163   return i18n("Extended Address Information");
    00164 }
    00165
    00166
    00167 void Address::setStreet( const QString &s )
    00168 {
    00169   mEmpty = false;
    00170
    00171   mStreet = s;
    00172 }
    00173
    00174 QString Address::street() const
    00175 {
    00176   return mStreet;
    00177 }
    00178
    00179 QString Address::streetLabel()
    00180 {
    00181   return i18n("Street");
    00182 }
    00183
    00184
    00185 void Address::setLocality( const QString &s )
    00186 {
    00187   mEmpty = false;
    00188
    00189   mLocality = s;
    00190 }
    00191
    00192 QString Address::locality() const
    00193 {
    00194   return mLocality;
    00195 }
    00196
    00197 QString Address::localityLabel()
    00198 {
    00199   return i18n("Locality");
    00200 }
    00201
    00202
    00203 void Address::setRegion( const QString &s )
    00204 {
    00205   mEmpty = false;
    00206
    00207   mRegion = s;
    00208 }
    00209
    00210 QString Address::region() const
    00211 {
    00212   return mRegion;
    00213 }
    00214
    00215 QString Address::regionLabel()
    00216 {
    00217   return i18n("Region");
    00218 }
    00219
    00220
    00221 void Address::setPostalCode( const QString &s )
    00222 {
    00223   mEmpty = false;
    00224
    00225   mPostalCode = s;
    00226 }
    00227
    00228 QString Address::postalCode() const
    00229 {
    00230   return mPostalCode;
    00231 }
    00232
    00233 QString Address::postalCodeLabel()
    00234 {
    00235   return i18n("Postal Code");
    00236 }
    00237
    00238
    00239 void Address::setCountry( const QString &s )
    00240 {
    00241   mEmpty = false;
    00242
    00243   mCountry = s;
    00244 }
    00245
    00246 QString Address::country() const
    00247 {
    00248   return mCountry;
    00249 }
    00250
    00251 QString Address::countryLabel()
    00252 {
    00253   return i18n("Country");
    00254 }
    00255
    00256
    00257 void Address::setLabel( const QString &s )
    00258 {
    00259   mEmpty = false;
    00260
    00261   mLabel = s;
    00262 }
    00263
    00264 QString Address::label() const
    00265 {
    00266   return mLabel;
    00267 }
    00268
    00269 QString Address::labelLabel()
    00270 {
    00271   return i18n("Delivery Label");
    00272 }
    00273
    00274 Address::TypeList Address::typeList()
    00275 {
    00276   static TypeList list;
    00277
    00278   if ( list.isEmpty() )
    00279     list << Dom << Intl << Postal << Parcel << Home << Work << Pref;
    00280
    00281   return list;
    00282 }
    00283
    00284 QString Address::typeLabel( int type )
    00285 {
    00286   if ( type & Pref )
    00287     return i18n( "Preferred address", "Preferred" );
    00288
    00289   switch ( type ) {
    00290     case Dom:
    00291       return i18n("Domestic");
    00292       break;
    00293     case Intl:
    00294       return i18n("International");
    00295       break;
    00296     case Postal:
    00297       return i18n("Postal");
    00298       break;
    00299     case Parcel:
    00300       return i18n("Parcel");
    00301       break;
    00302     case Home:
    00303       return i18n("Home Address", "Home");
    00304       break;
    00305     case Work:
    00306       return i18n("Work Address", "Work");
    00307       break;
    00308     case Pref:
    00309       return i18n("Preferred Address");
    00310       break;
    00311     default:
    00312       return i18n("Other");
    00313       break;
    00314   }
    00315 }
    00316
    00317 void Address::dump() const
    00318 {
    00319   kdDebug(5700) << "  Address {" << endl;
    00320   kdDebug(5700) << "    Id: " << id() << endl;
    00321   kdDebug(5700) << "    Extended: " << extended() << endl;
    00322   kdDebug(5700) << "    Street: " << street() << endl;
    00323   kdDebug(5700) << "    Postal Code: " << postalCode() << endl;
    00324   kdDebug(5700) << "    Locality: " << locality() << endl;
    00325   kdDebug(5700) << "  }" << endl;
    00326 }
    00327
    00328
    00329 QString Address::formattedAddress( const QString &realName,
    00330                                    const QString &orgaName ) const
    00331 {
    00332   QString ciso;
    00333   QString addrTemplate;
    00334   QString ret;
    00335
    00336   // FIXME: first check for iso-country-field and prefer that one
    00337   if ( !country().isEmpty() ) {
    00338     ciso = countryToISO( country() );
    00339   } else {
    00340     // fall back to our own country
    00341     ciso = KGlobal::locale()->country();
    00342   }
    00343   KSimpleConfig entry( locate( "locale",
    00344         QString( "l10n/" ) + ciso + QString( "/entry.desktop" ) ) );
    00345   entry.setGroup( "KCM Locale" );
    00346
    00347   // decide whether this needs special business address formatting
    00348   if ( orgaName.isNull() ) {
    00349     addrTemplate = entry.readEntry( "AddressFormat" );
    00350   } else {
    00351     addrTemplate = entry.readEntry( "BusinessAddressFormat" );
    00352     if ( addrTemplate.isEmpty() )
    00353       addrTemplate = entry.readEntry( "AddressFormat" );
    00354   }
    00355
    00356   // in the case there's no format found at all, default to what we've always
    00357   // used:
    00358   if ( addrTemplate.isEmpty() ) {
    00359     kdWarning(5700) << "address format database incomplete "
    00360         << "(no format for locale " << ciso
    00361         << " found). Using default address formatting." << endl;
    00362     addrTemplate = "%0(%n\\n)%0(%cm\\n)%0(%s\\n)%0(PO BOX %p\\n)%0(%l%w%r)%,%z";
    00363   }
    00364
    00365   // scan
    00366   parseAddressTemplateSection( addrTemplate, ret, realName, orgaName );
    00367
    00368   // now add the country line if needed (formatting this time according to
    00369   // the rules of our own system country )
    00370   if ( !country().isEmpty() ) {
    00371     KSimpleConfig entry( locate( "locale", QString( "l10n/" )
    00372           + KGlobal::locale()->country() + QString( "/entry.desktop" ) ) );
    00373     entry.setGroup( "KCM Locale" );
    00374     QString cpos = entry.readEntry( "AddressCountryPosition" );
    00375     if ( "BELOW" == cpos || cpos.isEmpty() ) {
    00376       ret = ret + "\n\n" + country().upper();
    00377     } else if ( "below" == cpos ) {
    00378       ret = ret + "\n\n" + country();
    00379     } else if ( "ABOVE" == cpos ) {
    00380       ret = country().upper() + "\n\n" + ret;
    00381     } else if ( "above" == cpos ) {
    00382       ret = country() + "\n\n" + ret;
    00383     }
    00384   }
    00385
    00386   return ret;
    00387 }
    00388
    00389 bool Address::parseAddressTemplateSection( const QString &tsection,
    00390     QString &result, const QString &realName, const QString &orgaName ) const
    00391 {
    00392   // This method first parses and substitutes any bracketed sections and
    00393   // after that replaces any tags with their values. If a bracketed section
    00394   // or a tag evaluate to zero, they are not just removed but replaced
    00395   // with a placeholder. This is because in the last step conditionals are
    00396   // resolved which depend on information about zero-evaluations.
    00397   result = tsection;
    00398   int stpos = 0;
    00399   bool ret = false;
    00400
    00401   // first check for brackets that have to be evaluated first
    00402   int fpos = result.find( KABC_FMTTAG_purgeempty, stpos );
    00403   while ( -1 != fpos ) {
    00404     int bpos1 = fpos + KABC_FMTTAG_purgeempty.length();
    00405     int bpos2;
    00406     // expect opening bracket and find next balanced closing bracket. If
    00407     // next char is no opening bracket, continue parsing (no valid tag)
    00408     if ( '(' == result[bpos1] ) {
    00409       bpos2 = findBalancedBracket( result, bpos1 );
    00410       if ( -1 != bpos2 ) {
    00411         // we have balanced brackets, recursively parse:
    00412         QString rplstr;
    00413         bool purge = !parseAddressTemplateSection( result.mid( bpos1+1,
    00414                                                    bpos2-bpos1-1 ), rplstr,
    00415                                                    realName, orgaName );
    00416         if ( purge ) {
    00417           // purge -> remove all
    00418           // replace with !_P_!, so conditional tags work later
    00419           result.replace( fpos, bpos2 - fpos + 1, "!_P_!" );
    00420           // leave stpos as it is
    00421         } else {
    00422           // no purge -> replace with recursively parsed string
    00423           result.replace( fpos, bpos2 - fpos + 1, rplstr );
    00424           ret = true;
    00425           stpos = fpos + rplstr.length();
    00426         }
    00427       } else {
    00428         // unbalanced brackets:  keep on parsing (should not happen
    00429         // and will result in bad formatting)
    00430         stpos = bpos1;
    00431       }
    00432     }
    00433     fpos = result.find( KABC_FMTTAG_purgeempty, stpos );
    00434   }
    00435
    00436   // after sorting out all purge tags, we just search'n'replace the rest,
    00437   // keeping track of whether at least one tag evaluates to something.
    00438   // The following macro needs QString for R_FIELD
    00439   // It substitutes !_P_! for empty fields so conditional tags work later
    00440 #define REPLTAG(R_TAG,R_FIELD) \
    00441   if ( result.find(R_TAG, false) != -1 ) { \
    00442     QString rpl = R_FIELD.isEmpty() ? QString("!_P_!") : R_FIELD; \
    00443     result.replace( R_TAG, rpl ); \
    00444     if ( !R_FIELD.isEmpty() ) { \
    00445       ret = true; \
    00446     } \
    00447   }
    00448   REPLTAG( KABC_FMTTAG_realname, realName );
    00449   REPLTAG( KABC_FMTTAG_REALNAME, realName.upper() );
    00450   REPLTAG( KABC_FMTTAG_company, orgaName );
    00451   REPLTAG( KABC_FMTTAG_COMPANY, orgaName.upper() );
    00452   REPLTAG( KABC_FMTTAG_pobox, postOfficeBox() );
    00453   REPLTAG( KABC_FMTTAG_street, street() );
    00454   REPLTAG( KABC_FMTTAG_STREET, street().upper() );
    00455   REPLTAG( KABC_FMTTAG_zipcode, postalCode() );
    00456   REPLTAG( KABC_FMTTAG_location, locality() );
    00457   REPLTAG( KABC_FMTTAG_LOCATION, locality().upper() );
    00458   REPLTAG( KABC_FMTTAG_region, region() );
    00459   REPLTAG( KABC_FMTTAG_REGION, region().upper() );
    00460   result.replace( KABC_FMTTAG_newline, "\n" );
    00461 #undef REPLTAG
    00462
    00463   // conditional comma
    00464   fpos = result.find( KABC_FMTTAG_condcomma, 0 );
    00465   while ( -1 != fpos ) {
    00466     QString str1 = result.mid( fpos - 5, 5 );
    00467     QString str2 = result.mid( fpos + 2, 5 );
    00468     if ( str1 != "!_P_!" && str2 != "!_P_!" ) {
    00469       result.replace( fpos, 2, ", " );
    00470     } else {
    00471       result.remove( fpos, 2 );
    00472     }
    00473     fpos = result.find( KABC_FMTTAG_condcomma, fpos );
    00474   }
    00475   // conditional whitespace
    00476   fpos = result.find( KABC_FMTTAG_condwhite, 0 );
    00477   while ( -1 != fpos ) {
    00478     QString str1 = result.mid( fpos - 5, 5 );
    00479     QString str2 = result.mid( fpos + 2, 5 );
    00480     if ( str1 != "!_P_!" && str2 != "!_P_!" ) {
    00481       result.replace( fpos, 2, " " );
    00482     } else {
    00483       result.remove( fpos, 2 );
    00484     }
    00485     fpos = result.find( KABC_FMTTAG_condwhite, fpos );
    00486   }
    00487
    00488   // remove purged:
    00489   result.remove( "!_P_!" );
    00490
    00491   return ret;
    00492 }
    00493
    00494 int Address::findBalancedBracket( const QString &tsection, int pos ) const
    00495 {
    00496   int balancecounter = 0;
    00497   for( unsigned int i = pos + 1; i < tsection.length(); i++ ) {
    00498     if ( ')' == tsection[i] && 0 == balancecounter ) {
    00499       // found end of brackets
    00500       return i;
    00501     } else
    00502     if ( '(' == tsection[i] ) {
    00503       // nested brackets
    00504       balancecounter++;
    00505     }
    00506   }
    00507   return -1;
    00508 }
    00509
    00510 QString Address::countryToISO( const QString &cname )
    00511 {
    00512   // we search a map file for translations from country names to
    00513   // iso codes, storing caching things in a QMap for faster future
    00514   // access.
    00515   if ( !mISOMap )
    00516     isoMapDeleter.setObject( mISOMap, new QMap<QString, QString>() );
    00517
    00518   QMap<QString, QString>::ConstIterator it;
    00519   it = mISOMap->find( cname );
    00520   if ( it != mISOMap->end() )
    00521     return it.data();
    00522
    00523   QString mapfile = KGlobal::dirs()->findResource( "data",
    00524           QString::fromLatin1( "kabc/countrytransl.map" ) );
    00525
    00526   QFile file( mapfile );
    00527   if ( file.open( IO_ReadOnly ) ) {
    00528     QTextStream s( &file );
    00529     QString strbuf = s.readLine();
    00530     while( !strbuf.isNull() ) {
    00531       QStringList countryInfo = QStringList::split( '\t', strbuf, true );
    00532       if ( countryInfo[ 0 ] == cname ) {
    00533         file.close();
    00534         mISOMap->insert( cname, countryInfo[ 1 ] );
    00535         return countryInfo[ 1 ];
    00536       }
    00537       strbuf = s.readLine();
    00538     }
    00539     file.close();
    00540   }
    00541
    00542   // fall back to system country
    00543   mISOMap->insert( cname, KGlobal::locale()->country() );
    00544   return KGlobal::locale()->country();
    00545 }
    00546
    00547 QString Address::ISOtoCountry( const QString &ISOname )
    00548 {
    00549   // get country name from ISO country code (e.g. "no" -> i18n("Norway"))
    00550   if ( ISOname.simplifyWhiteSpace().isEmpty() )
    00551     return QString::null;
    00552
    00553   QString mapfile = KGlobal::dirs()->findResource( "data",
    00554           QString::fromLatin1( "kabc/countrytransl.map" ) );
    00555
    00556   QFile file( mapfile );
    00557   if ( file.open( IO_ReadOnly ) ) {
    00558     QTextStream s( &file );
    00559     QString searchStr = "\t" + ISOname.simplifyWhiteSpace().lower();
    00560     QString strbuf = s.readLine();
    00561     int pos;
    00562     while ( !strbuf.isNull() ) {
    00563       if ( (pos = strbuf.find( searchStr )) != -1 ) {
    00564         file.close();
    00565         return i18n( strbuf.left( pos ).utf8() );
    00566       }
    00567       strbuf = s.readLine();
    00568     }
    00569     file.close();
    00570   }
    00571
    00572   return ISOname;
    00573 }
    00574
    00575 QDataStream &KABC::operator<<( QDataStream &s, const Address &addr )
    00576 {
    00577     return s << addr.mId << addr.mType << addr.mPostOfficeBox <<
    00578         addr.mExtended << addr.mStreet << addr.mLocality <<
    00579         addr.mRegion << addr.mPostalCode << addr.mCountry <<
    00580         addr.mLabel;
    00581 }
    00582
    00583 QDataStream &KABC::operator>>( QDataStream &s, Address &addr )
    00584 {
    00585     s >> addr.mId >> addr.mType >> addr.mPostOfficeBox >> addr.mExtended >>
    00586         addr.mStreet >> addr.mLocality >> addr.mRegion >>
    00587         addr.mPostalCode >> addr.mCountry >> addr.mLabel;
    00588
    00589     addr.mEmpty = false;
    00590
    00591     return s;
    00592 }

This file is part of the documentation for kabc Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:31:28 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003