kmail

kmedit.cpp

00001 // -*- mode: C++; c-file-style: "gnu" -*-
00002 // kmcomposewin.cpp
00003 // Author: Markus Wuebben <markus.wuebben@kde.org>
00004 // This code is published under the GPL.
00005 
00006 #include <config.h>
00007 
00008 #include "kmedit.h"
00009 #include "kmlineeditspell.h"
00010 
00011 #define REALLY_WANT_KMCOMPOSEWIN_H
00012 #include "kmcomposewin.h"
00013 #undef REALLY_WANT_KMCOMPOSEWIN_H
00014 #include "kmmsgdict.h"
00015 #include "kmfolder.h"
00016 #include "kmcommands.h"
00017 
00018 #include <maillistdrag.h>
00019 using KPIM::MailListDrag;
00020 
00021 #include <libkdepim/kfileio.h>
00022 #include <libemailfunctions/email.h>
00023 
00024 #include <kcursor.h>
00025 #include <kprocess.h>
00026 
00027 #include <kpopupmenu.h>
00028 #include <kdebug.h>
00029 #include <kmessagebox.h>
00030 #include <kurldrag.h>
00031 
00032 #include <ktempfile.h>
00033 #include <klocale.h>
00034 #include <kapplication.h>
00035 #include <kdirwatch.h>
00036 #include <kiconloader.h>
00037 
00038 #include "globalsettings.h"
00039 #include "replyphrases.h"
00040 
00041 #include <kspell.h>
00042 #include <kspelldlg.h>
00043 #include <spellingfilter.h>
00044 #include <ksyntaxhighlighter.h>
00045 
00046 #include <qregexp.h>
00047 #include <qbuffer.h>
00048 #include <qevent.h>
00049 
00050 #include <sys/stat.h>
00051 #include <sys/types.h>
00052 #include <stdlib.h>
00053 #include <unistd.h>
00054 #include <errno.h>
00055 #include <fcntl.h>
00056 #include <assert.h>
00057 
00058 
00059 void KMEdit::contentsDragEnterEvent(QDragEnterEvent *e)
00060 {
00061     if (e->provides(MailListDrag::format()))
00062         e->accept(true);
00063     else
00064         return KEdit::contentsDragEnterEvent(e);
00065 }
00066 
00067 void KMEdit::contentsDragMoveEvent(QDragMoveEvent *e)
00068 {
00069     if (e->provides(MailListDrag::format()))
00070         e->accept();
00071     else
00072         return KEdit::contentsDragMoveEvent(e);
00073 }
00074 
00075 void KMEdit::keyPressEvent( QKeyEvent* e )
00076 {
00077     if( e->key() == Key_Return ) {
00078         int line, col;
00079         getCursorPosition( &line, &col );
00080         QString lineText = text( line );
00081         // returns line with additional trailing space (bug in Qt?), cut it off
00082         lineText.truncate( lineText.length() - 1 );
00083         // special treatment of quoted lines only if the cursor is neither at
00084         // the begin nor at the end of the line
00085         if( ( col > 0 ) && ( col < int( lineText.length() ) ) ) {
00086             bool isQuotedLine = false;
00087             uint bot = 0; // bot = begin of text after quote indicators
00088             while( bot < lineText.length() ) {
00089                 if( ( lineText[bot] == '>' ) || ( lineText[bot] == '|' ) ) {
00090                     isQuotedLine = true;
00091                     ++bot;
00092                 }
00093                 else if( lineText[bot].isSpace() ) {
00094                     ++bot;
00095                 }
00096                 else {
00097                     break;
00098                 }
00099             }
00100 
00101             KEdit::keyPressEvent( e );
00102 
00103             // duplicate quote indicators of the previous line before the new
00104             // line if the line actually contained text (apart from the quote
00105             // indicators) and the cursor is behind the quote indicators
00106             if( isQuotedLine
00107                 && ( bot != lineText.length() )
00108                 && ( col >= int( bot ) ) ) {
00109 
00110         // The cursor position might have changed unpredictably if there was selected
00111         // text which got replaced by a new line, so we query it again:
00112         getCursorPosition( &line, &col );
00113                 QString newLine = text( line );
00114                 // remove leading white space from the new line and instead
00115                 // add the quote indicators of the previous line
00116                 unsigned int leadingWhiteSpaceCount = 0;
00117                 while( ( leadingWhiteSpaceCount < newLine.length() )
00118                        && newLine[leadingWhiteSpaceCount].isSpace() ) {
00119                     ++leadingWhiteSpaceCount;
00120                 }
00121                 newLine = newLine.replace( 0, leadingWhiteSpaceCount,
00122                                            lineText.left( bot ) );
00123                 removeParagraph( line );
00124                 insertParagraph( newLine, line );
00125                 // place the cursor at the begin of the new line since
00126                 // we assume that the user split the quoted line in order
00127                 // to add a comment to the first part of the quoted line
00128                 setCursorPosition( line, 0 );
00129             }
00130         }
00131         else
00132             KEdit::keyPressEvent( e );
00133     }
00134     else
00135         KEdit::keyPressEvent( e );
00136 }
00137 
00138 void KMEdit::contentsDropEvent(QDropEvent *e)
00139 {
00140     if (e->provides(MailListDrag::format())) {
00141         // Decode the list of serial numbers stored as the drag data
00142         QByteArray serNums;
00143         MailListDrag::decode( e, serNums );
00144         QBuffer serNumBuffer(serNums);
00145         serNumBuffer.open(IO_ReadOnly);
00146         QDataStream serNumStream(&serNumBuffer);
00147         Q_UINT32 serNum;
00148         KMFolder *folder = 0;
00149         int idx;
00150         QPtrList<KMMsgBase> messageList;
00151         while (!serNumStream.atEnd()) {
00152             KMMsgBase *msgBase = 0;
00153             serNumStream >> serNum;
00154             KMMsgDict::instance()->getLocation(serNum, &folder, &idx);
00155             if (folder)
00156                 msgBase = folder->getMsgBase(idx);
00157             if (msgBase)
00158                 messageList.append( msgBase );
00159         }
00160         serNumBuffer.close();
00161         uint identity = folder ? folder->identity() : 0;
00162         KMCommand *command =
00163             new KMForwardAttachedCommand(mComposer, messageList,
00164                                          identity, mComposer);
00165         command->start();
00166     }
00167     else if( KURLDrag::canDecode( e ) ) {
00168         KURL::List urlList;
00169         if( KURLDrag::decode( e, urlList ) ) {
00170             KPopupMenu p;
00171             p.insertItem( i18n("Add as Text"), 0 );
00172             p.insertItem( i18n("Add as Attachment"), 1 );
00173             int id = p.exec( mapToGlobal( e->pos() ) );
00174             switch ( id) {
00175               case 0:
00176                 for ( KURL::List::Iterator it = urlList.begin();
00177                      it != urlList.end(); ++it ) {
00178                   insert( (*it).url() );
00179                 }
00180                 break;
00181               case 1:
00182                 for ( KURL::List::Iterator it = urlList.begin();
00183                      it != urlList.end(); ++it ) {
00184                   mComposer->addAttach( *it );
00185                 }
00186                 break;
00187             }
00188         }
00189         else if ( QTextDrag::canDecode( e ) ) {
00190           QString s;
00191           if ( QTextDrag::decode( e, s ) )
00192             insert( s );
00193         }
00194         else
00195           kdDebug(5006) << "KMEdit::contentsDropEvent, unable to add dropped object" << endl;
00196     }
00197     else {
00198         return KEdit::contentsDropEvent(e);
00199     }
00200 }
00201 
00202 KMEdit::KMEdit(QWidget *parent, KMComposeWin* composer,
00203                KSpellConfig* autoSpellConfig,
00204                const char *name)
00205   : KEdit( parent, name ),
00206     mComposer( composer ),
00207     mKSpell( 0 ),
00208     mSpellConfig( autoSpellConfig ),
00209     mSpellingFilter( 0 ),
00210     mExtEditorTempFile( 0 ),
00211     mExtEditorTempFileWatcher( 0 ),
00212     mExtEditorProcess( 0 ),
00213     mUseExtEditor( false ),
00214     mWasModifiedBeforeSpellCheck( false ),
00215     mSpellChecker( 0 ),
00216     mSpellLineEdit( false )
00217 {
00218   installEventFilter(this);
00219   KCursor::setAutoHideCursor( this, true, true );
00220   setOverwriteEnabled( true );
00221 }
00222 
00223 
00224 void KMEdit::initializeAutoSpellChecking()
00225 {
00226   if ( mSpellChecker )
00227     return; // already initialized
00228   QColor defaultColor1( 0x00, 0x80, 0x00 ); // defaults from kmreaderwin.cpp
00229   QColor defaultColor2( 0x00, 0x70, 0x00 );
00230   QColor defaultColor3( 0x00, 0x60, 0x00 );
00231   QColor defaultForeground( kapp->palette().active().text() );
00232 
00233   QColor c = Qt::red;
00234   KConfigGroup readerConfig( KMKernel::config(), "Reader" );
00235   QColor col1;
00236   if ( !readerConfig.readBoolEntry(  "defaultColors", true ) )
00237       col1 = readerConfig.readColorEntry( "ForegroundColor", &defaultForeground );
00238   else
00239       col1 = defaultForeground;
00240   QColor col2 = readerConfig.readColorEntry( "QuotedText3", &defaultColor3 );
00241   QColor col3 = readerConfig.readColorEntry( "QuotedText2", &defaultColor2 );
00242   QColor col4 = readerConfig.readColorEntry( "QuotedText1", &defaultColor1 );
00243   QColor misspelled = readerConfig.readColorEntry( "MisspelledColor", &c );
00244   mSpellChecker = new KDictSpellingHighlighter( this, /*active*/ true,
00245                                                 /*autoEnabled*/ false,
00246                                                 /*spellColor*/ misspelled,
00247                                                 /*colorQuoting*/ true,
00248                                                 col1, col2, col3, col4,
00249                                                 mSpellConfig );
00250 
00251   connect( mSpellChecker, SIGNAL(newSuggestions(const QString&, const QStringList&, unsigned int)),
00252            this, SLOT(addSuggestion(const QString&, const QStringList&, unsigned int)) );
00253 }
00254 
00255 
00256 QPopupMenu *KMEdit::createPopupMenu( const QPoint& pos )
00257 {
00258   enum { IdUndo, IdRedo, IdSep1, IdCut, IdCopy, IdPaste, IdClear, IdSep2, IdSelectAll };
00259 
00260   QPopupMenu *menu = KEdit::createPopupMenu( pos );
00261   if ( !QApplication::clipboard()->image().isNull() ) {
00262     int id = menu->idAt(0);
00263     menu->setItemEnabled( id - IdPaste, true);
00264   }
00265 
00266   return menu;
00267 }
00268 
00269 void KMEdit::deleteAutoSpellChecking()
00270 { // because the highlighter doesn't support RichText, delete its instance.
00271   delete mSpellChecker;
00272   mSpellChecker =0;
00273 }
00274 
00275 void KMEdit::addSuggestion(const QString& text, const QStringList& lst, unsigned int )
00276 {
00277   mReplacements[text] = lst;
00278 }
00279 
00280 void KMEdit::setSpellCheckingActive(bool spellCheckingActive)
00281 {
00282   if ( mSpellChecker ) {
00283     mSpellChecker->setActive(spellCheckingActive);
00284   }
00285 }
00286 
00287 
00288 KMEdit::~KMEdit()
00289 {
00290   removeEventFilter(this);
00291 
00292   delete mKSpell;
00293   delete mSpellChecker;
00294   mSpellChecker = 0;
00295 
00296 }
00297 
00298 
00299 
00300 QString KMEdit::brokenText()
00301 {
00302   QString temp, line;
00303 
00304   int num_lines = numLines();
00305   for (int i = 0; i < num_lines; ++i)
00306   {
00307     int lastLine = 0;
00308     line = textLine(i);
00309     for (int j = 0; j < (int)line.length(); ++j)
00310     {
00311       if (lineOfChar(i, j) > lastLine)
00312       {
00313         lastLine = lineOfChar(i, j);
00314         temp += '\n';
00315       }
00316       temp += line[j];
00317     }
00318     if (i + 1 < num_lines) temp += '\n';
00319   }
00320 
00321   return temp;
00322 }
00323 
00324 
00325 unsigned int KMEdit::lineBreakColumn() const
00326 {
00327   unsigned int lineBreakColumn = 0;
00328   unsigned int numlines = numLines();
00329   while ( numlines-- ) {
00330     lineBreakColumn = QMAX( lineBreakColumn, textLine( numlines ).length() );
00331   }
00332   return lineBreakColumn;
00333 }
00334 
00335 
00336 bool KMEdit::eventFilter(QObject*o, QEvent* e)
00337 {
00338   if (o == this)
00339     KCursor::autoHideEventFilter(o, e);
00340 
00341   if (e->type() == QEvent::KeyPress)
00342   {
00343     QKeyEvent *k = (QKeyEvent*)e;
00344 
00345     if (mUseExtEditor) {
00346       if (k->key() == Key_Up)
00347       {
00348         emit focusUp();
00349         return TRUE;
00350       }
00351 
00352       // ignore modifier keys (cf. bug 48841)
00353       if ( (k->key() == Key_Shift) || (k->key() == Key_Control) ||
00354            (k->key() == Key_Meta) || (k->key() == Key_Alt) )
00355         return true;
00356       if (mExtEditorTempFile) return TRUE;
00357       QString sysLine = mExtEditor;
00358       mExtEditorTempFile = new KTempFile();
00359 
00360       mExtEditorTempFile->setAutoDelete(true);
00361 
00362       (*mExtEditorTempFile->textStream()) << text();
00363 
00364       mExtEditorTempFile->close();
00365       // replace %f in the system line
00366       sysLine.replace( "%f", mExtEditorTempFile->name() );
00367       mExtEditorProcess = new KProcess();
00368       mExtEditorProcess->setUseShell( true );
00369       sysLine += " ";
00370       while (!sysLine.isEmpty())
00371       {
00372         *mExtEditorProcess << sysLine.left(sysLine.find(" ")).local8Bit();
00373         sysLine.remove(0, sysLine.find(" ") + 1);
00374       }
00375       connect(mExtEditorProcess, SIGNAL(processExited(KProcess*)),
00376               SLOT(slotExternalEditorDone(KProcess*)));
00377       if (!mExtEditorProcess->start())
00378       {
00379         KMessageBox::error( topLevelWidget(),
00380                             i18n("Unable to start external editor.") );
00381         killExternalEditor();
00382       } else {
00383         mExtEditorTempFileWatcher = new KDirWatch( this, "mExtEditorTempFileWatcher" );
00384         connect( mExtEditorTempFileWatcher, SIGNAL(dirty(const QString&)),
00385                  SLOT(slotExternalEditorTempFileChanged(const QString&)) );
00386         mExtEditorTempFileWatcher->addFile( mExtEditorTempFile->name() );
00387       }
00388       return TRUE;
00389     } else {
00390     // ---sven's Arrow key navigation start ---
00391     // Key Up in first line takes you to Subject line.
00392     if (k->key() == Key_Up && k->state() != ShiftButton && currentLine() == 0
00393       && lineOfChar(0, currentColumn()) == 0)
00394     {
00395       deselect();
00396       emit focusUp();
00397       return TRUE;
00398     }
00399     // ---sven's Arrow key navigation end ---
00400 
00401     if (k->key() == Key_Backtab && k->state() == ShiftButton)
00402     {
00403       deselect();
00404       emit focusUp();
00405       return TRUE;
00406     }
00407 
00408     }
00409   } else if ( e->type() == QEvent::ContextMenu ) {
00410     QContextMenuEvent *event = (QContextMenuEvent*) e;
00411 
00412     int para = 1, charPos, firstSpace, lastSpace;
00413 
00414     //Get the character at the position of the click
00415     charPos = charAt( viewportToContents(event->pos()), &para );
00416     QString paraText = text( para );
00417 
00418     if( !paraText.at(charPos).isSpace() )
00419     {
00420       //Get word right clicked on
00421       const QRegExp wordBoundary( "[\\s\\W]" );
00422       firstSpace = paraText.findRev( wordBoundary, charPos ) + 1;
00423       lastSpace = paraText.find( wordBoundary, charPos );
00424       if( lastSpace == -1 )
00425         lastSpace = paraText.length();
00426       QString word = paraText.mid( firstSpace, lastSpace - firstSpace );
00427       //Continue if this word was misspelled
00428       if( !word.isEmpty() && mReplacements.contains( word ) )
00429       {
00430         KPopupMenu p;
00431         p.insertTitle( i18n("Suggestions") );
00432 
00433         //Add the suggestions to the popup menu
00434         QStringList reps = mReplacements[word];
00435         if( reps.count() > 0 )
00436         {
00437           int listPos = 0;
00438           for ( QStringList::Iterator it = reps.begin(); it != reps.end(); ++it ) {
00439             p.insertItem( *it, listPos );
00440             listPos++;
00441           }
00442         }
00443         else
00444         {
00445           p.insertItem( QString::fromLatin1("No Suggestions"), -2 );
00446         }
00447 
00448         //Execute the popup inline
00449         int id = p.exec( mapToGlobal( event->pos() ) );
00450 
00451         if( id > -1 )
00452         {
00453           //Save the cursor position
00454           int parIdx = 1, txtIdx = 1;
00455           getCursorPosition(&parIdx, &txtIdx);
00456           setSelection(para, firstSpace, para, lastSpace);
00457           insert(mReplacements[word][id]);
00458           // Restore the cursor position; if the cursor was behind the
00459           // misspelled word then adjust the cursor position
00460           if ( para == parIdx && txtIdx >= lastSpace )
00461             txtIdx += mReplacements[word][id].length() - word.length();
00462           setCursorPosition(parIdx, txtIdx);
00463         }
00464         //Cancel original event
00465         return true;
00466       }
00467     }
00468   } else if ( e->type() == QEvent::FocusIn || e->type() == QEvent::FocusOut ) {
00469     QFocusEvent *fe = static_cast<QFocusEvent*>(e);
00470     if(! (fe->reason() == QFocusEvent::ActiveWindow || fe->reason() == QFocusEvent::Popup) )
00471       emit focusChanged( fe->gotFocus() );
00472   }
00473 
00474   return KEdit::eventFilter(o, e);
00475 }
00476 
00477 
00478 int KMEdit::autoSpellChecking( bool on )
00479 {
00480   if ( textFormat() == Qt::RichText ) {
00481      // syntax highlighter doesn't support extended text properties
00482      if ( on )
00483        KMessageBox::sorry(this, i18n("Automatic spellchecking is not possible on text with markup."));
00484      return -1;
00485   }
00486   if ( mSpellChecker ) {
00487     // don't autoEnable spell checking if the user turned spell checking off
00488     mSpellChecker->setAutomatic( on );
00489     mSpellChecker->setActive( on );
00490   }
00491   return 1;
00492 }
00493 
00494 
00495 void KMEdit::slotExternalEditorTempFileChanged( const QString & fileName ) {
00496   if ( !mExtEditorTempFile )
00497     return;
00498   if ( fileName != mExtEditorTempFile->name() )
00499     return;
00500   // read data back in from file
00501   setAutoUpdate(false);
00502   clear();
00503 
00504   insertLine(QString::fromLocal8Bit(KPIM::kFileToString( fileName, true, false )), -1);
00505   setAutoUpdate(true);
00506   repaint();
00507 }
00508 
00509 void KMEdit::slotExternalEditorDone( KProcess * proc ) {
00510   assert(proc == mExtEditorProcess);
00511   // make sure, we update even when KDirWatcher is too slow:
00512   slotExternalEditorTempFileChanged( mExtEditorTempFile->name() );
00513   killExternalEditor();
00514 }
00515 
00516 void KMEdit::killExternalEditor() {
00517   delete mExtEditorTempFileWatcher; mExtEditorTempFileWatcher = 0;
00518   delete mExtEditorTempFile; mExtEditorTempFile = 0;
00519   delete mExtEditorProcess; mExtEditorProcess = 0;
00520 }
00521 
00522 
00523 bool KMEdit::checkExternalEditorFinished() {
00524   if ( !mExtEditorProcess )
00525     return true;
00526   switch ( KMessageBox::warningYesNoCancel( topLevelWidget(),
00527            i18n("The external editor is still running.\n"
00528                 "Abort the external editor or leave it open?"),
00529            i18n("External Editor"),
00530            i18n("Abort Editor"), i18n("Leave Editor Open") ) ) {
00531   case KMessageBox::Yes:
00532     killExternalEditor();
00533     return true;
00534   case KMessageBox::No:
00535     return true;
00536   default:
00537     return false;
00538   }
00539 }
00540 
00541 void KMEdit::spellcheck()
00542 {
00543   if ( mKSpell )
00544     return;
00545   mWasModifiedBeforeSpellCheck = isModified();
00546   mSpellLineEdit = !mSpellLineEdit;
00547 //  maybe for later, for now plaintext is given to KSpell
00548 //  if (textFormat() == Qt::RichText ) {
00549 //    kdDebug(5006) << "KMEdit::spellcheck, spellchecking for RichText" << endl;
00550 //    mKSpell = new KSpell(this, i18n("Spellcheck - KMail"), this,
00551 //                    SLOT(slotSpellcheck2(KSpell*)),0,true,false,KSpell::HTML);
00552 //  }
00553 //  else {
00554     mKSpell = new KSpell(this, i18n("Spellcheck - KMail"), this,
00555                       SLOT(slotSpellcheck2(KSpell*)));
00556 //  }
00557 
00558   QStringList l = KSpellingHighlighter::personalWords();
00559   for ( QStringList::Iterator it = l.begin(); it != l.end(); ++it ) {
00560       mKSpell->addPersonal( *it );
00561   }
00562   connect (mKSpell, SIGNAL( death()),
00563           this, SLOT (slotSpellDone()));
00564   connect (mKSpell, SIGNAL (misspelling (const QString &, const QStringList &, unsigned int)),
00565           this, SLOT (slotMisspelling (const QString &, const QStringList &, unsigned int)));
00566   connect (mKSpell, SIGNAL (corrected (const QString &, const QString &, unsigned int)),
00567           this, SLOT (slotCorrected (const QString &, const QString &, unsigned int)));
00568   connect (mKSpell, SIGNAL (done(const QString &)),
00569           this, SLOT (slotSpellResult (const QString&)));
00570 }
00571 
00572 void KMEdit::cut()
00573 {
00574   KEdit::cut();
00575   if ( textFormat() != Qt::RichText && mSpellChecker )
00576     mSpellChecker->restartBackgroundSpellCheck();
00577 }
00578 
00579 void KMEdit::clear()
00580 {
00581   KEdit::clear();
00582   if ( textFormat() != Qt::RichText && mSpellChecker )
00583     mSpellChecker->restartBackgroundSpellCheck();
00584 }
00585 
00586 void KMEdit::del()
00587 {
00588   KEdit::del();
00589   if ( textFormat() != Qt::RichText && mSpellChecker )
00590     mSpellChecker->restartBackgroundSpellCheck();
00591 }
00592 
00593 void KMEdit::paste()
00594 {
00595   if ( ! QApplication::clipboard()->image().isNull() )  {
00596     emit pasteImage();
00597   }
00598   else
00599     KEdit::paste();
00600 }
00601 
00602 void KMEdit::slotMisspelling(const QString &text, const QStringList &lst, unsigned int pos)
00603 {
00604     kdDebug(5006)<<"void KMEdit::slotMisspelling(const QString &text, const QStringList &lst, unsigned int pos) : "<<text <<endl;
00605     if( mSpellLineEdit )
00606         mComposer->sujectLineWidget()->spellCheckerMisspelling( text, lst, pos);
00607     else
00608         misspelling(text, lst, pos);
00609 }
00610 
00611 void KMEdit::slotCorrected (const QString &oldWord, const QString &newWord, unsigned int pos)
00612 {
00613     kdDebug(5006)<<"slotCorrected (const QString &oldWord, const QString &newWord, unsigned int pos) : "<<oldWord<<endl;
00614     if( mSpellLineEdit )
00615         mComposer->sujectLineWidget()->spellCheckerCorrected( oldWord, newWord, pos);
00616     else {
00617         unsigned int l = 0;
00618         unsigned int cnt = 0;
00619         bool _bold,_underline,_italic;
00620         QColor _color;
00621         QFont _font;
00622         posToRowCol (pos, l, cnt);
00623         setCursorPosition(l, cnt+1); // the new word will get the same markup now as the first character of the word
00624         _bold = bold();
00625         _underline = underline();
00626         _italic = italic();
00627         _color = color();
00628         _font = currentFont();
00629         corrected(oldWord, newWord, pos);
00630         setSelection (l, cnt, l, cnt+newWord.length());
00631         setBold(_bold);
00632         setItalic(_italic);
00633         setUnderline(_underline);
00634         setColor(_color);
00635         setCurrentFont(_font);
00636     }
00637 
00638 }
00639 
00640 void KMEdit::slotSpellcheck2(KSpell*)
00641 {
00642     if( !mSpellLineEdit)
00643     {
00644         spellcheck_start();
00645 
00646         QString quotePrefix;
00647         if(mComposer && mComposer->msg())
00648         {
00649             int languageNr = GlobalSettings::self()->replyCurrentLanguage();
00650             ReplyPhrases replyPhrases( QString::number(languageNr) );
00651             replyPhrases.readConfig();
00652 
00653             quotePrefix = mComposer->msg()->formatString(
00654                  replyPhrases.indentPrefix() );
00655         }
00656 
00657         kdDebug(5006) << "spelling: new SpellingFilter with prefix=\"" << quotePrefix << "\"" << endl;
00658         QTextEdit plaintext;
00659         plaintext.setText(text());
00660         plaintext.setTextFormat(Qt::PlainText);
00661         mSpellingFilter = new SpellingFilter(plaintext.text(), quotePrefix, SpellingFilter::FilterUrls,
00662                                              SpellingFilter::FilterEmailAddresses);
00663 
00664         mKSpell->check(mSpellingFilter->filteredText());
00665     }
00666     else if( mComposer )
00667         mKSpell->check( mComposer->sujectLineWidget()->text());
00668 }
00669 
00670 void KMEdit::slotSpellResult(const QString &s)
00671 {
00672     if( !mSpellLineEdit)
00673         spellcheck_stop();
00674 
00675   int dlgResult = mKSpell->dlgResult();
00676   if ( dlgResult == KS_CANCEL )
00677   {
00678       if( mSpellLineEdit)
00679       {
00680           //stop spell check
00681           mSpellLineEdit = false;
00682           QString tmpText( s );
00683           tmpText =  tmpText.remove('\n');
00684 
00685           if( tmpText != mComposer->sujectLineWidget()->text() )
00686               mComposer->sujectLineWidget()->setText( tmpText );
00687       }
00688       else
00689       {
00690           setModified(true);
00691       }
00692   }
00693   mKSpell->cleanUp();
00694   KDictSpellingHighlighter::dictionaryChanged();
00695 
00696   emit spellcheck_done( dlgResult );
00697 }
00698 
00699 void KMEdit::slotSpellDone()
00700 {
00701   kdDebug(5006)<<" void KMEdit::slotSpellDone()\n";
00702   KSpell::spellStatus status = mKSpell->status();
00703   delete mKSpell;
00704   mKSpell = 0;
00705 
00706   kdDebug(5006) << "spelling: delete SpellingFilter" << endl;
00707   delete mSpellingFilter;
00708   mSpellingFilter = 0;
00709   mComposer->sujectLineWidget()->deselect();
00710   if (status == KSpell::Error)
00711   {
00712      KMessageBox::sorry( topLevelWidget(),
00713                          i18n("ISpell/Aspell could not be started. Please "
00714                               "make sure you have ISpell or Aspell properly "
00715                               "configured and in your PATH.") );
00716      emit spellcheck_done( KS_CANCEL );
00717   }
00718   else if (status == KSpell::Crashed)
00719   {
00720      spellcheck_stop();
00721      KMessageBox::sorry( topLevelWidget(),
00722                          i18n("ISpell/Aspell seems to have crashed.") );
00723      emit spellcheck_done( KS_CANCEL );
00724   }
00725   else
00726   {
00727       if( mSpellLineEdit )
00728           spellcheck();
00729       else if( !mComposer->subjectTextWasSpellChecked() && status == KSpell::FinishedNoMisspellingsEncountered )
00730           KMessageBox::information( topLevelWidget(),
00731                                     i18n("No misspellings encountered.") );
00732   }
00733 }
00734 
00735 void KMEdit::setCursorPositionFromStart( unsigned int pos ) {
00736   unsigned int l = 0;
00737   unsigned int c = 0;
00738   posToRowCol( pos, l, c );
00739   // kdDebug() << "Num lines: " << numLines() << endl;
00740   // kdDebug() << "Position " << pos << " converted to " << l << ":" << c << endl;
00741   setCursorPosition( l, c );
00742   ensureCursorVisible();
00743 }
00744 
00745 #include "kmedit.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys