-rw-r--r-- | inputmethods/handwriting/qimpenchar.cpp | 20 |
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 | |||
@@ -1,512 +1,526 @@ | |||
1 | /********************************************************************** | 1 | /********************************************************************** |
2 | ** Copyright (C) 2000 Trolltech AS. All rights reserved. | 2 | ** Copyright (C) 2000 Trolltech AS. All rights reserved. |
3 | ** | 3 | ** |
4 | ** This file is part of Qtopia Environment. | 4 | ** This file is part of Qtopia Environment. |
5 | ** | 5 | ** |
6 | ** This file may be distributed and/or modified under the terms of the | 6 | ** This file may be distributed and/or modified under the terms of the |
7 | ** GNU General Public License version 2 as published by the Free Software | 7 | ** GNU General Public License version 2 as published by the Free Software |
8 | ** Foundation and appearing in the file LICENSE.GPL included in the | 8 | ** Foundation and appearing in the file LICENSE.GPL included in the |
9 | ** packaging of this file. | 9 | ** packaging of this file. |
10 | ** | 10 | ** |
11 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | 11 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE |
12 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | 12 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
13 | ** | 13 | ** |
14 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. | 14 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. |
15 | ** | 15 | ** |
16 | ** Contact info@trolltech.com if any conditions of this licensing are | 16 | ** Contact info@trolltech.com if any conditions of this licensing are |
17 | ** not clear to you. | 17 | ** not clear to you. |
18 | ** | 18 | ** |
19 | **********************************************************************/ | 19 | **********************************************************************/ |
20 | 20 | ||
21 | #include <qfile.h> | 21 | #include <qfile.h> |
22 | #include <qtl.h> | 22 | #include <qtl.h> |
23 | #include <math.h> | 23 | #include <math.h> |
24 | #include <limits.h> | 24 | #include <limits.h> |
25 | #include <errno.h> | 25 | #include <errno.h> |
26 | #include <qdatastream.h> | 26 | #include <qdatastream.h> |
27 | #include "qimpencombining.h" | 27 | #include "qimpencombining.h" |
28 | #include "qimpenchar.h" | 28 | #include "qimpenchar.h" |
29 | #include "opie2/odebug.h" | 29 | #include "opie2/odebug.h" |
30 | 30 | ||
31 | #define QIMPEN_MATCH_THRESHOLD 200000 | 31 | #define QIMPEN_MATCH_THRESHOLD 200000 |
32 | 32 | ||
33 | const QIMPenSpecialKeys qimpen_specialKeys[] = { | 33 | const QIMPenSpecialKeys qimpen_specialKeys[] = { |
34 | { Qt::Key_Escape, "[Esc]" }, | 34 | { Qt::Key_Escape, "[Esc]" }, |
35 | { Qt::Key_Tab, "[Tab]" }, | 35 | { Qt::Key_Tab, "[Tab]" }, |
36 | { Qt::Key_Backspace,"[BackSpace]" }, | 36 | { Qt::Key_Backspace,"[BackSpace]" }, |
37 | { Qt::Key_Return, "[Return]" }, | 37 | { Qt::Key_Return, "[Return]" }, |
38 | { QIMPenChar::Caps, "[Uppercase]" }, | 38 | { QIMPenChar::Caps, "[Uppercase]" }, |
39 | { QIMPenChar::CapsLock,"[Caps Lock]" }, | 39 | { QIMPenChar::CapsLock,"[Caps Lock]" }, |
40 | { QIMPenChar::Shortcut,"[Shortcut]" }, | 40 | { QIMPenChar::Shortcut,"[Shortcut]" }, |
41 | { QIMPenChar::Punctuation, "[Punctuation]" }, | 41 | { QIMPenChar::Punctuation, "[Punctuation]" }, |
42 | { QIMPenChar::Symbol,"[Symbol]" }, | 42 | { QIMPenChar::Symbol,"[Symbol]" }, |
43 | { QIMPenChar::Extended,"[Extended]" }, | 43 | { QIMPenChar::Extended,"[Extended]" }, |
44 | { Qt::Key_unknown, 0 } }; | 44 | { Qt::Key_unknown, 0 } }; |
45 | 45 | ||
46 | 46 | ||
47 | /*! | 47 | /*! |
48 | \class QIMPenChar qimpenchar.h | 48 | \class QIMPenChar qimpenchar.h |
49 | 49 | ||
50 | Handles a single character. Can calculate closeness of match to | 50 | Handles a single character. Can calculate closeness of match to |
51 | another character. | 51 | another character. |
52 | */ | 52 | */ |
53 | 53 | ||
54 | QIMPenChar::QIMPenChar() | 54 | QIMPenChar::QIMPenChar() |
55 | { | 55 | { |
56 | flags = 0; | 56 | flags = 0; |
57 | strokes.setAutoDelete( TRUE ); | 57 | strokes.setAutoDelete( TRUE ); |
58 | } | 58 | } |
59 | 59 | ||
60 | QIMPenChar::QIMPenChar( const QIMPenChar &chr ) | 60 | QIMPenChar::QIMPenChar( const QIMPenChar &chr ) |
61 | { | 61 | { |
62 | strokes.setAutoDelete( TRUE ); | 62 | strokes.setAutoDelete( TRUE ); |
63 | ch = chr.ch; | 63 | ch = chr.ch; |
64 | flags = chr.flags; | 64 | flags = chr.flags; |
65 | d = chr.d; | 65 | d = chr.d; |
66 | QIMPenStrokeIterator it( chr.strokes ); | 66 | QIMPenStrokeIterator it( chr.strokes ); |
67 | while ( it.current() ) { | 67 | while ( it.current() ) { |
68 | strokes.append( new QIMPenStroke( *it.current() ) ); | 68 | strokes.append( new QIMPenStroke( *it.current() ) ); |
69 | ++it; | 69 | ++it; |
70 | } | 70 | } |
71 | } | 71 | } |
72 | 72 | ||
73 | QIMPenChar &QIMPenChar::operator=( const QIMPenChar &chr ) | 73 | QIMPenChar &QIMPenChar::operator=( const QIMPenChar &chr ) |
74 | { | 74 | { |
75 | strokes.clear(); | 75 | strokes.clear(); |
76 | ch = chr.ch; | 76 | ch = chr.ch; |
77 | flags = chr.flags; | 77 | flags = chr.flags; |
78 | d = chr.d; | 78 | d = chr.d; |
79 | QIMPenStrokeIterator it( chr.strokes ); | 79 | QIMPenStrokeIterator it( chr.strokes ); |
80 | while ( it.current() ) { | 80 | while ( it.current() ) { |
81 | strokes.append( new QIMPenStroke( *it.current() ) ); | 81 | strokes.append( new QIMPenStroke( *it.current() ) ); |
82 | ++it; | 82 | ++it; |
83 | } | 83 | } |
84 | 84 | ||
85 | return *this; | 85 | return *this; |
86 | } | 86 | } |
87 | 87 | ||
88 | QString QIMPenChar::name() const | 88 | QString QIMPenChar::name() const |
89 | { | 89 | { |
90 | QString n; | 90 | QString n; |
91 | 91 | ||
92 | if ( (ch & 0x0000FFFF) == 0 ) { | 92 | if ( (ch & 0x0000FFFF) == 0 ) { |
93 | int code = ch >> 16; | 93 | int code = ch >> 16; |
94 | for ( int i = 0; qimpen_specialKeys[i].code != Qt::Key_unknown; i++ ) { | 94 | for ( int i = 0; qimpen_specialKeys[i].code != Qt::Key_unknown; i++ ) { |
95 | if ( qimpen_specialKeys[i].code == code ) { | 95 | if ( qimpen_specialKeys[i].code == code ) { |
96 | n = qimpen_specialKeys[i].name; | 96 | n = qimpen_specialKeys[i].name; |
97 | break; | 97 | break; |
98 | } | 98 | } |
99 | } | 99 | } |
100 | } else { | 100 | } else { |
101 | n = QChar( ch & 0x0000FFFF ); | 101 | n = QChar( ch & 0x0000FFFF ); |
102 | } | 102 | } |
103 | 103 | ||
104 | return n; | 104 | return n; |
105 | } | 105 | } |
106 | 106 | ||
107 | void QIMPenChar::clear() | 107 | void QIMPenChar::clear() |
108 | { | 108 | { |
109 | ch = 0; | 109 | ch = 0; |
110 | flags = 0; | 110 | flags = 0; |
111 | d = QString::null; | 111 | d = QString::null; |
112 | strokes.clear(); | 112 | strokes.clear(); |
113 | } | 113 | } |
114 | 114 | ||
115 | unsigned int QIMPenChar::strokeLength( int s ) const | 115 | unsigned int QIMPenChar::strokeLength( int s ) const |
116 | { | 116 | { |
117 | QIMPenStrokeIterator it( strokes ); | 117 | QIMPenStrokeIterator it( strokes ); |
118 | while ( it.current() && s ) { | 118 | while ( it.current() && s ) { |
119 | ++it; | 119 | ++it; |
120 | --s; | 120 | --s; |
121 | } | 121 | } |
122 | 122 | ||
123 | if ( it.current() ) | 123 | if ( it.current() ) |
124 | return it.current()->length(); | 124 | return it.current()->length(); |
125 | 125 | ||
126 | return 0; | 126 | return 0; |
127 | } | 127 | } |
128 | 128 | ||
129 | /*! | 129 | /*! |
130 | Add a stroke to the character | 130 | Add a stroke to the character |
131 | */ | 131 | */ |
132 | void QIMPenChar::addStroke( QIMPenStroke *st ) | 132 | void QIMPenChar::addStroke( QIMPenStroke *st ) |
133 | { | 133 | { |
134 | QIMPenStroke *stroke = new QIMPenStroke( *st ); | 134 | QIMPenStroke *stroke = new QIMPenStroke( *st ); |
135 | strokes.append( stroke ); | 135 | strokes.append( stroke ); |
136 | } | 136 | } |
137 | 137 | ||
138 | /*! | 138 | /*! |
139 | Return an indicator of the closeness of this character to \a pen. | 139 | Return an indicator of the closeness of this character to \a pen. |
140 | Lower value is better. | 140 | Lower value is better. |
141 | */ | 141 | */ |
142 | int QIMPenChar::match( QIMPenChar *pen ) | 142 | int QIMPenChar::match( QIMPenChar *pen ) |
143 | { | 143 | { |
144 | /* | 144 | /* |
145 | if ( strokes.count() > pen->strokes.count() ) | 145 | if ( strokes.count() > pen->strokes.count() ) |
146 | return INT_MAX; | 146 | return INT_MAX; |
147 | */ | 147 | */ |
148 | int err = 0; | 148 | int err = 0; |
149 | int maxErr = 0; | 149 | int maxErr = 0; |
150 | int diff = 0; | 150 | int diff = 0; |
151 | QIMPenStrokeIterator it1( strokes ); | 151 | QIMPenStrokeIterator it1( strokes ); |
152 | QIMPenStrokeIterator it2( pen->strokes ); | 152 | QIMPenStrokeIterator it2( pen->strokes ); |
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 | */ |
196 | QRect QIMPenChar::boundingRect() | 196 | QRect 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 | */ |
212 | QDataStream &operator<< (QDataStream &s, const QIMPenChar &ws) | 212 | QDataStream &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 | */ |
231 | QDataStream &operator>> (QDataStream &s, QIMPenChar &ws) | 231 | QDataStream &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 | ||
250 | bool QIMPenCharMatch::operator>( const QIMPenCharMatch &m ) | 250 | bool QIMPenCharMatch::operator>( const QIMPenCharMatch &m ) |
251 | { | 251 | { |
252 | return error > m.error; | 252 | return error > m.error; |
253 | } | 253 | } |
254 | 254 | ||
255 | bool QIMPenCharMatch::operator<( const QIMPenCharMatch &m ) | 255 | bool QIMPenCharMatch::operator<( const QIMPenCharMatch &m ) |
256 | { | 256 | { |
257 | return error < m.error; | 257 | return error < m.error; |
258 | } | 258 | } |
259 | 259 | ||
260 | bool QIMPenCharMatch::operator<=( const QIMPenCharMatch &m ) | 260 | bool 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 | ||
273 | QIMPenCharSet::QIMPenCharSet() | 273 | QIMPenCharSet::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 | */ |
285 | QIMPenCharSet::QIMPenCharSet( const QString &fn ) | 285 | QIMPenCharSet::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 | ||
295 | const QString &QIMPenCharSet::filename( Domain d ) const | 295 | const 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 | ||
303 | void QIMPenCharSet::setFilename( const QString &fn, Domain d ) | 303 | void 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 | */ |
314 | bool QIMPenCharSet::load( const QString &fn, Domain d ) | 314 | bool 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 | */ |
357 | bool QIMPenCharSet::save( Domain d ) | 358 | bool 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 | ||
406 | QIMPenChar *QIMPenCharSet::at( int i ) | 420 | QIMPenChar *QIMPenCharSet::at( int i ) |
407 | { | 421 | { |
408 | return chars.at(i); | 422 | return chars.at(i); |
409 | } | 423 | } |
410 | 424 | ||
411 | void QIMPenCharSet::markDeleted( uint ch ) | 425 | void 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 | */ |
424 | QIMPenCharMatchList QIMPenCharSet::match( QIMPenChar *ch ) | 438 | QIMPenCharMatchList 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 | */ |
473 | void QIMPenCharSet::addChar( QIMPenChar *ch ) | 487 | void 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 | */ |
484 | void QIMPenCharSet::removeChar( QIMPenChar *ch ) | 498 | void 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 | */ |
492 | void QIMPenCharSet::up( QIMPenChar *ch ) | 506 | void 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 | */ |
504 | void QIMPenCharSet::down( QIMPenChar *ch ) | 518 | void 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 | ||