1 /* 2 * Copyright (C) 2008,2009 OMRON SOFTWARE Co., Ltd. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package jp.co.omronsoft.openwnn; 18 19 import android.content.ContentValues; 20 import android.database.DatabaseUtils; 21 import android.database.SQLException; 22 import android.database.sqlite.SQLiteCursor; 23 import android.database.sqlite.SQLiteDatabase; 24 25 import android.util.Log; 26 27 /** 28 * The implementation class of WnnDictionary interface (JNI wrapper class). 29 * 30 * @author Copyright (C) 2008, 2009 OMRON SOFTWARE CO., LTD. All Rights Reserved. 31 */ 32 public class OpenWnnDictionaryImpl implements WnnDictionary { 33 /* 34 * DEFINITION FOR JNI 35 */ 36 static { 37 /* Load the dictionary search library */ 38 System.loadLibrary( "wnndict" ); 39 } 40 41 /* 42 * DEFINITION OF CONSTANTS 43 */ 44 /** The maximum length of stroke */ 45 public static final int MAX_STROKE_LENGTH = 50; 46 /** The maximum length of candidate */ 47 public static final int MAX_CANDIDATE_LENGTH = 50; 48 /** The table name of writable dictionary on the database */ 49 protected static final String TABLE_NAME_DIC = "dic"; 50 /** The type name of user word */ 51 protected static final int TYPE_NAME_USER = 0; 52 /** The type name of learn word */ 53 protected static final int TYPE_NAME_LEARN = 1; 54 55 /** The column name of database */ 56 protected static final String COLUMN_NAME_ID = "rowid"; 57 /** The column name of database */ 58 protected static final String COLUMN_NAME_TYPE = "type"; 59 /** The column name of database */ 60 protected static final String COLUMN_NAME_STROKE = "stroke"; 61 /** The column name of database */ 62 protected static final String COLUMN_NAME_CANDIDATE = "candidate"; 63 /** The column name of database */ 64 protected static final String COLUMN_NAME_POS_LEFT = "posLeft"; 65 /** The column name of database */ 66 protected static final String COLUMN_NAME_POS_RIGHT = "posRight"; 67 /** The column name of database */ 68 protected static final String COLUMN_NAME_PREVIOUS_STROKE = "prevStroke"; 69 /** The column name of database */ 70 protected static final String COLUMN_NAME_PREVIOUS_CANDIDATE = "prevCandidate"; 71 /** The column name of database */ 72 protected static final String COLUMN_NAME_PREVIOUS_POS_LEFT = "prevPosLeft"; 73 /** The column name of database */ 74 protected static final String COLUMN_NAME_PREVIOUS_POS_RIGHT = "prevPosRight"; 75 76 /** Query for normal search */ 77 protected static final String NORMAL_QUERY = 78 "select distinct " + COLUMN_NAME_STROKE + "," + 79 COLUMN_NAME_CANDIDATE + "," + 80 COLUMN_NAME_POS_LEFT + "," + 81 COLUMN_NAME_POS_RIGHT + "," + 82 COLUMN_NAME_TYPE + 83 " from " + TABLE_NAME_DIC + " where %s order by " + 84 COLUMN_NAME_TYPE + " DESC, %s"; 85 86 /** Query for link search */ 87 protected static final String LINK_QUERY = 88 "select distinct " + COLUMN_NAME_STROKE + "," + 89 COLUMN_NAME_CANDIDATE + "," + 90 COLUMN_NAME_POS_LEFT + "," + 91 COLUMN_NAME_POS_RIGHT + "," + 92 COLUMN_NAME_TYPE + 93 " from " + TABLE_NAME_DIC + " where %s = ? and %s = ? and %s order by " + 94 COLUMN_NAME_TYPE + " DESC, %s"; 95 96 /** The max words of user dictionary */ 97 protected static final int MAX_WORDS_IN_USER_DICTIONARY = 100; 98 /** The max words of learning dictionary */ 99 protected static final int MAX_WORDS_IN_LEARN_DICTIONARY = 2000; 100 101 /** The base frequency of user dictionary */ 102 protected static final int OFFSET_FREQUENCY_OF_USER_DICTIONARY = 1000; 103 /** The base frequency of learning dictionary */ 104 protected static final int OFFSET_FREQUENCY_OF_LEARN_DICTIONARY = 2000; 105 106 /* 107 * Constants to define the upper limit of query. 108 * 109 * That is used to fix the size of query expression. 110 * If the number of approximate patterns for a character is exceeded MAX_PATTERN_OF_APPROX, 111 * increase that constant to the maximum number of patterns. 112 */ 113 /** Constants to define the upper limit of approximate patterns */ 114 protected final static int MAX_PATTERN_OF_APPROX = 6; 115 /** Constants to define the upper limit of length of a query */ 116 protected final static int MAX_LENGTH_OF_QUERY = 50; 117 /** 118 * Constants to define the turn around time of query. 119 * <br> 120 * It can be set between 1 to {@code MAX_LENGTH_OF_QUERY}. If the length of query 121 * string is shorter than {@code FAST_QUERY_LENGTH}, the simple search logic is applied. 122 * Therefore, the turn around time for short query string is fast so that it is short. 123 * However, the difference of turn around time at the border length grows big. 124 * the value should be fixed carefully. 125 */ 126 protected final static int FAST_QUERY_LENGTH = 20; 127 128 /* 129 * DEFINITION OF PRIVATE FIELD 130 */ 131 /** Internal work area for the dictionary search library */ 132 protected long mWnnWork = 0; 133 134 /** The file path of the writable dictionary */ 135 protected String mDicFilePath = ""; 136 /** The writable dictionary object */ 137 protected SQLiteDatabase mDbDic = null; 138 /** The search cursor of the writable dictionary */ 139 protected SQLiteCursor mDbCursor = null; 140 /** The number of queried items */ 141 protected int mCountCursor = 0; 142 /** The type of the search cursor object */ 143 protected int mTypeOfQuery = -1; 144 145 /** The query base strings for query operation */ 146 protected String mExactQuerySqlOrderByFreq; 147 /** The query base strings for query operation */ 148 protected String mExactQuerySqlOrderByKey; 149 150 /** The query base strings for query operation */ 151 protected String mFullPrefixQuerySqlOrderByFreq; 152 /** The query base strings for query operation */ 153 protected String mFastPrefixQuerySqlOrderByFreq; 154 /** The query base strings for query operation */ 155 protected String mFullPrefixQuerySqlOrderByKey; 156 /** The query base strings for query operation */ 157 protected String mFastPrefixQuerySqlOrderByKey; 158 159 /** The query base strings for query operation */ 160 protected String mFullLinkQuerySqlOrderByFreq; 161 /** The query base strings for query operation */ 162 protected String mFastLinkQuerySqlOrderByFreq; 163 /** The query base strings for query operation */ 164 protected String mFullLinkQuerySqlOrderByKey; 165 /** The query base strings for query operation */ 166 protected String mFastLinkQuerySqlOrderByKey; 167 168 /** The string array used by query operation (for "selection") */ 169 protected String mExactQueryArgs[] = new String[ 1 ]; 170 /** The string array used by query operation (for "selection") */ 171 protected String mFullQueryArgs[] = new String[ MAX_LENGTH_OF_QUERY * (MAX_PATTERN_OF_APPROX+1) ]; 172 /** The string array used by query operation (for "selection") */ 173 protected String mFastQueryArgs[] = new String[ FAST_QUERY_LENGTH * (MAX_PATTERN_OF_APPROX+1) ]; 174 175 /** The Frequency offset of user dictionary */ 176 protected int mFrequencyOffsetOfUserDictionary = -1; 177 /** The Frequency offset of learn dictionary */ 178 protected int mFrequencyOffsetOfLearnDictionary = -1; 179 180 /* 181 * DEFINITION OF METHODS 182 */ 183 /** 184 * The constructor of this class without writable dictionary. 185 * 186 * Create a internal work area for the search engine. It is allocated for each object. 187 * 188 * @param dicLibPath The dictionary library file path 189 */ 190 public OpenWnnDictionaryImpl( String dicLibPath ) { 191 this( dicLibPath, null ); 192 } 193 194 /** 195 * The constructor of this class with writable dictionary. 196 * 197 * Create a internal work area and the writable dictionary for the search engine. It is allocated for each object. 198 * 199 * @param dicLibPath The dictionary library file path 200 * @param dicFilePath The path name of writable dictionary 201 */ 202 public OpenWnnDictionaryImpl( String dicLibPath, String dicFilePath ) { 203 /* Create the internal work area */ 204 this.mWnnWork = OpenWnnDictionaryImplJni.createWnnWork( dicLibPath ); 205 206 if( this.mWnnWork != 0 && dicFilePath != null ) { 207 /* Create query base strings */ 208 String queryFullBaseString = 209 OpenWnnDictionaryImplJni.createQueryStringBase( 210 this.mWnnWork, 211 MAX_LENGTH_OF_QUERY, 212 MAX_PATTERN_OF_APPROX, 213 COLUMN_NAME_STROKE ); 214 215 String queryFastBaseString = 216 OpenWnnDictionaryImplJni.createQueryStringBase( 217 this.mWnnWork, 218 FAST_QUERY_LENGTH, 219 MAX_PATTERN_OF_APPROX, 220 COLUMN_NAME_STROKE ); 221 222 223 mExactQuerySqlOrderByFreq = String.format( 224 NORMAL_QUERY, 225 String.format( "%s=?", COLUMN_NAME_STROKE ), String.format( "%s DESC", COLUMN_NAME_ID ) ); 226 227 mExactQuerySqlOrderByKey = String.format( 228 NORMAL_QUERY, 229 String.format( "%s=?", COLUMN_NAME_STROKE ), COLUMN_NAME_STROKE ); 230 231 232 mFullPrefixQuerySqlOrderByFreq = String.format( 233 NORMAL_QUERY, 234 queryFullBaseString, String.format( "%s DESC", COLUMN_NAME_ID ) ); 235 236 mFastPrefixQuerySqlOrderByFreq = String.format( 237 NORMAL_QUERY, 238 queryFastBaseString, String.format( "%s DESC", COLUMN_NAME_ID ) ); 239 240 mFullPrefixQuerySqlOrderByKey = String.format( 241 NORMAL_QUERY, 242 queryFullBaseString, COLUMN_NAME_STROKE ); 243 244 mFastPrefixQuerySqlOrderByKey = String.format( 245 NORMAL_QUERY, 246 queryFastBaseString, COLUMN_NAME_STROKE ); 247 248 249 mFullLinkQuerySqlOrderByFreq = String.format( 250 LINK_QUERY, COLUMN_NAME_PREVIOUS_STROKE, COLUMN_NAME_PREVIOUS_CANDIDATE, 251 queryFullBaseString, String.format( "%s DESC", COLUMN_NAME_ID ) ); 252 253 mFastLinkQuerySqlOrderByFreq = String.format( 254 LINK_QUERY, COLUMN_NAME_PREVIOUS_STROKE, COLUMN_NAME_PREVIOUS_CANDIDATE, 255 queryFastBaseString, String.format( "%s DESC", COLUMN_NAME_ID ) ); 256 257 mFullLinkQuerySqlOrderByKey = String.format( 258 LINK_QUERY, COLUMN_NAME_PREVIOUS_STROKE, COLUMN_NAME_PREVIOUS_CANDIDATE, 259 queryFullBaseString, COLUMN_NAME_STROKE ); 260 261 mFastLinkQuerySqlOrderByKey = String.format( 262 LINK_QUERY, COLUMN_NAME_PREVIOUS_STROKE, COLUMN_NAME_PREVIOUS_CANDIDATE, 263 queryFastBaseString, COLUMN_NAME_STROKE ); 264 265 266 try { 267 /* Create the database object */ 268 mDicFilePath = dicFilePath; 269 setInUseState( true ); 270 271 /* Create the table if not exist */ 272 createDictionaryTable( TABLE_NAME_DIC ); 273 } catch( SQLException e ) { 274 } 275 } 276 } 277 278 /** 279 * The finalizer of this class. 280 * Destroy the internal work area for the search engine. 281 */ 282 protected void finalize( ) { 283 /* Free the internal work area */ 284 if( this.mWnnWork != 0 ) { 285 OpenWnnDictionaryImplJni.freeWnnWork( this.mWnnWork ); 286 this.mWnnWork = 0; 287 288 freeDatabase(); 289 } 290 } 291 292 /** 293 * Create the table of writable dictionary. 294 * 295 * @param tableName The name of table 296 */ 297 protected void createDictionaryTable( String tableName ) { 298 String sqlStr = "create table if not exists " + tableName + 299 " (" + COLUMN_NAME_ID + " integer primary key autoincrement, " + 300 COLUMN_NAME_TYPE + " integer, " + 301 COLUMN_NAME_STROKE + " text, " + 302 COLUMN_NAME_CANDIDATE + " text, " + 303 COLUMN_NAME_POS_LEFT + " integer, " + 304 COLUMN_NAME_POS_RIGHT + " integer, " + 305 COLUMN_NAME_PREVIOUS_STROKE + " text, " + 306 COLUMN_NAME_PREVIOUS_CANDIDATE + " text, " + 307 COLUMN_NAME_PREVIOUS_POS_LEFT + " integer, " + 308 COLUMN_NAME_PREVIOUS_POS_RIGHT + " integer)"; 309 310 if( mDbDic != null ) { 311 mDbDic.execSQL( sqlStr ); 312 } 313 } 314 315 /** 316 * Free the {@link SQLiteDatabase} of writable dictionary. 317 */ 318 protected void freeDatabase( ) { 319 freeCursor(); 320 321 if( mDbDic != null ) { 322 /* The SQLiteDataBase object must close() before releasing. */ 323 mDbDic.close(); 324 mDbDic = null; 325 } 326 } 327 /** 328 * Free the {@link SQLiteCursor} of writable dictionary. 329 */ 330 protected void freeCursor( ) { 331 if( mDbCursor != null) { 332 /* The SQLiteCursor object must close() before releasing. */ 333 mDbCursor.close(); 334 mDbCursor = null; 335 336 mTypeOfQuery = -1; 337 } 338 } 339 340 341 /** 342 * @see jp.co.omronsoft.openwnn.WnnDictionary#setInUseState 343 */ 344 public boolean isActive() { 345 return (this.mWnnWork != 0); 346 } 347 348 /** 349 * @see jp.co.omronsoft.openwnn.WnnDictionary#setInUseState 350 */ 351 public void setInUseState( boolean flag ) { 352 if( flag ) { 353 if( mDbDic == null ) { 354 mDbDic = SQLiteDatabase.openOrCreateDatabase( mDicFilePath, null ); 355 } 356 } else { 357 freeDatabase(); 358 } 359 } 360 361 /** 362 * @see jp.co.omronsoft.openwnn.WnnDictionary#clearDictionary 363 */ 364 public int clearDictionary( ) { 365 if( this.mWnnWork != 0 ) { 366 mFrequencyOffsetOfUserDictionary = -1; 367 mFrequencyOffsetOfLearnDictionary = -1; 368 369 return OpenWnnDictionaryImplJni.clearDictionaryParameters( this.mWnnWork ); 370 } else { 371 return -1; 372 } 373 } 374 375 /** 376 * @see jp.co.omronsoft.openwnn.WnnDictionary#setDictionary 377 */ 378 public int setDictionary(int index, int base, int high ) { 379 if( this.mWnnWork != 0 ) { 380 switch( index ) { 381 case WnnDictionary.INDEX_USER_DICTIONARY: 382 if( base < 0 || high < 0 || base > high 383 /* || base < OFFSET_FREQUENCY_OF_USER_DICTIONARY || high >= OFFSET_FREQUENCY_OF_LEARN_DICTIONARY */ ) { 384 mFrequencyOffsetOfUserDictionary = -1; 385 } else { 386 mFrequencyOffsetOfUserDictionary = high; 387 } 388 return 0; 389 case WnnDictionary.INDEX_LEARN_DICTIONARY: 390 if( base < 0 || high < 0 || base > high 391 /* || base < OFFSET_FREQUENCY_OF_LEARN_DICTIONARY */ ) { 392 mFrequencyOffsetOfLearnDictionary = -1; 393 } else { 394 mFrequencyOffsetOfLearnDictionary = high; 395 } 396 return 0; 397 default: 398 return OpenWnnDictionaryImplJni.setDictionaryParameter( this.mWnnWork, index, base, high ); 399 } 400 } else { 401 return -1; 402 } 403 } 404 405 /** 406 * Query to the database 407 * 408 * @param keyString The key string 409 * @param wnnWord The previous word for link search 410 * @param operation The search operation 411 * @param order The type of sort order 412 */ 413 protected void createQuery( String keyString, WnnWord wnnWord, int operation, int order) { 414 int newTypeOfQuery, maxBindsOfQuery; 415 String querySqlOrderByFreq, querySqlOrderByKey; 416 String queryArgs[]; 417 418 if( operation != WnnDictionary.SEARCH_LINK ) { 419 wnnWord = null; 420 } 421 422 switch( operation ) { 423 case WnnDictionary.SEARCH_EXACT: 424 querySqlOrderByFreq = mExactQuerySqlOrderByFreq; 425 querySqlOrderByKey = mExactQuerySqlOrderByKey; 426 newTypeOfQuery = 0; 427 queryArgs = mExactQueryArgs; 428 429 queryArgs[ 0 ] = keyString; 430 break; 431 432 case WnnDictionary.SEARCH_PREFIX: 433 case WnnDictionary.SEARCH_LINK: 434 /* Select the suitable parameters for the query */ 435 if( keyString.length() <= FAST_QUERY_LENGTH ) { 436 if( wnnWord != null ) { 437 querySqlOrderByFreq = mFastLinkQuerySqlOrderByFreq; 438 querySqlOrderByKey = mFastLinkQuerySqlOrderByKey; 439 newTypeOfQuery = 1; 440 } else { 441 querySqlOrderByFreq = mFastPrefixQuerySqlOrderByFreq; 442 querySqlOrderByKey = mFastPrefixQuerySqlOrderByKey; 443 newTypeOfQuery = 2; 444 } 445 maxBindsOfQuery = FAST_QUERY_LENGTH; 446 queryArgs = mFastQueryArgs; 447 } else { 448 if( wnnWord != null ) { 449 querySqlOrderByFreq = mFullLinkQuerySqlOrderByFreq; 450 querySqlOrderByKey = mFullLinkQuerySqlOrderByKey; 451 newTypeOfQuery = 3; 452 } else { 453 querySqlOrderByFreq = mFullPrefixQuerySqlOrderByFreq; 454 querySqlOrderByKey = mFullPrefixQuerySqlOrderByKey; 455 newTypeOfQuery = 4; 456 } 457 maxBindsOfQuery = MAX_LENGTH_OF_QUERY; 458 queryArgs = mFullQueryArgs; 459 } 460 461 if( wnnWord != null ) { 462 /* If link search is enabled, insert information of the previous word */ 463 String[] queryArgsTemp = OpenWnnDictionaryImplJni.createBindArray( this.mWnnWork, keyString, maxBindsOfQuery, MAX_PATTERN_OF_APPROX ); 464 465 queryArgs = new String[ queryArgsTemp.length + 2 ]; 466 for( int i = 0 ; i < queryArgsTemp.length ; i++ ) { 467 queryArgs[ i + 2 ] = queryArgsTemp[ i ]; 468 } 469 470 queryArgs[ 0 ] = wnnWord.stroke; 471 queryArgs[ 1 ] = wnnWord.candidate; 472 } else { 473 queryArgs = OpenWnnDictionaryImplJni.createBindArray( this.mWnnWork, keyString, maxBindsOfQuery, MAX_PATTERN_OF_APPROX ); 474 } 475 break; 476 477 default: 478 mCountCursor = 0; 479 freeCursor( ); 480 return; 481 } 482 483 /* Create the cursor and set arguments */ 484 mCountCursor = 0; 485 486 if( mDbCursor == null || mTypeOfQuery != newTypeOfQuery ) { 487 /* If the cursor is not exist or the type of query is changed, compile the query string and query words */ 488 freeCursor( ); 489 490 try { 491 switch( order ) { 492 case WnnDictionary.ORDER_BY_FREQUENCY: 493 mDbCursor = ( SQLiteCursor )mDbDic.rawQuery( querySqlOrderByFreq, queryArgs ); 494 break; 495 case WnnDictionary.ORDER_BY_KEY: 496 mDbCursor = ( SQLiteCursor )mDbDic.rawQuery( querySqlOrderByKey, queryArgs ); 497 break; 498 default: 499 return; 500 } 501 } catch( SQLException e ) { 502 return; 503 } 504 505 mTypeOfQuery = newTypeOfQuery; 506 } else { 507 /* If the cursor is exist, bind new arguments and re-query words (DO NOT recompile the query string) */ 508 try { 509 mDbCursor.setSelectionArguments( queryArgs ); 510 mDbCursor.requery( ); 511 } catch( SQLException e ) { 512 return; 513 } 514 } 515 516 if( mDbCursor != null ) { 517 /* If querying is succeed, count the number of words */ 518 mCountCursor = mDbCursor.getCount(); 519 if( mCountCursor == 0 ) { 520 /* If no word is retrieved, deactivate the cursor for reduce the resource */ 521 mDbCursor.deactivate( ); 522 } 523 } 524 525 return; 526 } 527 528 /** 529 * @see jp.co.omronsoft.openwnn.WnnDictionary#searchWord 530 */ 531 public int searchWord( int operation, int order, String keyString ) { 532 /* Unset the previous word information */ 533 OpenWnnDictionaryImplJni.clearResult( this.mWnnWork ); 534 535 /* Search to user/learn dictionary */ 536 if( mDbDic != null && ( mFrequencyOffsetOfUserDictionary >= 0 || 537 mFrequencyOffsetOfLearnDictionary >= 0 ) ) { 538 try { 539 if( keyString.length() > 0 ) { 540 createQuery( keyString, null, operation, order ); 541 if( mDbCursor != null ) { 542 mDbCursor.moveToFirst(); 543 } 544 } else { 545 /* If the key string is "", no word is retrieved */ 546 if( mDbCursor != null ) { 547 mDbCursor.deactivate(); 548 } 549 mCountCursor = 0; 550 } 551 } catch( SQLException e ) { 552 if( mDbCursor != null ) { 553 mDbCursor.deactivate(); 554 } 555 mCountCursor = 0; 556 } 557 } else { 558 mCountCursor = 0; 559 } 560 561 /* Search to fixed dictionary */ 562 if( this.mWnnWork != 0 ) { 563 int ret = OpenWnnDictionaryImplJni.searchWord( this.mWnnWork, operation, order, keyString ); 564 if (mCountCursor > 0) { 565 ret = 1; 566 } 567 return ret; 568 } else { 569 return -1; 570 } 571 } 572 573 /** 574 * @see jp.co.omronsoft.openwnn.WnnDictionary#searchWord 575 */ 576 public int searchWord( int operation, int order, String keyString, WnnWord wnnWord ) { 577 if( wnnWord == null || wnnWord.partOfSpeech == null ) { 578 return -1; 579 } 580 581 /* Search to user/learn dictionary with link information */ 582 if( mDbDic != null && ( mFrequencyOffsetOfUserDictionary >= 0 || 583 mFrequencyOffsetOfLearnDictionary >= 0 ) ) { 584 try { 585 createQuery( keyString, wnnWord, operation, order ); 586 if( mDbCursor != null ) { 587 mDbCursor.moveToFirst(); 588 } 589 } catch( SQLException e ) { 590 if( mDbCursor != null ) { 591 mDbCursor.deactivate(); 592 } 593 mCountCursor = 0; 594 } 595 } else { 596 mCountCursor = 0; 597 } 598 599 /* Search to fixed dictionary with link information */ 600 OpenWnnDictionaryImplJni.clearResult( this.mWnnWork ); 601 OpenWnnDictionaryImplJni.setStroke( this.mWnnWork, wnnWord.stroke ); 602 OpenWnnDictionaryImplJni.setCandidate( this.mWnnWork, wnnWord.candidate ); 603 OpenWnnDictionaryImplJni.setLeftPartOfSpeech( this.mWnnWork, wnnWord.partOfSpeech.left ); 604 OpenWnnDictionaryImplJni.setRightPartOfSpeech( this.mWnnWork, wnnWord.partOfSpeech.right ); 605 OpenWnnDictionaryImplJni.selectWord( this.mWnnWork ); 606 607 if( this.mWnnWork != 0 ) { 608 int ret = OpenWnnDictionaryImplJni.searchWord( this.mWnnWork, operation, order, keyString ); 609 if (mCountCursor > 0) { 610 ret = 1; 611 } 612 return ret; 613 } else { 614 return -1; 615 } 616 } 617 618 /** 619 * @see jp.co.omronsoft.openwnn.WnnDictionary#getNextWord 620 */ 621 public WnnWord getNextWord( ) { 622 return getNextWord( 0 ); 623 } 624 625 /** 626 * @see jp.co.omronsoft.openwnn.WnnDictionary#getNextWord 627 */ 628 public WnnWord getNextWord( int length ) { 629 if( this.mWnnWork != 0 ) { 630 if( mDbDic != null && mDbCursor != null && mCountCursor > 0 ) { 631 /* If the user/learn dictionary is queried, get the result from the user/learn dictionary */ 632 WnnWord result = new WnnWord( ); 633 try { 634 /* Skip results if that is not contained the type of search or length of stroke is not equal specified length */ 635 while( mCountCursor > 0 && 636 ( ( mFrequencyOffsetOfUserDictionary < 0 && mDbCursor.getInt( 4 ) == TYPE_NAME_USER ) || 637 ( mFrequencyOffsetOfLearnDictionary < 0 && mDbCursor.getInt( 4 ) == TYPE_NAME_LEARN ) || 638 ( length > 0 && mDbCursor.getString( 0 ).length( ) != length ) ) ) { 639 mDbCursor.moveToNext(); 640 mCountCursor--; 641 } 642 643 if( mCountCursor > 0 ) { 644 /* Get the information of word */ 645 result.stroke = mDbCursor.getString( 0 ); 646 result.candidate = mDbCursor.getString( 1 ); 647 result.partOfSpeech.left = mDbCursor.getInt( 2 ); 648 result.partOfSpeech.right = mDbCursor.getInt( 3 ); 649 650 if( mDbCursor.getInt( 4 ) == TYPE_NAME_USER ) { 651 result.frequency = mFrequencyOffsetOfUserDictionary; 652 } else { 653 result.frequency = mFrequencyOffsetOfLearnDictionary; 654 } 655 656 /* Move cursor to next result. If the next result is not exist, deactivate the cursor */ 657 mDbCursor.moveToNext(); 658 if( --mCountCursor <= 0 ) { 659 mDbCursor.deactivate(); 660 } 661 662 return result; 663 } else { 664 /* if no result is found, terminate the searching of user/learn dictionary */ 665 mDbCursor.deactivate(); 666 result = null; 667 } 668 } catch( SQLException e ) { 669 mDbCursor.deactivate(); 670 mCountCursor = 0; 671 result = null; 672 } 673 } 674 675 /* Get the result from fixed dictionary */ 676 int res = OpenWnnDictionaryImplJni.getNextWord( this.mWnnWork, length ); 677 if( res > 0 ) { 678 WnnWord result = new WnnWord( ); 679 if( result != null ) { 680 result.stroke = OpenWnnDictionaryImplJni.getStroke( this.mWnnWork ); 681 result.candidate = OpenWnnDictionaryImplJni.getCandidate( this.mWnnWork ); 682 result.frequency = OpenWnnDictionaryImplJni.getFrequency( this.mWnnWork ); 683 result.partOfSpeech.left = OpenWnnDictionaryImplJni.getLeftPartOfSpeech( this.mWnnWork ); 684 result.partOfSpeech.right = OpenWnnDictionaryImplJni.getRightPartOfSpeech( this.mWnnWork ); 685 } 686 return result; 687 } else if ( res == 0 ) { 688 /* No result is found. */ 689 return null; 690 } else { 691 /* An error occur (It is regarded as "No result is found".) */ 692 return null; 693 } 694 } else { 695 return null; 696 } 697 } 698 699 /** 700 * @see jp.co.omronsoft.openwnn.WnnDictionary#getUserDictionaryWords 701 */ 702 public WnnWord[] getUserDictionaryWords( ) { 703 if( this.mWnnWork != 0 && mDbDic != null ) { 704 int numOfWords, i; 705 SQLiteCursor cursor = null; 706 707 try { 708 /* Count all words in the user dictionary */ 709 cursor = ( SQLiteCursor )mDbDic.query( 710 TABLE_NAME_DIC, 711 new String[] { COLUMN_NAME_STROKE, COLUMN_NAME_CANDIDATE }, 712 String.format( "%s=%d", COLUMN_NAME_TYPE, TYPE_NAME_USER ), 713 null, null, null, null); 714 numOfWords = cursor.getCount(); 715 716 if( numOfWords > 0 ) { 717 /* Retrieve all words in the user dictionary */ 718 WnnWord[] words = new WnnWord[ numOfWords ]; 719 720 cursor.moveToFirst(); 721 for( i = 0 ; i < numOfWords ; i++ ) { 722 words[ i ] = new WnnWord(); 723 words[ i ].stroke = cursor.getString( 0 ); 724 words[ i ].candidate = cursor.getString( 1 ); 725 cursor.moveToNext(); 726 } 727 728 return words; 729 } 730 } catch( SQLException e ) { 731 /* An error occurs */ 732 return null; 733 } finally { 734 if( cursor != null ) { 735 cursor.close( ); 736 } 737 } 738 } 739 return null; 740 } 741 742 /** 743 * @see jp.co.omronsoft.openwnn.WnnDictionary#clearApproxPattern 744 */ 745 public void clearApproxPattern( ) { 746 if( this.mWnnWork != 0 ) { 747 OpenWnnDictionaryImplJni.clearApproxPatterns( this.mWnnWork ); 748 } 749 } 750 751 /** 752 * @see jp.co.omronsoft.openwnn.WnnDictionary#setApproxPattern 753 */ 754 public int setApproxPattern( String src, String dst ) { 755 if( this.mWnnWork != 0 ) { 756 return OpenWnnDictionaryImplJni.setApproxPattern( this.mWnnWork, src, dst ); 757 } else { 758 return -1; 759 } 760 } 761 762 /** 763 * @see jp.co.omronsoft.openwnn.WnnDictionary#setApproxPattern 764 */ 765 public int setApproxPattern( int approxPattern ) { 766 if( this.mWnnWork != 0 ) { 767 return OpenWnnDictionaryImplJni.setApproxPattern( this.mWnnWork, approxPattern ); 768 } else { 769 return -1; 770 } 771 } 772 773 /** 774 * @see jp.co.omronsoft.openwnn.WnnDictionary#getConnectMatrix 775 */ 776 public byte[][] getConnectMatrix( ) { 777 byte[][] result; 778 int lcount, i; 779 780 if (this.mWnnWork != 0) { 781 /* 1-origin */ 782 lcount = OpenWnnDictionaryImplJni.getNumberOfLeftPOS( this.mWnnWork ); 783 result = new byte[ lcount + 1 ][ ]; 784 785 if( result != null ) { 786 for( i = 0 ; i < lcount + 1 ; i++ ) { 787 result[ i ] = OpenWnnDictionaryImplJni.getConnectArray( this.mWnnWork, i ); 788 789 if( result[ i ] == null ) { 790 return null; 791 } 792 } 793 } 794 } else { 795 result = new byte[1][1]; 796 } 797 return result; 798 } 799 800 /** 801 * @see jp.co.omronsoft.openwnn.WnnDictionary#getPOS 802 */ 803 public WnnPOS getPOS( int type ) { 804 WnnPOS result = new WnnPOS( ); 805 806 if( this.mWnnWork != 0 && result != null ) { 807 result.left = OpenWnnDictionaryImplJni.getLeftPartOfSpeechSpecifiedType( this.mWnnWork, type ); 808 result.right = OpenWnnDictionaryImplJni.getRightPartOfSpeechSpecifiedType( this.mWnnWork, type ); 809 810 if( result.left < 0 || result.right < 0 ) { 811 return null; 812 } 813 } 814 return result; 815 } 816 817 /** 818 * @see jp.co.omronsoft.openwnn.WnnDictionary#clearUserDictionary 819 */ 820 public int clearUserDictionary() { 821 if( mDbDic != null ) { 822 mDbDic.execSQL( String.format( "delete from %s where %s=%d", TABLE_NAME_DIC, COLUMN_NAME_TYPE, TYPE_NAME_USER ) ); 823 } 824 825 /* If no writable dictionary exists, no error occurs. */ 826 return 0; 827 } 828 829 /** 830 * @see jp.co.omronsoft.openwnn.WnnDictionary#clearLearnDictionary 831 */ 832 public int clearLearnDictionary() { 833 if( mDbDic != null ) { 834 mDbDic.execSQL( String.format( "delete from %s where %s=%d", TABLE_NAME_DIC, COLUMN_NAME_TYPE, TYPE_NAME_LEARN ) ); 835 } 836 837 /* If no writable dictionary exists, no error occurs. */ 838 return 0; 839 } 840 841 /** 842 * @see jp.co.omronsoft.openwnn.WnnDictionary#addWordToUserDictionary 843 */ 844 public int addWordToUserDictionary( WnnWord[] word ) { 845 int result = 0; 846 847 if( mDbDic != null ) { 848 SQLiteCursor cursor; 849 850 /* Count all words in the user dictionary */ 851 cursor = ( SQLiteCursor )mDbDic.query( 852 TABLE_NAME_DIC, 853 new String[] { COLUMN_NAME_ID }, 854 String.format( "%s=%d", COLUMN_NAME_TYPE, TYPE_NAME_USER ), 855 null, null, null, null); 856 857 int count = cursor.getCount(); 858 cursor.close(); 859 860 if( count + word.length > MAX_WORDS_IN_USER_DICTIONARY ) { 861 /* If user dictionary is full, an error occurs. */ 862 return -1; 863 } else { 864 mDbDic.beginTransaction(); 865 try { 866 StringBuilder strokeSQL = new StringBuilder(); 867 StringBuilder candidateSQL = new StringBuilder(); 868 869 for( int index = 0 ; index < word.length ; index++ ) { 870 if( word[index].stroke.length() > 0 && word[index].stroke.length() <= MAX_STROKE_LENGTH && 871 word[index].candidate.length() > 0 && word[index].candidate.length() <= MAX_CANDIDATE_LENGTH ) { 872 strokeSQL.setLength( 0 ); 873 candidateSQL.setLength( 0 ); 874 DatabaseUtils.appendEscapedSQLString( strokeSQL, word[index].stroke ); 875 DatabaseUtils.appendEscapedSQLString( candidateSQL, word[index].candidate ); 876 877 cursor = ( SQLiteCursor )mDbDic.query( 878 TABLE_NAME_DIC, 879 new String[] { COLUMN_NAME_ID }, 880 String.format( "%s=%d and %s=%s and %s=%s", 881 COLUMN_NAME_TYPE, TYPE_NAME_USER, 882 COLUMN_NAME_STROKE, strokeSQL.toString(), 883 COLUMN_NAME_CANDIDATE, candidateSQL.toString() ), 884 null, null, null, null ); 885 886 if( cursor.getCount() > 0 ) { 887 /* if the specified word is exist, an error reported and skipped that word. */ 888 result = -2; 889 } else { 890 ContentValues content = new ContentValues(); 891 892 content.clear(); 893 content.put( COLUMN_NAME_TYPE, TYPE_NAME_USER ); 894 content.put( COLUMN_NAME_STROKE, word[index].stroke ); 895 content.put( COLUMN_NAME_CANDIDATE, word[index].candidate ); 896 content.put( COLUMN_NAME_POS_LEFT, word[index].partOfSpeech.left ); 897 content.put( COLUMN_NAME_POS_RIGHT, word[index].partOfSpeech.right ); 898 899 mDbDic.insert( TABLE_NAME_DIC, null, content ); 900 } 901 902 cursor.close( ); 903 cursor = null; 904 } 905 } 906 mDbDic.setTransactionSuccessful(); 907 } catch( SQLException e ) { 908 /* An error occurs */ 909 return -1; 910 } finally { 911 mDbDic.endTransaction(); 912 if( cursor != null ) { 913 cursor.close( ); 914 } 915 } 916 } 917 } 918 919 /* If no writable dictionary exists, no error occurs. */ 920 return result; 921 } 922 923 /** 924 * @see jp.co.omronsoft.openwnn.WnnDictionary#addWordToUserDictionary 925 */ 926 public int addWordToUserDictionary( WnnWord word ) { 927 WnnWord[] words = new WnnWord[1]; 928 words[0] = word; 929 930 return addWordToUserDictionary( words ); 931 } 932 933 /** 934 * @see jp.co.omronsoft.openwnn.WnnDictionary#removeWordFromUserDictionary 935 */ 936 public int removeWordFromUserDictionary( WnnWord[] word ) { 937 if( mDbDic != null ) { 938 /* Remove the specified word */ 939 mDbDic.beginTransaction(); 940 try { 941 StringBuilder strokeSQL = new StringBuilder(); 942 StringBuilder candidateSQL = new StringBuilder(); 943 944 for( int index = 0 ; index < word.length ; index++ ) { 945 if( word[index].stroke.length() > 0 && word[index].stroke.length() <= MAX_STROKE_LENGTH && 946 word[index].candidate.length() > 0 && word[index].candidate.length() <= MAX_CANDIDATE_LENGTH ) { 947 strokeSQL.setLength( 0 ); 948 candidateSQL.setLength( 0 ); 949 DatabaseUtils.appendEscapedSQLString( strokeSQL, word[index].stroke ); 950 DatabaseUtils.appendEscapedSQLString( candidateSQL, word[index].candidate ); 951 952 mDbDic.delete( TABLE_NAME_DIC, 953 String.format( "%s=%d and %s=%s and %s=%s", 954 COLUMN_NAME_TYPE, TYPE_NAME_USER, 955 COLUMN_NAME_STROKE, strokeSQL, 956 COLUMN_NAME_CANDIDATE, candidateSQL ), 957 null ); 958 } 959 } 960 mDbDic.setTransactionSuccessful(); 961 } catch( SQLException e ) { 962 /* An error occurs */ 963 return -1; 964 } finally { 965 mDbDic.endTransaction(); 966 } 967 } 968 969 /* If no writable dictionary exists, no error occurs. */ 970 return 0; 971 } 972 973 /** 974 * @see jp.co.omronsoft.openwnn.WnnDictionary#removeWordFromUserDictionary 975 */ 976 public int removeWordFromUserDictionary( WnnWord word ) { 977 WnnWord[] words = new WnnWord[1]; 978 words[0] = word; 979 980 return removeWordFromUserDictionary( words ); 981 } 982 983 /** 984 * @see jp.co.omronsoft.openwnn.WnnDictionary#learnWord 985 */ 986 public int learnWord( WnnWord word ) { 987 return learnWord( word, null ); 988 } 989 990 /** 991 * Learn the word with connection. 992 * 993 * @param word The word to learn 994 * @param previousWord The word which is selected previously. 995 * @return 0 if success; minus value if fail. 996 */ 997 public int learnWord( WnnWord word, WnnWord previousWord ) { 998 if( mDbDic != null ) { 999 StringBuilder previousStrokeSQL = new StringBuilder(); 1000 StringBuilder previousCandidateSQL = new StringBuilder(); 1001 1002 if( previousWord != null && 1003 previousWord.stroke.length() > 0 && previousWord.stroke.length() <= MAX_STROKE_LENGTH && 1004 previousWord.candidate.length() > 0 && previousWord.candidate.length() <= MAX_CANDIDATE_LENGTH ) { 1005 DatabaseUtils.appendEscapedSQLString( previousStrokeSQL, previousWord.stroke ); 1006 DatabaseUtils.appendEscapedSQLString( previousCandidateSQL, previousWord.candidate ); 1007 /* If the information of previous word is set, perform the link learning */ 1008 } 1009 1010 if( word.stroke.length() > 0 && word.stroke.length() <= MAX_STROKE_LENGTH && 1011 word.candidate.length() > 0 && word.candidate.length() <= MAX_CANDIDATE_LENGTH ) { 1012 StringBuilder strokeSQL = new StringBuilder(); 1013 StringBuilder candidateSQL = new StringBuilder(); 1014 DatabaseUtils.appendEscapedSQLString( strokeSQL, word.stroke ); 1015 DatabaseUtils.appendEscapedSQLString( candidateSQL, word.candidate ); 1016 1017 SQLiteCursor cursor; 1018 1019 /* Count the number of registered words and retrieve that words ascending by the ID */ 1020 cursor = ( SQLiteCursor )mDbDic.query( 1021 TABLE_NAME_DIC, 1022 new String[] { COLUMN_NAME_STROKE, COLUMN_NAME_CANDIDATE }, 1023 String.format( "%s=%d", COLUMN_NAME_TYPE, TYPE_NAME_LEARN ), 1024 null, null, null, 1025 String.format( "%s ASC", COLUMN_NAME_ID ) ); 1026 1027 if( cursor.getCount( ) >= MAX_WORDS_IN_LEARN_DICTIONARY ) { 1028 /* If a registering space is short, delete the words that contain same stroke and candidate to the oldest word */ 1029 mDbDic.beginTransaction(); 1030 try { 1031 cursor.moveToFirst( ); 1032 1033 StringBuilder oldestStrokeSQL = new StringBuilder(); 1034 StringBuilder oldestCandidateSQL = new StringBuilder(); 1035 DatabaseUtils.appendEscapedSQLString( oldestStrokeSQL, cursor.getString( 0 ) ); 1036 DatabaseUtils.appendEscapedSQLString( oldestCandidateSQL, cursor.getString( 1 ) ); 1037 1038 mDbDic.delete( TABLE_NAME_DIC, 1039 String.format( "%s=%d and %s=%s and %s=%s", 1040 COLUMN_NAME_TYPE, TYPE_NAME_LEARN, 1041 COLUMN_NAME_STROKE, oldestStrokeSQL.toString( ), 1042 COLUMN_NAME_CANDIDATE, oldestCandidateSQL.toString( ) ), 1043 null ); 1044 1045 mDbDic.setTransactionSuccessful(); 1046 } catch( SQLException e ) { 1047 return -1; 1048 } finally { 1049 mDbDic.endTransaction(); 1050 cursor.close(); 1051 } 1052 } else { 1053 cursor.close(); 1054 } 1055 1056 /* learning the word */ 1057 ContentValues content = new ContentValues(); 1058 1059 content.clear(); 1060 content.put( COLUMN_NAME_TYPE, TYPE_NAME_LEARN ); 1061 content.put( COLUMN_NAME_STROKE, word.stroke ); 1062 content.put( COLUMN_NAME_CANDIDATE, word.candidate ); 1063 content.put( COLUMN_NAME_POS_LEFT, word.partOfSpeech.left ); 1064 content.put( COLUMN_NAME_POS_RIGHT, word.partOfSpeech.right ); 1065 if( previousWord != null ) { 1066 content.put( COLUMN_NAME_PREVIOUS_STROKE, previousWord.stroke ); 1067 content.put( COLUMN_NAME_PREVIOUS_CANDIDATE, previousWord.candidate ); 1068 content.put( COLUMN_NAME_PREVIOUS_POS_LEFT, previousWord.partOfSpeech.left ); 1069 content.put( COLUMN_NAME_PREVIOUS_POS_RIGHT, previousWord.partOfSpeech.right ); 1070 } 1071 1072 mDbDic.beginTransaction(); 1073 try { 1074 mDbDic.insert( TABLE_NAME_DIC, null, content ); 1075 mDbDic.setTransactionSuccessful(); 1076 } catch( SQLException e ) { 1077 mDbDic.endTransaction(); 1078 return -1; 1079 } finally { 1080 mDbDic.endTransaction(); 1081 } 1082 } 1083 } 1084 1085 /* If no writable dictionary exists, no error occurs. */ 1086 return 0; 1087 } 1088 } 1089