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;
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)) );
1334 QString marker(
"_MARKER_" );
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()) );
1493 QPoint pt( x,y ), pt2;
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()
1550 connect(
this, SIGNAL(
done(QString)),
1551 this, SLOT(slotModalDone(QString)) );
1552 QObject::connect(
this, SIGNAL(
corrected(QString,QString,uint)),
1553 this, SLOT(slotSpellCheckerCorrected(QString,QString,uint)) );
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"
void setNextOpenMode(QIODevice::OpenMode mode)
QString i18n(const char *text)
void setUpDialog(bool reallyusedialogbox=true)
void ignoreall(const QString &originalword)
Emitted when the user pressed "Ignore All" in the dialog.
static bool determineASpellV6()
TransferJob * put(const KUrl &url, int permissions, JobFlags flags=DefaultFlags)
QStringList ignoreList() const
int client() const
Spell checker client,.
void setAutoDelete(bool _autoDelete)
Sets the auto-delete flag.
unsigned int lastlastline
static QWidget * modalWidgetHack
static void information(QWidget *parent, const QString &text, const QString &caption=QString(), const QString &dontShowAgainName=QString(), Options options=Notify)
int parseOneResponse(const QString &_buffer, QString &word, QStringList &sugg)
virtual bool checkWord(const QString &_buffer, bool usedialog=false)
Spellchecks a single word.
void replaceall(const QString &origword, const QString &replacement)
Emitted when the user pressed "ReplaceAll" in the dialog.
static QDebug kError(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
void setOutputChannelMode(OutputChannelMode mode)
A configuration class/dialog for K3Spell.
bool writePersonalDictionary()
int widthDlg() const
Returns the width of the dialog box.
static QDebug kDebug(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
void setIgnoreTitleCase(bool b)
Call setIgnoreTitleCase(true) to tell the spell-checker to ignore words with a 'title' case,...
virtual ~K3Spell()
The destructor instructs ISpell/ASpell to write out the personal dictionary and then terminates ISpel...
void setProgressResolution(unsigned int res)
Sets the resolution (in percent) of the progress() signals.
virtual void setCaption(const QString &caption)
bool modaldlg
Used for modalCheck.
QStringList::Iterator wlIt
spellStatus
Possible states of the spell checker.
virtual bool addPersonal(const QString &word)
Adds a word to the user's personal dictionary.
QString funnyWord(const QString &word)
spellStatus status() const
Returns the status of K3Spell.
QString intermediateBuffer() const
Returns the partially spellchecked buffer.
QString replacement() const
K3Spell(QWidget *parent, const QString &caption, QObject *receiver, const char *slot, K3SpellConfig *kcs=0, bool progressbar=true, bool modal=false)
Starts the spellchecker.
virtual void cleanUp()
Cleans up ISpell.
void done(const QString &buffer)
Emitted when check() is done.
void progress(unsigned int i)
Emitted during a check().
void dialog2(int dlgresult)
int dlgResult() const
Gets the result code of the dialog box.
int lastPosition() const
Returns the position (when using check()) or word number (when using checkList()) of the last word ch...
SpellerType
These are possible types of documents which the spell checker can check.
int heightDlg() const
Returns the height of the dialog box.
void ignoreword(const QString &originalword)
Emitted when the user pressed "Ignore" in the dialog.
void dialog(const QString &word, QStringList &sugg, const char *_slot)
void setIgnoreUpperWords(bool b)
Call setIgnoreUpperWords(true) to tell the spell-checker to ignore words that are completely uppercas...
void misspelling(const QString &originalword, const QStringList &suggestions, unsigned int pos)
Emitted whenever a misspelled word is found by check() or by checkWord().
void ready(K3Spell *)
Emitted after K3Spell has verified that ISpell/ASpell is running and working properly.
K3SpellConfig ksConfig() const
void death()
Emitted on terminal errors and after clean up.
static int modalCheck(QString &text)
void setIgnoreList(const QStringList &_ignorelist)
@sect Options setting routines.
void setReplaceAllList(const QStringList &_replaceAllList)
The _replaceAllList contains word you like that replace word.
QString replacement() const
void hide()
Hides the dialog box.
void addword(const QString &originalword)
Emitted when the user pressed "Add" in the dialog.
QStringList replaceAllList() const
QStringList suggestions() const
Returns list of suggested word replacements.
void corrected(const QString &originalword, const QString &newword, unsigned int pos)
Emitted after the "Replace" or "Replace All" buttons of the dialog was pressed, or if the word was co...
void init(const QString &_word, QStringList *_sugg)
Change the misspelled word and suggested replacements and enable the disabled buttons on the dialog b...
void initialize(QWidget *_parent, const QString &_caption, QObject *obj, const char *slot, K3SpellConfig *_ksc, bool _progressbar, bool _modal, SpellerType type)
virtual bool check(const QString &_buffer, bool usedialog=true)
Spellchecks a buffer of many words in plain text format.
void checkListReplaceCurrent()
void moveDlg(int x, int y)
Moves the dialog.
bool cleanFputsWord(const QString &s)
virtual bool checkList(QStringList *_wordlist, bool usedialog=true)
Spellchecks a list of words.
virtual bool ignore(const QString &word)
Tells ISpell/ASpell to ignore this word for the life of this K3Spell instance.
const QString dictionary() const
bool cleanFputs(const QString &s)