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.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Apr 22 14:23:29 2004 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2003