8 #include "kmlineeditspell.h"
10 #define REALLY_WANT_KMCOMPOSEWIN_H
11 #include "kmcomposewin.h"
12 #undef REALLY_WANT_KMCOMPOSEWIN_H
13 #include "kmmsgdict.h"
15 #include "kmcommands.h"
17 #include <maillistdrag.h>
18 using KPIM::MailListDrag;
20 #include <libtdepim/tdefileio.h>
21 #include <libemailfunctions/email.h>
24 #include <tdeprocess.h>
26 #include <tdepopupmenu.h>
28 #include <tdemessagebox.h>
31 #include <tdetempfile.h>
32 #include <tdelocale.h>
33 #include <tdeapplication.h>
34 #include <kdirwatch.h>
35 #include <kiconloader.h>
37 #include "globalsettings.h"
38 #include "replyphrases.h"
41 #include <tdespelldlg.h>
42 #include <spellingfilter.h>
43 #include <ksyntaxhighlighter.h>
50 #include <sys/types.h>
58 void KMEdit::contentsDragEnterEvent(TQDragEnterEvent *e)
60 if (e->provides(MailListDrag::format()))
62 else if (e->provides(
"image/png"))
65 return KEdit::contentsDragEnterEvent(e);
68 void KMEdit::contentsDragMoveEvent(TQDragMoveEvent *e)
70 if (e->provides(MailListDrag::format()))
72 else if (e->provides(
"image/png"))
75 return KEdit::contentsDragMoveEvent(e);
78 void KMEdit::keyPressEvent( TQKeyEvent* e )
80 if( e->key() == Key_Return ) {
82 getCursorPosition( &line, &col );
83 TQString lineText = text( line );
85 lineText.truncate( lineText.length() - 1 );
88 if( ( col > 0 ) && ( col <
int( lineText.length() ) ) ) {
89 bool isQuotedLine =
false;
91 while( bot < lineText.length() ) {
92 if( ( lineText[bot] ==
'>' ) || ( lineText[bot] ==
'|' ) ) {
96 else if( lineText[bot].isSpace() ) {
104 KEdit::keyPressEvent( e );
110 && ( bot != lineText.length() )
111 && ( col >=
int( bot ) ) ) {
115 getCursorPosition( &line, &col );
116 TQString newLine = text( line );
119 unsigned int leadingWhiteSpaceCount = 0;
120 while( ( leadingWhiteSpaceCount < newLine.length() )
121 && newLine[leadingWhiteSpaceCount].isSpace() ) {
122 ++leadingWhiteSpaceCount;
124 newLine = newLine.replace( 0, leadingWhiteSpaceCount,
125 lineText.left( bot ) );
126 removeParagraph( line );
127 insertParagraph( newLine, line );
131 setCursorPosition( line, 0 );
135 KEdit::keyPressEvent( e );
138 KEdit::keyPressEvent( e );
141 void KMEdit::contentsDropEvent(TQDropEvent *e)
143 if (e->provides(MailListDrag::format())) {
146 MailListDrag::decode( e, serNums );
147 TQBuffer serNumBuffer(serNums);
148 serNumBuffer.open(IO_ReadOnly);
149 TQDataStream serNumStream(&serNumBuffer);
153 TQPtrList<KMMsgBase> messageList;
154 while (!serNumStream.atEnd()) {
155 KMMsgBase *msgBase = 0;
156 serNumStream >> serNum;
161 messageList.append( msgBase );
163 serNumBuffer.close();
164 uint identity = folder ? folder->identity() : 0;
166 new KMForwardAttachedCommand(mComposer, messageList,
167 identity, mComposer);
170 else if( e->provides(
"image/png") ) {
171 emit attachPNGImageData(e->encodedData(
"image/png"));
173 else if( KURLDrag::canDecode( e ) ) {
175 if( KURLDrag::decode( e, urlList ) ) {
177 p.insertItem( i18n(
"Add as Text"), 0 );
178 p.insertItem( i18n(
"Add as Attachment"), 1 );
179 int id = p.exec( mapToGlobal( e->pos() ) );
182 for ( KURL::List::Iterator it = urlList.begin();
183 it != urlList.end(); ++it ) {
184 insert( (*it).url() );
188 for ( KURL::List::Iterator it = urlList.begin();
189 it != urlList.end(); ++it ) {
190 mComposer->addAttach( *it );
195 else if ( TQTextDrag::canDecode( e ) ) {
197 if ( TQTextDrag::decode( e, s ) )
201 kdDebug(5006) <<
"KMEdit::contentsDropEvent, unable to add dropped object" << endl;
203 else if( e->provides(
"text/x-textsnippet") ) {
204 emit insertSnippet();
207 KEdit::contentsDropEvent(e);
211 KMEdit::KMEdit(TQWidget *parent, KMComposeWin* composer,
212 KSpellConfig* autoSpellConfig,
214 : KEdit( parent, name ),
215 mComposer( composer ),
216 mKSpellForDialog( 0 ),
218 mSpellConfig( autoSpellConfig ),
219 mSpellingFilter( 0 ),
220 mExtEditorTempFile( 0 ),
221 mExtEditorTempFileWatcher( 0 ),
222 mExtEditorProcess( 0 ),
223 mUseExtEditor( false ),
224 mWasModifiedBeforeSpellCheck( false ),
226 mSpellLineEdit( false ),
227 mPasteMode( TQClipboard::Clipboard )
229 connect(
this, TQ_SIGNAL(selectionChanged()),
this, TQ_SLOT(slotSelectionChanged()) );
230 installEventFilter(
this);
231 KCursor::setAutoHideCursor(
this,
true,
true );
232 setOverwriteEnabled(
true );
234 connect( mSpellConfig, TQ_SIGNAL( configChanged() ),
235 this, TQ_SLOT( createSpellers() ) );
236 connect( mSpeller, TQ_SIGNAL( death() ),
237 this, TQ_SLOT( spellerDied() ) );
240 void KMEdit::createSpellers()
243 mSpeller =
new KMSpell(
this, TQ_SLOT( spellerReady( KSpell * ) ), mSpellConfig );
246 void KMEdit::initializeAutoSpellChecking()
250 TQColor defaultColor1( 0x00, 0x80, 0x00 );
251 TQColor defaultColor2( 0x00, 0x70, 0x00 );
252 TQColor defaultColor3( 0x00, 0x60, 0x00 );
253 TQColor defaultForeground( kapp->palette().active().text() );
255 TQColor c = TQt::red;
256 TDEConfigGroup readerConfig( KMKernel::config(),
"Reader" );
258 if ( !readerConfig.readBoolEntry(
"defaultColors",
true ) )
259 col1 = readerConfig.readColorEntry(
"ForegroundColor", &defaultForeground );
261 col1 = defaultForeground;
262 TQColor col2 = readerConfig.readColorEntry(
"QuotedText3", &defaultColor3 );
263 TQColor col3 = readerConfig.readColorEntry(
"QuotedText2", &defaultColor2 );
264 TQColor col4 = readerConfig.readColorEntry(
"QuotedText1", &defaultColor1 );
265 TQColor misspelled = readerConfig.readColorEntry(
"MisspelledColor", &c );
270 col1, col2, col3, col4,
273 connect( mHighlighter, TQ_SIGNAL(newSuggestions(
const TQString&,
const TQStringList&,
unsigned int)),
274 this, TQ_SLOT(addSuggestion(
const TQString&,
const TQStringList&,
unsigned int)) );
278 TQPopupMenu *KMEdit::createPopupMenu(
const TQPoint& pos )
280 enum { IdUndo, IdRedo, IdSep1, IdCut, IdCopy, IdPaste, IdClear, IdSep2, IdSelectAll };
282 TQPopupMenu *menu = KEdit::createPopupMenu( pos );
283 if ( !TQApplication::clipboard()->image().isNull() ) {
284 int id = menu->idAt(0);
285 menu->setItemEnabled(
id - IdPaste,
true);
291 void KMEdit::deleteAutoSpellChecking()
297 void KMEdit::addSuggestion(
const TQString& text,
const TQStringList& lst,
unsigned int )
299 mReplacements[text] = lst;
302 void KMEdit::setSpellCheckingActive(
bool spellCheckingActive)
304 if ( mHighlighter ) {
305 mHighlighter->setActive(spellCheckingActive);
312 removeEventFilter(
this);
316 mSpeller->setAutoDelete(
true );
321 delete mKSpellForDialog;
328 TQString KMEdit::brokenText()
332 int num_lines = numLines();
333 for (
int i = 0; i < num_lines; ++i)
337 for (
int j = 0; j < (int)line.length(); ++j)
339 if (lineOfChar(i, j) > lastLine)
341 lastLine = lineOfChar(i, j);
346 if (i + 1 < num_lines) temp +=
'\n';
353 unsigned int KMEdit::lineBreakColumn()
const
355 unsigned int lineBreakColumn = 0;
356 unsigned int numlines = numLines();
357 while ( numlines-- ) {
358 lineBreakColumn = TQMAX( lineBreakColumn, textLine( numlines ).length() );
360 return lineBreakColumn;
363 KMSpell::KMSpell( TQObject *receiver,
const char *slot, KSpellConfig *spellConfig )
364 : KSpell( 0, TQString(), receiver, slot, spellConfig )
368 KMSyntaxHighter::KMSyntaxHighter( TQTextEdit *textEdit,
369 bool spellCheckingActive,
371 const TQColor& spellColor,
373 const TQColor& QuoteColor0,
374 const TQColor& QuoteColor1,
375 const TQColor& QuoteColor2,
376 const TQColor& QuoteColor3,
377 KSpellConfig *spellConfig )
378 : KDictSpellingHighlighter( textEdit, spellCheckingActive, autoEnable, spellColor, colorQuoting,
379 QuoteColor0, QuoteColor1, QuoteColor2, QuoteColor3, spellConfig )
385 if ( mIgnoredWords.contains( word ) ) {
389 return KDictSpellingHighlighter::isMisspelled( word );
393 void KMSyntaxHighter::ignoreWord(
const TQString &word )
395 mIgnoredWords << word;
398 TQStringList KMSyntaxHighter::ignoredWords()
const
400 return mIgnoredWords;
403 void KMEdit::spellerDied()
408 void KMEdit::spellerReady( KSpell *spell )
410 Q_ASSERT( mSpeller == spell );
413 bool KMEdit::eventFilter(TQObject*o, TQEvent* e)
416 KCursor::autoHideEventFilter(o, e);
418 if (e->type() == TQEvent::KeyPress)
420 TQKeyEvent *k = (TQKeyEvent*)e;
423 if (k->key() == Key_Up)
430 if ( (k->key() == Key_Shift) || (k->key() == Key_Control) ||
431 (k->key() == Key_Meta) || (k->key() == Key_Alt) )
433 if (mExtEditorTempFile)
return true;
434 TQString sysLine = mExtEditor;
435 mExtEditorTempFile =
new KTempFile();
437 mExtEditorTempFile->setAutoDelete(
true);
439 (*mExtEditorTempFile->textStream()) << text();
441 mExtEditorTempFile->close();
443 sysLine.replace(
"%f", mExtEditorTempFile->name() );
444 mExtEditorProcess =
new TDEProcess();
445 mExtEditorProcess->setUseShell(
true );
447 while (!sysLine.isEmpty())
449 *mExtEditorProcess << sysLine.left(sysLine.find(
" ")).local8Bit();
450 sysLine.remove(0, sysLine.find(
" ") + 1);
452 connect(mExtEditorProcess, TQ_SIGNAL(processExited(TDEProcess*)),
453 TQ_SLOT(slotExternalEditorDone(TDEProcess*)));
454 if (!mExtEditorProcess->start())
456 KMessageBox::error( topLevelWidget(),
457 i18n(
"Unable to start external editor.") );
458 killExternalEditor();
460 mExtEditorTempFileWatcher =
new KDirWatch(
this,
"mExtEditorTempFileWatcher" );
461 connect( mExtEditorTempFileWatcher, TQ_SIGNAL(dirty(
const TQString&)),
462 TQ_SLOT(slotExternalEditorTempFileChanged(
const TQString&)) );
463 mExtEditorTempFileWatcher->addFile( mExtEditorTempFile->name() );
469 if (k->key() == Key_Up && k->state() != ShiftButton && currentLine() == 0
470 && lineOfChar(0, currentColumn()) == 0)
478 if (k->key() == Key_Backtab && k->state() == ShiftButton)
486 }
else if ( e->type() == TQEvent::ContextMenu ) {
487 TQContextMenuEvent *
event = (TQContextMenuEvent*) e;
489 int para = 1, charPos, firstSpace, lastSpace;
492 charPos = charAt( viewportToContents(event->pos()), ¶ );
493 TQString paraText = text( para );
495 if( !paraText.at(charPos).isSpace() )
498 const TQRegExp wordBoundary(
"[\\s\\W]" );
499 firstSpace = paraText.findRev( wordBoundary, charPos ) + 1;
500 lastSpace = paraText.find( wordBoundary, charPos );
501 if( lastSpace == -1 )
502 lastSpace = paraText.length();
503 TQString word = paraText.mid( firstSpace, lastSpace - firstSpace );
505 if( !word.isEmpty() && mReplacements.contains( word ) )
510 TQStringList reps = mReplacements[word];
511 if( reps.count() > 0 )
514 for ( TQStringList::Iterator it = reps.begin(); it != reps.end(); ++it ) {
515 p.insertItem( *it, listPos );
521 p.setItemEnabled( p.insertItem( i18n(
"No Suggestions" ), -2 ),
false );
524 int addToDictionaryId = -42;
526 if ( mSpeller && mSpeller->status() == KSpell::Running ) {
528 addToDictionaryId = p.insertItem( i18n(
"Add to Dictionary" ) );
529 ignoreId = p.insertItem( i18n(
"Ignore All" ) );
533 const int id = p.exec( mapToGlobal( event->pos() ) );
535 if (
id == ignoreId ) {
536 mHighlighter->ignoreWord( word );
537 mHighlighter->rehighlight();
539 if (
id == addToDictionaryId ) {
540 mSpeller->addPersonal( word );
541 mSpeller->writePersonalDictionary();
542 if ( mHighlighter ) {
545 TQTimer::singleShot( 200, mHighlighter, TQ_SLOT( slotLocalSpellConfigChanged() ) );
551 int parIdx = 1, txtIdx = 1;
552 getCursorPosition(&parIdx, &txtIdx);
553 setSelection(para, firstSpace, para, lastSpace);
554 insert(mReplacements[word][
id]);
557 if ( para == parIdx && txtIdx >= lastSpace )
558 txtIdx += mReplacements[word][id].length() - word.length();
559 setCursorPosition(parIdx, txtIdx);
562 if (
id == addToDictionaryId ||
id == ignoreId ) {
564 mReplacements.remove( word );
571 }
else if ( e->type() == TQEvent::FocusIn || e->type() == TQEvent::FocusOut ) {
572 TQFocusEvent *fe =
static_cast<TQFocusEvent*
>(e);
573 if(! (fe->reason() == TQFocusEvent::ActiveWindow || fe->reason() == TQFocusEvent::Popup) )
574 emit focusChanged( fe->gotFocus() );
577 return KEdit::eventFilter(o, e);
581 int KMEdit::autoSpellChecking(
bool on )
583 if ( textFormat() == TQt::RichText ) {
586 KMessageBox::sorry(
this, i18n(
"Automatic spellchecking is not possible on text with markup."));
589 if ( mHighlighter ) {
591 mHighlighter->setAutomatic( on );
592 mHighlighter->setActive( on );
598 void KMEdit::slotExternalEditorTempFileChanged(
const TQString & fileName ) {
599 if ( !mExtEditorTempFile )
601 if ( fileName != mExtEditorTempFile->name() )
604 setAutoUpdate(
false);
607 insertLine(TQString::fromLocal8Bit(KPIM::kFileToString( fileName,
true,
false )), -1);
612 void KMEdit::slotExternalEditorDone( TDEProcess * proc ) {
613 assert(proc == mExtEditorProcess);
615 slotExternalEditorTempFileChanged( mExtEditorTempFile->name() );
616 killExternalEditor();
619 void KMEdit::killExternalEditor() {
620 delete mExtEditorTempFileWatcher; mExtEditorTempFileWatcher = 0;
621 delete mExtEditorTempFile; mExtEditorTempFile = 0;
622 delete mExtEditorProcess; mExtEditorProcess = 0;
626 bool KMEdit::checkExternalEditorFinished() {
627 if ( !mExtEditorProcess )
629 switch ( KMessageBox::warningYesNoCancel( topLevelWidget(),
630 i18n(
"The external editor is still running.\n"
631 "Abort the external editor or leave it open?"),
632 i18n(
"External Editor"),
633 i18n(
"Abort Editor"), i18n(
"Leave Editor Open") ) ) {
634 case KMessageBox::Yes:
635 killExternalEditor();
637 case KMessageBox::No:
644 void KMEdit::spellcheck()
646 if ( mKSpellForDialog )
648 mWasModifiedBeforeSpellCheck = isModified();
649 mSpellLineEdit = !mSpellLineEdit;
660 mKSpellForDialog =
new KSpell(
this, i18n(
"Spellcheck - KMail"),
this,
661 TQ_SLOT(slotSpellcheck2(KSpell*)) );
664 TQStringList l = KSpellingHighlighter::personalWords();
665 for ( TQStringList::Iterator it = l.begin(); it != l.end(); ++it ) {
666 mKSpellForDialog->addPersonal( *it );
668 connect (mKSpellForDialog, TQ_SIGNAL( death()),
669 this, TQ_SLOT (slotSpellDone()));
670 connect (mKSpellForDialog, TQ_SIGNAL (misspelling (
const TQString &,
const TQStringList &,
unsigned int)),
671 this, TQ_SLOT (slotMisspelling (
const TQString &,
const TQStringList &,
unsigned int)));
672 connect (mKSpellForDialog, TQ_SIGNAL (corrected (
const TQString &,
const TQString &,
unsigned int)),
673 this, TQ_SLOT (slotCorrected (
const TQString &,
const TQString &,
unsigned int)));
674 connect (mKSpellForDialog, TQ_SIGNAL (done(
const TQString &)),
675 this, TQ_SLOT (slotSpellResult (
const TQString&)));
681 if ( textFormat() != TQt::RichText && mHighlighter )
682 mHighlighter->restartBackgroundSpellCheck();
688 if ( textFormat() != TQt::RichText && mHighlighter )
689 mHighlighter->restartBackgroundSpellCheck();
695 if ( textFormat() != TQt::RichText && mHighlighter )
696 mHighlighter->restartBackgroundSpellCheck();
701 mComposer->paste( mPasteMode );
709 void KMEdit::contentsMouseReleaseEvent( TQMouseEvent * e )
711 if( e->button() != TQt::MidButton )
712 return KEdit::contentsMouseReleaseEvent( e );
713 mPasteMode = TQClipboard::Selection;
714 KEdit::contentsMouseReleaseEvent( e );
715 mPasteMode = TQClipboard::Clipboard;
718 void KMEdit::contentsMouseDoubleClickEvent( TQMouseEvent *e )
720 bool handled =
false;
721 if ( e->button() == TQt::LeftButton ) {
725 int charPos = charAt ( e->pos(), ¶graphPos );
726 TQString paraText = text( paragraphPos );
729 if ( charPos >= 0 &&
static_cast<unsigned int>( charPos ) <= paraText.length() ) {
733 unsigned int end = charPos;
737 if ( ( start - 1 ) < 0 )
739 TQChar charToTheLeft = paraText.at( start - 1 );
740 if ( charToTheLeft.isLetter() || charToTheLeft.isDigit() )
748 if ( ( end + 1 ) >= paraText.length() )
750 TQChar charToTheRight = paraText.at( end + 1 );
751 if ( charToTheRight.isLetter() || charToTheRight.isDigit() )
757 setSelection( paragraphPos, start, paragraphPos, end + 1 );
763 return KEdit::contentsMouseDoubleClickEvent( e );
766 void KMEdit::slotMisspelling(
const TQString &text,
const TQStringList &lst,
unsigned int pos)
768 kdDebug(5006)<<
"void KMEdit::slotMisspelling(const TQString &text, const TQStringList &lst, unsigned int pos) : "<<text <<endl;
770 mComposer->sujectLineWidget()->spellCheckerMisspelling( text, lst, pos);
772 misspelling(text, lst, pos);
775 void KMEdit::slotCorrected (
const TQString &oldWord,
const TQString &newWord,
unsigned int pos)
777 kdDebug(5006)<<
"slotCorrected (const TQString &oldWord, const TQString &newWord, unsigned int pos) : "<<oldWord<<endl;
779 mComposer->sujectLineWidget()->spellCheckerCorrected( oldWord, newWord, pos);
782 unsigned int cnt = 0;
783 bool _bold,_underline,_italic;
786 posToRowCol (pos, l, cnt);
787 setCursorPosition(l, cnt+1);
789 _underline = underline();
792 _font = currentFont();
793 corrected(oldWord, newWord, pos);
794 setSelection (l, cnt, l, cnt+newWord.length());
797 setUnderline(_underline);
799 setCurrentFont(_font);
804 void KMEdit::slotSpellcheck2(KSpell*)
807 if ( mHighlighter ) {
808 for ( uint i = 0; i < mHighlighter->ignoredWords().size(); i++ )
809 mKSpellForDialog->ignore( mHighlighter->ignoredWords()[i] );
816 TQString quotePrefix;
817 if(mComposer && mComposer->msg())
819 int languageNr = GlobalSettings::self()->replyCurrentLanguage();
820 ReplyPhrases replyPhrases( TQString::number(languageNr) );
821 replyPhrases.readConfig();
823 quotePrefix = mComposer->msg()->formatString(
824 replyPhrases.indentPrefix() );
827 kdDebug(5006) <<
"spelling: new SpellingFilter with prefix=\"" << quotePrefix <<
"\"" << endl;
828 TQTextEdit plaintext;
829 plaintext.setText(text());
830 plaintext.setTextFormat(TQt::PlainText);
831 mSpellingFilter =
new SpellingFilter(plaintext.text(), quotePrefix, SpellingFilter::FilterUrls,
832 SpellingFilter::FilterEmailAddresses);
834 mKSpellForDialog->check(mSpellingFilter->filteredText());
837 mKSpellForDialog->check( mComposer->sujectLineWidget()->text());
840 void KMEdit::slotSpellResult(
const TQString &s)
845 int dlgResult = mKSpellForDialog->dlgResult();
846 if ( dlgResult == KS_CANCEL )
851 mSpellLineEdit =
false;
852 TQString tmpText( s );
853 tmpText = tmpText.remove(
'\n');
855 if( tmpText != mComposer->sujectLineWidget()->text() )
856 mComposer->sujectLineWidget()->setText( tmpText );
863 mKSpellForDialog->cleanUp();
864 KDictSpellingHighlighter::dictionaryChanged();
866 emit spellcheck_done( dlgResult );
869 void KMEdit::slotSpellDone()
871 kdDebug(5006)<<
" void KMEdit::slotSpellDone()\n";
872 KSpell::spellStatus status = mKSpellForDialog->status();
873 delete mKSpellForDialog;
874 mKSpellForDialog = 0;
876 kdDebug(5006) <<
"spelling: delete SpellingFilter" << endl;
877 delete mSpellingFilter;
879 mComposer->sujectLineWidget()->deselect();
880 if (status == KSpell::Error)
882 KMessageBox::sorry( topLevelWidget(),
883 i18n(
"ISpell/Aspell could not be started. Please "
884 "make sure you have ISpell or Aspell properly "
885 "configured and in your PATH.") );
886 emit spellcheck_done( KS_CANCEL );
888 else if (status == KSpell::Crashed)
891 KMessageBox::sorry( topLevelWidget(),
892 i18n(
"ISpell/Aspell seems to have crashed.") );
893 emit spellcheck_done( KS_CANCEL );
899 else if( !mComposer->subjectTextWasSpellChecked() && status == KSpell::FinishedNoMisspellingsEncountered )
900 KMessageBox::information( topLevelWidget(),
901 i18n(
"No misspellings encountered.") );
905 void KMEdit::setCursorPositionFromStart(
unsigned int pos ) {
908 posToRowCol( pos, l, c );
911 setCursorPosition( l, c );
912 ensureCursorVisible();
915 int KMEdit::indexOfCurrentLineStart(
int paragraph,
int index )
917 Q_ASSERT( paragraph >= 0 && paragraph < paragraphs() );
918 Q_ASSERT( index >= 0 && ( index == 0 || index < paragraphLength( paragraph ) ) );
920 const int startLine = lineOfChar( paragraph, index );
921 Q_ASSERT( startLine >= 0 && startLine < linesOfParagraph( paragraph ) );
922 for (
int curIndex = index; curIndex >= 0; curIndex-- ) {
923 const int line = lineOfChar( paragraph, curIndex );
924 if ( line != startLine ) {
931 #include "kmedit.moc"
const KMMsgBase * getMsgBase(int idx) const
Provides access to the basic message fields that are also stored in the index.
void getLocation(unsigned long key, KMFolder **retFolder, int *retIndex) const
Returns the folder the message represented by the serial number key is in and the index in that folde...
static const KMMsgDict * instance()
Access the globally unique MessageDict.
Reimplemented to make writePersonalDictionary() public, which we call everytime after adding a word t...
Reimplemented to add support for ignored words.
virtual bool isMisspelled(const TQString &word)
Reimplemented.