| /* |
| * Copyright (C) 2008,2009 OMRON SOFTWARE Co., Ltd. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package jp.co.omronsoft.openwnn; |
| |
| import android.content.ContentValues; |
| import android.content.Context; |
| import android.database.DatabaseUtils; |
| import android.database.sqlite.*; |
| import android.database.SQLException; |
| import android.database.sqlite.SQLiteCursor; |
| import android.database.sqlite.SQLiteDatabase; |
| |
| import android.util.Log; |
| |
| /** |
| * The implementation of WnnDictionary class (JNI wrapper class) |
| * |
| * @author Copyright (C) 2008-2009, OMRON SOFTWARE CO., LTD. All Rights Reserved. |
| */ |
| public class OpenWnnDictionaryImpl implements WnnDictionary { |
| /* |
| * DEFINITION FOR JNI |
| */ |
| static { |
| /* |
| * Load the dictionary search library |
| */ |
| System.loadLibrary( "wnndict" ); |
| } |
| |
| /* |
| * DEFINITION OF CONSTANTS |
| */ |
| /** |
| * The maximum length of stroke |
| */ |
| public static final int MAX_STROKE_LENGTH = 50; |
| /** |
| * The maximum length of candidate |
| */ |
| public static final int MAX_CANDIDATE_LENGTH = 50; |
| /** |
| * The table name of writable dictionary on the database |
| */ |
| protected static final String TABLE_NAME_DIC = "dic"; |
| /** |
| * The type name of user word |
| */ |
| protected static final int TYPE_NAME_USER = 0; |
| /** |
| * The type name of learn word |
| */ |
| protected static final int TYPE_NAME_LEARN = 1; |
| |
| /** The column name of database */ |
| protected static final String COLUMN_NAME_ID = "rowid"; |
| /** The column name of database */ |
| protected static final String COLUMN_NAME_TYPE = "type"; |
| /** The column name of database */ |
| protected static final String COLUMN_NAME_STROKE = "stroke"; |
| /** The column name of database */ |
| protected static final String COLUMN_NAME_CANDIDATE = "candidate"; |
| /** The column name of database */ |
| protected static final String COLUMN_NAME_POS_LEFT = "posLeft"; |
| /** The column name of database */ |
| protected static final String COLUMN_NAME_POS_RIGHT = "posRight"; |
| /** The column name of database */ |
| protected static final String COLUMN_NAME_PREVIOUS_STROKE = "prevStroke"; |
| /** The column name of database */ |
| protected static final String COLUMN_NAME_PREVIOUS_CANDIDATE = "prevCandidate"; |
| /** The column name of database */ |
| protected static final String COLUMN_NAME_PREVIOUS_POS_LEFT = "prevPosLeft"; |
| /** The column name of database */ |
| protected static final String COLUMN_NAME_PREVIOUS_POS_RIGHT = "prevPosRight"; |
| |
| /** Query for normal search */ |
| protected static final String NORMAL_QUERY = |
| "select distinct " + COLUMN_NAME_STROKE + "," + |
| COLUMN_NAME_CANDIDATE + "," + |
| COLUMN_NAME_POS_LEFT + "," + |
| COLUMN_NAME_POS_RIGHT + "," + |
| COLUMN_NAME_TYPE + |
| " from " + TABLE_NAME_DIC + " where %s order by " + |
| COLUMN_NAME_TYPE + " DESC, %s"; |
| |
| /** Query for link search */ |
| protected static final String LINK_QUERY = |
| "select distinct " + COLUMN_NAME_STROKE + "," + |
| COLUMN_NAME_CANDIDATE + "," + |
| COLUMN_NAME_POS_LEFT + "," + |
| COLUMN_NAME_POS_RIGHT + "," + |
| COLUMN_NAME_TYPE + |
| " from " + TABLE_NAME_DIC + " where %s = ? and %s = ? and %s order by " + |
| COLUMN_NAME_TYPE + " DESC, %s"; |
| |
| /** The max words of user dictionary */ |
| protected static final int MAX_WORDS_IN_USER_DICTIONARY = 100; |
| /** The max words of learning dictionary */ |
| protected static final int MAX_WORDS_IN_LEARN_DICTIONARY = 2000; |
| |
| /** The base frequency of user dictionary */ |
| protected static final int OFFSET_FREQUENCY_OF_USER_DICTIONARY = 1000; |
| /** The base frequency of learning dictionary */ |
| protected static final int OFFSET_FREQUENCY_OF_LEARN_DICTIONARY = 2000; |
| |
| /** |
| * Constants to define the upper limit of query. |
| * |
| * That is used to fix the size of query expression. |
| * If the number of approximate patterns for a character is exceeded MAX_PATTERN_OF_APPROX, |
| * increase that constant to the maximum number of patterns. |
| */ |
| /** Constants to define the upper limit of approximate patterns */ |
| protected final static int MAX_PATTERN_OF_APPROX = 6; |
| /** Constants to define the upper limit of length of a query */ |
| protected final static int MAX_LENGTH_OF_QUERY = 50; |
| /** |
| * Constants to define the turn around time of query. |
| * <br> |
| * It can be set between 1 to MAX_LENGTH_OF_QUERY. If the length of query |
| * string is shorter than FAST_QUERY_LENGTH, the simple search logic is applied. |
| * Therefore, the turn around time for short query string is fast so that it is short. |
| * However, the difference of turn around time at the border length grows big. |
| * the value should be fixed carefully. |
| */ |
| protected final static int FAST_QUERY_LENGTH = 20; |
| |
| /* |
| * DEFINITION OF PRIVATE FIELD |
| */ |
| /** |
| * Internal work area for the dictionary search library. |
| */ |
| protected long mWnnWork = 0; |
| |
| /** |
| * The file path of the writable dictionary |
| */ |
| protected String mDicFilePath = ""; |
| /** |
| * The writable dictionary object |
| */ |
| protected SQLiteDatabase mDbDic = null; |
| /** |
| * The search cursor of the writable dictionary |
| */ |
| protected SQLiteCursor mDbCursor = null; |
| /** |
| * The number of queried items |
| */ |
| protected int mCountCursor = 0; |
| /** |
| * The type of the search cursor object |
| */ |
| protected int mTypeOfQuery = -1; |
| |
| /** The query base strings for query operation */ |
| protected String mExactQuerySqlOrderByFreq; |
| /** The query base strings for query operation */ |
| protected String mExactQuerySqlOrderByKey; |
| |
| /** The query base strings for query operation */ |
| protected String mFullPrefixQuerySqlOrderByFreq; |
| /** The query base strings for query operation */ |
| protected String mFastPrefixQuerySqlOrderByFreq; |
| /** The query base strings for query operation */ |
| protected String mFullPrefixQuerySqlOrderByKey; |
| /** The query base strings for query operation */ |
| protected String mFastPrefixQuerySqlOrderByKey; |
| |
| /** The query base strings for query operation */ |
| protected String mFullLinkQuerySqlOrderByFreq; |
| /** The query base strings for query operation */ |
| protected String mFastLinkQuerySqlOrderByFreq; |
| /** The query base strings for query operation */ |
| protected String mFullLinkQuerySqlOrderByKey; |
| /** The query base strings for query operation */ |
| protected String mFastLinkQuerySqlOrderByKey; |
| |
| /** The string array used by query operation (for "selection") */ |
| protected String mExactQueryArgs[] = new String[ 1 ]; |
| /** The string array used by query operation (for "selection") */ |
| protected String mFullQueryArgs[] = new String[ MAX_LENGTH_OF_QUERY * (MAX_PATTERN_OF_APPROX+1) ]; |
| /** The string array used by query operation (for "selection") */ |
| protected String mFastQueryArgs[] = new String[ FAST_QUERY_LENGTH * (MAX_PATTERN_OF_APPROX+1) ]; |
| |
| /** |
| * The Frequency offset of user dictionary |
| */ |
| protected int mFrequencyOffsetOfUserDictionary = -1; |
| /** |
| * The Frequency offset of learn dictionary |
| */ |
| protected int mFrequencyOffsetOfLearnDictionary = -1; |
| |
| /* |
| * DEFINITION OF METHOD |
| */ |
| /** |
| * The constructor of this class without writable dictionary. |
| * |
| * Create a internal work area for the search engine. It is allocated for each object. |
| * |
| * @param dicLibPath the dictionary library file path |
| */ |
| public OpenWnnDictionaryImpl( String dicLibPath ) { |
| this( dicLibPath, null ); |
| } |
| |
| /** |
| * The constructor of this class with writable dictionary. |
| * |
| * Create a internal work area and the writable dictionary for the search engine. It is allocated for each object. |
| * |
| * @param dicLibPath the dictionary library file path |
| * @param dicFilePath the path name of writable dictionary |
| */ |
| public OpenWnnDictionaryImpl( String dicLibPath, String dicFilePath ) { |
| /* Create the internal work area */ |
| this.mWnnWork = OpenWnnDictionaryImplJni.createWnnWork( dicLibPath ); |
| |
| if( this.mWnnWork != 0 && dicFilePath != null ) { |
| /* Create query base strings */ |
| String queryFullBaseString = |
| OpenWnnDictionaryImplJni.createQueryStringBase( |
| this.mWnnWork, |
| MAX_LENGTH_OF_QUERY, |
| MAX_PATTERN_OF_APPROX, |
| COLUMN_NAME_STROKE ); |
| |
| String queryFastBaseString = |
| OpenWnnDictionaryImplJni.createQueryStringBase( |
| this.mWnnWork, |
| FAST_QUERY_LENGTH, |
| MAX_PATTERN_OF_APPROX, |
| COLUMN_NAME_STROKE ); |
| |
| |
| mExactQuerySqlOrderByFreq = String.format( |
| NORMAL_QUERY, |
| String.format( "%s=?", COLUMN_NAME_STROKE ), String.format( "%s DESC", COLUMN_NAME_ID ) ); |
| |
| mExactQuerySqlOrderByKey = String.format( |
| NORMAL_QUERY, |
| String.format( "%s=?", COLUMN_NAME_STROKE ), COLUMN_NAME_STROKE ); |
| |
| |
| mFullPrefixQuerySqlOrderByFreq = String.format( |
| NORMAL_QUERY, |
| queryFullBaseString, String.format( "%s DESC", COLUMN_NAME_ID ) ); |
| |
| mFastPrefixQuerySqlOrderByFreq = String.format( |
| NORMAL_QUERY, |
| queryFastBaseString, String.format( "%s DESC", COLUMN_NAME_ID ) ); |
| |
| mFullPrefixQuerySqlOrderByKey = String.format( |
| NORMAL_QUERY, |
| queryFullBaseString, COLUMN_NAME_STROKE ); |
| |
| mFastPrefixQuerySqlOrderByKey = String.format( |
| NORMAL_QUERY, |
| queryFastBaseString, COLUMN_NAME_STROKE ); |
| |
| |
| mFullLinkQuerySqlOrderByFreq = String.format( |
| LINK_QUERY, COLUMN_NAME_PREVIOUS_STROKE, COLUMN_NAME_PREVIOUS_CANDIDATE, |
| queryFullBaseString, String.format( "%s DESC", COLUMN_NAME_ID ) ); |
| |
| mFastLinkQuerySqlOrderByFreq = String.format( |
| LINK_QUERY, COLUMN_NAME_PREVIOUS_STROKE, COLUMN_NAME_PREVIOUS_CANDIDATE, |
| queryFastBaseString, String.format( "%s DESC", COLUMN_NAME_ID ) ); |
| |
| mFullLinkQuerySqlOrderByKey = String.format( |
| LINK_QUERY, COLUMN_NAME_PREVIOUS_STROKE, COLUMN_NAME_PREVIOUS_CANDIDATE, |
| queryFullBaseString, COLUMN_NAME_STROKE ); |
| |
| mFastLinkQuerySqlOrderByKey = String.format( |
| LINK_QUERY, COLUMN_NAME_PREVIOUS_STROKE, COLUMN_NAME_PREVIOUS_CANDIDATE, |
| queryFastBaseString, COLUMN_NAME_STROKE ); |
| |
| |
| try { |
| /* Create the database object */ |
| mDicFilePath = dicFilePath; |
| setInUseState( true ); |
| |
| /* Create the table if not exist */ |
| createDictionaryTable( TABLE_NAME_DIC ); |
| } catch( SQLException e ) { |
| } |
| } |
| } |
| |
| /** |
| * The finalizer of this class. |
| * Destroy the internal work area for the search engine. |
| */ |
| protected void finalize( ) { |
| /* Free the internal work area */ |
| if( this.mWnnWork != 0 ) { |
| OpenWnnDictionaryImplJni.freeWnnWork( this.mWnnWork ); |
| this.mWnnWork = 0; |
| |
| freeDatabase(); |
| } |
| } |
| |
| /** |
| * Create the table of writable dictionary |
| * |
| * @param tableName the name of table |
| */ |
| protected void createDictionaryTable( String tableName ) { |
| String sqlStr = "create table if not exists " + tableName + |
| " (" + COLUMN_NAME_ID + " integer primary key autoincrement, " + |
| COLUMN_NAME_TYPE + " integer, " + |
| COLUMN_NAME_STROKE + " text, " + |
| COLUMN_NAME_CANDIDATE + " text, " + |
| COLUMN_NAME_POS_LEFT + " integer, " + |
| COLUMN_NAME_POS_RIGHT + " integer, " + |
| COLUMN_NAME_PREVIOUS_STROKE + " text, " + |
| COLUMN_NAME_PREVIOUS_CANDIDATE + " text, " + |
| COLUMN_NAME_PREVIOUS_POS_LEFT + " integer, " + |
| COLUMN_NAME_PREVIOUS_POS_RIGHT + " integer)"; |
| |
| if( mDbDic != null ) { |
| mDbDic.execSQL( sqlStr ); |
| } |
| } |
| |
| /** |
| * Free the SQLiteDatabase of writable dictionary |
| */ |
| protected void freeDatabase( ) { |
| freeCursor(); |
| |
| if( mDbDic != null ) { |
| /* The SQLiteDataBase object must close() before releasing. */ |
| mDbDic.close(); |
| mDbDic = null; |
| } |
| } |
| /** |
| * Free the SQLiteCursor of writable dictionary |
| */ |
| protected void freeCursor( ) { |
| if( mDbCursor != null) { |
| /* The SQLiteCursor object must close() before releasing. */ |
| mDbCursor.close(); |
| mDbCursor = null; |
| |
| mTypeOfQuery = -1; |
| } |
| } |
| |
| /** |
| * @see jp.co.omronsoft.openwnn.WnnDictionary#setInUseState |
| */ |
| public void setInUseState( boolean flag ) { |
| if( flag ) { |
| if( mDbDic == null ) { |
| mDbDic = SQLiteDatabase.openOrCreateDatabase( mDicFilePath, null ); |
| } |
| } else { |
| freeDatabase(); |
| } |
| } |
| |
| /** |
| * @see jp.co.omronsoft.openwnn.WnnDictionary#clearDictionary |
| */ |
| public int clearDictionary( ) { |
| if( this.mWnnWork != 0 ) { |
| mFrequencyOffsetOfUserDictionary = -1; |
| mFrequencyOffsetOfLearnDictionary = -1; |
| |
| return OpenWnnDictionaryImplJni.clearDictionaryParameters( this.mWnnWork ); |
| } else { |
| return -1; |
| } |
| } |
| |
| /** |
| * @see jp.co.omronsoft.openwnn.WnnDictionary#setDictionary |
| */ |
| public int setDictionary(int index, int base, int high ) { |
| if( this.mWnnWork != 0 ) { |
| switch( index ) { |
| case WnnDictionary.INDEX_USER_DICTIONARY: |
| if( base < 0 || high < 0 || base > high |
| /* || base < OFFSET_FREQUENCY_OF_USER_DICTIONARY || high >= OFFSET_FREQUENCY_OF_LEARN_DICTIONARY */ ) { |
| mFrequencyOffsetOfUserDictionary = -1; |
| } else { |
| mFrequencyOffsetOfUserDictionary = high; |
| } |
| return 0; |
| case WnnDictionary.INDEX_LEARN_DICTIONARY: |
| if( base < 0 || high < 0 || base > high |
| /* || base < OFFSET_FREQUENCY_OF_LEARN_DICTIONARY */ ) { |
| mFrequencyOffsetOfLearnDictionary = -1; |
| } else { |
| mFrequencyOffsetOfLearnDictionary = high; |
| } |
| return 0; |
| default: |
| return OpenWnnDictionaryImplJni.setDictionaryParameter( this.mWnnWork, index, base, high ); |
| } |
| } else { |
| return -1; |
| } |
| } |
| |
| /** |
| * Query to the database |
| * |
| * @param keyString the key string |
| * @param wnnWord the previous word for link search |
| * @param operation the search operation |
| * @param order the type of sort order |
| */ |
| protected void createQuery( String keyString, WnnWord wnnWord, int operation, int order) { |
| int newTypeOfQuery, maxBindsOfQuery; |
| String querySqlOrderByFreq, querySqlOrderByKey; |
| String queryArgs[]; |
| |
| if( operation != WnnDictionary.SEARCH_LINK ) { |
| wnnWord = null; |
| } |
| |
| switch( operation ) { |
| case WnnDictionary.SEARCH_EXACT: |
| querySqlOrderByFreq = mExactQuerySqlOrderByFreq; |
| querySqlOrderByKey = mExactQuerySqlOrderByKey; |
| newTypeOfQuery = 0; |
| queryArgs = mExactQueryArgs; |
| |
| queryArgs[ 0 ] = keyString; |
| break; |
| |
| case WnnDictionary.SEARCH_PREFIX: |
| case WnnDictionary.SEARCH_LINK: |
| /* Select the suitable paramters for the query */ |
| if( keyString.length() <= FAST_QUERY_LENGTH ) { |
| if( wnnWord != null ) { |
| querySqlOrderByFreq = mFastLinkQuerySqlOrderByFreq; |
| querySqlOrderByKey = mFastLinkQuerySqlOrderByKey; |
| newTypeOfQuery = 1; |
| } else { |
| querySqlOrderByFreq = mFastPrefixQuerySqlOrderByFreq; |
| querySqlOrderByKey = mFastPrefixQuerySqlOrderByKey; |
| newTypeOfQuery = 2; |
| } |
| maxBindsOfQuery = FAST_QUERY_LENGTH; |
| queryArgs = mFastQueryArgs; |
| } else { |
| if( wnnWord != null ) { |
| querySqlOrderByFreq = mFullLinkQuerySqlOrderByFreq; |
| querySqlOrderByKey = mFullLinkQuerySqlOrderByKey; |
| newTypeOfQuery = 3; |
| } else { |
| querySqlOrderByFreq = mFullPrefixQuerySqlOrderByFreq; |
| querySqlOrderByKey = mFullPrefixQuerySqlOrderByKey; |
| newTypeOfQuery = 4; |
| } |
| maxBindsOfQuery = MAX_LENGTH_OF_QUERY; |
| queryArgs = mFullQueryArgs; |
| } |
| |
| if( wnnWord != null ) { |
| /* If link search is enabled, insert information of the previous word */ |
| String[] queryArgsTemp = OpenWnnDictionaryImplJni.createBindArray( this.mWnnWork, keyString, maxBindsOfQuery, MAX_PATTERN_OF_APPROX ); |
| |
| queryArgs = new String[ queryArgsTemp.length + 2 ]; |
| for( int i = 0 ; i < queryArgsTemp.length ; i++ ) { |
| queryArgs[ i + 2 ] = queryArgsTemp[ i ]; |
| } |
| |
| queryArgs[ 0 ] = wnnWord.stroke; |
| queryArgs[ 1 ] = wnnWord.candidate; |
| } else { |
| queryArgs = OpenWnnDictionaryImplJni.createBindArray( this.mWnnWork, keyString, maxBindsOfQuery, MAX_PATTERN_OF_APPROX ); |
| } |
| break; |
| |
| default: |
| mCountCursor = 0; |
| freeCursor( ); |
| return; |
| } |
| |
| /* Create the cursor and set arguments */ |
| mCountCursor = 0; |
| |
| if( mDbCursor == null || mTypeOfQuery != newTypeOfQuery ) { |
| /* If the cursor is not exist or the type of query is changed, compile the query string and query words */ |
| freeCursor( ); |
| |
| try { |
| switch( order ) { |
| case WnnDictionary.ORDER_BY_FREQUENCY: |
| mDbCursor = ( SQLiteCursor )mDbDic.rawQuery( querySqlOrderByFreq, queryArgs ); |
| break; |
| case WnnDictionary.ORDER_BY_KEY: |
| mDbCursor = ( SQLiteCursor )mDbDic.rawQuery( querySqlOrderByKey, queryArgs ); |
| break; |
| default: |
| return; |
| } |
| } catch( SQLException e ) { |
| return; |
| } |
| |
| mTypeOfQuery = newTypeOfQuery; |
| } else { |
| /* If the cursor is exist, bind new arguments and requery words (DO NOT recompile the query string) */ |
| try { |
| mDbCursor.setSelectionArguments( queryArgs ); |
| mDbCursor.requery( ); |
| } catch( SQLException e ) { |
| return; |
| } |
| } |
| |
| if( mDbCursor != null ) { |
| /* If querying is succeed, count the number of words */ |
| mCountCursor = mDbCursor.getCount(); |
| if( mCountCursor == 0 ) { |
| /* If no word is retrieved, deactivate the cursor for reduce the resource */ |
| mDbCursor.deactivate( ); |
| } |
| } |
| |
| return; |
| } |
| |
| /** |
| * @see jp.co.omronsoft.openwnn.WnnDictionary#searchWord |
| */ |
| public int searchWord( int operation, int order, String keyString ) { |
| /* Unset the previous word information */ |
| OpenWnnDictionaryImplJni.clearResult( this.mWnnWork ); |
| |
| /* Search to user/learn dictionary */ |
| if( mDbDic != null && ( mFrequencyOffsetOfUserDictionary >= 0 || |
| mFrequencyOffsetOfLearnDictionary >= 0 ) ) { |
| try { |
| if( keyString.length() > 0 ) { |
| createQuery( keyString, null, operation, order ); |
| if( mDbCursor != null ) { |
| mDbCursor.moveToFirst(); |
| } |
| } else { |
| /* If the key string is "", no word is retrieved */ |
| if( mDbCursor != null ) { |
| mDbCursor.deactivate(); |
| } |
| mCountCursor = 0; |
| } |
| } catch( SQLException e ) { |
| if( mDbCursor != null ) { |
| mDbCursor.deactivate(); |
| } |
| mCountCursor = 0; |
| } |
| } else { |
| mCountCursor = 0; |
| } |
| |
| /* Search to fixed dictionary */ |
| if( this.mWnnWork != 0 ) { |
| return OpenWnnDictionaryImplJni.searchWord( this.mWnnWork, operation, order, keyString ); |
| } else { |
| return -1; |
| } |
| } |
| |
| /** |
| * @see jp.co.omronsoft.openwnn.WnnDictionary#searchWord |
| */ |
| public int searchWord( int operation, int order, String keyString, WnnWord wnnWord ) { |
| if( wnnWord == null || wnnWord.partOfSpeech == null ) { |
| return -1; |
| } |
| |
| /* Search to user/learn dictionary with link information */ |
| if( mDbDic != null && ( mFrequencyOffsetOfUserDictionary >= 0 || |
| mFrequencyOffsetOfLearnDictionary >= 0 ) ) { |
| try { |
| createQuery( keyString, wnnWord, operation, order ); |
| if( mDbCursor != null ) { |
| mDbCursor.moveToFirst(); |
| } |
| } catch( SQLException e ) { |
| if( mDbCursor != null ) { |
| mDbCursor.deactivate(); |
| } |
| mCountCursor = 0; |
| } |
| } else { |
| mCountCursor = 0; |
| } |
| |
| /* Search to fixed dictionary with link information */ |
| OpenWnnDictionaryImplJni.clearResult( this.mWnnWork ); |
| OpenWnnDictionaryImplJni.setStroke( this.mWnnWork, wnnWord.stroke ); |
| OpenWnnDictionaryImplJni.setCandidate( this.mWnnWork, wnnWord.candidate ); |
| OpenWnnDictionaryImplJni.setLeftPartOfSpeech( this.mWnnWork, wnnWord.partOfSpeech.left ); |
| OpenWnnDictionaryImplJni.setRightPartOfSpeech( this.mWnnWork, wnnWord.partOfSpeech.right ); |
| OpenWnnDictionaryImplJni.selectWord( this.mWnnWork ); |
| |
| if( this.mWnnWork != 0 ) { |
| return OpenWnnDictionaryImplJni.searchWord( this.mWnnWork, operation, order, keyString ); |
| } else { |
| return -1; |
| } |
| } |
| |
| /** |
| * @see jp.co.omronsoft.openwnn.WnnDictionary#getNextWord |
| */ |
| public WnnWord getNextWord( ) { |
| if( this.mWnnWork != 0 ) { |
| if( mDbDic != null && mDbCursor != null && mCountCursor > 0 ) { |
| /* If the user/learn dictionary is queried, get the result from the user/learn dictionary */ |
| WnnWord result = new WnnWord( ); |
| try { |
| /* Skip results if that is not contained the type of search */ |
| while( mCountCursor > 0 && |
| ( ( mFrequencyOffsetOfUserDictionary < 0 && mDbCursor.getInt( 4 ) == TYPE_NAME_USER ) || |
| ( mFrequencyOffsetOfLearnDictionary < 0 && mDbCursor.getInt( 4 ) == TYPE_NAME_LEARN ) ) ) { |
| mDbCursor.moveToNext(); |
| mCountCursor--; |
| } |
| |
| if( mCountCursor > 0 ) { |
| /* Get the information of word */ |
| result.stroke = mDbCursor.getString( 0 ); |
| result.candidate = mDbCursor.getString( 1 ); |
| result.partOfSpeech.left = mDbCursor.getInt( 2 ); |
| result.partOfSpeech.right = mDbCursor.getInt( 3 ); |
| |
| if( mDbCursor.getInt( 4 ) == TYPE_NAME_USER ) { |
| result.frequency = mFrequencyOffsetOfUserDictionary; |
| } else { |
| result.frequency = mFrequencyOffsetOfLearnDictionary; |
| } |
| |
| /* Move cursor to next result. If the next result is not exist, deactivate the cursor */ |
| mDbCursor.moveToNext(); |
| if( --mCountCursor <= 0 ) { |
| mDbCursor.deactivate(); |
| } |
| |
| return result; |
| } else { |
| /* if no result is found, terminate the searching of user/learn dictionary */ |
| mDbCursor.deactivate(); |
| result = null; |
| } |
| } catch( SQLException e ) { |
| mDbCursor.deactivate(); |
| mCountCursor = 0; |
| result = null; |
| } |
| } |
| |
| /* Get the result from fixed dictionary */ |
| int res = OpenWnnDictionaryImplJni.getNextWord( this.mWnnWork ); |
| if( res > 0 ) { |
| WnnWord result = new WnnWord( ); |
| if( result != null ) { |
| result.stroke = OpenWnnDictionaryImplJni.getStroke( this.mWnnWork ); |
| result.candidate = OpenWnnDictionaryImplJni.getCandidate( this.mWnnWork ); |
| result.frequency = OpenWnnDictionaryImplJni.getFrequency( this.mWnnWork ); |
| result.partOfSpeech.left = OpenWnnDictionaryImplJni.getLeftPartOfSpeech( this.mWnnWork ); |
| result.partOfSpeech.right = OpenWnnDictionaryImplJni.getRightPartOfSpeech( this.mWnnWork ); |
| } |
| return result; |
| } else if ( res == 0 ) { |
| /* No result is found. */ |
| return null; |
| } else { |
| /* An error occur (It is regarded as "No result is found".) */ |
| return null; |
| } |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * @see jp.co.omronsoft.openwnn.WnnDictionary#getUserDictionaryWords |
| */ |
| public WnnWord[] getUserDictionaryWords( ) { |
| if( this.mWnnWork != 0 && mDbDic != null ) { |
| int numOfWords, i; |
| SQLiteCursor cursor = null; |
| |
| try { |
| /* Count all words in the user dictionary */ |
| cursor = ( SQLiteCursor )mDbDic.query( |
| TABLE_NAME_DIC, |
| new String[] { COLUMN_NAME_STROKE, COLUMN_NAME_CANDIDATE }, |
| String.format( "%s=%d", COLUMN_NAME_TYPE, TYPE_NAME_USER ), |
| null, null, null, null); |
| numOfWords = cursor.getCount(); |
| |
| if( numOfWords > 0 ) { |
| /* Retrieve all words in the user dictionary */ |
| WnnWord[] words = new WnnWord[ numOfWords ]; |
| |
| cursor.moveToFirst(); |
| for( i = 0 ; i < numOfWords ; i++ ) { |
| words[ i ] = new WnnWord(); |
| words[ i ].stroke = cursor.getString( 0 ); |
| words[ i ].candidate = cursor.getString( 1 ); |
| cursor.moveToNext(); |
| } |
| |
| return words; |
| } |
| } catch( SQLException e ) { |
| /* An error occurs */ |
| return null; |
| } finally { |
| if( cursor != null ) { |
| cursor.close( ); |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * @see jp.co.omronsoft.openwnn.WnnDictionary#clearApproxPattern |
| */ |
| public void clearApproxPattern( ) { |
| if( this.mWnnWork != 0 ) { |
| OpenWnnDictionaryImplJni.clearApproxPatterns( this.mWnnWork ); |
| } |
| } |
| |
| /** |
| * @see jp.co.omronsoft.openwnn.WnnDictionary#setApproxPattern |
| */ |
| public int setApproxPattern( String src, String dst ) { |
| if( this.mWnnWork != 0 ) { |
| return OpenWnnDictionaryImplJni.setApproxPattern( this.mWnnWork, src, dst ); |
| } else { |
| return -1; |
| } |
| } |
| |
| /** |
| * @see jp.co.omronsoft.openwnn.WnnDictionary#setApproxPattern |
| */ |
| public int setApproxPattern( int approxPattern ) { |
| if( this.mWnnWork != 0 ) { |
| return OpenWnnDictionaryImplJni.setApproxPattern( this.mWnnWork, approxPattern ); |
| } else { |
| return -1; |
| } |
| } |
| |
| /** |
| * @see jp.co.omronsoft.openwnn.WnnDictionary#getConnectMatrix |
| */ |
| public byte[][] getConnectMatrix( ) { |
| byte[][] result; |
| int lcount, i; |
| |
| /* 1-origin */ |
| lcount = OpenWnnDictionaryImplJni.getNumberOfLeftPOS( this.mWnnWork ); |
| result = new byte[ lcount + 1 ][ ]; |
| |
| if( result != null ) { |
| for( i = 0 ; i < lcount + 1 ; i++ ) { |
| result[ i ] = OpenWnnDictionaryImplJni.getConnectArray( this.mWnnWork, i ); |
| |
| if( result[ i ] == null ) { |
| return null; |
| } |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * @see jp.co.omronsoft.openwnn.WnnDictionary#getPOS |
| */ |
| public WnnPOS getPOS( int type ) { |
| WnnPOS result = new WnnPOS( ); |
| |
| if( result != null ) { |
| result.left = OpenWnnDictionaryImplJni.getLeftPartOfSpeechSpecifiedType( this.mWnnWork, type ); |
| result.right = OpenWnnDictionaryImplJni.getRightPartOfSpeechSpecifiedType( this.mWnnWork, type ); |
| |
| if( result.left < 0 || result.right < 0 ) { |
| return null; |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * @see jp.co.omronsoft.openwnn.WnnDictionary#clearUserDictionary |
| */ |
| public int clearUserDictionary() { |
| if( mDbDic != null ) { |
| mDbDic.execSQL( String.format( "delete from %s where %s=%d", TABLE_NAME_DIC, COLUMN_NAME_TYPE, TYPE_NAME_USER ) ); |
| } |
| |
| /* If no writable dictionary exists, no error occurs. */ |
| return 0; |
| } |
| |
| /** |
| * @see jp.co.omronsoft.openwnn.WnnDictionary#clearLearnDictionary |
| */ |
| public int clearLearnDictionary() { |
| if( mDbDic != null ) { |
| mDbDic.execSQL( String.format( "delete from %s where %s=%d", TABLE_NAME_DIC, COLUMN_NAME_TYPE, TYPE_NAME_LEARN ) ); |
| } |
| |
| /* If no writable dictionary exists, no error occurs. */ |
| return 0; |
| } |
| |
| /** |
| * @see jp.co.omronsoft.openwnn.WnnDictionary#addWordToUserDictionary |
| */ |
| public int addWordToUserDictionary( WnnWord[] word ) { |
| int result = 0; |
| |
| if( mDbDic != null ) { |
| SQLiteCursor cursor; |
| |
| /* Count all words in the user dictionary */ |
| cursor = ( SQLiteCursor )mDbDic.query( |
| TABLE_NAME_DIC, |
| new String[] { COLUMN_NAME_ID }, |
| String.format( "%s=%d", COLUMN_NAME_TYPE, TYPE_NAME_USER ), |
| null, null, null, null); |
| |
| int count = cursor.getCount(); |
| cursor.close(); |
| |
| if( count + word.length > MAX_WORDS_IN_USER_DICTIONARY ) { |
| /* If user dictionary is full, an error occurs. */ |
| return -1; |
| } else { |
| mDbDic.beginTransaction(); |
| try { |
| StringBuilder strokeSQL = new StringBuilder(); |
| StringBuilder candidateSQL = new StringBuilder(); |
| |
| for( int index = 0 ; index < word.length ; index++ ) { |
| if( word[index].stroke.length() > 0 && word[index].stroke.length() <= MAX_STROKE_LENGTH && |
| word[index].candidate.length() > 0 && word[index].candidate.length() <= MAX_CANDIDATE_LENGTH ) { |
| strokeSQL.setLength( 0 ); |
| candidateSQL.setLength( 0 ); |
| DatabaseUtils.appendEscapedSQLString( strokeSQL, word[index].stroke ); |
| DatabaseUtils.appendEscapedSQLString( candidateSQL, word[index].candidate ); |
| |
| cursor = ( SQLiteCursor )mDbDic.query( |
| TABLE_NAME_DIC, |
| new String[] { COLUMN_NAME_ID }, |
| String.format( "%s=%d and %s=%s and %s=%s", |
| COLUMN_NAME_TYPE, TYPE_NAME_USER, |
| COLUMN_NAME_STROKE, strokeSQL.toString(), |
| COLUMN_NAME_CANDIDATE, candidateSQL.toString() ), |
| null, null, null, null ); |
| |
| if( cursor.getCount() > 0 ) { |
| /* if the specified word is exist, an error reported and skipped that word. */ |
| result = -2; |
| } else { |
| ContentValues content = new ContentValues(); |
| |
| content.clear(); |
| content.put( COLUMN_NAME_TYPE, TYPE_NAME_USER ); |
| content.put( COLUMN_NAME_STROKE, word[index].stroke ); |
| content.put( COLUMN_NAME_CANDIDATE, word[index].candidate ); |
| content.put( COLUMN_NAME_POS_LEFT, word[index].partOfSpeech.left ); |
| content.put( COLUMN_NAME_POS_RIGHT, word[index].partOfSpeech.right ); |
| |
| mDbDic.insert( TABLE_NAME_DIC, null, content ); |
| } |
| |
| cursor.close( ); |
| cursor = null; |
| } |
| } |
| mDbDic.setTransactionSuccessful(); |
| } catch( SQLException e ) { |
| /* An error occurs */ |
| return -1; |
| } finally { |
| mDbDic.endTransaction(); |
| if( cursor != null ) { |
| cursor.close( ); |
| } |
| } |
| } |
| } |
| |
| /* If no writable dictionary exists, no error occurs. */ |
| return result; |
| } |
| |
| /** |
| * @see jp.co.omronsoft.openwnn.WnnDictionary#addWordToUserDictionary |
| */ |
| public int addWordToUserDictionary( WnnWord word ) { |
| WnnWord[] words = new WnnWord[1]; |
| words[0] = word; |
| |
| return addWordToUserDictionary( words ); |
| } |
| |
| /** |
| * @see jp.co.omronsoft.openwnn.WnnDictionary#removeWordFromUserDictionary |
| */ |
| public int removeWordFromUserDictionary( WnnWord[] word ) { |
| if( mDbDic != null ) { |
| /* Remove the specified word */ |
| mDbDic.beginTransaction(); |
| try { |
| StringBuilder strokeSQL = new StringBuilder(); |
| StringBuilder candidateSQL = new StringBuilder(); |
| |
| for( int index = 0 ; index < word.length ; index++ ) { |
| if( word[index].stroke.length() > 0 && word[index].stroke.length() <= MAX_STROKE_LENGTH && |
| word[index].candidate.length() > 0 && word[index].candidate.length() <= MAX_CANDIDATE_LENGTH ) { |
| strokeSQL.setLength( 0 ); |
| candidateSQL.setLength( 0 ); |
| DatabaseUtils.appendEscapedSQLString( strokeSQL, word[index].stroke ); |
| DatabaseUtils.appendEscapedSQLString( candidateSQL, word[index].candidate ); |
| |
| mDbDic.delete( TABLE_NAME_DIC, |
| String.format( "%s=%d and %s=%s and %s=%s", |
| COLUMN_NAME_TYPE, TYPE_NAME_USER, |
| COLUMN_NAME_STROKE, strokeSQL, |
| COLUMN_NAME_CANDIDATE, candidateSQL ), |
| null ); |
| } |
| } |
| mDbDic.setTransactionSuccessful(); |
| } catch( SQLException e ) { |
| /* An error occurs */ |
| return -1; |
| } finally { |
| mDbDic.endTransaction(); |
| } |
| } |
| |
| /* If no writable dictionary exists, no error occurs. */ |
| return 0; |
| } |
| |
| /** |
| * @see jp.co.omronsoft.openwnn.WnnDictionary#removeWordFromUserDictionary |
| */ |
| public int removeWordFromUserDictionary( WnnWord word ) { |
| WnnWord[] words = new WnnWord[1]; |
| words[0] = word; |
| |
| return removeWordFromUserDictionary( words ); |
| } |
| |
| /** |
| * @see jp.co.omronsoft.openwnn.WnnDictionary#learnWord |
| */ |
| public int learnWord( WnnWord word ) { |
| return learnWord( word, null ); |
| } |
| |
| /** |
| * Learn the word with connection. |
| */ |
| public int learnWord( WnnWord word, WnnWord previousWord ) { |
| if( mDbDic != null ) { |
| StringBuilder previousStrokeSQL = new StringBuilder(); |
| StringBuilder previousCandidateSQL = new StringBuilder(); |
| boolean isConnectLearn = false; |
| |
| if( previousWord != null && |
| previousWord.stroke.length() > 0 && previousWord.stroke.length() <= MAX_STROKE_LENGTH && |
| previousWord.candidate.length() > 0 && previousWord.candidate.length() <= MAX_CANDIDATE_LENGTH ) { |
| DatabaseUtils.appendEscapedSQLString( previousStrokeSQL, previousWord.stroke ); |
| DatabaseUtils.appendEscapedSQLString( previousCandidateSQL, previousWord.candidate ); |
| /* If the information of previous word is set, perform the link learning */ |
| isConnectLearn = true; |
| } |
| |
| if( word.stroke.length() > 0 && word.stroke.length() <= MAX_STROKE_LENGTH && |
| word.candidate.length() > 0 && word.candidate.length() <= MAX_CANDIDATE_LENGTH ) { |
| StringBuilder strokeSQL = new StringBuilder(); |
| StringBuilder candidateSQL = new StringBuilder(); |
| DatabaseUtils.appendEscapedSQLString( strokeSQL, word.stroke ); |
| DatabaseUtils.appendEscapedSQLString( candidateSQL, word.candidate ); |
| |
| SQLiteCursor cursor; |
| |
| /* If the words which have same stroke and same candidate is already learned, move to the tail */ |
| cursor = ( SQLiteCursor )mDbDic.query( |
| TABLE_NAME_DIC, |
| new String[] { COLUMN_NAME_ID, |
| COLUMN_NAME_STROKE, |
| COLUMN_NAME_CANDIDATE, |
| COLUMN_NAME_POS_LEFT, |
| COLUMN_NAME_POS_RIGHT, |
| COLUMN_NAME_PREVIOUS_STROKE, |
| COLUMN_NAME_PREVIOUS_CANDIDATE, |
| COLUMN_NAME_PREVIOUS_POS_LEFT, |
| COLUMN_NAME_PREVIOUS_POS_RIGHT }, |
| String.format( "%s=%d and %s=%s and %s=%s", |
| COLUMN_NAME_TYPE, TYPE_NAME_LEARN, |
| COLUMN_NAME_STROKE, strokeSQL.toString(), |
| COLUMN_NAME_CANDIDATE, candidateSQL.toString() ), |
| null, null, null, |
| String.format( "%s ASC", COLUMN_NAME_ID ) ); |
| |
| if( cursor.getCount() > 0 ) { |
| /* The results are arranged ascending by the ID. In other words, The results are arranged in an old turn. */ |
| cursor.moveToFirst( ); |
| |
| ContentValues content = new ContentValues(); |
| int[] idArray = new int[ cursor.getCount() ]; |
| int idIndex = 0; |
| |
| boolean isExistConnectLearnData = false; |
| |
| mDbDic.beginTransaction(); |
| try { |
| do { |
| /* Record the ID that is removed later */ |
| idArray[ idIndex++ ] = cursor.getInt( 0 ); |
| |
| /* Add the word to tail */ |
| content.clear(); |
| content.put( COLUMN_NAME_TYPE, TYPE_NAME_LEARN ); |
| content.put( COLUMN_NAME_STROKE, cursor.getString( 1 ) ); |
| content.put( COLUMN_NAME_CANDIDATE, cursor.getString( 2 ) ); |
| content.put( COLUMN_NAME_POS_LEFT, cursor.getInt( 3 ) ); |
| content.put( COLUMN_NAME_POS_RIGHT, cursor.getInt( 4 ) ); |
| content.put( COLUMN_NAME_PREVIOUS_STROKE, cursor.getString( 5 ) ); |
| content.put( COLUMN_NAME_PREVIOUS_CANDIDATE, cursor.getString( 6 ) ); |
| content.put( COLUMN_NAME_PREVIOUS_POS_LEFT, cursor.getInt( 7 ) ); |
| content.put( COLUMN_NAME_PREVIOUS_POS_RIGHT, cursor.getInt( 8 ) ); |
| mDbDic.insert( TABLE_NAME_DIC, null, content ); |
| |
| /* If the word that contain same link information exist, need NOT to add link information. */ |
| if( isConnectLearn && |
| previousWord.stroke.equals( cursor.getString( 5 ) ) && |
| previousWord.candidate.equals( cursor.getString( 6 ) ) ) { |
| isExistConnectLearnData = true; |
| } |
| } while( cursor.moveToNext( ) ); |
| |
| /* Delete the recorded words */ |
| while( --idIndex >= 0 ) { |
| mDbDic.delete( TABLE_NAME_DIC, |
| String.format( "%s=%d", COLUMN_NAME_ID, idArray[ idIndex ] ), |
| null ); |
| } |
| |
| mDbDic.setTransactionSuccessful(); |
| |
| /* If the link information is not specified or the word that contain same link information exist, */ |
| /* need NOT to add link information. Otherwise, go to next section for adding link information. */ |
| if( !isConnectLearn || isExistConnectLearnData ) { |
| return 0; |
| } |
| } catch( SQLException e ) { |
| return -1; |
| } finally { |
| mDbDic.endTransaction(); |
| cursor.close(); |
| } |
| } else { |
| cursor.close(); |
| } |
| |
| /* Count the number of registered words and retrieve that words ascending by the ID */ |
| cursor = ( SQLiteCursor )mDbDic.query( |
| TABLE_NAME_DIC, |
| new String[] { COLUMN_NAME_STROKE, COLUMN_NAME_CANDIDATE }, |
| String.format( "%s=%d", COLUMN_NAME_TYPE, TYPE_NAME_LEARN ), |
| null, null, null, |
| String.format( "%s ASC", COLUMN_NAME_ID ) ); |
| |
| if( cursor.getCount( ) >= MAX_WORDS_IN_LEARN_DICTIONARY ) { |
| /* If a registering space is short, delete the words that contain same stroke and candidate to the oldest word */ |
| mDbDic.beginTransaction(); |
| try { |
| cursor.moveToFirst( ); |
| |
| StringBuilder oldestStrokeSQL = new StringBuilder(); |
| StringBuilder oldestCandidateSQL = new StringBuilder(); |
| DatabaseUtils.appendEscapedSQLString( oldestStrokeSQL, cursor.getString( 0 ) ); |
| DatabaseUtils.appendEscapedSQLString( oldestCandidateSQL, cursor.getString( 1 ) ); |
| |
| mDbDic.delete( TABLE_NAME_DIC, |
| String.format( "%s=%d and %s=%s and %s=%s", |
| COLUMN_NAME_TYPE, TYPE_NAME_LEARN, |
| COLUMN_NAME_STROKE, oldestStrokeSQL.toString( ), |
| COLUMN_NAME_CANDIDATE, oldestCandidateSQL.toString( ) ), |
| null ); |
| |
| mDbDic.setTransactionSuccessful(); |
| } catch( SQLException e ) { |
| return -1; |
| } finally { |
| mDbDic.endTransaction(); |
| cursor.close(); |
| } |
| } else { |
| cursor.close(); |
| } |
| |
| /* learning the word */ |
| ContentValues content = new ContentValues(); |
| |
| content.clear(); |
| content.put( COLUMN_NAME_TYPE, TYPE_NAME_LEARN ); |
| content.put( COLUMN_NAME_STROKE, word.stroke ); |
| content.put( COLUMN_NAME_CANDIDATE, word.candidate ); |
| content.put( COLUMN_NAME_POS_LEFT, word.partOfSpeech.left ); |
| content.put( COLUMN_NAME_POS_RIGHT, word.partOfSpeech.right ); |
| if( previousWord != null ) { |
| content.put( COLUMN_NAME_PREVIOUS_STROKE, previousWord.stroke ); |
| content.put( COLUMN_NAME_PREVIOUS_CANDIDATE, previousWord.candidate ); |
| content.put( COLUMN_NAME_PREVIOUS_POS_LEFT, previousWord.partOfSpeech.left ); |
| content.put( COLUMN_NAME_PREVIOUS_POS_RIGHT, previousWord.partOfSpeech.right ); |
| } |
| |
| mDbDic.beginTransaction(); |
| try { |
| mDbDic.insert( TABLE_NAME_DIC, null, content ); |
| mDbDic.setTransactionSuccessful(); |
| } catch( SQLException e ) { |
| mDbDic.endTransaction(); |
| return -1; |
| } finally { |
| mDbDic.endTransaction(); |
| } |
| } |
| } |
| |
| /* If no writable dictionary exists, no error occurs. */ |
| return 0; |
| } |
| } |