summaryrefslogtreecommitdiff
path: root/inputmethods/handwriting/qimpenmatch.cpp
Side-by-side diff
Diffstat (limited to 'inputmethods/handwriting/qimpenmatch.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--inputmethods/handwriting/qimpenmatch.cpp35
1 files changed, 18 insertions, 17 deletions
diff --git a/inputmethods/handwriting/qimpenmatch.cpp b/inputmethods/handwriting/qimpenmatch.cpp
index 0d3e25a..a0448b6 100644
--- a/inputmethods/handwriting/qimpenmatch.cpp
+++ b/inputmethods/handwriting/qimpenmatch.cpp
@@ -1,365 +1,366 @@
/**********************************************************************
** Copyright (C) 2000 Trolltech AS. All rights reserved.
**
** This file is part of Qtopia Environment.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/gpl/ for GPL licensing information.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/
#include "qimpenmatch.h"
#include <qpe/qdawg.h>
#include <qpe/global.h>
#include <qapplication.h>
#include <qtimer.h>
+#include <opie2/odebug.h>
#include <limits.h>
#define ERROR_THRESHOLD 200000
#define LOOKAHEAD_ERROR 2500
//#define DEBUG_QIMPEN
QIMPenMatch::QIMPenMatch( QObject *parent, const char *name )
: QObject( parent, name )
{
strokes.setAutoDelete( TRUE );
wordChars.setAutoDelete( TRUE );
wordMatches.setAutoDelete( TRUE );
multiTimer = new QTimer( this );
connect( multiTimer, SIGNAL(timeout()), this, SLOT(endMulti()) );
prevMatchChar = 0;
prevMatchError = INT_MAX;
charSet = 0;
multiCharSet = 0;
multiTimeout = 500;
canErase = FALSE;
doWordMatching = true;
}
QIMPenMatch::~QIMPenMatch()
{
}
void QIMPenMatch::setCharSet( QIMPenCharSet *cs )
{
charSet = cs;
}
void QIMPenMatch::beginStroke()
{
multiTimer->stop();
}
void QIMPenMatch::strokeEntered( QIMPenStroke *st )
{
#ifdef DEBUG_QIMPEN
- qDebug( "---------- new stroke -------------" );
+ odebug << "---------- new stroke -------------" << oendl;
#endif
strokes.append( new QIMPenStroke( *st ) );
QIMPenChar testChar;
QIMPenStrokeIterator it(strokes);
for ( ; it.current(); ++it ) {
testChar.addStroke( it.current() );
}
QIMPenCharMatchList ml;
if ( strokes.count() > 1 && multiCharSet ) {
#ifdef DEBUG_QIMPEN
- qDebug( "Matching against multi set" );
+ odebug << "Matching against multi set" << oendl;
#endif
ml = multiCharSet->match( &testChar );
} else {
#ifdef DEBUG_QIMPEN
- qDebug( "Matching against single set" );
+ odebug << "Matching against single set" << oendl;
#endif
ml = charSet->match( &testChar );
}
processMatches( ml );
}
void QIMPenMatch::processMatches( QIMPenCharMatchList &ml )
{
#ifdef DEBUG_QIMPEN
- qDebug( "Entering strokes.count() = %d", strokes.count() );
+ odebug << "Entering strokes.count() = " << strokes.count() << oendl;
#endif
QIMPenCharMatch candidate1 = { INT_MAX, 0 };
QIMPenCharMatch candidate2 = { INT_MAX, 0 };
QIMPenCharMatchList ml2;
if ( ml.count() ) {//&&
// ml.first().penChar->penStrokes().count() == strokes.count() ) {
candidate1 = ml.first();
#ifdef DEBUG_QIMPEN
- qDebug( QString("Candidate1 = %1").arg(QChar(candidate1.penChar->character())) );
+ odebug << "Candidate1 = " << candidate1.penChar->character() << oendl;
#endif
}
if ( strokes.count() > 1 ) {
// See if the last stroke can match a new character
QIMPenChar testChar;
QIMPenStroke *st = strokes.at(strokes.count()-1);
testChar.addStroke( st );
ml2 = charSet->match( &testChar );
if ( ml2.count() ) {
candidate2 = ml2.first();
#ifdef DEBUG_QIMPEN
- qDebug( QString("Candidate2 = %1").arg(QChar(candidate2.penChar->character())) );
+ odebug << "Candidate2 = " << candidate2.penChar->character() << oendl;
#endif
}
}
bool eraseLast = FALSE;
bool output = TRUE;
if ( candidate1.penChar && candidate2.penChar ) {
// Hmmm, a multi-stroke or a new character are both possible.
// Bias the multi-stroke case.
if ( QMAX(candidate2.error, prevMatchError)*3 < candidate1.error ) {
int i = strokes.count()-1;
while ( i-- ) {
strokes.removeFirst();
emit removeStroke();
}
prevMatchChar = candidate2.penChar;
prevMatchError = candidate2.error;
multiCharSet = charSet;
ml = ml2;
#ifdef DEBUG_QIMPEN
- qDebug( "** Using Candidate2" );
+ odebug << "** Using Candidate2" << oendl;
#endif
} else {
if ( (prevMatchChar->character() >> 16) != Qt::Key_Backspace &&
(prevMatchChar->character() >> 16) < QIMPenChar::ModeBase )
eraseLast = TRUE;
prevMatchChar = candidate1.penChar;
prevMatchError = candidate1.error;
#ifdef DEBUG_QIMPEN
- qDebug( "** Using Candidate1, with erase" );
+ odebug << "** Using Candidate1, with erase" << oendl;
#endif
}
} else if ( candidate1.penChar ) {
if ( strokes.count() != 1 )
eraseLast = TRUE;
else
multiCharSet = charSet;
prevMatchChar = candidate1.penChar;
prevMatchError = candidate1.error;
#ifdef DEBUG_QIMPEN
- qDebug( "** Using Candidate1" );
+ odebug << "** Using Candidate1" << oendl;
#endif
} else if ( candidate2.penChar ) {
int i = strokes.count()-1;
while ( i-- ) {
strokes.removeFirst();
emit removeStroke();
}
prevMatchChar = candidate2.penChar;
prevMatchError = candidate2.error;
multiCharSet = charSet;
ml = ml2;
#ifdef DEBUG_QIMPEN
- qDebug( "** Using Candidate2" );
+ odebug << "** Using Candidate2" << oendl;
#endif
} else {
if ( !ml.count() ) {
#ifdef DEBUG_QIMPEN
- qDebug( "** Failed" );
+ odebug << "** Failed" << oendl;
#endif
canErase = FALSE;
} else {
#ifdef DEBUG_QIMPEN
- qDebug( "Need more strokes" );
+ odebug << "Need more strokes" << oendl;
#endif
if ( strokes.count() == 1 )
canErase = FALSE;
multiCharSet = charSet;
}
output = FALSE;
emit noMatch();
}
if ( eraseLast && canErase ) {
#ifdef DEBUG_QIMPEN
- qDebug( "deleting last" );
+ odebug << "deleting last" << oendl;
#endif
emit erase();
wordChars.removeLast();
wordEntered.truncate( wordEntered.length() - 1 );
}
if ( output ) {
emit matchedCharacters( ml );
uint code = prevMatchChar->character() >> 16;
if ( code < QIMPenChar::ModeBase ) {
updateWordMatch( ml );
emit keypress( prevMatchChar->character() );
}
canErase = TRUE;
}
if ( strokes.count() )
multiTimer->start( multiTimeout, TRUE );
}
void QIMPenMatch::updateWordMatch( QIMPenCharMatchList &ml )
{
if ( !ml.count() || !doWordMatching )
return;
int ch = ml.first().penChar->character();
QChar qch( ch );
int code = ch >> 16;
if ( qch.isPunct() || qch.isSpace() ||
code == Qt::Key_Enter || code == Qt::Key_Return ||
code == Qt::Key_Tab || code == Qt::Key_Escape ) {
-// qDebug( "Word Matching: Clearing word" );
+// odebug << "Word Matching: Clearing word" << oendl;
wordChars.clear();
wordMatches.clear();
wordEntered = QString();
} else if ( code == Qt::Key_Backspace ) {
- //qDebug( "Word Matching: Handle backspace" );
+ //odebug << "Word Matching: Handle backspace" << oendl;
wordChars.removeLast();
wordEntered.truncate( wordEntered.length() - 1 );
matchWords();
} else {
QIMPenChar *matchCh;
wordChars.append( new QIMPenCharMatchList() );
wordEntered += ml.first().penChar->character();
QIMPenCharMatchList::Iterator it;
for ( it = ml.begin(); it != ml.end(); ++it ) {
matchCh = (*it).penChar;
if ( matchCh->penStrokes().count() == strokes.count() ) {
QChar ch(matchCh->character());
if ( !ch.isPunct() && !ch.isSpace() ) {
wordChars.last()->append( QIMPenCharMatch( (*it) ) );
}
}
}
matchWords();
}
if ( !wordMatches.count() || wordMatches.getFirst()->word != wordEntered )
wordMatches.prepend( new MatchWord( wordEntered, 0 ) );
emit matchedWords( wordMatches );
}
void QIMPenMatch::matchWords()
{
if ( wordEntered.length() > 0 ) {
// more leaniency if we don't have many matches
if ( badMatches < 200 )
errorThreshold += (200 - badMatches) * 100;
} else
errorThreshold = ERROR_THRESHOLD;
wordMatches.clear();
goodMatches = 0;
badMatches = 0;
if ( wordChars.count() > 0 ) {
maxGuess = (int)wordChars.count() * 2;
if ( maxGuess < 3 )
maxGuess = 3;
QString str;
scanDict( Global::fixedDawg().root(), 0, str, 0 );
/*
QListIterator<MatchWord> it( wordMatches);
for ( ; it.current(); ++it ) {
- qDebug( QString("Match word: %1").arg(it.current()->word) );
+ odebug << "Match word: " << it.current()->word << oendl;
}
*/
}
- //qDebug( "Possibles: Good %d, total %d", goodMatches, wordMatches.count() );
+ //odebug << "Possibles: Good " << goodMatches << ", total " << wordMatches.count() << oendl;
wordMatches.sort();
}
void QIMPenMatch::scanDict( const QDawg::Node* n, int ipos, const QString& str, int error )
{
if ( !n )
return;
if ( error / (ipos+1) > errorThreshold )
return;
while (n) {
if ( goodMatches > 20 )
break;
if ( ipos < (int)wordChars.count() ) {
int i;
QChar testCh = QChar(n->letter());
QIMPenCharMatchList::Iterator it;
for ( i = 0, it = wordChars.at(ipos)->begin();
it != wordChars.at(ipos)->end() && i < 8; ++it, i++ ) {
QChar ch( (*it).penChar->character() );
if ( ch == testCh || ( !ipos && ch.lower() == testCh.lower() ) ) {
int newerr = error + (*it).error;
if ( testCh.category() == QChar::Letter_Uppercase )
ch = testCh;
QString newstr( str + ch );
if ( n->isWord() && ipos == (int)wordChars.count() - 1 ) {
wordMatches.append( new MatchWord( newstr, newerr ) );
goodMatches++;
}
scanDict( n->jump(), ipos+1, newstr, newerr );
}
}
} else if ( badMatches < 200 && ipos < maxGuess ) {
int d = ipos - wordChars.count();
int newerr = error + ERROR_THRESHOLD + LOOKAHEAD_ERROR*d;
QString newstr( str + n->letter() );
if ( n->isWord() ) {
wordMatches.append( new MatchWord( newstr, newerr ) );
badMatches++;
}
scanDict( n->jump(), ipos+1, newstr, newerr );
}
n = n->next();
}
}
void QIMPenMatch::backspace()
{
wordChars.removeLast();
wordEntered.truncate( wordEntered.length() - 1 );
matchWords();
if ( !wordMatches.count() || wordMatches.getFirst()->word != wordEntered )
wordMatches.prepend( new MatchWord( wordEntered, 0 ) );
emit matchedWords( wordMatches );
if ( wordEntered.length() )
canErase = TRUE;
}
void QIMPenMatch::endMulti()
{
int i = strokes.count();
while ( i-- )
emit removeStroke();
strokes.clear();
multiCharSet = 0;
}
void QIMPenMatch::resetState()
{
if ( !wordEntered.isEmpty() ) {
wordChars.clear();
wordMatches.clear();
wordEntered = QString();
emit matchedWords( wordMatches );
canErase = FALSE;
}
}