28 #include <sys/types.h>
38 #include <QtGui/QApplication>
39 #include <QtCore/QTextCodec>
40 #include <QtCore/QTimer>
48 #include <QTextStream>
50 #define MAXLINELENGTH 10000
51 #undef IGNORE //fix possible conflict
70 class K3Spell::K3SpellPrivate
74 bool m_bIgnoreUpperWords;
75 bool m_bIgnoreTitleCase;
76 bool m_bNoMisspellingsEncountered;
80 QList<BufferedWord> unchecked;
81 QTimer *checkNextTimer;
84 QString convertQByteArray(
const QByteArray& b )
86 QTextCodec* originalCodec = QTextCodec::codecForCStrings();
87 QTextCodec::setCodecForCStrings( m_codec );
89 QTextCodec::setCodecForCStrings( originalCodec );
92 QByteArray convertQString(
const QString& s )
94 QTextCodec* originalCodec = QTextCodec::codecForCStrings();
95 QTextCodec::setCodecForCStrings( m_codec );
96 QByteArray b = s.toLatin1();
97 QTextCodec::setCodecForCStrings( originalCodec );
118 #define OUTPUT(x) (connect (proc, SIGNAL (readyReadStandardOutput()), this, SLOT (x())))
121 #define NOOUTPUT(x) (disconnect (proc, SIGNAL (readyReadStandardOutput()), this, SLOT (x())))
127 bool _progressbar,
bool _modal )
129 initialize( _parent, _caption, obj, slot, _ksc,
130 _progressbar, _modal,
Text );
137 initialize( _parent, _caption, obj, slot, _ksc,
138 _progressbar, _modal, type );
170 FILE *fs = popen(
"aspell -v",
"r");
175 QTextStream ts(fs, QIODevice::ReadOnly);
176 result = ts.readAll().trimmed();
181 QRegExp rx(
"Aspell (\\d.\\d)");
182 if (rx.indexIn(result) != -1)
184 float version = rx.cap(1).toFloat();
185 return (version >= 0.6);
208 kDebug(750) <<
"Using ispell";
212 kDebug(750) <<
"Using aspell";
216 kDebug(750) <<
"Using hspell";
220 kDebug(750) <<
"Using zemberek(zpspell)";
224 kDebug(750) <<
"Using hunspell";
231 *
proc <<
"-a" <<
"-S";
291 *
proc <<
"-i" <<
"ISO-8859-1";
294 *
proc <<
"-i" <<
"ISO-8859-2";
297 *
proc <<
"-i" <<
"ISO-8859-3";
300 *
proc <<
"-i" <<
"ISO-8859-4";
303 *
proc <<
"-i" <<
"ISO-8859-5";
306 *
proc <<
"-i" <<
"ISO-8859-7";
309 *
proc <<
"-i" <<
"ISO-8859-8";
312 *
proc <<
"-i" <<
"ISO-8859-9";
315 *
proc <<
"-i" <<
"ISO-8859-13";
318 *
proc <<
"-i" <<
"ISO-8859-15";
321 *
proc <<
"-i" <<
"UTF-8";
324 *
proc <<
"-i" <<
"KOI8-R";
327 *
proc <<
"-i" <<
"KOI8-U";
330 *
proc <<
"-i" <<
"CP1251";
333 *
proc <<
"-i" <<
"CP1255";
359 kError(750) <<
"charsets ISO-8859-4, -5, -7, -8, -9 and -13 not supported yet" << endl;
372 kError(750) <<
"ISO-8859-15 not supported for aspell yet." << endl;
377 *
proc <<
"--encoding=utf-8";
395 connect(
proc, SIGNAL(readyReadStandardError()),
398 connect(
proc, SIGNAL(finished(
int,QProcess::ExitStatus)),
408 if ( !
proc->waitForStarted() )
411 QTimer::singleShot( 0,
this, SLOT(
emitDeath()));
427 kDebug(750) <<
"K3Spell::K3Spell2";
433 qint64 read =
proc->readLine(data.data(),data.count());
436 QTimer::singleShot( 0,
this, SLOT(
emitDeath()) );
439 line = d->convertQByteArray( data );
441 if ( !line.startsWith(
'@') )
443 QTimer::singleShot( 0,
this, SLOT(
emitDeath()) );
450 kDebug(750) <<
"@KDE was false";
451 QTimer::singleShot( 0,
this, SLOT(
emitDeath()) );
458 kDebug(750) <<
"@Linux was false";
459 QTimer::singleShot( 0,
this, SLOT(
emitDeath()) );
479 connect(
ksdlg, SIGNAL(command(
int)),
481 connect(
this, SIGNAL(
progress(uint)),
482 ksdlg, SLOT(slotProgress(uint)) );
491 QString qs = word.simplified();
494 if ( qs.indexOf(
' ') != -1 || qs.isEmpty() )
500 return proc->write( d->convertQString( qs ) );
505 return proc->write( QByteArray(
"#" ) );
510 QString qs = word.simplified();
513 if ( qs.indexOf (
' ') != -1 || qs.isEmpty() )
518 return proc->write( d->convertQString( qs ) );
527 for(
int i = 0; i < qs.length(); i++ )
530 if ( (qs[i] !=
'\'' && qs[i] !=
'\"' && qs[i] !=
'-'
531 && qs[i].isPunct()) || qs[i].isSpace() )
536 if ( qs[i].isLetter() )
545 return proc->write( d->convertQString(
QString(
'^'+qs+
'\n') ) );
552 unsigned l = qs.length();
555 for(
unsigned int i = 0; i < l; ++i )
565 return proc->write( d->convertQString(
'^'+qs+
'\n') );
568 return proc->write( d->convertQString(
"^\n" ) );
574 BufferedWord bufferedWord;
576 bufferedWord.word = buffer;
577 bufferedWord.useDialog = _usedialog;
578 d->unchecked.append( bufferedWord );
582 QString qs = buffer.simplified();
584 if ( qs.indexOf (
' ') != -1 || qs.isEmpty() ) {
585 d->checkNextTimer->setInterval(0);
586 d->checkNextTimer->setSingleShot(
true);
587 d->checkNextTimer->start();
603 while (
proc->readLine( data.data(), data.count() ) != -1 )
609 proc->write( d->convertQString(
QString(
"%" ) ) );
610 proc->write( d->convertQString( buffer ) );
618 BufferedWord bufferedWord;
620 bufferedWord.word = buffer;
621 bufferedWord.useDialog = _usedialog;
622 bufferedWord.suggest = suggest;
623 d->unchecked.append( bufferedWord );
627 QString qs = buffer.simplified();
629 if ( qs.indexOf (
' ') != -1 || qs.isEmpty() ) {
630 d->checkNextTimer->setInterval(0);
631 d->checkNextTimer->setSingleShot(
true);
632 d->checkNextTimer->start();
650 while (
proc->readLine( data.data(), data.count() ) != -1 ) ;
655 proc->write( d->convertQString(
QString(
"%" ) ) );
656 proc->write( d->convertQString( buffer ) );
665 line = d->convertQByteArray(
proc->readLine() );
677 while (
proc->readLine( data.data(), data.count() ) != -1 ) ;
685 d->checkNextTimer->setInterval(0);
686 d->checkNextTimer->setSingleShot(
true);
687 d->checkNextTimer->start();
698 d->checkNextTimer->setInterval(0);
699 d->checkNextTimer->setSingleShot(
true);
700 d->checkNextTimer->start();
707 if (!d->unchecked.empty()) {
708 BufferedWord buf = d->unchecked.front();
709 d->unchecked.pop_front();
714 checkWord( buf.word, buf.useDialog, buf.suggest );
722 line = d->convertQByteArray(
proc->readLine() );
728 while (
proc->readLine( data.data(), data.count() ) != -1 ) ;
753 for(
int i=0; i<word.size(); i++ )
762 for( j = i+1; j < word.size() && word[j] !=
'+' && word[j] !=
'-'; j++ )
767 if ( !( k = qs.lastIndexOf(shorty) ) || k != -1 )
768 qs.remove( k, shorty.length() );
796 if ( buffer[0] ==
'*' || buffer[0] ==
'+' || buffer[0] ==
'-' )
801 if ( buffer[0] ==
'&' || buffer[0] ==
'?' || buffer[0] ==
'#' )
806 word = buffer.mid( 2, buffer.indexOf(
' ', 3 ) -2 );
810 if( d->m_bIgnoreTitleCase && word == word.toUpper() )
813 if( d->m_bIgnoreUpperWords && word[0] == word[0].toUpper() )
815 QString text = word[0] + word.right( word.length()-1 ).toLower();
824 if (
ignorelist.indexOf( word.toLower() ) != -1 )
830 if ( buffer.indexOf(
':' ) != -1 )
831 qs2 = buffer.left( buffer.indexOf(
':') );
835 posinline = qs2.right( qs2.length()-qs2.lastIndexOf(
' ') ).toInt()-1;
850 if ( buffer[0] !=
'#' )
852 QString qs = buffer.mid( buffer.indexOf(
':')+2, buffer.length() );
857 while( i < qs.length() )
859 QString temp = qs.mid( i, (j=qs.indexOf(
',',i)) - i );
866 if ( (sugg.count()==1) && (sugg.first() == word) )
872 if ( buffer.isEmpty() ) {
873 kDebug(750) <<
"Got an empty response: ignoring";
877 kError(750) <<
"HERE?: [" << buffer <<
"]" << endl;
878 kError(750) <<
"Please report this to zack@kde.org" << endl;
879 kError(750) <<
"Thank you!" << endl;
901 proc->write(QByteArray(
'%' ) );
922 d->endOfResponse =
false;
965 tempe =
proc->readLine( data.data(), data.count() );
968 line = d->convertQByteArray( data );
971 d->endOfResponse =
true;
973 }
else if ( tempe>0 ) {
997 d->m_bNoMisspellingsEncountered =
false;
1006 }
while (tempe > 0);
1012 if (d->endOfResponse && !
dlgon) {
1076 if (!d->endOfResponse) {
1091 kDebug(750) <<
"KS: check";
1117 proc->write( QByteArray(
"!" ) );
1154 static bool recursive =
false;
1165 tempe =
proc->readLine( data.data(), data.count() );
1166 line = d->convertQByteArray( data );
1210 d->m_bNoMisspellingsEncountered =
false;
1226 if ( tempe == -1 ) {
1269 disconnect (
this, SIGNAL (
dialog3()),
this, SLOT (
check3()));
1310 kDebug(750) <<
"K3Spell::slotStopCancel [" << result <<
"]";
1328 connect(
ksdlg, SIGNAL(command(
int)),
this, SLOT(
dialog2(
int)) );
1335 tmpBuf.replace(
lastpos, word.length(), marker );
1336 QString context = tmpBuf.mid(qMax(
lastpos-18,0), 2*18+marker.length());
1337 context.replace(
'\n',QLatin1Char(
' '));
1338 context.replace(
'<', QLatin1String(
"<") );
1339 context.replace(
'>', QLatin1String(
">") );
1340 context.replace( marker, QString::fromLatin1(
"<b>%1</b>").arg( word ) );
1341 context =
"<qt>" + context +
"</qt>";
1344 d->m_bNoMisspellingsEncountered =
false;
1360 disconnect(
ksdlg, SIGNAL(command(
int)),
this, SLOT(
dialog2(
int)) );
1409 delete d->checkNextTimer;
1432 proc->closeWriteChannel();
1461 QTimer::singleShot( 0,
this, SLOT(
emitDeath()) );
1494 pt2 =
parent->mapToGlobal( pt );
1495 ksdlg->move( pt2.x(),pt2.y() );
1500 d->m_bIgnoreUpperWords=_ignore;
1505 d->m_bIgnoreTitleCase=_ignore;
1527 0, _kcs,
true,
true );
1530 qApp->processEvents();
1538 void K3Spell::slotSpellCheckerCorrected(
const QString & oldText,
const QString & newText,
unsigned int pos )
1544 void K3Spell::slotModalReady()
1551 this, SLOT(slotModalDone(
QString)) );
1554 QObject::connect(
this, SIGNAL(
death()),
1555 this, SLOT(slotModalSpellCheckerFinished()) );
1559 void K3Spell::slotModalDone(
const QString & )
1569 slotModalSpellCheckerFinished();
1572 void K3Spell::slotModalSpellCheckerFinished( )
1579 bool _progressbar,
bool _modal,
SpellerType type )
1581 d =
new K3SpellPrivate;
1583 d->m_bIgnoreUpperWords =
false;
1584 d->m_bIgnoreTitleCase =
false;
1585 d->m_bNoMisspellingsEncountered =
true;
1587 d->checking =
false;
1588 d->aspellV6 =
false;
1589 d->checkNextTimer =
new QTimer(
this );
1590 connect( d->checkNextTimer, SIGNAL(
timeout()),
1611 d->m_codec = QTextCodec::codecForName(
"ISO 8859-1");
1614 d->m_codec = QTextCodec::codecForName(
"ISO 8859-2");
1617 d->m_codec = QTextCodec::codecForName(
"ISO 8859-3");
1620 d->m_codec = QTextCodec::codecForName(
"ISO 8859-4");
1623 d->m_codec = QTextCodec::codecForName(
"ISO 8859-5");
1626 d->m_codec = QTextCodec::codecForName(
"ISO 8859-7");
1629 d->m_codec = QTextCodec::codecForName(
"ISO 8859-8-i");
1632 d->m_codec = QTextCodec::codecForName(
"ISO 8859-9");
1635 d->m_codec = QTextCodec::codecForName(
"ISO 8859-13");
1638 d->m_codec = QTextCodec::codecForName(
"ISO 8859-15");
1641 d->m_codec = QTextCodec::codecForName(
"UTF-8");
1644 d->m_codec = QTextCodec::codecForName(
"KOI8-R");
1647 d->m_codec = QTextCodec::codecForName(
"KOI8-U");
1650 d->m_codec = QTextCodec::codecForName(
"CP1251");
1653 d->m_codec = QTextCodec::codecForName(
"CP1255");
1659 kDebug(750) << __FILE__ <<
":" << __LINE__ <<
" Codec = " << (d->m_codec ? d->m_codec->name() :
"<default>");
1689 connect(
this, SIGNAL(
ready(
K3Spell*)),
this, SLOT(slotModalReady()) );
1700 #include "k3spell.moc"