• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
OpenWnnDictionaryImpl( String dicLibPath )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      */
OpenWnnDictionaryImpl( String dicLibPath, String dicFilePath )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      */
finalize( )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      */
createDictionaryTable( String tableName )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      */
freeDatabase( )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      */
freeCursor( )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      */
isActive()347     public boolean isActive() {
348         return (this.mWnnWork != 0);
349     }
350 
351     /**
352      * @see jp.co.omronsoft.openwnn.WnnDictionary#setInUseState
353      */
setInUseState( boolean flag )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      */
clearDictionary( )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      */
setDictionary(int index, int base, int high )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      */
createQuery( String keyString, WnnWord wnnWord, int operation, int order)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      */
searchWord( int operation, int order, String keyString )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      */
searchWord( int operation, int order, String keyString, WnnWord wnnWord )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      */
getNextWord( )625     public WnnWord getNextWord( ) {
626         return getNextWord( 0 );
627     }
628 
629     /**
630      * @see jp.co.omronsoft.openwnn.WnnDictionary#getNextWord
631      */
getNextWord( int length )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      */
getUserDictionaryWords( )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      */
clearApproxPattern( )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      */
setApproxPattern( String src, String dst )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      */
setApproxPattern( int approxPattern )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      */
getConnectMatrix( )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      */
getPOS( int type )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      */
clearUserDictionary()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      */
clearLearnDictionary()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      */
addWordToUserDictionary( WnnWord[] word )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      */
addWordToUserDictionary( WnnWord word )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      */
removeWordFromUserDictionary( WnnWord[] word )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      */
removeWordFromUserDictionary( WnnWord word )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      */
learnWord( WnnWord word )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      */
learnWord( WnnWord word, WnnWord previousWord )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