kabc
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., 51 Franklin Street, Fifth Floor, 00018 Boston, MA 02110-1301, USA. 00019 */ 00020 00021 #include "address.h" 00022 00023 #include <krandom.h> 00024 #include <kdebug.h> 00025 #include <klocale.h> 00026 #include <kconfig.h> 00027 #include <kstandarddirs.h> 00028 #include <kconfiggroup.h> 00029 00030 #include <QtCore/QFile> 00031 #include <QtCore/QMap> 00032 #include <QtCore/QTextStream> 00033 #include <QtCore/QSharedData> 00034 00035 using namespace KABC; 00036 00037 // template tags for address formatting localization 00038 #define KABC_FMTTAG_realname QString::fromLatin1("%n") 00039 #define KABC_FMTTAG_REALNAME QString::fromLatin1("%N") 00040 #define KABC_FMTTAG_company QString::fromLatin1("%cm") 00041 #define KABC_FMTTAG_COMPANY QString::fromLatin1("%CM") 00042 #define KABC_FMTTAG_pobox QString::fromLatin1("%p") 00043 #define KABC_FMTTAG_street QString::fromLatin1("%s") 00044 #define KABC_FMTTAG_STREET QString::fromLatin1("%S") 00045 #define KABC_FMTTAG_zipcode QString::fromLatin1("%z") 00046 #define KABC_FMTTAG_location QString::fromLatin1("%l") 00047 #define KABC_FMTTAG_LOCATION QString::fromLatin1("%L") 00048 #define KABC_FMTTAG_region QString::fromLatin1("%r") 00049 #define KABC_FMTTAG_REGION QString::fromLatin1("%R") 00050 #define KABC_FMTTAG_newline QString::fromLatin1("\\n") 00051 #define KABC_FMTTAG_condcomma QString::fromLatin1("%,") 00052 #define KABC_FMTTAG_condwhite QString::fromLatin1("%w") 00053 #define KABC_FMTTAG_purgeempty QString::fromLatin1("%0") 00054 00060 static int findBalancedBracket( const QString &tsection, int pos ) 00061 { 00062 int balancecounter = 0; 00063 for ( int i = pos + 1; i < tsection.length(); ++i ) { 00064 if ( QLatin1Char( ')' ) == tsection[i] && 0 == balancecounter ) { 00065 // found end of brackets 00066 return i; 00067 } else { 00068 if ( QLatin1Char( '(' ) == tsection[i] ) { 00069 // nested brackets 00070 balancecounter++; 00071 } 00072 } 00073 } 00074 return -1; 00075 } 00076 00083 static bool parseAddressTemplateSection( const QString &tsection, QString &result, 00084 const QString &realName, const QString &orgaName, 00085 const KABC::Address &address ) 00086 { 00087 // This method first parses and substitutes any bracketed sections and 00088 // after that replaces any tags with their values. If a bracketed section 00089 // or a tag evaluate to zero, they are not just removed but replaced 00090 // with a placeholder. This is because in the last step conditionals are 00091 // resolved which depend on information about zero-evaluations. 00092 result = tsection; 00093 int stpos = 0; 00094 bool ret = false; 00095 00096 // first check for brackets that have to be evaluated first 00097 int fpos = result.indexOf( KABC_FMTTAG_purgeempty, stpos ); 00098 while ( -1 != fpos ) { 00099 int bpos1 = fpos + KABC_FMTTAG_purgeempty.length(); 00100 int bpos2; 00101 // expect opening bracket and find next balanced closing bracket. If 00102 // next char is no opening bracket, continue parsing (no valid tag) 00103 if ( QLatin1Char( '(' ) == result[bpos1] ) { 00104 bpos2 = findBalancedBracket( result, bpos1 ); 00105 if ( -1 != bpos2 ) { 00106 // we have balanced brackets, recursively parse: 00107 QString rplstr; 00108 bool purge = !parseAddressTemplateSection( result.mid( bpos1+1, 00109 bpos2-bpos1-1 ), rplstr, 00110 realName, orgaName, address ); 00111 if ( purge ) { 00112 // purge -> remove all 00113 // replace with !_P_!, so conditional tags work later 00114 result.replace( fpos, bpos2 - fpos + 1, QLatin1String( "!_P_!" ) ); 00115 // leave stpos as it is 00116 } else { 00117 // no purge -> replace with recursively parsed string 00118 result.replace( fpos, bpos2 - fpos + 1, rplstr ); 00119 ret = true; 00120 stpos = fpos + rplstr.length(); 00121 } 00122 } else { 00123 // unbalanced brackets: keep on parsing (should not happen 00124 // and will result in bad formatting) 00125 stpos = bpos1; 00126 } 00127 } 00128 fpos = result.indexOf( KABC_FMTTAG_purgeempty, stpos ); 00129 } 00130 00131 // after sorting out all purge tags, we just search'n'replace the rest, 00132 // keeping track of whether at least one tag evaluates to something. 00133 // The following macro needs QString for R_FIELD 00134 // It substitutes !_P_! for empty fields so conditional tags work later 00135 #define REPLTAG(R_TAG,R_FIELD) \ 00136 if ( result.indexOf( R_TAG, false ) != -1 ) { \ 00137 QString rpl = R_FIELD.isEmpty() ? QLatin1String( "!_P_!" ) : R_FIELD; \ 00138 result.replace( R_TAG, rpl ); \ 00139 if ( !R_FIELD.isEmpty() ) { \ 00140 ret = true; \ 00141 } \ 00142 } 00143 REPLTAG( KABC_FMTTAG_realname, realName ); 00144 REPLTAG( KABC_FMTTAG_REALNAME, realName.toUpper() ); 00145 REPLTAG( KABC_FMTTAG_company, orgaName ); 00146 REPLTAG( KABC_FMTTAG_COMPANY, orgaName.toUpper() ); 00147 REPLTAG( KABC_FMTTAG_pobox, address.postOfficeBox() ); 00148 REPLTAG( KABC_FMTTAG_street, address.street() ); 00149 REPLTAG( KABC_FMTTAG_STREET, address.street().toUpper() ); 00150 REPLTAG( KABC_FMTTAG_zipcode, address.postalCode() ); 00151 REPLTAG( KABC_FMTTAG_location, address.locality() ); 00152 REPLTAG( KABC_FMTTAG_LOCATION, address.locality().toUpper() ); 00153 REPLTAG( KABC_FMTTAG_region, address.region() ); 00154 REPLTAG( KABC_FMTTAG_REGION, address.region().toUpper() ); 00155 result.replace( KABC_FMTTAG_newline, QLatin1String( "\n" ) ); 00156 #undef REPLTAG 00157 00158 // conditional comma 00159 fpos = result.indexOf( KABC_FMTTAG_condcomma, 0 ); 00160 while ( -1 != fpos ) { 00161 const QString str1 = result.mid( fpos - 5, 5 ); 00162 const QString str2 = result.mid( fpos + 2, 5 ); 00163 if ( str1 != QLatin1String( "!_P_!" ) && str2 != QLatin1String( "!_P_!" ) ) { 00164 result.replace( fpos, 2, QLatin1String( ", " ) ); 00165 } else { 00166 result.remove( fpos, 2 ); 00167 } 00168 fpos = result.indexOf( KABC_FMTTAG_condcomma, fpos ); 00169 } 00170 // conditional whitespace 00171 fpos = result.indexOf( KABC_FMTTAG_condwhite, 0 ); 00172 while ( -1 != fpos ) { 00173 const QString str1 = result.mid( fpos - 5, 5 ); 00174 const QString str2 = result.mid( fpos + 2, 5 ); 00175 if ( str1 != QLatin1String( "!_P_!" ) && str2 != QLatin1String( "!_P_!" ) ) { 00176 result.replace( fpos, 2, QLatin1String( " " ) ); 00177 } else { 00178 result.remove( fpos, 2 ); 00179 } 00180 fpos = result.indexOf( KABC_FMTTAG_condwhite, fpos ); 00181 } 00182 00183 // remove purged: 00184 result.remove( QLatin1String( "!_P_!" ) ); 00185 00186 return ret; 00187 } 00188 00189 class Address::Private : public QSharedData 00190 { 00191 public: 00192 Private() 00193 : mEmpty( true ), mType( 0 ) 00194 { 00195 mId = KRandom::randomString( 10 ); 00196 } 00197 00198 Private( const Private &other ) 00199 : QSharedData( other ) 00200 { 00201 mEmpty = other.mEmpty; 00202 mId = other.mId; 00203 mType = other.mType; 00204 00205 mPostOfficeBox = other.mPostOfficeBox; 00206 mExtended = other.mExtended; 00207 mStreet = other.mStreet; 00208 mLocality = other.mLocality; 00209 mRegion = other.mRegion; 00210 mPostalCode = other.mPostalCode; 00211 mCountry = other.mCountry; 00212 mLabel = other.mLabel; 00213 } 00214 00215 bool mEmpty; 00216 QString mId; 00217 Type mType; 00218 00219 QString mPostOfficeBox; 00220 QString mExtended; 00221 QString mStreet; 00222 QString mLocality; 00223 QString mRegion; 00224 QString mPostalCode; 00225 QString mCountry; 00226 QString mLabel; 00227 }; 00228 00229 Address::Address() 00230 : d( new Private ) 00231 { 00232 } 00233 00234 Address::Address( Type type ) 00235 : d( new Private ) 00236 { 00237 d->mType = type; 00238 } 00239 00240 Address::Address( const Address &other ) 00241 : d( other.d ) 00242 { 00243 } 00244 00245 Address::~Address() 00246 { 00247 } 00248 00249 Address &Address::operator=( const Address &other ) 00250 { 00251 if ( this != &other ) { 00252 d = other.d; 00253 } 00254 00255 return *this; 00256 } 00257 00258 bool Address::operator==( const Address &other ) const 00259 { 00260 if ( d->mId != other.d->mId ) { 00261 return false; 00262 } 00263 if ( d->mType != other.d->mType ) { 00264 return false; 00265 } 00266 if ( d->mPostOfficeBox != other.d->mPostOfficeBox ) { 00267 return false; 00268 } 00269 if ( d->mExtended != other.d->mExtended ) { 00270 return false; 00271 } 00272 if ( d->mStreet != other.d->mStreet ) { 00273 return false; 00274 } 00275 if ( d->mLocality != other.d->mLocality ) { 00276 return false; 00277 } 00278 if ( d->mRegion != other.d->mRegion ) { 00279 return false; 00280 } 00281 if ( d->mPostalCode != other.d->mPostalCode ) { 00282 return false; 00283 } 00284 if ( d->mCountry != other.d->mCountry ) { 00285 return false; 00286 } 00287 if ( d->mLabel != other.d->mLabel ) { 00288 return false; 00289 } 00290 00291 return true; 00292 } 00293 00294 bool Address::operator!=( const Address &a ) const 00295 { 00296 return !( a == *this ); 00297 } 00298 00299 bool Address::isEmpty() const 00300 { 00301 return d->mEmpty; 00302 } 00303 00304 void Address::clear() 00305 { 00306 *this = Address(); 00307 } 00308 00309 void Address::setId( const QString &id ) 00310 { 00311 d->mEmpty = false; 00312 d->mId = id; 00313 } 00314 00315 QString Address::id() const 00316 { 00317 return d->mId; 00318 } 00319 00320 void Address::setType( Type type ) 00321 { 00322 d->mEmpty = false; 00323 d->mType = type; 00324 } 00325 00326 Address::Type Address::type() const 00327 { 00328 return d->mType; 00329 } 00330 00331 QString Address::typeLabel() const 00332 { 00333 QString label; 00334 bool first = true; 00335 00336 const TypeList list = typeList(); 00337 00338 TypeList::ConstIterator it; 00339 for ( it = list.begin(); it != list.end(); ++it ) { 00340 if ( ( type() & (*it) ) && ( (*it) != Pref ) ) { 00341 if ( !first ) { 00342 label.append( QLatin1Char( '/' ) ); 00343 } 00344 label.append( typeLabel( *it ) ); 00345 if ( first ) { 00346 first = false; 00347 } 00348 } 00349 } 00350 00351 return label; 00352 } 00353 00354 void Address::setPostOfficeBox( const QString &postOfficeBox ) 00355 { 00356 d->mEmpty = false; 00357 d->mPostOfficeBox = postOfficeBox; 00358 } 00359 00360 QString Address::postOfficeBox() const 00361 { 00362 return d->mPostOfficeBox; 00363 } 00364 00365 QString Address::postOfficeBoxLabel() 00366 { 00367 return i18n( "Post Office Box" ); 00368 } 00369 00370 void Address::setExtended( const QString &extended ) 00371 { 00372 d->mEmpty = false; 00373 d->mExtended = extended; 00374 } 00375 00376 QString Address::extended() const 00377 { 00378 return d->mExtended; 00379 } 00380 00381 QString Address::extendedLabel() 00382 { 00383 return i18n( "Extended Address Information" ); 00384 } 00385 00386 void Address::setStreet( const QString &street ) 00387 { 00388 d->mEmpty = false; 00389 d->mStreet = street; 00390 } 00391 00392 QString Address::street() const 00393 { 00394 return d->mStreet; 00395 } 00396 00397 QString Address::streetLabel() 00398 { 00399 return i18n( "Street" ); 00400 } 00401 00402 void Address::setLocality( const QString &locality ) 00403 { 00404 d->mEmpty = false; 00405 d->mLocality = locality; 00406 } 00407 00408 QString Address::locality() const 00409 { 00410 return d->mLocality; 00411 } 00412 00413 QString Address::localityLabel() 00414 { 00415 return i18n( "Locality" ); 00416 } 00417 00418 void Address::setRegion( const QString ®ion ) 00419 { 00420 d->mEmpty = false; 00421 d->mRegion = region; 00422 } 00423 00424 QString Address::region() const 00425 { 00426 return d->mRegion; 00427 } 00428 00429 QString Address::regionLabel() 00430 { 00431 return i18n( "Region" ); 00432 } 00433 00434 void Address::setPostalCode( const QString &postalCode ) 00435 { 00436 d->mEmpty = false; 00437 d->mPostalCode = postalCode; 00438 } 00439 00440 QString Address::postalCode() const 00441 { 00442 return d->mPostalCode; 00443 } 00444 00445 QString Address::postalCodeLabel() 00446 { 00447 return i18n( "Postal Code" ); 00448 } 00449 00450 void Address::setCountry( const QString &country ) 00451 { 00452 d->mEmpty = false; 00453 d->mCountry = country; 00454 } 00455 00456 QString Address::country() const 00457 { 00458 return d->mCountry; 00459 } 00460 00461 QString Address::countryLabel() 00462 { 00463 return i18n( "Country" ); 00464 } 00465 00466 void Address::setLabel( const QString &label ) 00467 { 00468 d->mEmpty = false; 00469 d->mLabel = label; 00470 } 00471 00472 QString Address::label() const 00473 { 00474 return d->mLabel; 00475 } 00476 00477 QString Address::labelLabel() 00478 { 00479 return i18n( "Delivery Label" ); 00480 } 00481 00482 Address::TypeList Address::typeList() 00483 { 00484 static TypeList list; 00485 00486 if ( list.isEmpty() ) { 00487 list << Dom << Intl << Postal << Parcel << Home << Work << Pref; 00488 } 00489 00490 return list; 00491 } 00492 00493 QString Address::typeLabel( Type type ) 00494 { 00495 if ( type & Pref ) { 00496 return i18nc( "Preferred address", "Preferred" ); 00497 } 00498 00499 switch ( type ) { 00500 case Dom: 00501 return i18nc( "Address is in home country", "Domestic" ); 00502 break; 00503 case Intl: 00504 return i18nc( "Address is not in home country", "International" ); 00505 break; 00506 case Postal: 00507 return i18nc( "Address for delivering letters", "Postal" ); 00508 break; 00509 case Parcel: 00510 return i18nc( "Address for delivering packages", "Parcel" ); 00511 break; 00512 case Home: 00513 return i18nc( "Home Address", "Home" ); 00514 break; 00515 case Work: 00516 return i18nc( "Work Address", "Work" ); 00517 break; 00518 case Pref: 00519 return i18n( "Preferred Address" ); 00520 break; 00521 default: 00522 return i18nc( "another type of address", "Other" ); 00523 break; 00524 } 00525 } 00526 00527 QString Address::toString() const 00528 { 00529 QString str; 00530 00531 str += QLatin1String( "Address {\n" ); 00532 str += QString::fromLatin1( " IsEmpty: %1\n" ). 00533 arg( d->mEmpty ? QLatin1String( "true" ) : QLatin1String( "false" ) ); 00534 str += QString::fromLatin1( " Id: %1\n" ).arg( d->mId ); 00535 str += QString::fromLatin1( " Type: %1\n" ).arg( typeLabel( d->mType ) ); 00536 str += QString::fromLatin1( " Post office box: %1\n" ).arg( d->mPostOfficeBox ); 00537 str += QString::fromLatin1( " Extended: %1\n" ).arg( d->mExtended ); 00538 str += QString::fromLatin1( " Street: %1\n" ).arg( d->mStreet ); 00539 str += QString::fromLatin1( " Locality: %1\n" ).arg( d->mLocality ); 00540 str += QString::fromLatin1( " Region: %1\n" ).arg( d->mRegion ); 00541 str += QString::fromLatin1( " Postal code: %1\n" ).arg( d->mPostalCode ); 00542 str += QString::fromLatin1( " Country: %1\n" ).arg( d->mCountry ); 00543 str += QString::fromLatin1( " Label: %1\n" ).arg( d->mLabel ); 00544 str += QLatin1String( "}\n" ); 00545 00546 return str; 00547 } 00548 00549 QString Address::formattedAddress( const QString &realName, 00550 const QString &orgaName ) const 00551 { 00552 QString ciso; 00553 QString addrTemplate; 00554 QString ret; 00555 00556 // FIXME: first check for iso-country-field and prefer that one 00557 if ( !country().isEmpty() ) { 00558 ciso = countryToISO( country() ); 00559 } else { 00560 // fall back to our own country 00561 ciso = KGlobal::locale()->country(); 00562 } 00563 KConfig entry( KStandardDirs::locate( "locale", 00564 QLatin1String( "l10n/" ) + ciso + QLatin1String( "/entry.desktop" ) ) ); 00565 00566 KConfigGroup group = entry.group( "KCM Locale" ); 00567 // decide whether this needs special business address formatting 00568 if ( orgaName.isEmpty() ) { 00569 addrTemplate = group.readEntry( "AddressFormat" ); 00570 } else { 00571 addrTemplate = group.readEntry( "BusinessAddressFormat" ); 00572 if ( addrTemplate.isEmpty() ) { 00573 addrTemplate = group.readEntry( "AddressFormat" ); 00574 } 00575 } 00576 00577 // in the case there's no format found at all, default to what we've always 00578 // used: 00579 if ( addrTemplate.isEmpty() ) { 00580 kWarning(5700) << "address format database incomplete" 00581 << "(no format for locale" << ciso 00582 << "found). Using default address formatting."; 00583 addrTemplate = QLatin1String( "%0(%n\\n)%0(%cm\\n)%0(%s\\n)%0(PO BOX %p\\n)%0(%l%w%r)%,%z" ); 00584 } 00585 00586 // scan 00587 parseAddressTemplateSection( addrTemplate, ret, realName, orgaName, *this ); 00588 00589 // now add the country line if needed (formatting this time according to 00590 // the rules of our own system country ) 00591 if ( !country().isEmpty() ) { 00592 KConfig entry( KStandardDirs::locate( "locale", QLatin1String( "l10n/" ) + 00593 KGlobal::locale()->country() + 00594 QLatin1String( "/entry.desktop" ) ) ); 00595 KConfigGroup group = entry.group( "KCM Locale" ); 00596 QString cpos = group.readEntry( "AddressCountryPosition" ); 00597 if ( QLatin1String( "BELOW" ) == cpos || cpos.isEmpty() ) { 00598 ret = ret + QLatin1String( "\n\n" ) + country().toUpper(); 00599 } else if ( QLatin1String( "below" ) == cpos ) { 00600 ret = ret + QLatin1String( "\n\n" ) + country(); 00601 } else if ( QLatin1String( "ABOVE" ) == cpos ) { 00602 ret = country().toUpper() + QLatin1String( "\n\n" ) + ret; 00603 } else if ( QLatin1String( "above" ) == cpos ) { 00604 ret = country() + QLatin1String( "\n\n" ) + ret; 00605 } 00606 } 00607 00608 return ret; 00609 } 00610 00611 QString Address::countryToISO( const QString &cname ) 00612 { 00613 // we search a map file for translations from country names to 00614 // iso codes, storing caching things in a QMap for faster future 00615 // access. 00616 typedef QMap<QString, QString> stringMap; 00617 K_GLOBAL_STATIC( stringMap, sISOMap ) 00618 00619 QMap<QString, QString>::ConstIterator it; 00620 it = sISOMap->constFind( cname ); 00621 if ( it != sISOMap->constEnd() ) { 00622 return it.value(); 00623 } 00624 00625 QString mapfile = KGlobal::dirs()->findResource( "data", 00626 QLatin1String( "kabc/countrytransl.map" ) ); 00627 00628 QFile file( mapfile ); 00629 if ( file.open( QIODevice::ReadOnly ) ) { 00630 QTextStream s( &file ); 00631 QString strbuf = s.readLine(); 00632 while ( !strbuf.isEmpty() ) { 00633 QStringList countryInfo = strbuf.split( QLatin1Char( '\t' ), QString::KeepEmptyParts ); 00634 if ( countryInfo[ 0 ] == cname ) { 00635 file.close(); 00636 sISOMap->insert( cname, countryInfo[ 1 ] ); 00637 return countryInfo[ 1 ]; 00638 } 00639 strbuf = s.readLine(); 00640 } 00641 file.close(); 00642 } 00643 00644 // fall back to system country 00645 sISOMap->insert( cname, KGlobal::locale()->country() ); 00646 return KGlobal::locale()->country(); 00647 } 00648 00649 QString Address::ISOtoCountry( const QString &ISOname ) 00650 { 00651 // get country name from ISO country code (e.g. "no" -> i18n("Norway")) 00652 if ( ISOname.simplified().isEmpty() ) { 00653 return QString(); 00654 } 00655 00656 QString mapfile = KGlobal::dirs()->findResource( "data", 00657 QLatin1String( "kabc/countrytransl.map" ) ); 00658 00659 QFile file( mapfile ); 00660 if ( file.open( QIODevice::ReadOnly ) ) { 00661 QTextStream s( &file ); 00662 QString searchStr = QLatin1Char( '\t' ) + ISOname.simplified().toLower(); 00663 QString strbuf = s.readLine(); 00664 int pos; 00665 while ( !strbuf.isEmpty() ) { 00666 if ( ( pos = strbuf.indexOf( searchStr ) ) != -1 ) { 00667 file.close(); 00668 return i18n( strbuf.left( pos ).toUtf8() ); 00669 } 00670 strbuf = s.readLine(); 00671 } 00672 file.close(); 00673 } 00674 00675 return ISOname; 00676 } 00677 00678 QDataStream &KABC::operator<<( QDataStream &s, const Address &addr ) 00679 { 00680 return s << addr.d->mId << (uint)addr.d->mType << addr.d->mPostOfficeBox 00681 << addr.d->mExtended << addr.d->mStreet << addr.d->mLocality 00682 << addr.d->mRegion << addr.d->mPostalCode << addr.d->mCountry 00683 << addr.d->mLabel << addr.d->mEmpty; 00684 } 00685 00686 QDataStream &KABC::operator>>( QDataStream &s, Address &addr ) 00687 { 00688 uint type; 00689 s >> addr.d->mId >> type >> addr.d->mPostOfficeBox >> addr.d->mExtended 00690 >> addr.d->mStreet >> addr.d->mLocality >> addr.d->mRegion 00691 >> addr.d->mPostalCode >> addr.d->mCountry >> addr.d->mLabel 00692 >> addr.d->mEmpty; 00693 00694 addr.d->mType = Address::Type( type ); 00695 00696 return s; 00697 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon Apr 30 2012 21:49:55 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon Apr 30 2012 21:49:55 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.