summaryrefslogtreecommitdiffstats
path: root/kmail/kmedit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kmail/kmedit.cpp')
-rw-r--r--kmail/kmedit.cpp766
1 files changed, 766 insertions, 0 deletions
diff --git a/kmail/kmedit.cpp b/kmail/kmedit.cpp
new file mode 100644
index 000000000..b20570f47
--- /dev/null
+++ b/kmail/kmedit.cpp
@@ -0,0 +1,766 @@
+// -*- mode: C++; c-file-style: "gnu" -*-
+// kmcomposewin.cpp
+// Author: Markus Wuebben <markus.wuebben@kde.org>
+// This code is published under the GPL.
+
+#include <config.h>
+
+#include "kmedit.h"
+#include "kmlineeditspell.h"
+
+#define REALLY_WANT_KMCOMPOSEWIN_H
+#include "kmcomposewin.h"
+#undef REALLY_WANT_KMCOMPOSEWIN_H
+#include "kmmsgdict.h"
+#include "kmfolder.h"
+#include "kmcommands.h"
+
+#include <maillistdrag.h>
+using KPIM::MailListDrag;
+
+#include <libkdepim/kfileio.h>
+#include <libemailfunctions/email.h>
+
+#include <kcursor.h>
+#include <kprocess.h>
+
+#include <kpopupmenu.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <kurldrag.h>
+
+#include <ktempfile.h>
+#include <klocale.h>
+#include <kapplication.h>
+#include <kdirwatch.h>
+#include <kiconloader.h>
+
+#include "globalsettings.h"
+#include "replyphrases.h"
+
+#include <kspell.h>
+#include <kspelldlg.h>
+#include <spellingfilter.h>
+#include <ksyntaxhighlighter.h>
+
+#include <qregexp.h>
+#include <qbuffer.h>
+#include <qevent.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <assert.h>
+
+
+void KMEdit::contentsDragEnterEvent(QDragEnterEvent *e)
+{
+ if (e->provides(MailListDrag::format()))
+ e->accept(true);
+ else if (e->provides("image/png"))
+ e->accept();
+ else
+ return KEdit::contentsDragEnterEvent(e);
+}
+
+void KMEdit::contentsDragMoveEvent(QDragMoveEvent *e)
+{
+ if (e->provides(MailListDrag::format()))
+ e->accept();
+ else if (e->provides("image/png"))
+ e->accept();
+ else
+ return KEdit::contentsDragMoveEvent(e);
+}
+
+void KMEdit::keyPressEvent( QKeyEvent* e )
+{
+ if( e->key() == Key_Return ) {
+ int line, col;
+ getCursorPosition( &line, &col );
+ QString lineText = text( line );
+ // returns line with additional trailing space (bug in Qt?), cut it off
+ lineText.truncate( lineText.length() - 1 );
+ // special treatment of quoted lines only if the cursor is neither at
+ // the begin nor at the end of the line
+ if( ( col > 0 ) && ( col < int( lineText.length() ) ) ) {
+ bool isQuotedLine = false;
+ uint bot = 0; // bot = begin of text after quote indicators
+ while( bot < lineText.length() ) {
+ if( ( lineText[bot] == '>' ) || ( lineText[bot] == '|' ) ) {
+ isQuotedLine = true;
+ ++bot;
+ }
+ else if( lineText[bot].isSpace() ) {
+ ++bot;
+ }
+ else {
+ break;
+ }
+ }
+
+ KEdit::keyPressEvent( e );
+
+ // duplicate quote indicators of the previous line before the new
+ // line if the line actually contained text (apart from the quote
+ // indicators) and the cursor is behind the quote indicators
+ if( isQuotedLine
+ && ( bot != lineText.length() )
+ && ( col >= int( bot ) ) ) {
+
+ // The cursor position might have changed unpredictably if there was selected
+ // text which got replaced by a new line, so we query it again:
+ getCursorPosition( &line, &col );
+ QString newLine = text( line );
+ // remove leading white space from the new line and instead
+ // add the quote indicators of the previous line
+ unsigned int leadingWhiteSpaceCount = 0;
+ while( ( leadingWhiteSpaceCount < newLine.length() )
+ && newLine[leadingWhiteSpaceCount].isSpace() ) {
+ ++leadingWhiteSpaceCount;
+ }
+ newLine = newLine.replace( 0, leadingWhiteSpaceCount,
+ lineText.left( bot ) );
+ removeParagraph( line );
+ insertParagraph( newLine, line );
+ // place the cursor at the begin of the new line since
+ // we assume that the user split the quoted line in order
+ // to add a comment to the first part of the quoted line
+ setCursorPosition( line, 0 );
+ }
+ }
+ else
+ KEdit::keyPressEvent( e );
+ }
+ else
+ KEdit::keyPressEvent( e );
+}
+
+void KMEdit::contentsDropEvent(QDropEvent *e)
+{
+ if (e->provides(MailListDrag::format())) {
+ // Decode the list of serial numbers stored as the drag data
+ QByteArray serNums;
+ MailListDrag::decode( e, serNums );
+ QBuffer serNumBuffer(serNums);
+ serNumBuffer.open(IO_ReadOnly);
+ QDataStream serNumStream(&serNumBuffer);
+ Q_UINT32 serNum;
+ KMFolder *folder = 0;
+ int idx;
+ QPtrList<KMMsgBase> messageList;
+ while (!serNumStream.atEnd()) {
+ KMMsgBase *msgBase = 0;
+ serNumStream >> serNum;
+ KMMsgDict::instance()->getLocation(serNum, &folder, &idx);
+ if (folder)
+ msgBase = folder->getMsgBase(idx);
+ if (msgBase)
+ messageList.append( msgBase );
+ }
+ serNumBuffer.close();
+ uint identity = folder ? folder->identity() : 0;
+ KMCommand *command =
+ new KMForwardAttachedCommand(mComposer, messageList,
+ identity, mComposer);
+ command->start();
+ }
+ else if( e->provides("image/png") ) {
+ emit attachPNGImageData(e->encodedData("image/png"));
+ }
+ else if( KURLDrag::canDecode( e ) ) {
+ KURL::List urlList;
+ if( KURLDrag::decode( e, urlList ) ) {
+ KPopupMenu p;
+ p.insertItem( i18n("Add as Text"), 0 );
+ p.insertItem( i18n("Add as Attachment"), 1 );
+ int id = p.exec( mapToGlobal( e->pos() ) );
+ switch ( id) {
+ case 0:
+ for ( KURL::List::Iterator it = urlList.begin();
+ it != urlList.end(); ++it ) {
+ insert( (*it).url() );
+ }
+ break;
+ case 1:
+ for ( KURL::List::Iterator it = urlList.begin();
+ it != urlList.end(); ++it ) {
+ mComposer->addAttach( *it );
+ }
+ break;
+ }
+ }
+ else if ( QTextDrag::canDecode( e ) ) {
+ QString s;
+ if ( QTextDrag::decode( e, s ) )
+ insert( s );
+ }
+ else
+ kdDebug(5006) << "KMEdit::contentsDropEvent, unable to add dropped object" << endl;
+ }
+ else if( e->provides("text/x-textsnippet") ) {
+ emit insertSnippet();
+ }
+ else {
+ KEdit::contentsDropEvent(e);
+ }
+}
+
+KMEdit::KMEdit(QWidget *parent, KMComposeWin* composer,
+ KSpellConfig* autoSpellConfig,
+ const char *name)
+ : KEdit( parent, name ),
+ mComposer( composer ),
+ mKSpell( 0 ),
+ mSpellConfig( autoSpellConfig ),
+ mSpellingFilter( 0 ),
+ mExtEditorTempFile( 0 ),
+ mExtEditorTempFileWatcher( 0 ),
+ mExtEditorProcess( 0 ),
+ mUseExtEditor( false ),
+ mWasModifiedBeforeSpellCheck( false ),
+ mSpellChecker( 0 ),
+ mSpellLineEdit( false ),
+ mPasteMode( QClipboard::Clipboard )
+{
+ installEventFilter(this);
+ KCursor::setAutoHideCursor( this, true, true );
+ setOverwriteEnabled( true );
+}
+
+
+void KMEdit::initializeAutoSpellChecking()
+{
+ if ( mSpellChecker )
+ return; // already initialized
+ QColor defaultColor1( 0x00, 0x80, 0x00 ); // defaults from kmreaderwin.cpp
+ QColor defaultColor2( 0x00, 0x70, 0x00 );
+ QColor defaultColor3( 0x00, 0x60, 0x00 );
+ QColor defaultForeground( kapp->palette().active().text() );
+
+ QColor c = Qt::red;
+ KConfigGroup readerConfig( KMKernel::config(), "Reader" );
+ QColor col1;
+ if ( !readerConfig.readBoolEntry( "defaultColors", true ) )
+ col1 = readerConfig.readColorEntry( "ForegroundColor", &defaultForeground );
+ else
+ col1 = defaultForeground;
+ QColor col2 = readerConfig.readColorEntry( "QuotedText3", &defaultColor3 );
+ QColor col3 = readerConfig.readColorEntry( "QuotedText2", &defaultColor2 );
+ QColor col4 = readerConfig.readColorEntry( "QuotedText1", &defaultColor1 );
+ QColor misspelled = readerConfig.readColorEntry( "MisspelledColor", &c );
+ mSpellChecker = new KDictSpellingHighlighter( this, /*active*/ true,
+ /*autoEnabled*/ false,
+ /*spellColor*/ misspelled,
+ /*colorQuoting*/ true,
+ col1, col2, col3, col4,
+ mSpellConfig );
+
+ connect( mSpellChecker, SIGNAL(newSuggestions(const QString&, const QStringList&, unsigned int)),
+ this, SLOT(addSuggestion(const QString&, const QStringList&, unsigned int)) );
+}
+
+
+QPopupMenu *KMEdit::createPopupMenu( const QPoint& pos )
+{
+ enum { IdUndo, IdRedo, IdSep1, IdCut, IdCopy, IdPaste, IdClear, IdSep2, IdSelectAll };
+
+ QPopupMenu *menu = KEdit::createPopupMenu( pos );
+ if ( !QApplication::clipboard()->image().isNull() ) {
+ int id = menu->idAt(0);
+ menu->setItemEnabled( id - IdPaste, true);
+ }
+
+ return menu;
+}
+
+void KMEdit::deleteAutoSpellChecking()
+{ // because the highlighter doesn't support RichText, delete its instance.
+ delete mSpellChecker;
+ mSpellChecker =0;
+}
+
+void KMEdit::addSuggestion(const QString& text, const QStringList& lst, unsigned int )
+{
+ mReplacements[text] = lst;
+}
+
+void KMEdit::setSpellCheckingActive(bool spellCheckingActive)
+{
+ if ( mSpellChecker ) {
+ mSpellChecker->setActive(spellCheckingActive);
+ }
+}
+
+
+KMEdit::~KMEdit()
+{
+ removeEventFilter(this);
+
+ delete mKSpell;
+ delete mSpellChecker;
+ mSpellChecker = 0;
+
+}
+
+
+
+QString KMEdit::brokenText()
+{
+ QString temp, line;
+
+ int num_lines = numLines();
+ for (int i = 0; i < num_lines; ++i)
+ {
+ int lastLine = 0;
+ line = textLine(i);
+ for (int j = 0; j < (int)line.length(); ++j)
+ {
+ if (lineOfChar(i, j) > lastLine)
+ {
+ lastLine = lineOfChar(i, j);
+ temp += '\n';
+ }
+ temp += line[j];
+ }
+ if (i + 1 < num_lines) temp += '\n';
+ }
+
+ return temp;
+}
+
+
+unsigned int KMEdit::lineBreakColumn() const
+{
+ unsigned int lineBreakColumn = 0;
+ unsigned int numlines = numLines();
+ while ( numlines-- ) {
+ lineBreakColumn = QMAX( lineBreakColumn, textLine( numlines ).length() );
+ }
+ return lineBreakColumn;
+}
+
+
+bool KMEdit::eventFilter(QObject*o, QEvent* e)
+{
+ if (o == this)
+ KCursor::autoHideEventFilter(o, e);
+
+ if (e->type() == QEvent::KeyPress)
+ {
+ QKeyEvent *k = (QKeyEvent*)e;
+
+ if (mUseExtEditor) {
+ if (k->key() == Key_Up)
+ {
+ emit focusUp();
+ return true;
+ }
+
+ // ignore modifier keys (cf. bug 48841)
+ if ( (k->key() == Key_Shift) || (k->key() == Key_Control) ||
+ (k->key() == Key_Meta) || (k->key() == Key_Alt) )
+ return true;
+ if (mExtEditorTempFile) return true;
+ QString sysLine = mExtEditor;
+ mExtEditorTempFile = new KTempFile();
+
+ mExtEditorTempFile->setAutoDelete(true);
+
+ (*mExtEditorTempFile->textStream()) << text();
+
+ mExtEditorTempFile->close();
+ // replace %f in the system line
+ sysLine.replace( "%f", mExtEditorTempFile->name() );
+ mExtEditorProcess = new KProcess();
+ mExtEditorProcess->setUseShell( true );
+ sysLine += " ";
+ while (!sysLine.isEmpty())
+ {
+ *mExtEditorProcess << sysLine.left(sysLine.find(" ")).local8Bit();
+ sysLine.remove(0, sysLine.find(" ") + 1);
+ }
+ connect(mExtEditorProcess, SIGNAL(processExited(KProcess*)),
+ SLOT(slotExternalEditorDone(KProcess*)));
+ if (!mExtEditorProcess->start())
+ {
+ KMessageBox::error( topLevelWidget(),
+ i18n("Unable to start external editor.") );
+ killExternalEditor();
+ } else {
+ mExtEditorTempFileWatcher = new KDirWatch( this, "mExtEditorTempFileWatcher" );
+ connect( mExtEditorTempFileWatcher, SIGNAL(dirty(const QString&)),
+ SLOT(slotExternalEditorTempFileChanged(const QString&)) );
+ mExtEditorTempFileWatcher->addFile( mExtEditorTempFile->name() );
+ }
+ return true;
+ } else {
+ // ---sven's Arrow key navigation start ---
+ // Key Up in first line takes you to Subject line.
+ if (k->key() == Key_Up && k->state() != ShiftButton && currentLine() == 0
+ && lineOfChar(0, currentColumn()) == 0)
+ {
+ deselect();
+ emit focusUp();
+ return true;
+ }
+ // ---sven's Arrow key navigation end ---
+
+ if (k->key() == Key_Backtab && k->state() == ShiftButton)
+ {
+ deselect();
+ emit focusUp();
+ return true;
+ }
+
+ }
+ } else if ( e->type() == QEvent::ContextMenu ) {
+ QContextMenuEvent *event = (QContextMenuEvent*) e;
+
+ int para = 1, charPos, firstSpace, lastSpace;
+
+ //Get the character at the position of the click
+ charPos = charAt( viewportToContents(event->pos()), &para );
+ QString paraText = text( para );
+
+ if( !paraText.at(charPos).isSpace() )
+ {
+ //Get word right clicked on
+ const QRegExp wordBoundary( "[\\s\\W]" );
+ firstSpace = paraText.findRev( wordBoundary, charPos ) + 1;
+ lastSpace = paraText.find( wordBoundary, charPos );
+ if( lastSpace == -1 )
+ lastSpace = paraText.length();
+ QString word = paraText.mid( firstSpace, lastSpace - firstSpace );
+ //Continue if this word was misspelled
+ if( !word.isEmpty() && mReplacements.contains( word ) )
+ {
+ KPopupMenu p;
+ p.insertTitle( i18n("Suggestions") );
+
+ //Add the suggestions to the popup menu
+ QStringList reps = mReplacements[word];
+ if( reps.count() > 0 )
+ {
+ int listPos = 0;
+ for ( QStringList::Iterator it = reps.begin(); it != reps.end(); ++it ) {
+ p.insertItem( *it, listPos );
+ listPos++;
+ }
+ }
+ else
+ {
+ p.insertItem( QString::fromLatin1("No Suggestions"), -2 );
+ }
+
+ //Execute the popup inline
+ int id = p.exec( mapToGlobal( event->pos() ) );
+
+ if( id > -1 )
+ {
+ //Save the cursor position
+ int parIdx = 1, txtIdx = 1;
+ getCursorPosition(&parIdx, &txtIdx);
+ setSelection(para, firstSpace, para, lastSpace);
+ insert(mReplacements[word][id]);
+ // Restore the cursor position; if the cursor was behind the
+ // misspelled word then adjust the cursor position
+ if ( para == parIdx && txtIdx >= lastSpace )
+ txtIdx += mReplacements[word][id].length() - word.length();
+ setCursorPosition(parIdx, txtIdx);
+ }
+ //Cancel original event
+ return true;
+ }
+ }
+ } else if ( e->type() == QEvent::FocusIn || e->type() == QEvent::FocusOut ) {
+ QFocusEvent *fe = static_cast<QFocusEvent*>(e);
+ if(! (fe->reason() == QFocusEvent::ActiveWindow || fe->reason() == QFocusEvent::Popup) )
+ emit focusChanged( fe->gotFocus() );
+ }
+
+ return KEdit::eventFilter(o, e);
+}
+
+
+int KMEdit::autoSpellChecking( bool on )
+{
+ if ( textFormat() == Qt::RichText ) {
+ // syntax highlighter doesn't support extended text properties
+ if ( on )
+ KMessageBox::sorry(this, i18n("Automatic spellchecking is not possible on text with markup."));
+ return -1;
+ }
+ if ( mSpellChecker ) {
+ // don't autoEnable spell checking if the user turned spell checking off
+ mSpellChecker->setAutomatic( on );
+ mSpellChecker->setActive( on );
+ }
+ return 1;
+}
+
+
+void KMEdit::slotExternalEditorTempFileChanged( const QString & fileName ) {
+ if ( !mExtEditorTempFile )
+ return;
+ if ( fileName != mExtEditorTempFile->name() )
+ return;
+ // read data back in from file
+ setAutoUpdate(false);
+ clear();
+
+ insertLine(QString::fromLocal8Bit(KPIM::kFileToString( fileName, true, false )), -1);
+ setAutoUpdate(true);
+ repaint();
+}
+
+void KMEdit::slotExternalEditorDone( KProcess * proc ) {
+ assert(proc == mExtEditorProcess);
+ // make sure, we update even when KDirWatcher is too slow:
+ slotExternalEditorTempFileChanged( mExtEditorTempFile->name() );
+ killExternalEditor();
+}
+
+void KMEdit::killExternalEditor() {
+ delete mExtEditorTempFileWatcher; mExtEditorTempFileWatcher = 0;
+ delete mExtEditorTempFile; mExtEditorTempFile = 0;
+ delete mExtEditorProcess; mExtEditorProcess = 0;
+}
+
+
+bool KMEdit::checkExternalEditorFinished() {
+ if ( !mExtEditorProcess )
+ return true;
+ switch ( KMessageBox::warningYesNoCancel( topLevelWidget(),
+ i18n("The external editor is still running.\n"
+ "Abort the external editor or leave it open?"),
+ i18n("External Editor"),
+ i18n("Abort Editor"), i18n("Leave Editor Open") ) ) {
+ case KMessageBox::Yes:
+ killExternalEditor();
+ return true;
+ case KMessageBox::No:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void KMEdit::spellcheck()
+{
+ if ( mKSpell )
+ return;
+ mWasModifiedBeforeSpellCheck = isModified();
+ mSpellLineEdit = !mSpellLineEdit;
+// maybe for later, for now plaintext is given to KSpell
+// if (textFormat() == Qt::RichText ) {
+// kdDebug(5006) << "KMEdit::spellcheck, spellchecking for RichText" << endl;
+// mKSpell = new KSpell(this, i18n("Spellcheck - KMail"), this,
+// SLOT(slotSpellcheck2(KSpell*)),0,true,false,KSpell::HTML);
+// }
+// else {
+ mKSpell = new KSpell(this, i18n("Spellcheck - KMail"), this,
+ SLOT(slotSpellcheck2(KSpell*)));
+// }
+
+ QStringList l = KSpellingHighlighter::personalWords();
+ for ( QStringList::Iterator it = l.begin(); it != l.end(); ++it ) {
+ mKSpell->addPersonal( *it );
+ }
+ connect (mKSpell, SIGNAL( death()),
+ this, SLOT (slotSpellDone()));
+ connect (mKSpell, SIGNAL (misspelling (const QString &, const QStringList &, unsigned int)),
+ this, SLOT (slotMisspelling (const QString &, const QStringList &, unsigned int)));
+ connect (mKSpell, SIGNAL (corrected (const QString &, const QString &, unsigned int)),
+ this, SLOT (slotCorrected (const QString &, const QString &, unsigned int)));
+ connect (mKSpell, SIGNAL (done(const QString &)),
+ this, SLOT (slotSpellResult (const QString&)));
+}
+
+void KMEdit::cut()
+{
+ KEdit::cut();
+ if ( textFormat() != Qt::RichText && mSpellChecker )
+ mSpellChecker->restartBackgroundSpellCheck();
+}
+
+void KMEdit::clear()
+{
+ KEdit::clear();
+ if ( textFormat() != Qt::RichText && mSpellChecker )
+ mSpellChecker->restartBackgroundSpellCheck();
+}
+
+void KMEdit::del()
+{
+ KEdit::del();
+ if ( textFormat() != Qt::RichText && mSpellChecker )
+ mSpellChecker->restartBackgroundSpellCheck();
+}
+
+void KMEdit::paste()
+{
+ mComposer->paste( mPasteMode );
+}
+
+// KMEdit indirectly inherits from QTextEdit, which has virtual paste() method,
+// but it controls whether it pastes clipboard or selection by an internal
+// flag that is not accessible in any way, so paste() being virtual is actually
+// useless, because reimplementations can't known where to paste from anyway.
+// Roll our own internal flag.
+void KMEdit::contentsMouseReleaseEvent( QMouseEvent * e )
+{
+ if( e->button() != Qt::MidButton )
+ return KEdit::contentsMouseReleaseEvent( e );
+ mPasteMode = QClipboard::Selection;
+ KEdit::contentsMouseReleaseEvent( e );
+ mPasteMode = QClipboard::Clipboard;
+}
+
+void KMEdit::slotMisspelling(const QString &text, const QStringList &lst, unsigned int pos)
+{
+ kdDebug(5006)<<"void KMEdit::slotMisspelling(const QString &text, const QStringList &lst, unsigned int pos) : "<<text <<endl;
+ if( mSpellLineEdit )
+ mComposer->sujectLineWidget()->spellCheckerMisspelling( text, lst, pos);
+ else
+ misspelling(text, lst, pos);
+}
+
+void KMEdit::slotCorrected (const QString &oldWord, const QString &newWord, unsigned int pos)
+{
+ kdDebug(5006)<<"slotCorrected (const QString &oldWord, const QString &newWord, unsigned int pos) : "<<oldWord<<endl;
+ if( mSpellLineEdit )
+ mComposer->sujectLineWidget()->spellCheckerCorrected( oldWord, newWord, pos);
+ else {
+ unsigned int l = 0;
+ unsigned int cnt = 0;
+ bool _bold,_underline,_italic;
+ QColor _color;
+ QFont _font;
+ posToRowCol (pos, l, cnt);
+ setCursorPosition(l, cnt+1); // the new word will get the same markup now as the first character of the word
+ _bold = bold();
+ _underline = underline();
+ _italic = italic();
+ _color = color();
+ _font = currentFont();
+ corrected(oldWord, newWord, pos);
+ setSelection (l, cnt, l, cnt+newWord.length());
+ setBold(_bold);
+ setItalic(_italic);
+ setUnderline(_underline);
+ setColor(_color);
+ setCurrentFont(_font);
+ }
+
+}
+
+void KMEdit::slotSpellcheck2(KSpell*)
+{
+ if( !mSpellLineEdit)
+ {
+ spellcheck_start();
+
+ QString quotePrefix;
+ if(mComposer && mComposer->msg())
+ {
+ int languageNr = GlobalSettings::self()->replyCurrentLanguage();
+ ReplyPhrases replyPhrases( QString::number(languageNr) );
+ replyPhrases.readConfig();
+
+ quotePrefix = mComposer->msg()->formatString(
+ replyPhrases.indentPrefix() );
+ }
+
+ kdDebug(5006) << "spelling: new SpellingFilter with prefix=\"" << quotePrefix << "\"" << endl;
+ QTextEdit plaintext;
+ plaintext.setText(text());
+ plaintext.setTextFormat(Qt::PlainText);
+ mSpellingFilter = new SpellingFilter(plaintext.text(), quotePrefix, SpellingFilter::FilterUrls,
+ SpellingFilter::FilterEmailAddresses);
+
+ mKSpell->check(mSpellingFilter->filteredText());
+ }
+ else if( mComposer )
+ mKSpell->check( mComposer->sujectLineWidget()->text());
+}
+
+void KMEdit::slotSpellResult(const QString &s)
+{
+ if( !mSpellLineEdit)
+ spellcheck_stop();
+
+ int dlgResult = mKSpell->dlgResult();
+ if ( dlgResult == KS_CANCEL )
+ {
+ if( mSpellLineEdit)
+ {
+ //stop spell check
+ mSpellLineEdit = false;
+ QString tmpText( s );
+ tmpText = tmpText.remove('\n');
+
+ if( tmpText != mComposer->sujectLineWidget()->text() )
+ mComposer->sujectLineWidget()->setText( tmpText );
+ }
+ else
+ {
+ setModified(true);
+ }
+ }
+ mKSpell->cleanUp();
+ KDictSpellingHighlighter::dictionaryChanged();
+
+ emit spellcheck_done( dlgResult );
+}
+
+void KMEdit::slotSpellDone()
+{
+ kdDebug(5006)<<" void KMEdit::slotSpellDone()\n";
+ KSpell::spellStatus status = mKSpell->status();
+ delete mKSpell;
+ mKSpell = 0;
+
+ kdDebug(5006) << "spelling: delete SpellingFilter" << endl;
+ delete mSpellingFilter;
+ mSpellingFilter = 0;
+ mComposer->sujectLineWidget()->deselect();
+ if (status == KSpell::Error)
+ {
+ KMessageBox::sorry( topLevelWidget(),
+ i18n("ISpell/Aspell could not be started. Please "
+ "make sure you have ISpell or Aspell properly "
+ "configured and in your PATH.") );
+ emit spellcheck_done( KS_CANCEL );
+ }
+ else if (status == KSpell::Crashed)
+ {
+ spellcheck_stop();
+ KMessageBox::sorry( topLevelWidget(),
+ i18n("ISpell/Aspell seems to have crashed.") );
+ emit spellcheck_done( KS_CANCEL );
+ }
+ else
+ {
+ if( mSpellLineEdit )
+ spellcheck();
+ else if( !mComposer->subjectTextWasSpellChecked() && status == KSpell::FinishedNoMisspellingsEncountered )
+ KMessageBox::information( topLevelWidget(),
+ i18n("No misspellings encountered.") );
+ }
+}
+
+void KMEdit::setCursorPositionFromStart( unsigned int pos ) {
+ unsigned int l = 0;
+ unsigned int c = 0;
+ posToRowCol( pos, l, c );
+ // kdDebug() << "Num lines: " << numLines() << endl;
+ // kdDebug() << "Position " << pos << " converted to " << l << ":" << c << endl;
+ setCursorPosition( l, c );
+ ensureCursorVisible();
+}
+
+#include "kmedit.moc"