addressee.src.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <ksharedptr.h>
00021 #include <kdebug.h>
00022 #include <kapplication.h>
00023 #include <klocale.h>
00024
00025 #include "resource.h"
00026 #include "addressee.h"
00027
00028 using namespace KABC;
00029
00030 bool matchBinaryPattern( int value, int pattern, int max );
00031
00032 struct Addressee::AddresseeData : public KShared
00033 {
00034 --VARIABLES--
00035
00036 PhoneNumber::List phoneNumbers;
00037 Address::List addresses;
00038 Key::List keys;
00039 QStringList emails;
00040 QStringList categories;
00041 QStringList custom;
00042
00043 Resource *resource;
00044
00045 bool empty;
00046 bool changed;
00047 };
00048
00049 Addressee::Addressee()
00050 {
00051 mData = new AddresseeData;
00052 mData->uid = KApplication::randomString( 10 );
00053 mData->empty = true;
00054 mData->changed = false;
00055 mData->resource = 0;
00056 }
00057
00058 Addressee::~Addressee()
00059 {
00060 }
00061
00062 Addressee::Addressee( const Addressee &a )
00063 {
00064 mData = a.mData;
00065 }
00066
00067 Addressee &Addressee::operator=( const Addressee &a )
00068 {
00069 mData = a.mData;
00070 return (*this);
00071 }
00072
00073 Addressee Addressee::copy()
00074 {
00075 Addressee a;
00076 *(a.mData) = *mData;
00077 return a;
00078 }
00079
00080 void Addressee::detach()
00081 {
00082 if ( mData.count() == 1 ) return;
00083 *this = copy();
00084 }
00085
00086 bool Addressee::operator==( const Addressee &a ) const
00087 {
00088 --EQUALSTEST--
00089 if ( ( mData->url.isValid() || a.mData->url.isValid() ) &&
00090 ( mData->url != a.mData->url ) ) return false;
00091 if ( mData->phoneNumbers != a.mData->phoneNumbers ) return false;
00092 if ( mData->addresses != a.mData->addresses ) return false;
00093 if ( mData->keys != a.mData->keys ) return false;
00094 if ( mData->emails != a.mData->emails ) return false;
00095 if ( mData->categories != a.mData->categories ) return false;
00096 if ( mData->custom != a.mData->custom ) return false;
00097
00098 return true;
00099 }
00100
00101 bool Addressee::operator!=( const Addressee &a ) const
00102 {
00103 return !( a == *this );
00104 }
00105
00106 bool Addressee::isEmpty() const
00107 {
00108 return mData->empty;
00109 }
00110
00111 --DEFINITIONS--
00112
00113 void Addressee::setNameFromString( const QString &str )
00114 {
00115 setFormattedName( str );
00116 setName( str );
00117
00118 QStringList titles;
00119 titles += i18n( "Dr." );
00120 titles += i18n( "Miss" );
00121 titles += i18n( "Mr." );
00122 titles += i18n( "Mrs." );
00123 titles += i18n( "Ms." );
00124 titles += i18n( "Prof." );
00125
00126 QStringList suffixes;
00127 suffixes += i18n( "I" );
00128 suffixes += i18n( "II" );
00129 suffixes += i18n( "III" );
00130 suffixes += i18n( "Jr." );
00131 suffixes += i18n( "Sr." );
00132
00133 QStringList prefixes;
00134 prefixes += "van";
00135 prefixes += "von";
00136 prefixes += "de";
00137
00138
00139 setPrefix( "" );
00140 setGivenName( "" );
00141 setAdditionalName( "" );
00142 setFamilyName( "" );
00143 setSuffix( "" );
00144
00145 if ( str.isEmpty() )
00146 return;
00147
00148 int i = str.find(',');
00149 if( i < 0 ) {
00150 QStringList parts = QStringList::split( " ", str );
00151 int leftOffset = 0;
00152 int rightOffset = parts.count() - 1;
00153
00154 QString suffix;
00155 while ( rightOffset >= 0 ) {
00156 if ( suffixes.contains( parts[ rightOffset ] ) ) {
00157 suffix.prepend(parts[ rightOffset ] + (suffix.isEmpty() ? "" : " "));
00158 rightOffset--;
00159 } else
00160 break;
00161 }
00162 setSuffix( suffix );
00163
00164 if ( rightOffset < 0 )
00165 return;
00166
00167 if ( rightOffset - 1 >= 0 && prefixes.contains( parts[ rightOffset - 1 ].lower() ) ) {
00168 setFamilyName( parts[ rightOffset - 1 ] + " " + parts[ rightOffset ] );
00169 rightOffset--;
00170 } else
00171 setFamilyName( parts[ rightOffset ] );
00172
00173 QString prefix;
00174 while ( leftOffset < rightOffset ) {
00175 if ( titles.contains( parts[ leftOffset ] ) ) {
00176 prefix.append( ( prefix.isEmpty() ? "" : " ") + parts[ leftOffset ] );
00177 leftOffset++;
00178 } else
00179 break;
00180 }
00181 setPrefix( prefix );
00182
00183 if ( leftOffset < rightOffset ) {
00184 setGivenName( parts[ leftOffset ] );
00185 leftOffset++;
00186 }
00187
00188 QString additionalName;
00189 while ( leftOffset < rightOffset ) {
00190 additionalName.append( ( additionalName.isEmpty() ? "" : " ") + parts[ leftOffset ] );
00191 leftOffset++;
00192 }
00193 setAdditionalName( additionalName );
00194 } else {
00195 QString part1 = str.left( i );
00196 QString part2 = str.mid( i + 1 );
00197
00198 QStringList parts = QStringList::split( " ", part1 );
00199 int leftOffset = 0;
00200 int rightOffset = parts.count() - 1;
00201
00202 QString suffix;
00203 while ( rightOffset >= 0 ) {
00204 if ( suffixes.contains( parts[ rightOffset ] ) ) {
00205 suffix.prepend(parts[ rightOffset ] + (suffix.isEmpty() ? "" : " "));
00206 rightOffset--;
00207 } else
00208 break;
00209 }
00210 setSuffix( suffix );
00211
00212 if ( rightOffset - 1 >= 0 && prefixes.contains( parts[ rightOffset - 1 ].lower() ) ) {
00213 setFamilyName( parts[ rightOffset - 1 ] + " " + parts[ rightOffset ] );
00214 rightOffset--;
00215 } else
00216 setFamilyName( parts[ rightOffset ] );
00217
00218 QString prefix;
00219 while ( leftOffset < rightOffset ) {
00220 if ( titles.contains( parts[ leftOffset ] ) ) {
00221 prefix.append( ( prefix.isEmpty() ? "" : " ") + parts[ leftOffset ] );
00222 leftOffset++;
00223 } else
00224 break;
00225 }
00226
00227 parts = QStringList::split( " ", part2 );
00228
00229 leftOffset = 0;
00230 rightOffset = parts.count();
00231
00232 while ( leftOffset < rightOffset ) {
00233 if ( titles.contains( parts[ leftOffset ] ) ) {
00234 prefix.append( ( prefix.isEmpty() ? "" : " ") + parts[ leftOffset ] );
00235 leftOffset++;
00236 } else
00237 break;
00238 }
00239 setPrefix( prefix );
00240
00241 if ( leftOffset < rightOffset ) {
00242 setGivenName( parts[ leftOffset ] );
00243 leftOffset++;
00244 }
00245
00246 QString additionalName;
00247 while ( leftOffset < rightOffset ) {
00248 additionalName.append( ( additionalName.isEmpty() ? "" : " ") + parts[ leftOffset ] );
00249 leftOffset++;
00250 }
00251 setAdditionalName( additionalName );
00252 }
00253 }
00254
00255 QString Addressee::realName() const
00256 {
00257 if ( !formattedName().isEmpty() )
00258 return formattedName();
00259
00260 QString n = assembledName();
00261
00262 if ( n.isEmpty() )
00263 n = name();
00264
00265 return n;
00266 }
00267
00268 QString Addressee::assembledName() const
00269 {
00270 QString name = prefix() + " " + givenName() + " " + additionalName() + " " +
00271 familyName() + " " + suffix();
00272
00273 return name.simplifyWhiteSpace();
00274 }
00275
00276 QString Addressee::fullEmail( const QString &email ) const
00277 {
00278 QString e;
00279 if ( email.isNull() ) {
00280 e = preferredEmail();
00281 } else {
00282 e = email;
00283 }
00284 if ( e.isEmpty() ) return QString::null;
00285
00286 QString text;
00287 if ( realName().isEmpty() )
00288 text = e;
00289 else
00290 text = assembledName() + " <" + e + ">";
00291
00292 return text;
00293 }
00294
00295 void Addressee::insertEmail( const QString &email, bool preferred )
00296 {
00297 detach();
00298
00299 QStringList::Iterator it = mData->emails.find( email );
00300
00301 if ( it != mData->emails.end() ) {
00302 if ( !preferred || it == mData->emails.begin() ) return;
00303 mData->emails.remove( it );
00304 mData->emails.prepend( email );
00305 } else {
00306 if ( preferred ) {
00307 mData->emails.prepend( email );
00308 } else {
00309 mData->emails.append( email );
00310 }
00311 }
00312 }
00313
00314 void Addressee::removeEmail( const QString &email )
00315 {
00316 detach();
00317
00318 QStringList::Iterator it = mData->emails.find( email );
00319 if ( it == mData->emails.end() ) return;
00320
00321 mData->emails.remove( it );
00322 }
00323
00324 QString Addressee::preferredEmail() const
00325 {
00326 if ( mData->emails.count() == 0 ) return QString::null;
00327 else return mData->emails.first();
00328 }
00329
00330 QStringList Addressee::emails() const
00331 {
00332 return mData->emails;
00333 }
00334
00335 void Addressee::insertPhoneNumber( const PhoneNumber &phoneNumber )
00336 {
00337 detach();
00338 mData->empty = false;
00339
00340 PhoneNumber::List::Iterator it;
00341 for( it = mData->phoneNumbers.begin(); it != mData->phoneNumbers.end(); ++it ) {
00342 if ( (*it).id() == phoneNumber.id() ) {
00343 *it = phoneNumber;
00344 return;
00345 }
00346 }
00347 mData->phoneNumbers.append( phoneNumber );
00348 }
00349
00350 void Addressee::removePhoneNumber( const PhoneNumber &phoneNumber )
00351 {
00352 detach();
00353
00354 PhoneNumber::List::Iterator it;
00355 for( it = mData->phoneNumbers.begin(); it != mData->phoneNumbers.end(); ++it ) {
00356 if ( (*it).id() == phoneNumber.id() ) {
00357 mData->phoneNumbers.remove( it );
00358 return;
00359 }
00360 }
00361 }
00362
00363 PhoneNumber Addressee::phoneNumber( int type ) const
00364 {
00365 PhoneNumber phoneNumber( "", type );
00366 PhoneNumber::List::ConstIterator it;
00367 for( it = mData->phoneNumbers.begin(); it != mData->phoneNumbers.end(); ++it ) {
00368 if ( matchBinaryPattern( (*it).type(), type, PhoneNumber::Pager ) ) {
00369 if ( (*it).type() & PhoneNumber::Pref )
00370 return (*it);
00371 else if ( phoneNumber.number().isEmpty() )
00372 phoneNumber = (*it);
00373 }
00374 }
00375
00376 return phoneNumber;
00377 }
00378
00379 PhoneNumber::List Addressee::phoneNumbers() const
00380 {
00381 return mData->phoneNumbers;
00382 }
00383
00384 PhoneNumber::List Addressee::phoneNumbers( int type ) const
00385 {
00386 PhoneNumber::List list;
00387
00388 PhoneNumber::List::ConstIterator it;
00389 for( it = mData->phoneNumbers.begin(); it != mData->phoneNumbers.end(); ++it ) {
00390 if ( matchBinaryPattern( (*it).type(), type, PhoneNumber::Pager ) ) {
00391 list.append( *it );
00392 }
00393 }
00394 return list;
00395 }
00396
00397 PhoneNumber Addressee::findPhoneNumber( const QString &id ) const
00398 {
00399 PhoneNumber::List::ConstIterator it;
00400 for( it = mData->phoneNumbers.begin(); it != mData->phoneNumbers.end(); ++it ) {
00401 if ( (*it).id() == id ) {
00402 return *it;
00403 }
00404 }
00405 return PhoneNumber();
00406 }
00407
00408 void Addressee::insertKey( const Key &key )
00409 {
00410 detach();
00411 mData->empty = false;
00412
00413 Key::List::Iterator it;
00414 for( it = mData->keys.begin(); it != mData->keys.end(); ++it ) {
00415 if ( (*it).id() == key.id() ) {
00416 *it = key;
00417 return;
00418 }
00419 }
00420 mData->keys.append( key );
00421 }
00422
00423 void Addressee::removeKey( const Key &key )
00424 {
00425 detach();
00426
00427 Key::List::Iterator it;
00428 for( it = mData->keys.begin(); it != mData->keys.end(); ++it ) {
00429 if ( (*it).id() == key.id() ) {
00430 mData->keys.remove( key );
00431 return;
00432 }
00433 }
00434 }
00435
00436 Key Addressee::key( int type, QString customTypeString ) const
00437 {
00438 Key::List::ConstIterator it;
00439 for( it = mData->keys.begin(); it != mData->keys.end(); ++it ) {
00440 if ( (*it).type() == type ) {
00441 if ( type == Key::Custom ) {
00442 if ( customTypeString.isEmpty() ) {
00443 return *it;
00444 } else {
00445 if ( (*it).customTypeString() == customTypeString )
00446 return (*it);
00447 }
00448 } else {
00449 return *it;
00450 }
00451 }
00452 }
00453 return Key( QString(), type );
00454 }
00455
00456 Key::List Addressee::keys() const
00457 {
00458 return mData->keys;
00459 }
00460
00461 Key::List Addressee::keys( int type, QString customTypeString ) const
00462 {
00463 Key::List list;
00464
00465 Key::List::ConstIterator it;
00466 for( it = mData->keys.begin(); it != mData->keys.end(); ++it ) {
00467 if ( (*it).type() == type ) {
00468 if ( type == Key::Custom ) {
00469 if ( customTypeString.isEmpty() ) {
00470 list.append(*it);
00471 } else {
00472 if ( (*it).customTypeString() == customTypeString )
00473 list.append(*it);
00474 }
00475 } else {
00476 list.append(*it);
00477 }
00478 }
00479 }
00480 return list;
00481 }
00482
00483 Key Addressee::findKey( const QString &id ) const
00484 {
00485 Key::List::ConstIterator it;
00486 for( it = mData->keys.begin(); it != mData->keys.end(); ++it ) {
00487 if ( (*it).id() == id ) {
00488 return *it;
00489 }
00490 }
00491 return Key();
00492 }
00493
00494 QString Addressee::asString() const
00495 {
00496 return "Smith, special agent Smith...";
00497 }
00498
00499 void Addressee::dump() const
00500 {
00501 kdDebug(5700) << "Addressee {" << endl;
00502
00503 --DEBUG--
00504
00505 kdDebug(5700) << " Emails {" << endl;
00506 QStringList e = emails();
00507 QStringList::ConstIterator it;
00508 for( it = e.begin(); it != e.end(); ++it ) {
00509 kdDebug(5700) << " " << (*it) << endl;
00510 }
00511 kdDebug(5700) << " }" << endl;
00512
00513 kdDebug(5700) << " PhoneNumbers {" << endl;
00514 PhoneNumber::List p = phoneNumbers();
00515 PhoneNumber::List::ConstIterator it2;
00516 for( it2 = p.begin(); it2 != p.end(); ++it2 ) {
00517 kdDebug(5700) << " Type: " << int((*it2).type()) << " Number: " << (*it2).number() << endl;
00518 }
00519 kdDebug(5700) << " }" << endl;
00520
00521 Address::List a = addresses();
00522 Address::List::ConstIterator it3;
00523 for( it3 = a.begin(); it3 != a.end(); ++it3 ) {
00524 (*it3).dump();
00525 }
00526
00527 kdDebug(5700) << " Keys {" << endl;
00528 Key::List k = keys();
00529 Key::List::ConstIterator it4;
00530 for( it4 = k.begin(); it4 != k.end(); ++it4 ) {
00531 kdDebug(5700) << " Type: " << int((*it4).type()) <<
00532 " Key: " << (*it4).textData() <<
00533 " CustomString: " << (*it4).customTypeString() << endl;
00534 }
00535 kdDebug(5700) << " }" << endl;
00536
00537 kdDebug(5700) << "}" << endl;
00538 }
00539
00540
00541 void Addressee::insertAddress( const Address &address )
00542 {
00543 detach();
00544 mData->empty = false;
00545
00546 Address::List::Iterator it;
00547 for( it = mData->addresses.begin(); it != mData->addresses.end(); ++it ) {
00548 if ( (*it).id() == address.id() ) {
00549 *it = address;
00550 return;
00551 }
00552 }
00553 mData->addresses.append( address );
00554 }
00555
00556 void Addressee::removeAddress( const Address &address )
00557 {
00558 detach();
00559
00560 Address::List::Iterator it;
00561 for( it = mData->addresses.begin(); it != mData->addresses.end(); ++it ) {
00562 if ( (*it).id() == address.id() ) {
00563 mData->addresses.remove( it );
00564 return;
00565 }
00566 }
00567 }
00568
00569 Address Addressee::address( int type ) const
00570 {
00571 Address address( type );
00572 Address::List::ConstIterator it;
00573 for( it = mData->addresses.begin(); it != mData->addresses.end(); ++it ) {
00574 if ( matchBinaryPattern( (*it).type(), type, Address::Pref ) ) {
00575 if ( (*it).type() & Address::Pref )
00576 return (*it);
00577 else if ( address.isEmpty() )
00578 address = (*it);
00579 }
00580 }
00581
00582 return address;
00583 }
00584
00585 Address::List Addressee::addresses() const
00586 {
00587 return mData->addresses;
00588 }
00589
00590 Address::List Addressee::addresses( int type ) const
00591 {
00592 Address::List list;
00593
00594 Address::List::ConstIterator it;
00595 for( it = mData->addresses.begin(); it != mData->addresses.end(); ++it ) {
00596 if ( matchBinaryPattern( (*it).type(), type , Address::Pref ) ) {
00597 list.append( *it );
00598 }
00599 }
00600
00601 return list;
00602 }
00603
00604 Address Addressee::findAddress( const QString &id ) const
00605 {
00606 Address::List::ConstIterator it;
00607 for( it = mData->addresses.begin(); it != mData->addresses.end(); ++it ) {
00608 if ( (*it).id() == id ) {
00609 return *it;
00610 }
00611 }
00612 return Address();
00613 }
00614
00615 void Addressee::insertCategory( const QString &c )
00616 {
00617 detach();
00618 mData->empty = false;
00619
00620 if ( mData->categories.contains( c ) ) return;
00621
00622 mData->categories.append( c );
00623 }
00624
00625 void Addressee::removeCategory( const QString &c )
00626 {
00627 detach();
00628
00629 QStringList::Iterator it = mData->categories.find( c );
00630 if ( it == mData->categories.end() ) return;
00631
00632 mData->categories.remove( it );
00633 }
00634
00635 bool Addressee::hasCategory( const QString &c ) const
00636 {
00637 return ( mData->categories.contains( c ) );
00638 }
00639
00640 void Addressee::setCategories( const QStringList &c )
00641 {
00642 detach();
00643 mData->empty = false;
00644
00645 mData->categories = c;
00646 }
00647
00648 QStringList Addressee::categories() const
00649 {
00650 return mData->categories;
00651 }
00652
00653 void Addressee::insertCustom( const QString &app, const QString &name,
00654 const QString &value )
00655 {
00656 if ( value.isNull() || name.isEmpty() || app.isEmpty() ) return;
00657
00658 detach();
00659 mData->empty = false;
00660
00661 QString qualifiedName = app + "-" + name + ":";
00662
00663 QStringList::Iterator it;
00664 for( it = mData->custom.begin(); it != mData->custom.end(); ++it ) {
00665 if ( (*it).startsWith( qualifiedName ) ) {
00666 (*it) = qualifiedName + value;
00667 return;
00668 }
00669 }
00670
00671 mData->custom.append( qualifiedName + value );
00672 }
00673
00674 void Addressee::removeCustom( const QString &app, const QString &name)
00675 {
00676 detach();
00677
00678 QString qualifiedName = app + "-" + name + ":";
00679
00680 QStringList::Iterator it;
00681 for( it = mData->custom.begin(); it != mData->custom.end(); ++it ) {
00682 if ( (*it).startsWith( qualifiedName ) ) {
00683 mData->custom.remove( it );
00684 return;
00685 }
00686 }
00687 }
00688
00689 QString Addressee::custom( const QString &app, const QString &name ) const
00690 {
00691 QString qualifiedName = app + "-" + name + ":";
00692 QString value;
00693
00694 QStringList::ConstIterator it;
00695 for( it = mData->custom.begin(); it != mData->custom.end(); ++it ) {
00696 if ( (*it).startsWith( qualifiedName ) ) {
00697 value = (*it).mid( (*it).find( ":" ) + 1 );
00698 break;
00699 }
00700 }
00701
00702 return value;
00703 }
00704
00705 void Addressee::setCustoms( const QStringList &l )
00706 {
00707 detach();
00708 mData->empty = false;
00709
00710 mData->custom = l;
00711 }
00712
00713 QStringList Addressee::customs() const
00714 {
00715 return mData->custom;
00716 }
00717
00718 void Addressee::parseEmailAddress( const QString &rawEmail, QString &fullName,
00719 QString &email)
00720 {
00721 int startPos, endPos, len;
00722 QString partA, partB, result;
00723 char endCh = '>';
00724
00725 startPos = rawEmail.find('<');
00726 if (startPos < 0)
00727 {
00728 startPos = rawEmail.find('(');
00729 endCh = ')';
00730 }
00731 if (startPos < 0)
00732 {
00733
00734
00735 email = rawEmail;
00736 fullName = "";
00737 }
00738 else
00739 {
00740
00741 endPos = rawEmail.find(endCh, startPos+1);
00742
00743 if (endPos < 0)
00744 {
00745
00746
00747 email = rawEmail;
00748 fullName = "";
00749 }
00750 else
00751 {
00752
00753
00754
00755 fullName = rawEmail.left(startPos).stripWhiteSpace();
00756
00757
00758 email = rawEmail.mid(startPos+1, endPos-startPos-1).stripWhiteSpace();
00759
00760
00761
00762 len = fullName.length();
00763 if (fullName[0]=='"' && fullName[len-1]=='"')
00764 fullName = fullName.mid(1, len-2);
00765 else if (fullName[0]=='<' && fullName[len-1]=='>')
00766 fullName = fullName.mid(1, len-2);
00767 else if (fullName[0]=='(' && fullName[len-1]==')')
00768 fullName = fullName.mid(1, len-2);
00769 }
00770 }
00771 }
00772
00773 void Addressee::setResource( Resource *resource )
00774 {
00775 detach();
00776 mData->resource = resource;
00777 }
00778
00779 Resource *Addressee::resource() const
00780 {
00781 return mData->resource;
00782 }
00783
00784 void Addressee::setChanged( bool value )
00785 {
00786 detach();
00787 mData->changed = value;
00788 }
00789
00790 bool Addressee::changed() const
00791 {
00792 return mData->changed;
00793 }
00794
00795 QDataStream &KABC::operator<<( QDataStream &s, const Addressee &a )
00796 {
00797 if (!a.mData) return s;
00798
00799 --STREAMOUT--
00800 s << a.mData->phoneNumbers;
00801 s << a.mData->addresses;
00802 s << a.mData->emails;
00803 s << a.mData->categories;
00804 s << a.mData->custom;
00805 s << a.mData->keys;
00806 return s;
00807 }
00808
00809 QDataStream &KABC::operator>>( QDataStream &s, Addressee &a )
00810 {
00811 if (!a.mData) return s;
00812
00813 --STREAMIN--
00814 s >> a.mData->phoneNumbers;
00815 s >> a.mData->addresses;
00816 s >> a.mData->emails;
00817 s >> a.mData->categories;
00818 s >> a.mData->custom;
00819 s >> a.mData->keys;
00820
00821 a.mData->empty = false;
00822
00823 return s;
00824 }
00825
00826 bool matchBinaryPattern( int value, int pattern, int max )
00827 {
00828 if ( pattern == 0 ) {
00829 if ( value != 0 )
00830 return false;
00831 else
00832 return true;
00833 }
00834
00835 int counter = 0;
00836 while ( 1 ) {
00837 if ( ( pattern & ( 1 << counter ) ) && !( value & ( 1 << counter ) ) )
00838 return false;
00839
00840 if ( ( 1 << counter ) == max )
00841 break;
00842
00843 counter++;
00844 }
00845
00846 return true;
00847 }
This file is part of the documentation for kdelibs Version 3.1.4.