00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
00337 if ( !country().isEmpty() ) {
00338 ciso = countryToISO( country() );
00339 } else {
00340
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
00348 if ( orgaName.isEmpty() ) {
00349 addrTemplate = entry.readEntry( "AddressFormat" );
00350 } else {
00351 addrTemplate = entry.readEntry( "BusinessAddressFormat" );
00352 if ( addrTemplate.isEmpty() )
00353 addrTemplate = entry.readEntry( "AddressFormat" );
00354 }
00355
00356
00357
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
00366 parseAddressTemplateSection( addrTemplate, ret, realName, orgaName );
00367
00368
00369
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
00393
00394
00395
00396
00397 result = tsection;
00398 int stpos = 0;
00399 bool ret = false;
00400
00401
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
00407
00408 if ( '(' == result[bpos1] ) {
00409 bpos2 = findBalancedBracket( result, bpos1 );
00410 if ( -1 != bpos2 ) {
00411
00412 QString rplstr;
00413 bool purge = !parseAddressTemplateSection( result.mid( bpos1+1,
00414 bpos2-bpos1-1 ), rplstr,
00415 realName, orgaName );
00416 if ( purge ) {
00417
00418
00419 result.replace( fpos, bpos2 - fpos + 1, "!_P_!" );
00420
00421 } else {
00422
00423 result.replace( fpos, bpos2 - fpos + 1, rplstr );
00424 ret = true;
00425 stpos = fpos + rplstr.length();
00426 }
00427 } else {
00428
00429
00430 stpos = bpos1;
00431 }
00432 }
00433 fpos = result.find( KABC_FMTTAG_purgeempty, stpos );
00434 }
00435
00436
00437
00438
00439
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
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
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
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
00500 return i;
00501 } else
00502 if ( '(' == tsection[i] ) {
00503
00504 balancecounter++;
00505 }
00506 }
00507 return -1;
00508 }
00509
00510 QString Address::countryToISO( const QString &cname )
00511 {
00512
00513
00514
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.isEmpty() ) {
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
00543 mISOMap->insert( cname, KGlobal::locale()->country() );
00544 return KGlobal::locale()->country();
00545 }
00546
00547 QString Address::ISOtoCountry( const QString &ISOname )
00548 {
00549
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.isEmpty() ) {
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 }