kabc Library API Documentation

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 <kapplication.h> 00022 #include <kdebug.h> 00023 #include <klocale.h> 00024 #include <ksimpleconfig.h> 00025 #include <kstandarddirs.h> 00026 #include <kstaticdeleter.h> 00027 00028 #include <qfile.h> 00029 00030 #include "address.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 TypeList list = typeList(); 00118 00119 TypeList::Iterator 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 TypeList list; 00277 00278 list << Dom << Intl << Postal << Parcel << Home << Work << Pref; 00279 00280 return list; 00281 } 00282 00283 QString Address::typeLabel( int type ) 00284 { 00285 if ( type & Pref ) 00286 return i18n( "Preferred address", "Preferred" ); 00287 00288 switch ( type ) { 00289 case Dom: 00290 return i18n("Domestic"); 00291 break; 00292 case Intl: 00293 return i18n("International"); 00294 break; 00295 case Postal: 00296 return i18n("Postal"); 00297 break; 00298 case Parcel: 00299 return i18n("Parcel"); 00300 break; 00301 case Home: 00302 return i18n("Home Address", "Home"); 00303 break; 00304 case Work: 00305 return i18n("Work Address", "Work"); 00306 break; 00307 case Pref: 00308 return i18n("Preferred Address"); 00309 break; 00310 default: 00311 return i18n("Other"); 00312 break; 00313 } 00314 } 00315 00316 void Address::dump() const 00317 { 00318 kdDebug(5700) << " Address {" << endl; 00319 kdDebug(5700) << " Id: " << id() << endl; 00320 kdDebug(5700) << " Extended: " << extended() << endl; 00321 kdDebug(5700) << " Street: " << street() << endl; 00322 kdDebug(5700) << " Postal Code: " << postalCode() << endl; 00323 kdDebug(5700) << " Locality: " << locality() << endl; 00324 kdDebug(5700) << " }" << endl; 00325 } 00326 00327 00328 QString Address::formattedAddress( const QString &realName 00329 , const QString &orgaName ) const 00330 { 00331 QString ciso; 00332 QString addrTemplate; 00333 QString ret; 00334 00335 // FIXME: first check for iso-country-field and prefer that one 00336 if ( !country().isEmpty() ) { 00337 ciso = countryToISO( country() ); 00338 } else { 00339 // fall back to our own country 00340 ciso = KGlobal::locale()->country(); 00341 } 00342 KSimpleConfig entry( locate( "locale", 00343 QString( "l10n/" ) + ciso + QString( "/entry.desktop" ) ) ); 00344 entry.setGroup( "KCM Locale" ); 00345 00346 // decide whether this needs special business address formatting 00347 if ( orgaName.isNull() ) { 00348 addrTemplate = entry.readEntry( "AddressFormat" ); 00349 } else { 00350 addrTemplate = entry.readEntry( "BusinessAddressFormat" ); 00351 if ( addrTemplate.isEmpty() ) 00352 addrTemplate = entry.readEntry( "AddressFormat" ); 00353 } 00354 00355 // in the case there's no format found at all, default to what we've always 00356 // used: 00357 if ( addrTemplate.isEmpty() ) { 00358 kdWarning(5700) << "address format database incomplete " 00359 << "(no format for locale " << ciso 00360 << " found). Using default address formatting." << endl; 00361 addrTemplate = "%0(%n\\n)%0(%cm\\n)%0(%s\\n)%0(PO BOX %p\\n)%0(%l%w%r)%,%z"; 00362 } 00363 00364 // scan 00365 parseAddressTemplateSection( addrTemplate, ret, realName, orgaName ); 00366 00367 // now add the country line if needed (formatting this time according to 00368 // the rules of our own system country ) 00369 if ( !country().isEmpty() ) { 00370 KSimpleConfig entry( locate( "locale", QString( "l10n/" ) 00371 + KGlobal::locale()->country() + QString( "/entry.desktop" ) ) ); 00372 entry.setGroup( "KCM Locale" ); 00373 QString cpos = entry.readEntry( "AddressCountryPosition" ); 00374 if ( "BELOW" == cpos || cpos.isEmpty() ) { 00375 ret = ret + "\n\n" + country().upper(); 00376 } else if ( "below" == cpos ) { 00377 ret = ret + "\n\n" + country(); 00378 } else if ( "ABOVE" == cpos ) { 00379 ret = country().upper() + "\n\n" + ret; 00380 } else if ( "above" == cpos ) { 00381 ret = country() + "\n\n" + ret; 00382 } 00383 } 00384 00385 return ret; 00386 } 00387 00388 bool Address::parseAddressTemplateSection( const QString &tsection, 00389 QString &result, const QString &realName, const QString &orgaName ) const 00390 { 00391 // This method first parses and substitutes any bracketed sections and 00392 // after that replaces any tags with their values. If a bracketed section 00393 // or a tag evaluate to zero, they are not just removed but replaced 00394 // with a placeholder. This is because in the last step conditionals are 00395 // resolved which depend on information about zero-evaluations. 00396 result = tsection; 00397 int stpos = 0; 00398 bool ret = false; 00399 00400 // first check for brackets that have to be evaluated first 00401 int fpos = result.find( KABC_FMTTAG_purgeempty, stpos ); 00402 while ( -1 != fpos ) { 00403 int bpos1 = fpos + KABC_FMTTAG_purgeempty.length(); 00404 int bpos2; 00405 // expect opening bracket and find next balanced closing bracket. If 00406 // next char is no opening bracket, continue parsing (no valid tag) 00407 if ( '(' == result[bpos1] ) { 00408 bpos2 = findBalancedBracket( result, bpos1 ); 00409 if ( -1 != bpos2 ) { 00410 // we have balanced brackets, recursively parse: 00411 QString rplstr; 00412 bool purge = !parseAddressTemplateSection( result.mid( bpos1+1, 00413 bpos2-bpos1-1 ), rplstr, 00414 realName, orgaName ); 00415 if ( purge ) { 00416 // purge -> remove all 00417 // replace with !_P_!, so conditional tags work later 00418 result.replace( fpos, bpos2 - fpos + 1, "!_P_!" ); 00419 // leave stpos as it is 00420 } else { 00421 // no purge -> replace with recursively parsed string 00422 result.replace( fpos, bpos2 - fpos + 1, rplstr ); 00423 ret = true; 00424 stpos = fpos + rplstr.length(); 00425 } 00426 } else { 00427 // unbalanced brackets: keep on parsing (should not happen 00428 // and will result in bad formatting) 00429 stpos = bpos1; 00430 } 00431 } 00432 fpos = result.find( KABC_FMTTAG_purgeempty, stpos ); 00433 } 00434 00435 // after sorting out all purge tags, we just search'n'replace the rest, 00436 // keeping track of whether at least one tag evaluates to something. 00437 // The following macro needs QString for R_FIELD 00438 // It substitutes !_P_! for empty fields so conditional tags work later 00439 #define REPLTAG(R_TAG,R_FIELD) \ 00440 if ( result.find(R_TAG, false) != -1 ) { \ 00441 QString rpl = R_FIELD.isEmpty() ? QString("!_P_!") : R_FIELD; \ 00442 result.replace( R_TAG, rpl ); \ 00443 if ( !R_FIELD.isEmpty() ) { \ 00444 ret = true; \ 00445 } \ 00446 } 00447 REPLTAG( KABC_FMTTAG_realname, realName ); 00448 REPLTAG( KABC_FMTTAG_REALNAME, realName.upper() ); 00449 REPLTAG( KABC_FMTTAG_company, orgaName ); 00450 REPLTAG( KABC_FMTTAG_COMPANY, orgaName.upper() ); 00451 REPLTAG( KABC_FMTTAG_pobox, postOfficeBox() ); 00452 REPLTAG( KABC_FMTTAG_street, street() ); 00453 REPLTAG( KABC_FMTTAG_STREET, street().upper() ); 00454 REPLTAG( KABC_FMTTAG_zipcode, postalCode() ); 00455 REPLTAG( KABC_FMTTAG_location, locality() ); 00456 REPLTAG( KABC_FMTTAG_LOCATION, locality().upper() ); 00457 REPLTAG( KABC_FMTTAG_region, region() ); 00458 REPLTAG( KABC_FMTTAG_REGION, region().upper() ); 00459 result.replace( KABC_FMTTAG_newline, "\n" ); 00460 #undef REPLTAG 00461 00462 // conditional comma 00463 fpos = result.find( KABC_FMTTAG_condcomma, 0 ); 00464 while ( -1 != fpos ) { 00465 QString str1 = result.mid( fpos - 5, 5 ); 00466 QString str2 = result.mid( fpos + 2, 5 ); 00467 if ( str1 != "!_P_!" && str2 != "!_P_!" ) { 00468 result.replace( fpos, 2, ", " ); 00469 } else { 00470 result.remove( fpos, 2 ); 00471 } 00472 fpos = result.find( KABC_FMTTAG_condcomma, fpos ); 00473 } 00474 // conditional whitespace 00475 fpos = result.find( KABC_FMTTAG_condwhite, 0 ); 00476 while ( -1 != fpos ) { 00477 QString str1 = result.mid( fpos - 5, 5 ); 00478 QString str2 = result.mid( fpos + 2, 5 ); 00479 if ( str1 != "!_P_!" && str2 != "!_P_!" ) { 00480 result.replace( fpos, 2, " " ); 00481 } else { 00482 result.remove( fpos, 2 ); 00483 } 00484 fpos = result.find( KABC_FMTTAG_condwhite, fpos ); 00485 } 00486 00487 // remove purged: 00488 result.remove( "!_P_!" ); 00489 00490 return ret; 00491 } 00492 00493 int Address::findBalancedBracket( const QString &tsection, int pos ) const 00494 { 00495 int balancecounter = 0; 00496 for( unsigned int i = pos + 1; i < tsection.length(); i++ ) { 00497 if ( ')' == tsection[i] && 0 == balancecounter ) { 00498 // found end of brackets 00499 return i; 00500 } else 00501 if ( '(' == tsection[i] ) { 00502 // nested brackets 00503 balancecounter++; 00504 } 00505 } 00506 return -1; 00507 } 00508 00509 QString Address::countryToISO( const QString &cname ) 00510 { 00511 // we search a map file for translations from country names to 00512 // iso codes, storing caching things in a QMap for faster future 00513 // access. 00514 if ( !mISOMap ) 00515 isoMapDeleter.setObject( mISOMap, new QMap<QString, QString>() ); 00516 00517 QMap<QString, QString>::ConstIterator it; 00518 it = mISOMap->find( cname ); 00519 if ( it != mISOMap->end() ) 00520 return it.data(); 00521 00522 QString mapfile = KGlobal::dirs()->findResource( "data", 00523 QString::fromLatin1( "kabc/countrytransl.map" ) ); 00524 00525 QFile file( mapfile ); 00526 if ( file.open( IO_ReadOnly ) ) { 00527 QTextStream s( &file ); 00528 QString strbuf = s.readLine(); 00529 while( !strbuf.isNull() ) { 00530 if ( strbuf.startsWith( cname ) ) { 00531 int index = strbuf.findRev('\t'); 00532 strbuf = strbuf.mid(index+1, 2); 00533 file.close(); 00534 mISOMap->insert( cname, strbuf ); 00535 return strbuf; 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 }
KDE Logo
This file is part of the documentation for kabc Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Aug 20 09:50:08 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003