kdeui Library API Documentation

ksyntaxhighlighter.cpp

00001 /* 00002 ksyntaxhighlighter.cpp 00003 00004 Copyright (c) 2003 Trolltech AS 00005 Copyright (c) 2003 Scott Wheeler <wheeler@kde.org> 00006 00007 This file is part of the KDE libraries 00008 00009 This library is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU Library General Public 00011 License version 2 as published by the Free Software Foundation. 00012 00013 This library is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 Library General Public License for more details. 00017 00018 You should have received a copy of the GNU Library General Public License 00019 along with this library; see the file COPYING.LIB. If not, write to 00020 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00021 Boston, MA 02111-1307, USA. 00022 */ 00023 00024 #include <qcolor.h> 00025 #include <qregexp.h> 00026 #include <qsyntaxhighlighter.h> 00027 #include <qtimer.h> 00028 00029 #include <klocale.h> 00030 #include <kconfig.h> 00031 #include <kdebug.h> 00032 #include <kglobal.h> 00033 #include <kspell.h> 00034 #include <kapplication.h> 00035 00036 #include "ksyntaxhighlighter.h" 00037 00038 static int dummy, dummy2, dummy3, dummy4; 00039 static int *Okay = &dummy; 00040 static int *NotOkay = &dummy2; 00041 static int *Ignore = &dummy3; 00042 static int *Unknown = &dummy4; 00043 static const int tenSeconds = 10*1000; 00044 00045 class KSyntaxHighlighter::KSyntaxHighlighterPrivate 00046 { 00047 public: 00048 QColor col1, col2, col3, col4, col5; 00049 SyntaxMode mode; 00050 bool enabled; 00051 }; 00052 00053 class KSpellingHighlighter::KSpellingHighlighterPrivate 00054 { 00055 public: 00056 00057 KSpellingHighlighterPrivate() : 00058 alwaysEndsWithSpace( true ), 00059 intraWordEditing( false ) {} 00060 00061 QString currentWord; 00062 int currentPos; 00063 bool alwaysEndsWithSpace; 00064 QColor color; 00065 bool intraWordEditing; 00066 }; 00067 00068 class KDictSpellingHighlighter::KDictSpellingHighlighterPrivate 00069 { 00070 public: 00071 KDictSpellingHighlighterPrivate() : 00072 mDict( 0 ), 00073 spell( 0 ), 00074 mSpellConfig( 0 ), 00075 rehighlightRequest( 0 ), 00076 wordCount( 0 ), 00077 errorCount( 0 ), 00078 autoReady( false ), 00079 globalConfig( true ), 00080 spellReady( false ) {} 00081 00082 ~KDictSpellingHighlighterPrivate() { 00083 delete rehighlightRequest; 00084 delete spell; 00085 } 00086 00087 static QDict<int>* sDict() 00088 { 00089 if (!statDict) 00090 statDict = new QDict<int>(50021); 00091 return statDict; 00092 } 00093 00094 QDict<int>* mDict; 00095 QDict<int> autoDict; 00096 QDict<int> autoIgnoreDict; 00097 static QObject *sDictionaryMonitor; 00098 KSpell *spell; 00099 KSpellConfig *mSpellConfig; 00100 QTimer *rehighlightRequest, *spellTimeout; 00101 QString spellKey; 00102 int wordCount, errorCount; 00103 int checksRequested, checksDone; 00104 bool completeRehighlightRequired; 00105 bool active, automatic, autoReady; 00106 bool globalConfig, spellReady; 00107 private: 00108 static QDict<int>* statDict; 00109 00110 }; 00111 00112 QDict<int>* KDictSpellingHighlighter::KDictSpellingHighlighterPrivate::statDict = 0; 00113 00114 00115 KSyntaxHighlighter::KSyntaxHighlighter( QTextEdit *textEdit, 00116 bool colorQuoting, 00117 const QColor& depth0, 00118 const QColor& depth1, 00119 const QColor& depth2, 00120 const QColor& depth3, 00121 SyntaxMode mode ) 00122 : QSyntaxHighlighter( textEdit ) 00123 { 00124 d = new KSyntaxHighlighterPrivate(); 00125 00126 d->enabled = colorQuoting; 00127 d->col1 = depth0; 00128 d->col2 = depth1; 00129 d->col3 = depth2; 00130 d->col4 = depth3; 00131 d->col5 = depth0; 00132 00133 d->mode = mode; 00134 } 00135 00136 KSyntaxHighlighter::~KSyntaxHighlighter() 00137 { 00138 delete d; 00139 } 00140 00141 int KSyntaxHighlighter::highlightParagraph( const QString &text, int ) 00142 { 00143 if (!d->enabled) { 00144 setFormat( 0, text.length(), textEdit()->viewport()->paletteForegroundColor() ); 00145 return 0; 00146 } 00147 00148 QString simplified = text; 00149 simplified = simplified.replace( QRegExp( "\\s" ), "" ).replace( "|", ">" ); 00150 while ( simplified.startsWith( ">>>>" ) ) 00151 simplified = simplified.mid(3); 00152 if ( simplified.startsWith( ">>>" ) || simplified.startsWith( "> > >" ) ) 00153 setFormat( 0, text.length(), d->col2 ); 00154 else if ( simplified.startsWith( ">>" ) || simplified.startsWith( "> >" ) ) 00155 setFormat( 0, text.length(), d->col3 ); 00156 else if ( simplified.startsWith( ">" ) ) 00157 setFormat( 0, text.length(), d->col4 ); 00158 else 00159 setFormat( 0, text.length(), d->col5 ); 00160 return 0; 00161 } 00162 00163 KSpellingHighlighter::KSpellingHighlighter( QTextEdit *textEdit, 00164 const QColor& spellColor, 00165 bool colorQuoting, 00166 const QColor& depth0, 00167 const QColor& depth1, 00168 const QColor& depth2, 00169 const QColor& depth3 ) 00170 : KSyntaxHighlighter( textEdit, colorQuoting, depth0, depth1, depth2, depth3 ) 00171 { 00172 d = new KSpellingHighlighterPrivate(); 00173 00174 d->color = spellColor; 00175 } 00176 00177 KSpellingHighlighter::~KSpellingHighlighter() 00178 { 00179 delete d; 00180 } 00181 00182 int KSpellingHighlighter::highlightParagraph( const QString &text, 00183 int paraNo ) 00184 { 00185 if ( paraNo == -2 ) 00186 paraNo = 0; 00187 // leave #includes, diffs, and quoted replies alone 00188 QString diffAndCo( ">|" ); 00189 00190 bool isCode = diffAndCo.find(text[0]) != -1; 00191 00192 if ( !text.endsWith(" ") ) 00193 d->alwaysEndsWithSpace = false; 00194 00195 KSyntaxHighlighter::highlightParagraph( text, -2 ); 00196 00197 if ( !isCode ) { 00198 int para, index; 00199 textEdit()->getCursorPosition( &para, &index ); 00200 int len = text.length(); 00201 if ( d->alwaysEndsWithSpace ) 00202 len--; 00203 00204 d->currentPos = 0; 00205 d->currentWord = ""; 00206 for ( int i = 0; i < len; i++ ) { 00207 if ( !text[i].isLetter() && (!(text[i] == '\'')) ) { 00208 if ( ( para != paraNo ) || 00209 !intraWordEditing() || 00210 ( i - d->currentWord.length() > (uint)index ) || 00211 ( i < index ) ) { 00212 flushCurrentWord(); 00213 } else { 00214 d->currentWord = ""; 00215 } 00216 d->currentPos = i + 1; 00217 } else { 00218 d->currentWord += text[i]; 00219 } 00220 } 00221 if ( !text[len - 1].isLetter() || 00222 (uint)( index + 1 ) != text.length() || 00223 para != paraNo ) 00224 flushCurrentWord(); 00225 } 00226 return ++paraNo; 00227 } 00228 00229 QStringList KSpellingHighlighter::personalWords() 00230 { 00231 QStringList l; 00232 l.append( "KMail" ); 00233 l.append( "KOrganizer" ); 00234 l.append( "KAddressBook" ); 00235 l.append( "KHTML" ); 00236 l.append( "KIO" ); 00237 l.append( "KJS" ); 00238 l.append( "Konqueror" ); 00239 l.append( "KSpell" ); 00240 l.append( "Kontact" ); 00241 l.append( "Qt" ); 00242 return l; 00243 } 00244 00245 void KSpellingHighlighter::flushCurrentWord() 00246 { 00247 while ( d->currentWord[0].isPunct() ) { 00248 d->currentWord = d->currentWord.mid( 1 ); 00249 d->currentPos++; 00250 } 00251 00252 QChar ch; 00253 while ( ( ch = d->currentWord[(int) d->currentWord.length() - 1] ).isPunct() && 00254 ch != '(' && ch != '@' ) 00255 d->currentWord.truncate( d->currentWord.length() - 1 ); 00256 00257 if ( !d->currentWord.isEmpty() ) { 00258 if ( isMisspelled( d->currentWord ) ) { 00259 setFormat( d->currentPos, d->currentWord.length(), d->color ); 00260 // setMisspelled( d->currentPos, d->currentWord.length(), true ); 00261 } 00262 } 00263 d->currentWord = ""; 00264 } 00265 00266 QObject *KDictSpellingHighlighter::KDictSpellingHighlighterPrivate::sDictionaryMonitor = 0; 00267 00268 KDictSpellingHighlighter::KDictSpellingHighlighter( QTextEdit *textEdit, 00269 bool spellCheckingActive , 00270 bool autoEnable, 00271 const QColor& spellColor, 00272 bool colorQuoting, 00273 const QColor& depth0, 00274 const QColor& depth1, 00275 const QColor& depth2, 00276 const QColor& depth3, 00277 KSpellConfig *spellConfig ) 00278 : KSpellingHighlighter( textEdit, spellColor, 00279 colorQuoting, depth0, depth1, depth2, depth3 ) 00280 { 00281 d = new KDictSpellingHighlighterPrivate(); 00282 00283 d->mSpellConfig = spellConfig; 00284 d->globalConfig = ( spellConfig == 0 ); 00285 d->automatic = autoEnable; 00286 d->active = spellCheckingActive; 00287 d->checksRequested = 0; 00288 d->checksDone = 0; 00289 d->completeRehighlightRequired = false; 00290 00291 textEdit->installEventFilter( this ); 00292 textEdit->viewport()->installEventFilter( this ); 00293 00294 d->rehighlightRequest = new QTimer(this); 00295 connect( d->rehighlightRequest, SIGNAL( timeout() ), 00296 this, SLOT( slotRehighlight() )); 00297 d->spellTimeout = new QTimer(this); 00298 connect( d->spellTimeout, SIGNAL( timeout() ), 00299 this, SLOT( slotKSpellNotResponding() )); 00300 00301 if ( d->globalConfig ) { 00302 d->spellKey = spellKey(); 00303 00304 if ( !d->sDictionaryMonitor ) 00305 d->sDictionaryMonitor = new QObject(); 00306 } 00307 else { 00308 d->mDict = new QDict<int>(4001); 00309 connect( d->mSpellConfig, SIGNAL( configChanged() ), 00310 this, SLOT( slotLocalSpellConfigChanged() ) ); 00311 } 00312 00313 slotDictionaryChanged(); 00314 startTimer( 2 * 1000 ); 00315 } 00316 00317 KDictSpellingHighlighter::~KDictSpellingHighlighter() 00318 { 00319 delete d->spell; 00320 d->spell = 0; 00321 delete d->mDict; 00322 d->mDict = 0; 00323 delete d; 00324 } 00325 00326 void KDictSpellingHighlighter::slotSpellReady( KSpell *spell ) 00327 { 00328 kdDebug(0) << "KDictSpellingHighlighter::slotSpellReady( " << spell << " )" << endl; 00329 if ( d->globalConfig ) { 00330 connect( d->sDictionaryMonitor, SIGNAL( destroyed()), 00331 this, SLOT( slotDictionaryChanged() )); 00332 } 00333 if ( spell != d->spell ) 00334 { 00335 delete d->spell; 00336 d->spell = spell; 00337 } 00338 d->spellReady = true; 00339 const QStringList l = KSpellingHighlighter::personalWords(); 00340 for ( QStringList::ConstIterator it = l.begin(); it != l.end(); ++it ) { 00341 d->spell->addPersonal( *it ); 00342 } 00343 connect( spell, SIGNAL( misspelling( const QString &, const QStringList &, unsigned int )), 00344 this, SLOT( slotMisspelling( const QString &, const QStringList &, unsigned int ))); 00345 connect( spell, SIGNAL( corrected( const QString &, const QString &, unsigned int )), 00346 this, SLOT( slotCorrected( const QString &, const QString &, unsigned int ))); 00347 d->checksRequested = 0; 00348 d->checksDone = 0; 00349 d->completeRehighlightRequired = true; 00350 d->rehighlightRequest->start( 0, true ); 00351 } 00352 00353 bool KDictSpellingHighlighter::isMisspelled( const QString &word ) 00354 { 00355 if (!d->spellReady) 00356 return false; 00357 00358 // This debug is expensive, only enable it locally 00359 //kdDebug(0) << "KDictSpellingHighlighter::isMisspelled( \"" << word << "\" )" << endl; 00360 // Normally isMisspelled would look up a dictionary and return 00361 // true or false, but kspell is asynchronous and slow so things 00362 // get tricky... 00363 // For auto detection ignore signature and reply prefix 00364 if ( !d->autoReady ) 00365 d->autoIgnoreDict.replace( word, Ignore ); 00366 00367 // "dict" is used as a cache to store the results of KSpell 00368 QDict<int>* dict = ( d->globalConfig ? d->sDict() : d->mDict ); 00369 if ( !dict->isEmpty() && (*dict)[word] == NotOkay ) { 00370 if ( d->autoReady && ( d->autoDict[word] != NotOkay )) { 00371 if ( !d->autoIgnoreDict[word] ) 00372 ++d->errorCount; 00373 d->autoDict.replace( word, NotOkay ); 00374 } 00375 00376 return d->active; 00377 } 00378 if ( !dict->isEmpty() && (*dict)[word] == Okay ) { 00379 if ( d->autoReady && !d->autoDict[word] ) { 00380 d->autoDict.replace( word, Okay ); 00381 } 00382 return false; 00383 } 00384 00385 if ((dict->isEmpty() || ((*dict)[word] == 0)) && d->spell ) { 00386 int para, index; 00387 textEdit()->getCursorPosition( &para, &index ); 00388 ++d->wordCount; 00389 dict->replace( word, Unknown ); 00390 ++d->checksRequested; 00391 if (currentParagraph() != para) 00392 d->completeRehighlightRequired = true; 00393 d->spellTimeout->start( tenSeconds, true ); 00394 d->spell->checkWord( word, false ); 00395 } 00396 return false; 00397 } 00398 00399 bool KSpellingHighlighter::intraWordEditing() const 00400 { 00401 return d->intraWordEditing; 00402 } 00403 00404 void KSpellingHighlighter::setIntraWordEditing( bool editing ) 00405 { 00406 d->intraWordEditing = editing; 00407 } 00408 00409 void KDictSpellingHighlighter::slotMisspelling (const QString &originalWord, const QStringList &suggestions, 00410 unsigned int pos) 00411 { 00412 Q_UNUSED( suggestions ); 00413 // kdDebug() << suggestions.join( " " ).latin1() << endl; 00414 if ( d->globalConfig ) 00415 d->sDict()->replace( originalWord, NotOkay ); 00416 else 00417 d->mDict->replace( originalWord, NotOkay ); 00418 00419 //Emit this baby so that apps that want to have suggestions in a popup over 00420 //the misspelled word can catch them. 00421 emit newSuggestions( originalWord, suggestions, pos ); 00422 } 00423 00424 void KDictSpellingHighlighter::slotCorrected(const QString &word, 00425 const QString &, 00426 unsigned int) 00427 00428 { 00429 QDict<int>* dict = ( d->globalConfig ? d->sDict() : d->mDict ); 00430 if ( !dict->isEmpty() && (*dict)[word] == Unknown ) { 00431 dict->replace( word, Okay ); 00432 } 00433 ++d->checksDone; 00434 if (d->checksDone == d->checksRequested) { 00435 d->spellTimeout->stop(); 00436 slotRehighlight(); 00437 } else { 00438 d->spellTimeout->start( tenSeconds, true ); 00439 } 00440 } 00441 00442 void KDictSpellingHighlighter::dictionaryChanged() 00443 { 00444 QObject *oldMonitor = KDictSpellingHighlighterPrivate::sDictionaryMonitor; 00445 KDictSpellingHighlighterPrivate::sDictionaryMonitor = new QObject(); 00446 KDictSpellingHighlighterPrivate::sDict()->clear(); 00447 delete oldMonitor; 00448 } 00449 00450 void KDictSpellingHighlighter::restartBackgroundSpellCheck() 00451 { 00452 kdDebug(0) << "KDictSpellingHighlighter::restartBackgroundSpellCheck()" << endl; 00453 slotDictionaryChanged(); 00454 } 00455 00456 void KDictSpellingHighlighter::setActive( bool active ) 00457 { 00458 if ( active == d->active ) 00459 return; 00460 00461 d->active = active; 00462 rehighlight(); 00463 if ( d->active ) 00464 emit activeChanged( i18n("As-you-type spell checking enabled.") ); 00465 else 00466 emit activeChanged( i18n("As-you-type spell checking disabled.") ); 00467 } 00468 00469 bool KDictSpellingHighlighter::isActive() const 00470 { 00471 return d->active; 00472 } 00473 00474 void KDictSpellingHighlighter::setAutomatic( bool automatic ) 00475 { 00476 if ( automatic == d->automatic ) 00477 return; 00478 00479 d->automatic = automatic; 00480 if ( d->automatic ) 00481 slotAutoDetection(); 00482 } 00483 00484 bool KDictSpellingHighlighter::automatic() const 00485 { 00486 return d->automatic; 00487 } 00488 00489 void KDictSpellingHighlighter::slotRehighlight() 00490 { 00491 kdDebug(0) << "KDictSpellingHighlighter::slotRehighlight()" << endl; 00492 if (d->completeRehighlightRequired) { 00493 rehighlight(); 00494 } else { 00495 int para, index; 00496 textEdit()->getCursorPosition( &para, &index ); 00497 //rehighlight the current para only (undo/redo safe) 00498 textEdit()->insertAt( "", para, index ); 00499 } 00500 if (d->checksDone == d->checksRequested) 00501 d->completeRehighlightRequired = false; 00502 QTimer::singleShot( 0, this, SLOT( slotAutoDetection() )); 00503 } 00504 00505 void KDictSpellingHighlighter::slotDictionaryChanged() 00506 { 00507 delete d->spell; 00508 d->spellReady = false; 00509 d->wordCount = 0; 00510 d->errorCount = 0; 00511 d->autoDict.clear(); 00512 00513 d->spell = new KSpell( 0, i18n( "Incremental Spellcheck" ), this, 00514 SLOT( slotSpellReady( KSpell * ) ), d->mSpellConfig ); 00515 } 00516 00517 void KDictSpellingHighlighter::slotLocalSpellConfigChanged() 00518 { 00519 kdDebug(0) << "KDictSpellingHighlighter::slotSpellConfigChanged()" << endl; 00520 // the spell config has been changed, so we have to restart from scratch 00521 d->mDict->clear(); 00522 slotDictionaryChanged(); 00523 } 00524 00525 QString KDictSpellingHighlighter::spellKey() 00526 { 00527 KConfig *config = KGlobal::config(); 00528 KConfigGroupSaver cs( config, "KSpell" ); 00529 config->reparseConfiguration(); 00530 QString key; 00531 key += QString::number( config->readNumEntry( "KSpell_NoRootAffix", 0 )); 00532 key += '/'; 00533 key += QString::number( config->readNumEntry( "KSpell_RunTogether", 0 )); 00534 key += '/'; 00535 key += config->readEntry( "KSpell_Dictionary", "" ); 00536 key += '/'; 00537 key += QString::number( config->readNumEntry( "KSpell_DictFromList", false )); 00538 key += '/'; 00539 key += QString::number( config->readNumEntry( "KSpell_Encoding", KS_E_ASCII )); 00540 key += '/'; 00541 key += QString::number( config->readNumEntry( "KSpell_Client", KS_CLIENT_ISPELL )); 00542 return key; 00543 } 00544 00545 00546 // Automatic spell checking support 00547 // In auto spell checking mode disable as-you-type spell checking 00548 // iff more than one third of words are spelt incorrectly. 00549 // 00550 // Words in the signature and reply prefix are ignored. 00551 // Only unique words are counted. 00552 00553 void KDictSpellingHighlighter::slotAutoDetection() 00554 { 00555 if ( !d->autoReady ) 00556 return; 00557 00558 bool savedActive = d->active; 00559 00560 if ( d->automatic ) { 00561 if ( d->active && ( d->errorCount * 3 >= d->wordCount )) // too many errors 00562 d->active = false; 00563 else if ( !d->active && ( d->errorCount * 3 < d->wordCount )) 00564 d->active = true; 00565 } 00566 if ( d->active != savedActive ) { 00567 if ( d->wordCount > 1 ) 00568 if ( d->active ) 00569 emit activeChanged( i18n("As-you-type spell checking enabled.") ); 00570 else 00571 emit activeChanged( i18n( "Too many misspelled words. " 00572 "As-you-type spell checking disabled." ) ); 00573 d->completeRehighlightRequired = true; 00574 d->rehighlightRequest->start( 100, true ); 00575 } 00576 } 00577 00578 void KDictSpellingHighlighter::slotKSpellNotResponding() 00579 { 00580 static int retries = 0; 00581 if (retries < 10) { 00582 if ( d->globalConfig ) 00583 KDictSpellingHighlighter::dictionaryChanged(); 00584 else 00585 slotLocalSpellConfigChanged(); 00586 } else { 00587 setAutomatic( false ); 00588 setActive( false ); 00589 } 00590 ++retries; 00591 } 00592 00593 bool KDictSpellingHighlighter::eventFilter( QObject *o, QEvent *e) 00594 { 00595 if (o == textEdit() && (e->type() == QEvent::FocusIn)) { 00596 if ( d->globalConfig ) { 00597 QString skey = spellKey(); 00598 if ( d->spell && d->spellKey != skey ) { 00599 d->spellKey = skey; 00600 KDictSpellingHighlighter::dictionaryChanged(); 00601 } 00602 } 00603 } 00604 00605 if (o == textEdit() && (e->type() == QEvent::KeyPress)) { 00606 QKeyEvent *k = static_cast<QKeyEvent *>(e); 00607 d->autoReady = true; 00608 if (d->rehighlightRequest->isActive()) // try to stay out of the users way 00609 d->rehighlightRequest->changeInterval( 500 ); 00610 if ( k->key() == Key_Enter || 00611 k->key() == Key_Return || 00612 k->key() == Key_Up || 00613 k->key() == Key_Down || 00614 k->key() == Key_Left || 00615 k->key() == Key_Right || 00616 k->key() == Key_PageUp || 00617 k->key() == Key_PageDown || 00618 k->key() == Key_Home || 00619 k->key() == Key_End || 00620 (( k->state() & ControlButton ) && 00621 ((k->key() == Key_A) || 00622 (k->key() == Key_B) || 00623 (k->key() == Key_E) || 00624 (k->key() == Key_N) || 00625 (k->key() == Key_P))) ) { 00626 if ( intraWordEditing() ) { 00627 setIntraWordEditing( false ); 00628 d->completeRehighlightRequired = true; 00629 d->rehighlightRequest->start( 500, true ); 00630 } 00631 if (d->checksDone != d->checksRequested) { 00632 // Handle possible change of paragraph while 00633 // words are pending spell checking 00634 d->completeRehighlightRequired = true; 00635 d->rehighlightRequest->start( 500, true ); 00636 } 00637 } else { 00638 setIntraWordEditing( true ); 00639 } 00640 if ( k->key() == Key_Space || 00641 k->key() == Key_Enter || 00642 k->key() == Key_Return ) { 00643 QTimer::singleShot( 0, this, SLOT( slotAutoDetection() )); 00644 } 00645 } 00646 00647 else if ( o == textEdit()->viewport() && 00648 ( e->type() == QEvent::MouseButtonPress )) { 00649 d->autoReady = true; 00650 if ( intraWordEditing() ) { 00651 setIntraWordEditing( false ); 00652 d->completeRehighlightRequired = true; 00653 d->rehighlightRequest->start( 0, true ); 00654 } 00655 } 00656 00657 return false; 00658 } 00659 00660 #include "ksyntaxhighlighter.moc"
KDE Logo
This file is part of the documentation for kdeui Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Mon Aug 30 22:54:00 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003