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