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