/* * Copyright (C) 2008-2012 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.database.DatabaseUtils; import android.database.SQLException; import android.database.sqlite.SQLiteCursor; import android.database.sqlite.SQLiteDatabase; import android.util.Log; /** * The implementation class of WnnDictionary interface (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 {@code MAX_LENGTH_OF_QUERY}. If the length of query * string is shorter than {@code 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 writable dictionary object Access helper */ protected OpenWnnSQLiteOpenHelper mDbOpenHelper = 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 METHODS */ /** * 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 {@link SQLiteDatabase} of writable dictionary. */ protected void freeDatabase( ) { freeCursor(); if( mDbDic != null ) { /* The SQLiteDataBase object must close() before releasing. */ mDbDic.close(); mDbDic = null; mDbOpenHelper = null; } } /** * Free the {@link 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 boolean isActive() { return (this.mWnnWork != 0); } /** * @see jp.co.omronsoft.openwnn.WnnDictionary#setInUseState */ public void setInUseState( boolean flag ) { if( flag ) { if( mDbDic == null ) { mDbOpenHelper = new OpenWnnSQLiteOpenHelper(OpenWnn.getCurrentIme(), mDicFilePath); mDbDic = mDbOpenHelper.getWritableDatabase(); } } 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 parameters 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 re-query 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 ) { int ret = OpenWnnDictionaryImplJni.searchWord( this.mWnnWork, operation, order, keyString ); if (mCountCursor > 0) { ret = 1; } return ret; } 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 ) { int ret = OpenWnnDictionaryImplJni.searchWord( this.mWnnWork, operation, order, keyString ); if (mCountCursor > 0) { ret = 1; } return ret; } else { return -1; } } /** * @see jp.co.omronsoft.openwnn.WnnDictionary#getNextWord */ public WnnWord getNextWord( ) { return getNextWord( 0 ); } /** * @see jp.co.omronsoft.openwnn.WnnDictionary#getNextWord */ public WnnWord getNextWord( int length ) { 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 or length of stroke is not equal specified length */ while( mCountCursor > 0 && ( ( mFrequencyOffsetOfUserDictionary < 0 && mDbCursor.getInt( 4 ) == TYPE_NAME_USER ) || ( mFrequencyOffsetOfLearnDictionary < 0 && mDbCursor.getInt( 4 ) == TYPE_NAME_LEARN ) || ( length > 0 && mDbCursor.getString( 0 ).length( ) != length ) ) ) { 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, length ); 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; if (this.mWnnWork != 0) { /* 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; } } } } else { result = new byte[1][1]; } return result; } /** * @see jp.co.omronsoft.openwnn.WnnDictionary#getPOS */ public WnnPOS getPOS( int type ) { WnnPOS result = new WnnPOS( ); if( this.mWnnWork != 0 && 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. * * @param word The word to learn * @param previousWord The word which is selected previously. * @return 0 if success; minus value if fail. */ public int learnWord( WnnWord word, WnnWord previousWord ) { if( mDbDic != null ) { StringBuilder previousStrokeSQL = new StringBuilder(); StringBuilder previousCandidateSQL = new StringBuilder(); 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 */ } 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; /* 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; } }