summaryrefslogtreecommitdiff
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--inputmethods/handwriting/qimpenchar.cpp20
1 files changed, 17 insertions, 3 deletions
diff --git a/inputmethods/handwriting/qimpenchar.cpp b/inputmethods/handwriting/qimpenchar.cpp
index b83b2a4..96a0502 100644
--- a/inputmethods/handwriting/qimpenchar.cpp
+++ b/inputmethods/handwriting/qimpenchar.cpp
@@ -153,360 +153,374 @@ int QIMPenChar::match( QIMPenChar *pen )
153 err = it1.current()->match( it2.current() ); 153 err = it1.current()->match( it2.current() );
154 if ( err > maxErr ) 154 if ( err > maxErr )
155 maxErr = err; 155 maxErr = err;
156 ++it1; 156 ++it1;
157 ++it2; 157 ++it2;
158 while ( err < 400000 && it1.current() && it2.current() ) { 158 while ( err < 400000 && it1.current() && it2.current() ) {
159 QPoint p1 = it1.current()->boundingRect().center() - 159 QPoint p1 = it1.current()->boundingRect().center() -
160 strokes.getFirst()->boundingRect().center(); 160 strokes.getFirst()->boundingRect().center();
161 QPoint p2 = it2.current()->boundingRect().center() - 161 QPoint p2 = it2.current()->boundingRect().center() -
162 pen->strokes.getFirst()->boundingRect().center(); 162 pen->strokes.getFirst()->boundingRect().center();
163 int xdiff = QABS( p1.x() - p2.x() ) - 6; 163 int xdiff = QABS( p1.x() - p2.x() ) - 6;
164 int ydiff = QABS( p1.y() - p2.y() ) - 5; 164 int ydiff = QABS( p1.y() - p2.y() ) - 5;
165 if ( xdiff < 0 ) 165 if ( xdiff < 0 )
166 xdiff = 0; 166 xdiff = 0;
167 if ( ydiff < 0 ) 167 if ( ydiff < 0 )
168 ydiff = 0; 168 ydiff = 0;
169 if ( xdiff > 10 || ydiff > 10 ) { // not a chance 169 if ( xdiff > 10 || ydiff > 10 ) { // not a chance
170#ifdef DEBUG_QIMPEN 170#ifdef DEBUG_QIMPEN
171 odebug << "char " << pen->ch <<", stroke starting pt diff excessive" << oendl; 171 odebug << "char " << pen->ch <<", stroke starting pt diff excessive" << oendl;
172#endif 172#endif
173 return INT_MAX; 173 return INT_MAX;
174 } 174 }
175 diff += xdiff*xdiff + ydiff*ydiff; 175 diff += xdiff*xdiff + ydiff*ydiff;
176 err = it1.current()->match( it2.current() ); 176 err = it1.current()->match( it2.current() );
177 if ( err > maxErr ) 177 if ( err > maxErr )
178 maxErr = err; 178 maxErr = err;
179 ++it1; 179 ++it1;
180 ++it2; 180 ++it2;
181 } 181 }
182 182
183 maxErr += diff * diff * 6; // magic weighting :) 183 maxErr += diff * diff * 6; // magic weighting :)
184 184
185#ifdef DEBUG_QIMPEN 185#ifdef DEBUG_QIMPEN
186 odebug << "char: " << pen->ch << ", maxErr " << maxErr << ", diff " << diff << ", " << strokes.count() << oendl; 186 odebug << "char: " << pen->ch << ", maxErr " << maxErr << ", diff " << diff << ", " << strokes.count() << oendl;
187#endif 187#endif
188 return maxErr; 188 return maxErr;
189} 189}
190 190
191/*! 191/*!
192 Return the bounding rect of this character. It may have sides with 192 Return the bounding rect of this character. It may have sides with
193 negative coords since its origin is where the user started drawing 193 negative coords since its origin is where the user started drawing
194 the character. 194 the character.
195 */ 195 */
196QRect QIMPenChar::boundingRect() 196QRect QIMPenChar::boundingRect()
197{ 197{
198 QRect br; 198 QRect br;
199 QIMPenStroke *st = strokes.first(); 199 QIMPenStroke *st = strokes.first();
200 while ( st ) { 200 while ( st ) {
201 br |= st->boundingRect(); 201 br |= st->boundingRect();
202 st = strokes.next(); 202 st = strokes.next();
203 } 203 }
204 204
205 return br; 205 return br;
206} 206}
207 207
208 208
209/*! 209/*!
210 Write the character's data to the stream. 210 Write the character's data to the stream.
211 */ 211 */
212QDataStream &operator<< (QDataStream &s, const QIMPenChar &ws) 212QDataStream &operator<< (QDataStream &s, const QIMPenChar &ws)
213{ 213{
214 s << ws.ch; 214 s << ws.ch;
215 s << ws.flags; 215 s << ws.flags;
216 if ( ws.flags & QIMPenChar::Data ) 216 if ( ws.flags & QIMPenChar::Data )
217 s << ws.d; 217 s << ws.d;
218 s << ws.strokes.count(); 218 s << ws.strokes.count();
219 QIMPenStrokeIterator it( ws.strokes ); 219 QIMPenStrokeIterator it( ws.strokes );
220 while ( it.current() ) { 220 while ( it.current() ) {
221 s << *it.current(); 221 s << *it.current();
222 ++it; 222 ++it;
223 } 223 }
224 224
225 return s; 225 return s;
226} 226}
227 227
228/*! 228/*!
229 Read the character's data from the stream. 229 Read the character's data from the stream.
230 */ 230 */
231QDataStream &operator>> (QDataStream &s, QIMPenChar &ws) 231QDataStream &operator>> (QDataStream &s, QIMPenChar &ws)
232{ 232{
233 s >> ws.ch; 233 s >> ws.ch;
234 s >> ws.flags; 234 s >> ws.flags;
235 if ( ws.flags & QIMPenChar::Data ) 235 if ( ws.flags & QIMPenChar::Data )
236 s >> ws.d; 236 s >> ws.d;
237 unsigned size; 237 unsigned size;
238 s >> size; 238 s >> size;
239 for ( unsigned i = 0; i < size; i++ ) { 239 for ( unsigned i = 0; i < size; i++ ) {
240 QIMPenStroke *st = new QIMPenStroke(); 240 QIMPenStroke *st = new QIMPenStroke();
241 s >> *st; 241 s >> *st;
242 ws.strokes.append( st ); 242 ws.strokes.append( st );
243 } 243 }
244 244
245 return s; 245 return s;
246} 246}
247 247
248//=========================================================================== 248//===========================================================================
249 249
250bool QIMPenCharMatch::operator>( const QIMPenCharMatch &m ) 250bool QIMPenCharMatch::operator>( const QIMPenCharMatch &m )
251{ 251{
252 return error > m.error; 252 return error > m.error;
253} 253}
254 254
255bool QIMPenCharMatch::operator<( const QIMPenCharMatch &m ) 255bool QIMPenCharMatch::operator<( const QIMPenCharMatch &m )
256{ 256{
257 return error < m.error; 257 return error < m.error;
258} 258}
259 259
260bool QIMPenCharMatch::operator<=( const QIMPenCharMatch &m ) 260bool QIMPenCharMatch::operator<=( const QIMPenCharMatch &m )
261{ 261{
262 return error <= m.error; 262 return error <= m.error;
263} 263}
264 264
265//=========================================================================== 265//===========================================================================
266 266
267/*! 267/*!
268 \class QIMPenCharSet qimpenchar.h 268 \class QIMPenCharSet qimpenchar.h
269 269
270 Maintains a set of related characters. 270 Maintains a set of related characters.
271 */ 271 */
272 272
273QIMPenCharSet::QIMPenCharSet() 273QIMPenCharSet::QIMPenCharSet()
274{ 274{
275 chars.setAutoDelete( TRUE ); 275 chars.setAutoDelete( TRUE );
276 desc = "Unnamed"; 276 desc = "Unnamed";
277 csTitle = "abc"; 277 csTitle = "abc";
278 csType = Unknown; 278 csType = Unknown;
279 maxStrokes = 0; 279 maxStrokes = 0;
280} 280}
281 281
282/*! 282/*!
283 Construct and load a characters set from file \a fn. 283 Construct and load a characters set from file \a fn.
284 */ 284 */
285QIMPenCharSet::QIMPenCharSet( const QString &fn ) 285QIMPenCharSet::QIMPenCharSet( const QString &fn )
286{ 286{
287 chars.setAutoDelete( TRUE ); 287 chars.setAutoDelete( TRUE );
288 desc = "Unnamed"; 288 desc = "Unnamed";
289 csTitle = "abc"; 289 csTitle = "abc";
290 csType = Unknown; 290 csType = Unknown;
291 maxStrokes = 0; 291 maxStrokes = 0;
292 load( fn, System ); 292 load( fn, System );
293} 293}
294 294
295const QString &QIMPenCharSet::filename( Domain d ) const 295const QString &QIMPenCharSet::filename( Domain d ) const
296{ 296{
297 if ( d == System ) 297 if ( d == System )
298 return sysFilename; 298 return sysFilename;
299 else 299 else
300 return userFilename; 300 return userFilename;
301} 301}
302 302
303void QIMPenCharSet::setFilename( const QString &fn, Domain d ) 303void QIMPenCharSet::setFilename( const QString &fn, Domain d )
304{ 304{
305 if ( d == System ) 305 if ( d == System )
306 sysFilename = fn; 306 sysFilename = fn;
307 else if ( d == User ) 307 else if ( d == User )
308 userFilename = fn; 308 userFilename = fn;
309} 309}
310 310
311/*! 311/*!
312 Load a character set from file \a fn. 312 Load a character set from file \a fn.
313 */ 313 */
314bool QIMPenCharSet::load( const QString &fn, Domain d ) 314bool QIMPenCharSet::load( const QString &fn, Domain d )
315{ 315{
316 setFilename( fn, d ); 316 setFilename( fn, d );
317 317
318 bool ok = FALSE; 318 bool ok = FALSE;
319 QFile file( fn ); 319 QFile file( fn );
320 if ( file.open( IO_ReadOnly ) ) { 320 if ( file.open( IO_ReadOnly ) ) {
321 QDataStream ds( &file ); 321 QDataStream ds( &file );
322 QString version; 322 QString version;
323 ds >> version; 323 ds >> version;
324 ds >> csTitle; 324 ds >> csTitle;
325 ds >> desc; 325 ds >> desc;
326 int major = version.mid( 4, 1 ).toInt(); 326 int major = version.mid( 4, 1 ).toInt();
327 int minor = version.mid( 6 ).toInt(); 327 int minor = version.mid( 6 ).toInt();
328 if ( major >= 1 && minor > 0 ) { 328 if ( major >= 1 && minor > 0 ) {
329 ds >> (Q_INT8 &)csType; 329 ds >> (Q_INT8 &)csType;
330 } else { 330 } else {
331 if ( csTitle == "abc" ) 331 if ( csTitle == "abc" )
332 csType = Lower; 332 csType = Lower;
333 else if ( csTitle == "ABC" ) 333 else if ( csTitle == "ABC" )
334 csType = Upper; 334 csType = Upper;
335 else if ( csTitle == "123" ) 335 else if ( csTitle == "123" )
336 csType = Numeric; 336 csType = Numeric;
337 else if ( fn == "Combining" ) 337 else if ( fn == "Combining" )
338 csType = Combining; 338 csType = Combining;
339 } 339 }
340 while ( !ds.atEnd() ) { 340 while ( !ds.atEnd() ) {
341 QIMPenChar *pc = new QIMPenChar; 341 QIMPenChar *pc = new QIMPenChar;
342 ds >> *pc; 342 ds >> *pc;
343 if ( d == User ) 343 if ( d == User )
344 markDeleted( pc->character() ); // override system 344 markDeleted( pc->character() ); // override system
345 addChar( pc ); 345 if ( !pc->testFlag( QIMPenChar::Deleted ) )
346 addChar( pc );
346 } 347 }
347 if ( file.status() == IO_Ok ) 348 if ( file.status() == IO_Ok )
348 ok = TRUE; 349 ok = TRUE;
349 } 350 }
350 setHidden ( false ); 351 setHidden ( false );
351 return ok; 352 return ok;
352} 353}
353 354
354/*! 355/*!
355 Save this character set. 356 Save this character set.
356 */ 357 */
357bool QIMPenCharSet::save( Domain d ) 358bool QIMPenCharSet::save( Domain d )
358{ 359{
359 if ( filename( d ).isEmpty() ) 360 if ( filename( d ).isEmpty() )
360 return FALSE; 361 return FALSE;
361 362
362 if ( hidden() ) 363 if ( hidden() )
363 return TRUE; 364 return TRUE;
364 365
365 bool ok = FALSE; 366 bool ok = FALSE;
366 367
367 QString fn = filename( d ); 368 QString fn = filename( d );
368 QString tmpFn = fn + ".new"; 369 QString tmpFn = fn + ".new";
369 QFile file( tmpFn ); 370 QFile file( tmpFn );
370 if ( file.open( IO_WriteOnly|IO_Raw ) ) { 371 if ( file.open( IO_WriteOnly|IO_Raw ) ) {
371 QByteArray buf; 372 QByteArray buf;
372 QDataStream ds( buf, IO_WriteOnly ); 373 QDataStream ds( buf, IO_WriteOnly );
373 ds << QString( "QPT 1.1" ); 374 ds << QString( "QPT 1.1" );
374 ds << csTitle; 375 ds << csTitle;
375 ds << desc; 376 ds << desc;
376 ds << (Q_INT8)csType; 377 ds << (Q_INT8)csType;
377 QIMPenCharIterator ci( chars ); 378 QIMPenCharIterator ci( chars );
378 for ( ; ci.current(); ++ci ) { 379 for ( ; ci.current(); ++ci ) {
379 QIMPenChar *pc = ci.current(); 380 QIMPenChar *pc = ci.current();
380 if ( ( ( (d == System) && pc->testFlag( QIMPenChar::System ) ) || 381/*
381 ( (d == User) && !pc->testFlag( QIMPenChar::System ) ) ) && 382 * If the Domain is System and the Char is marked System - OR
383 * the domain is User, the Char is User and it's not deleted - OR
384 * the domain is User, the Char is System and it is deleted - AND
385 * the character is not an automated Combined Character
386 *
387 * This is required to ensure that we don't save user defined chars that have been deleted, but
388 * we *DO* save System chars that have been deleted. There is still the issue of deleted combined
389 * chars but I'm not sure how to tackle that yet
390 *
391 */
392
393 if ( ( ( (d == System) && pc->testFlag( QIMPenChar::System ) ) ||
394 ( (d == User) && !pc->testFlag( QIMPenChar::System ) && !pc->testFlag( QIMPenChar::Deleted ) ) ||
395 ( (d == User) && pc->testFlag( QIMPenChar::System ) && pc->testFlag( QIMPenChar::Deleted ) ) ) &&
382 ( !pc->testFlag (QIMPenChar::Combined ) ) ) { 396 ( !pc->testFlag (QIMPenChar::Combined ) ) ) {
383 ds << *pc; 397 ds << *pc;
384 } 398 }
385 } 399 }
386 400
387 file.writeBlock( buf ); 401 file.writeBlock( buf );
388 file.close(); 402 file.close();
389 if ( file.status() == IO_Ok ) 403 if ( file.status() == IO_Ok )
390 ok = TRUE; 404 ok = TRUE;
391 } 405 }
392 406
393 if ( ok ) { 407 if ( ok ) {
394 if ( ::rename( tmpFn.latin1(), fn.latin1() ) < 0 ) { 408 if ( ::rename( tmpFn.latin1(), fn.latin1() ) < 0 ) {
395 owarn << "problem renaming file " <<tmpFn.latin1() << " to "<< fn.latin1() 409 owarn << "problem renaming file " <<tmpFn.latin1() << " to "<< fn.latin1()
396 << ", errno: " << errno << oendl; 410 << ", errno: " << errno << oendl;
397 // remove the tmp file, otherwise, it will just lay around... 411 // remove the tmp file, otherwise, it will just lay around...
398 QFile::remove( tmpFn.latin1() ); 412 QFile::remove( tmpFn.latin1() );
399 ok = FALSE; 413 ok = FALSE;
400 } 414 }
401 } 415 }
402 416
403 return ok; 417 return ok;
404} 418}
405 419
406QIMPenChar *QIMPenCharSet::at( int i ) 420QIMPenChar *QIMPenCharSet::at( int i )
407{ 421{
408 return chars.at(i); 422 return chars.at(i);
409} 423}
410 424
411void QIMPenCharSet::markDeleted( uint ch ) 425void QIMPenCharSet::markDeleted( uint ch )
412{ 426{
413 QIMPenCharIterator ci( chars ); 427 QIMPenCharIterator ci( chars );
414 for ( ; ci.current(); ++ci ) { 428 for ( ; ci.current(); ++ci ) {
415 QIMPenChar *pc = ci.current(); 429 QIMPenChar *pc = ci.current();
416 if ( pc->character() == ch && pc->testFlag( QIMPenChar::System ) ) 430 if ( pc->character() == ch && pc->testFlag( QIMPenChar::System ) )
417 pc->setFlag( QIMPenChar::Deleted ); 431 pc->setFlag( QIMPenChar::Deleted );
418 } 432 }
419} 433}
420 434
421/*! 435/*!
422 Find the best matches for \a ch in this character set. 436 Find the best matches for \a ch in this character set.
423 */ 437 */
424QIMPenCharMatchList QIMPenCharSet::match( QIMPenChar *ch ) 438QIMPenCharMatchList QIMPenCharSet::match( QIMPenChar *ch )
425{ 439{
426 QIMPenCharMatchList matches; 440 QIMPenCharMatchList matches;
427 441
428 QIMPenCharIterator ci( chars ); 442 QIMPenCharIterator ci( chars );
429 for ( ; ci.current(); ++ci ) { 443 for ( ; ci.current(); ++ci ) {
430 QIMPenChar *tmplChar = ci.current(); 444 QIMPenChar *tmplChar = ci.current();
431 if ( tmplChar->testFlag( QIMPenChar::Deleted ) ) { 445 if ( tmplChar->testFlag( QIMPenChar::Deleted ) ) {
432 continue; 446 continue;
433 } 447 }
434 int err; 448 int err;
435 if ( ch->penStrokes().count() <= tmplChar->penStrokes().count() ) { 449 if ( ch->penStrokes().count() <= tmplChar->penStrokes().count() ) {
436 err = ch->match( tmplChar ); 450 err = ch->match( tmplChar );
437 if ( err <= QIMPEN_MATCH_THRESHOLD ) { 451 if ( err <= QIMPEN_MATCH_THRESHOLD ) {
438 if (tmplChar->penStrokes().count() != ch->penStrokes().count()) 452 if (tmplChar->penStrokes().count() != ch->penStrokes().count())
439 err = QMIN(err*3, QIMPEN_MATCH_THRESHOLD); 453 err = QMIN(err*3, QIMPEN_MATCH_THRESHOLD);
440 QIMPenCharMatchList::Iterator it; 454 QIMPenCharMatchList::Iterator it;
441 for ( it = matches.begin(); it != matches.end(); ++it ) { 455 for ( it = matches.begin(); it != matches.end(); ++it ) {
442 if ( (*it).penChar->character() == tmplChar->character() && 456 if ( (*it).penChar->character() == tmplChar->character() &&
443 (*it).penChar->penStrokes().count() == tmplChar->penStrokes().count() ) { 457 (*it).penChar->penStrokes().count() == tmplChar->penStrokes().count() ) {
444 if ( (*it).error > err ) 458 if ( (*it).error > err )
445 (*it).error = err; 459 (*it).error = err;
446 break; 460 break;
447 } 461 }
448 } 462 }
449 if ( it == matches.end() ) { 463 if ( it == matches.end() ) {
450 QIMPenCharMatch m; 464 QIMPenCharMatch m;
451 m.error = err; 465 m.error = err;
452 m.penChar = tmplChar; 466 m.penChar = tmplChar;
453 matches.append( m ); 467 matches.append( m );
454 } 468 }
455 } 469 }
456 } 470 }
457 } 471 }
458 qHeapSort( matches ); 472 qHeapSort( matches );
459 /* 473 /*
460 QIMPenCharMatchList::Iterator it; 474 QIMPenCharMatchList::Iterator it;
461 for ( it = matches.begin(); it != matches.end(); ++it ) { 475 for ( it = matches.begin(); it != matches.end(); ++it ) {
462 476
463 odebug << "Match: \'" << (*it).penChar->character() "\', error " << (*it).error ", strokes " <<(*it).penChar->penStrokes().count() << oendl; 477 odebug << "Match: \'" << (*it).penChar->character() "\', error " << (*it).error ", strokes " <<(*it).penChar->penStrokes().count() << oendl;
464 } 478 }
465 */ 479 */
466 return matches; 480 return matches;
467} 481}
468 482
469/*! 483/*!
470 Add a character \a ch to this set. 484 Add a character \a ch to this set.
471 QIMPenCharSet will delete this character when it is no longer needed. 485 QIMPenCharSet will delete this character when it is no longer needed.
472 */ 486 */
473void QIMPenCharSet::addChar( QIMPenChar *ch ) 487void QIMPenCharSet::addChar( QIMPenChar *ch )
474{ 488{
475 if ( ch->penStrokes().count() > maxStrokes ) 489 if ( ch->penStrokes().count() > maxStrokes )
476 maxStrokes = ch->penStrokes().count(); 490 maxStrokes = ch->penStrokes().count();
477 chars.append( ch ); 491 chars.append( ch );
478} 492}
479 493
480/*! 494/*!
481 Remove a character by reference \a ch from this set. 495 Remove a character by reference \a ch from this set.
482 QIMPenCharSet will delete this character. 496 QIMPenCharSet will delete this character.
483 */ 497 */
484void QIMPenCharSet::removeChar( QIMPenChar *ch ) 498void QIMPenCharSet::removeChar( QIMPenChar *ch )
485{ 499{
486 chars.remove( ch ); 500 chars.remove( ch );
487} 501}
488 502
489/*! 503/*!
490 Move the character up the list of characters. 504 Move the character up the list of characters.
491 */ 505 */
492void QIMPenCharSet::up( QIMPenChar *ch ) 506void QIMPenCharSet::up( QIMPenChar *ch )
493{ 507{
494 int idx = chars.findRef( ch ); 508 int idx = chars.findRef( ch );
495 if ( idx > 0 ) { 509 if ( idx > 0 ) {
496 chars.take(); 510 chars.take();
497 chars.insert( idx - 1, ch ); 511 chars.insert( idx - 1, ch );
498 } 512 }
499} 513}
500 514
501/*! 515/*!
502 Move the character down the list of characters. 516 Move the character down the list of characters.
503 */ 517 */
504void QIMPenCharSet::down( QIMPenChar *ch ) 518void QIMPenCharSet::down( QIMPenChar *ch )
505{ 519{
506 int idx = chars.findRef( ch ); 520 int idx = chars.findRef( ch );
507 if ( idx >= 0 && idx < (int)chars.count() - 1 ) { 521 if ( idx >= 0 && idx < (int)chars.count() - 1 ) {
508 chars.take(); 522 chars.take();
509 chars.insert( idx + 1, ch ); 523 chars.insert( idx + 1, ch );
510 } 524 }
511} 525}
512 526