00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <kapplication.h>
00022 #include <kdebug.h>
00023 #include <klocale.h>
00024 #include <ksimpleconfig.h>
00025 #include <kstandarddirs.h>
00026
00027 #include <qfile.h>
00028
00029 #include "address.h"
00030
00031 using namespace KABC;
00032
00033 QMap<QString, QString> Address::mISOMap;
00034
00035 Address::Address() :
00036 mEmpty( true ), mType( 0 )
00037 {
00038 mId = KApplication::randomString( 10 );
00039 }
00040
00041 Address::Address( int type ) :
00042 mEmpty( true ), mType( type )
00043 {
00044 mId = KApplication::randomString( 10 );
00045 }
00046
00047 bool Address::operator==( const Address &a ) const
00048 {
00049 if ( mPostOfficeBox != a.mPostOfficeBox ) return false;
00050 if ( mExtended != a.mExtended ) return false;
00051 if ( mStreet != a.mStreet ) return false;
00052 if ( mLocality != a.mLocality ) return false;
00053 if ( mRegion != a.mRegion ) return false;
00054 if ( mPostalCode != a.mPostalCode ) return false;
00055 if ( mCountry != a.mCountry ) return false;
00056 if ( mLabel != a.mLabel ) return false;
00057
00058 return true;
00059 }
00060
00061 bool Address::operator!=( const Address &a ) const
00062 {
00063 return !( a == *this );
00064 }
00065
00066 bool Address::isEmpty() const
00067 {
00068 if ( mPostOfficeBox.isEmpty() &&
00069 mExtended.isEmpty() &&
00070 mStreet.isEmpty() &&
00071 mLocality.isEmpty() &&
00072 mRegion.isEmpty() &&
00073 mPostalCode.isEmpty() &&
00074 mCountry.isEmpty() &&
00075 mLabel.isEmpty() ) {
00076 return true;
00077 }
00078 return false;
00079 }
00080
00081 void Address::clear()
00082 {
00083 *this = Address();
00084 }
00085
00086 void Address::setId( const QString &id )
00087 {
00088 mEmpty = false;
00089
00090 mId = id;
00091 }
00092
00093 QString Address::id() const
00094 {
00095 return mId;
00096 }
00097
00098 void Address::setType( int type )
00099 {
00100 mEmpty = false;
00101
00102 mType = type;
00103 }
00104
00105 int Address::type() const
00106 {
00107 return mType;
00108 }
00109
00110 QString Address::typeLabel() const
00111 {
00112 QString label;
00113 bool first = true;
00114
00115 TypeList list = typeList();
00116
00117 TypeList::Iterator it;
00118 for ( it = list.begin(); it != list.end(); ++it ) {
00119 if ( ( type() & (*it) ) && ( (*it) != Pref ) ) {
00120 label.append( ( first ? "" : "/" ) + typeLabel( *it ) );
00121 if ( first )
00122 first = false;
00123 }
00124 }
00125
00126 return label;
00127 }
00128
00129 void Address::setPostOfficeBox( const QString &s )
00130 {
00131 mEmpty = false;
00132
00133 mPostOfficeBox = s;
00134 }
00135
00136 QString Address::postOfficeBox() const
00137 {
00138 return mPostOfficeBox;
00139 }
00140
00141 QString Address::postOfficeBoxLabel()
00142 {
00143 return i18n("Post Office Box");
00144 }
00145
00146
00147 void Address::setExtended( const QString &s )
00148 {
00149 mEmpty = false;
00150
00151 mExtended = s;
00152 }
00153
00154 QString Address::extended() const
00155 {
00156 return mExtended;
00157 }
00158
00159 QString Address::extendedLabel()
00160 {
00161 return i18n("Extended Address Information");
00162 }
00163
00164
00165 void Address::setStreet( const QString &s )
00166 {
00167 mEmpty = false;
00168
00169 mStreet = s;
00170 }
00171
00172 QString Address::street() const
00173 {
00174 return mStreet;
00175 }
00176
00177 QString Address::streetLabel()
00178 {
00179 return i18n("Street");
00180 }
00181
00182
00183 void Address::setLocality( const QString &s )
00184 {
00185 mEmpty = false;
00186
00187 mLocality = s;
00188 }
00189
00190 QString Address::locality() const
00191 {
00192 return mLocality;
00193 }
00194
00195 QString Address::localityLabel()
00196 {
00197 return i18n("Locality");
00198 }
00199
00200
00201 void Address::setRegion( const QString &s )
00202 {
00203 mEmpty = false;
00204
00205 mRegion = s;
00206 }
00207
00208 QString Address::region() const
00209 {
00210 return mRegion;
00211 }
00212
00213 QString Address::regionLabel()
00214 {
00215 return i18n("Region");
00216 }
00217
00218
00219 void Address::setPostalCode( const QString &s )
00220 {
00221 mEmpty = false;
00222
00223 mPostalCode = s;
00224 }
00225
00226 QString Address::postalCode() const
00227 {
00228 return mPostalCode;
00229 }
00230
00231 QString Address::postalCodeLabel()
00232 {
00233 return i18n("Postal Code");
00234 }
00235
00236
00237 void Address::setCountry( const QString &s )
00238 {
00239 mEmpty = false;
00240
00241 mCountry = s;
00242 }
00243
00244 QString Address::country() const
00245 {
00246 return mCountry;
00247 }
00248
00249 QString Address::countryLabel()
00250 {
00251 return i18n("Country");
00252 }
00253
00254
00255 void Address::setLabel( const QString &s )
00256 {
00257 mEmpty = false;
00258
00259 mLabel = s;
00260 }
00261
00262 QString Address::label() const
00263 {
00264 return mLabel;
00265 }
00266
00267 QString Address::labelLabel()
00268 {
00269 return i18n("Delivery Label");
00270 }
00271
00272 Address::TypeList Address::typeList()
00273 {
00274 TypeList list;
00275
00276 list << Dom << Intl << Postal << Parcel << Home << Work << Pref;
00277
00278 return list;
00279 }
00280
00281 QString Address::typeLabel( int type )
00282 {
00283 if ( type & Pref )
00284 return i18n( "Preferred address", "Preferred" );
00285
00286 switch ( type ) {
00287 case Dom:
00288 return i18n("Domestic");
00289 break;
00290 case Intl:
00291 return i18n("International");
00292 break;
00293 case Postal:
00294 return i18n("Postal");
00295 break;
00296 case Parcel:
00297 return i18n("Parcel");
00298 break;
00299 case Home:
00300 return i18n("Home Address", "Home");
00301 break;
00302 case Work:
00303 return i18n("Work Address", "Work");
00304 break;
00305 case Pref:
00306 return i18n("Preferred Address");
00307 break;
00308 default:
00309 return i18n("Other");
00310 break;
00311 }
00312 }
00313
00314 void Address::dump() const
00315 {
00316 kdDebug(5700) << " Address {" << endl;
00317 kdDebug(5700) << " Id: " << id() << endl;
00318 kdDebug(5700) << " Extended: " << extended() << endl;
00319 kdDebug(5700) << " Street: " << street() << endl;
00320 kdDebug(5700) << " Postal Code: " << postalCode() << endl;
00321 kdDebug(5700) << " Locality: " << locality() << endl;
00322 kdDebug(5700) << " }" << endl;
00323 }
00324
00325
00326 QString Address::formattedAddress( const QString &realName
00327 , const QString &orgaName ) const
00328 {
00329 QString ciso;
00330 QString addrTemplate;
00331 QString ret;
00332
00333
00334 if ( !country().isEmpty() ) {
00335 ciso = countryToISO( country() );
00336 } else {
00337
00338 ciso = KGlobal::locale()->country();
00339 }
00340 KSimpleConfig entry( locate( "locale",
00341 QString( "l10n/" ) + ciso + QString( "/entry.desktop" ) ) );
00342 entry.setGroup( "KCM Locale" );
00343
00344
00345 if ( orgaName.isNull() ) {
00346 addrTemplate = entry.readEntry( "AddressFormat" );
00347 } else {
00348 addrTemplate = entry.readEntry( "BusinessAddressFormat" );
00349 if ( addrTemplate.isEmpty() )
00350 addrTemplate = entry.readEntry( "AddressFormat" );
00351 }
00352
00353
00354
00355 if ( addrTemplate.isEmpty() ) {
00356 kdWarning(5700) << "address format database incomplete "
00357 << "(no format for locale " << ciso
00358 << " found). Using default address formatting." << endl;
00359 addrTemplate = "%0(%n\\n)%0(%cm\\n)%0(%s\\n)%0(PO BOX %p\\n)%0(%l%w%r)%,%z";
00360 }
00361
00362
00363 parseAddressTemplateSection( addrTemplate, ret, realName, orgaName );
00364
00365
00366
00367 if ( !country().isEmpty() ) {
00368 KSimpleConfig entry( locate( "locale", QString( "l10n/" )
00369 + KGlobal::locale()->country() + QString( "/entry.desktop" ) ) );
00370 entry.setGroup( "KCM Locale" );
00371 QString cpos = entry.readEntry( "AddressCountryPosition" );
00372 if ( "BELOW" == cpos || cpos.isEmpty() ) {
00373 ret = ret + "\n\n" + country().upper();
00374 } else if ( "below" == cpos ) {
00375 ret = ret + "\n\n" + country();
00376 } else if ( "ABOVE" == cpos ) {
00377 ret = country().upper() + "\n\n" + ret;
00378 } else if ( "above" == cpos ) {
00379 ret = country() + "\n\n" + ret;
00380 }
00381 }
00382
00383 return ret;
00384 }
00385
00386 bool Address::parseAddressTemplateSection( const QString &tsection,
00387 QString &result, const QString &realName, const QString &orgaName ) const
00388 {
00389
00390
00391
00392
00393
00394 result = tsection;
00395 int stpos = 0;
00396 bool ret = false;
00397
00398
00399 int fpos = result.find( KABC_FMTTAG_purgeempty, stpos );
00400 while ( -1 != fpos ) {
00401 int bpos1 = fpos + KABC_FMTTAG_purgeempty.length();
00402 int bpos2;
00403
00404
00405 if ( '(' == result[bpos1] ) {
00406 bpos2 = findBalancedBracket( result, bpos1 );
00407 if ( -1 != bpos2 ) {
00408
00409 QString rplstr;
00410 bool purge = !parseAddressTemplateSection( result.mid( bpos1+1,
00411 bpos2-bpos1-1 ), rplstr,
00412 realName, orgaName );
00413 if ( purge ) {
00414
00415
00416 result.replace( fpos, bpos2 - fpos + 1, "!_P_!" );
00417
00418 } else {
00419
00420 result.replace( fpos, bpos2 - fpos + 1, rplstr );
00421 ret = true;
00422 stpos = fpos + rplstr.length();
00423 }
00424 } else {
00425
00426
00427 stpos = bpos1;
00428 }
00429 }
00430 fpos = result.find( KABC_FMTTAG_purgeempty, stpos );
00431 }
00432
00433
00434
00435
00436
00437 #define REPLTAG(R_TAG,R_FIELD) \
00438 if ( result.find(R_TAG, false) != -1 ) { \
00439 QString rpl = R_FIELD.isEmpty() ? QString("!_P_!") : R_FIELD; \
00440 result.replace( R_TAG, rpl ); \
00441 if ( !R_FIELD.isEmpty() ) { \
00442 ret = true; \
00443 } \
00444 }
00445 REPLTAG( KABC_FMTTAG_realname, realName );
00446 REPLTAG( KABC_FMTTAG_REALNAME, realName.upper() );
00447 REPLTAG( KABC_FMTTAG_company, orgaName );
00448 REPLTAG( KABC_FMTTAG_COMPANY, orgaName.upper() );
00449 REPLTAG( KABC_FMTTAG_pobox, postOfficeBox() );
00450 REPLTAG( KABC_FMTTAG_street, street() );
00451 REPLTAG( KABC_FMTTAG_STREET, street().upper() );
00452 REPLTAG( KABC_FMTTAG_zipcode, postalCode() );
00453 REPLTAG( KABC_FMTTAG_location, locality() );
00454 REPLTAG( KABC_FMTTAG_LOCATION, locality().upper() );
00455 REPLTAG( KABC_FMTTAG_region, region() );
00456 REPLTAG( KABC_FMTTAG_REGION, region().upper() );
00457 result.replace( KABC_FMTTAG_newline, "\n" );
00458 #undef REPLTAG
00459
00460
00461 fpos = result.find( KABC_FMTTAG_condcomma, 0 );
00462 while ( -1 != fpos ) {
00463 QString str1 = result.mid( fpos - 5, 5 );
00464 QString str2 = result.mid( fpos + 2, 5 );
00465 if ( str1 != "!_P_!" && str2 != "!_P_!" ) {
00466 result.replace( fpos, 2, ", " );
00467 } else {
00468 result.remove( fpos, 2 );
00469 }
00470 fpos = result.find( KABC_FMTTAG_condcomma, fpos );
00471 }
00472
00473 fpos = result.find( KABC_FMTTAG_condwhite, 0 );
00474 while ( -1 != fpos ) {
00475 QString str1 = result.mid( fpos - 5, 5 );
00476 QString str2 = result.mid( fpos + 2, 5 );
00477 if ( str1 != "!_P_!" && str2 != "!_P_!" ) {
00478 result.replace( fpos, 2, " " );
00479 } else {
00480 result.remove( fpos, 2 );
00481 }
00482 fpos = result.find( KABC_FMTTAG_condwhite, fpos );
00483 }
00484
00485
00486 result.remove( "!_P_!" );
00487
00488 return ret;
00489 }
00490
00491 int Address::findBalancedBracket( const QString &tsection, int pos ) const
00492 {
00493 int balancecounter = 0;
00494 for( unsigned int i = pos + 1; i < tsection.length(); i++ ) {
00495 if ( ')' == tsection[i] && 0 == balancecounter ) {
00496
00497 return i;
00498 } else
00499 if ( '(' == tsection[i] ) {
00500
00501 balancecounter++;
00502 }
00503 }
00504 return -1;
00505 }
00506
00507 QString Address::countryToISO( const QString &cname )
00508 {
00509
00510
00511
00512 QString isoCode = mISOMap[ cname ];
00513 if ( !isoCode.isEmpty() )
00514 return isoCode;
00515
00516 QString mapfile = KGlobal::dirs()->findResource( "data",
00517 QString::fromLatin1( "kabc/countrytransl.map" ) );
00518
00519 QFile file( mapfile );
00520 if ( file.open( IO_ReadOnly ) ) {
00521 QTextStream s( &file );
00522 QString strbuf = s.readLine();
00523 while( !strbuf.isNull() ) {
00524 if ( strbuf.startsWith( cname ) ) {
00525 int index = strbuf.findRev('\t');
00526 strbuf = strbuf.mid(index+1, 2);
00527 file.close();
00528 mISOMap[ cname ] = strbuf;
00529 return strbuf;
00530 }
00531 strbuf = s.readLine();
00532 }
00533 file.close();
00534 }
00535
00536
00537 mISOMap[ cname ] = KGlobal::locale()->country();
00538 return KGlobal::locale()->country();
00539 }
00540
00541 QString Address::ISOtoCountry( const QString &ISOname )
00542 {
00543
00544 if (ISOname.simplifyWhiteSpace().isEmpty())
00545 return QString::null;
00546
00547 QString mapfile = KGlobal::dirs()->findResource( "data",
00548 QString::fromLatin1( "kabc/countrytransl.map" ) );
00549
00550 QFile file( mapfile );
00551 if ( file.open( IO_ReadOnly ) ) {
00552 QTextStream s( &file );
00553 QString searchStr = "\t" + ISOname.simplifyWhiteSpace().lower();
00554 QString strbuf = s.readLine();
00555 int pos;
00556 while( !strbuf.isNull() ) {
00557 if ( (pos=strbuf.find( searchStr )) != -1 ) {
00558 file.close();
00559 return i18n(strbuf.left(pos).utf8());
00560 }
00561 strbuf = s.readLine();
00562 }
00563 file.close();
00564 }
00565
00566 return ISOname;
00567 }
00568
00569 QDataStream &KABC::operator<<( QDataStream &s, const Address &addr )
00570 {
00571 return s << addr.mId << addr.mType << addr.mPostOfficeBox <<
00572 addr.mExtended << addr.mStreet << addr.mLocality <<
00573 addr.mRegion << addr.mPostalCode << addr.mCountry <<
00574 addr.mLabel;
00575 }
00576
00577 QDataStream &KABC::operator>>( QDataStream &s, Address &addr )
00578 {
00579 s >> addr.mId >> addr.mType >> addr.mPostOfficeBox >> addr.mExtended >>
00580 addr.mStreet >> addr.mLocality >> addr.mRegion >>
00581 addr.mPostalCode >> addr.mCountry >> addr.mLabel;
00582
00583 addr.mEmpty = false;
00584
00585 return s;
00586 }