<activity android:name="AboutActivity" />
<activity android:name="PreferenceActivity" />
<activity android:name="DownloadActivity" />
- <activity android:name="NoDictionaryActivity" />
</application>
android:persistent="true"\r
/>\r
\r
- <EditTextPreference \r
- android:key="@string/dictFileKey"\r
- android:title="@string/dictFileTitle"\r
- android:summary="@string/dictFileSummary"\r
- android:defaultValue="@string/dictFileDefault"\r
- android:persistent="true" \r
- />\r
-
- <EditTextPreference \r
- android:key="@string/dictFetchUrlKey"\r
- android:title="@string/dictFetchUrlTitle"
- android:summary="@string/dictFetchUrlSummary"\r
- android:defaultValue="@string/dictFetchUrlDefault"
- android:persistent="true"\r
- />
-\r
</PreferenceScreen>
\ No newline at end of file
+++ /dev/null
-package com.hughes.android.dictionary;\r
-\r
-import java.io.IOException;\r
-import java.io.RandomAccessFile;\r
-import java.util.ArrayList;\r
-import java.util.List;\r
-import java.util.concurrent.atomic.AtomicBoolean;\r
-\r
-import com.hughes.android.dictionary.engine.Language;\r
-import com.hughes.util.CachingList;\r
-import com.hughes.util.raf.RAFList;\r
-import com.hughes.util.raf.RAFFactory;\r
-import com.hughes.util.raf.RAFSerializable;\r
-import com.hughes.util.raf.RAFSerializableSerializer;\r
-import com.hughes.util.raf.RAFSerializer;\r
-import com.hughes.util.raf.UniformRAFList;\r
-\r
-public final class Dictionary implements RAFSerializable<Dictionary> {\r
- \r
- private static final String VERSION_CODE = "DictionaryVersion=2.0";\r
-\r
- static final RAFSerializer<SimpleEntry> ENTRY_SERIALIZER = null;\r
- static final RAFSerializer<Row> ROW_SERIALIZER = new RAFSerializableSerializer<Row>(\r
- Row.RAF_FACTORY);\r
- static final RAFSerializer<IndexEntry> INDEX_ENTRY_SERIALIZER = new RAFSerializableSerializer<IndexEntry>(\r
- IndexEntry.RAF_FACTORY);\r
-\r
- final String dictionaryInfo;\r
- final List<String> sources;\r
- final List<Entry> entries;\r
- final LanguageData[] languageDatas = new LanguageData[2];\r
-\r
- public Dictionary(final String dictionaryInfo, final Language language0, final Language language1) {\r
- this.dictionaryInfo = dictionaryInfo;\r
- sources = new ArrayList<String>();\r
- languageDatas[0] = new LanguageData(this, language0, SimpleEntry.LANG1);\r
- languageDatas[1] = new LanguageData(this, language1, SimpleEntry.LANG2);\r
- entries = new ArrayList<Entry>();\r
- }\r
-\r
- public Dictionary(final RandomAccessFile raf) throws IOException {\r
- dictionaryInfo = raf.readUTF();\r
- sources = new ArrayList<String>(RAFList.create(raf, RAFSerializer.STRING, raf.getFilePointer()));\r
- entries = null;\r
- languageDatas[0] = new LanguageData(this, raf, SimpleEntry.LANG1);\r
- languageDatas[1] = new LanguageData(this, raf, SimpleEntry.LANG2);\r
- final String version = raf.readUTF();\r
- if (!VERSION_CODE.equals(version)) {\r
- throw new IOException("Invalid dictionary version, found " + version + ", expected: " + VERSION_CODE);\r
- }\r
- }\r
-\r
- public void write(RandomAccessFile raf) throws IOException {\r
- raf.writeUTF(dictionaryInfo);\r
- RAFList.write(raf, sources, RAFSerializer.STRING);\r
- //RAFList.write(raf, entries, ENTRY_SERIALIZER);\r
- languageDatas[0].write(raf);\r
- languageDatas[1].write(raf);\r
- raf.writeUTF(VERSION_CODE);\r
- }\r
-\r
- final class LanguageData implements RAFSerializable<LanguageData> {\r
- final Dictionary dictionary;\r
- final Language language;\r
- final byte lang;\r
- final List<Row> rows;\r
- final List<IndexEntry> sortedIndex;\r
-\r
- LanguageData(final Dictionary dictionary, final Language language, final byte lang) {\r
- this.dictionary = dictionary;\r
- this.language = language;\r
- this.lang = lang;\r
- rows = new ArrayList<Row>();\r
- sortedIndex = new ArrayList<IndexEntry>();\r
- }\r
-\r
- LanguageData(final Dictionary dictionary, final RandomAccessFile raf, final byte lang) throws IOException {\r
- this.dictionary = dictionary;\r
- language = Language.lookup(raf.readUTF());\r
- if (language == null) {\r
- throw new RuntimeException("Unknown language.");\r
- }\r
- this.lang = lang;\r
- rows = CachingList.create(UniformRAFList.create(raf, ROW_SERIALIZER, raf\r
- .getFilePointer()), 10000);\r
- sortedIndex = CachingList.create(RAFList.create(raf,\r
- INDEX_ENTRY_SERIALIZER, raf.getFilePointer()), 10000);\r
- }\r
-\r
- public void write(final RandomAccessFile raf) throws IOException {\r
- raf.writeUTF(language.symbol);\r
- UniformRAFList.write(raf, rows, ROW_SERIALIZER, 4);\r
- RAFList.write(raf, sortedIndex, INDEX_ENTRY_SERIALIZER);\r
- }\r
-\r
- String rowToString(final Row row, final boolean onlyFirstSubentry) {\r
- return null;\r
- //return row.isToken() ? sortedIndex.get(row.getIndex()).word : entries\r
- // .get(row.getIndex()).getRawText(onlyFirstSubentry);\r
- }\r
-\r
- int lookup(String word, final AtomicBoolean interrupted) {\r
- word = word.toLowerCase();\r
-\r
- int start = 0;\r
- int end = sortedIndex.size();\r
- while (start < end) {\r
- final int mid = (start + end) / 2;\r
- if (interrupted.get()) {\r
- return mid;\r
- }\r
- final IndexEntry midEntry = sortedIndex.get(mid);\r
- if (midEntry.word.equals("pre-print")) {\r
- System.out.println();\r
- }\r
-\r
- final int comp = language.sortComparator.compare(word, midEntry.word.toLowerCase());\r
- if (comp == 0) {\r
- int result = mid;\r
- while (result > 0 && language.findComparator.compare(word, sortedIndex.get(result - 1).word.toLowerCase()) == 0) {\r
- --result;\r
- if (interrupted.get()) {\r
- return result;\r
- }\r
- }\r
- return result;\r
- } else if (comp < 0) {\r
-// Log.d("THAD", "Upper bound: " + midEntry);\r
- end = mid;\r
- } else {\r
-// Log.d("THAD", "Lower bound: " + midEntry);\r
- start = mid + 1;\r
- }\r
- }\r
- return Math.min(sortedIndex.size() - 1, start);\r
- }\r
- \r
- public int getPrevTokenRow(final int rowIndex) {\r
- final IndexEntry indexEntry = getIndexEntryForRow(rowIndex);\r
- final Row tokenRow = rows.get(indexEntry.startRow);\r
- assert tokenRow.isToken();\r
- final int prevTokenIndex = tokenRow.getIndex() - 1;\r
- if (indexEntry.startRow == rowIndex && prevTokenIndex >= 0) {\r
- return sortedIndex.get(prevTokenIndex).startRow;\r
- }\r
- return indexEntry.startRow;\r
- }\r
-\r
- public int getNextTokenRow(final int rowIndex) {\r
- final IndexEntry indexEntry = getIndexEntryForRow(rowIndex);\r
- final Row tokenRow = rows.get(indexEntry.startRow);\r
- assert tokenRow.isToken();\r
- final int nextTokenIndex = tokenRow.getIndex() + 1;\r
- if (nextTokenIndex < sortedIndex.size()) {\r
- return sortedIndex.get(nextTokenIndex).startRow;\r
- }\r
- return rows.size() - 1;\r
- }\r
-\r
- public IndexEntry getIndexEntryForRow(final int rowIndex) {\r
- // TODO: this kinda blows.\r
- int r = rowIndex;\r
- Row row;\r
- while (true) {\r
- row = rows.get(r); \r
- if (row.isToken() || row.indexEntry != null) {\r
- break;\r
- }\r
- --r;\r
- }\r
- final IndexEntry indexEntry = row.isToken() ? sortedIndex.get(row.getIndex()) : row.indexEntry;\r
- for (; r <= rowIndex; ++r) {\r
- rows.get(r).indexEntry = indexEntry;\r
- }\r
- assert rows.get(indexEntry.startRow).isToken();\r
- return indexEntry;\r
- }\r
- }\r
-\r
- public static final class Row implements RAFSerializable<Row> {\r
- final int index;\r
-\r
- IndexEntry indexEntry = null;\r
-\r
- public Row(final int index) {\r
- this.index = index;\r
- }\r
-\r
- static final RAFFactory<Row> RAF_FACTORY = new RAFFactory<Row>() {\r
- public Row create(RandomAccessFile raf) throws IOException {\r
- return new Row(raf.readInt());\r
- }\r
- };\r
-\r
- public void write(RandomAccessFile raf) throws IOException {\r
- raf.writeInt(index);\r
- }\r
-\r
- boolean isToken() {\r
- return index < 0;\r
- }\r
-\r
- public int getIndex() {\r
- if (index >= 0) {\r
- return index;\r
- }\r
- return -index - 1;\r
- }\r
- }\r
-\r
- public static final class IndexEntry implements RAFSerializable<IndexEntry> {\r
- final String word;\r
- final int startRow;\r
-\r
- public IndexEntry(final String word, final int startRow) {\r
- this.word = word;\r
- this.startRow = startRow;\r
- }\r
-\r
- static final RAFFactory<IndexEntry> RAF_FACTORY = new RAFFactory<IndexEntry>() {\r
- public IndexEntry create(RandomAccessFile raf) throws IOException {\r
- final String word = raf.readUTF();\r
- final int startRow = raf.readInt();\r
- return new IndexEntry(word, startRow);\r
- }\r
- };\r
-\r
- public void write(final RandomAccessFile raf) throws IOException {\r
- raf.writeUTF(word);\r
- raf.writeInt(startRow);\r
- }\r
-\r
- @Override\r
- public String toString() {\r
- return word + "@" + startRow;\r
- }\r
-\r
- }\r
-\r
-}\r
import android.widget.TextView;
import android.widget.Toast;
-import com.hughes.android.dictionary.Dictionary.IndexEntry;
-import com.hughes.android.dictionary.Dictionary.LanguageData;
-import com.hughes.android.dictionary.Dictionary.Row;
+import com.hughes.android.dictionary.engine.Dictionary;
import com.hughes.android.dictionary.engine.Language;
import com.ibm.icu.text.Collator;
private boolean prefsMightHaveChanged = true;
// Never null.
- private File wordList;
+ private File wordList = null;
private RandomAccessFile dictRaf = null;
private Dictionary dictionary = null;
private boolean saveOnlyFirstSubentry = false;
// Visible for testing.
- LanguageListAdapter languageList = null;
+ IndexAdapter indexAdapter = null;
private SearchOperation searchOperation = null;
public DictionaryActivity() {
searchText = (EditText) findViewById(R.id.SearchText);
langButton = (Button) findViewById(R.id.LangButton);
- Log.d(LOG, "adding text changed listener");
searchText.addTextChangedListener(new SearchTextWatcher());
getListView().setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
Log.d(LOG, "Read dictionary millis: " + (System.currentTimeMillis() - startMillis));
} catch (IOException e) {
Log.e(LOG, "Couldn't open dictionary.", e);
- this.startActivity(new Intent(this, NoDictionaryActivity.class));
+
+ this.startActivity(new asdfIntent(this, DictionaryEditActivity.class));
finish();
- throw new Exception(e);
}
final byte lang = prefs.getInt(PREF_DICT_ACTIVE_LANG, SimpleEntry.LANG1) == SimpleEntry.LANG1 ? SimpleEntry.LANG1
: SimpleEntry.LANG2;
- languageList = new LanguageListAdapter(dictionary.languageDatas[lang]);
- setListAdapter(languageList);
+ indexAdapter = new IndexAdapter(dictionary.languageDatas[lang]);
+ setListAdapter(indexAdapter);
prefsMightHaveChanged = false;
}
Log.d(LOG, "onPause:" + this);
final Editor prefs = PreferenceManager.getDefaultSharedPreferences(this)
.edit();
- prefs.putInt(PREF_DICT_ACTIVE_LANG, languageList.languageData.lang);
+ prefs.putInt(PREF_DICT_ACTIVE_LANG, indexAdapter.languageData.lang);
prefs.putString(PREF_ACTIVE_SEARCH_TEXT, searchText.getText().toString());
prefs.commit();
}
return;
}
waitForSearchEnd();
- languageList = null;
+ indexAdapter = null;
setListAdapter(null);
Log.d(LOG, "setListAdapter finished.");
dictionary = null;
}
public String getSelectedRowRawText(final boolean onlyFirstSubentry) {
- final Row row = languageList.languageData.rows.get(getSelectedRow());
- return languageList.languageData.rowToString(row, onlyFirstSubentry);
+ final Row row = indexAdapter.languageData.rows.get(getSelectedRow());
+ return indexAdapter.languageData.rowToString(row, onlyFirstSubentry);
}
// ----------------------------------------------------------------
public boolean onPrepareOptionsMenu(final Menu menu) {
switchLanguageMenuItem.setTitle(getString(R.string.switchToLanguage,
dictionary.languageDatas[SimpleEntry
- .otherLang(languageList.languageData.lang)].language.symbol));
+ .otherLang(indexAdapter.languageData.lang)].language.symbol));
return super.onPrepareOptionsMenu(menu);
}
void updateLangButton() {
- langButton.setText(languageList.languageData.language.symbol);
+ langButton.setText(indexAdapter.languageData.language.symbol);
}
// ----------------------------------------------------------------
void onLanguageButton() {
waitForSearchEnd();
- languageList = new LanguageListAdapter(
- dictionary.languageDatas[(languageList.languageData == dictionary.languageDatas[0]) ? 1
+ indexAdapter = new IndexAdapter(
+ dictionary.languageDatas[(indexAdapter.languageData == dictionary.languageDatas[0]) ? 1
: 0]);
- Log.d(LOG, "onLanguageButton, newLang=" + languageList.languageData.language.symbol);
- setListAdapter(languageList);
+ Log.d(LOG, "onLanguageButton, newLang=" + indexAdapter.languageData.language.symbol);
+ setListAdapter(indexAdapter);
updateLangButton();
onSearchTextChange(searchText.getText().toString());
}
void onUpButton() {
- final int destRowIndex = languageList.languageData.getPrevTokenRow(getSelectedRow());
+ final int destRowIndex = indexAdapter.languageData.getPrevTokenRow(getSelectedRow());
Log.d(LOG, "onUpButton, destRowIndex=" + destRowIndex);
- jumpToRow(languageList, destRowIndex);
+ jumpToRow(indexAdapter, destRowIndex);
}
void onDownButton() {
- final int destRowIndex = languageList.languageData.getNextTokenRow(getSelectedRow());
+ final int destRowIndex = indexAdapter.languageData.getNextTokenRow(getSelectedRow());
Log.d(LOG, "onDownButton, destRowIndex=" + destRowIndex);
- jumpToRow(languageList, destRowIndex);
+ jumpToRow(indexAdapter, destRowIndex);
}
void onAppendToWordList() {
return;
}
final StringBuilder rawText = new StringBuilder();
- final String word = languageList.languageData.getIndexEntryForRow(row).word;
+ final String word = indexAdapter.languageData.getIndexEntryForRow(row).word;
rawText.append(
new SimpleDateFormat("yyyy.MM.dd HH:mm:ss").format(new Date()))
.append("\t");
void onSearchTextChange(final String searchText) {
Log.d(LOG, "onSearchTextChange: " + searchText);
synchronized (this) {
- searchOperation = new SearchOperation(languageList, searchText.trim(), searchOperation);
+ searchOperation = new SearchOperation(indexAdapter, searchText.trim(), searchOperation);
searchExecutor.execute(searchOperation);
}
}
}
- private void jumpToRow(final LanguageListAdapter dictionaryListAdapter,
+ private void jumpToRow(final IndexAdapter dictionaryListAdapter,
final int rowIndex) {
Log.d(LOG, "jumpToRow: " + rowIndex);
- if (dictionaryListAdapter != this.languageList) {
+ if (dictionaryListAdapter != this.indexAdapter) {
Log.w(LOG, "skipping jumpToRow for old list adapter: " + rowIndex);
return;
}
final int selectedRowIndex = getSelectedRow();
if (!searchText.hasFocus()) {
if (selectedRowIndex >= 0) {
- final String word = languageList.languageData
+ final String word = indexAdapter.languageData
.getIndexEntryForRow(selectedRowIndex).word;
if (!word.equals(searchText.getText().toString())) {
Log.d(LOG, "updateSearchText: setText: " + word);
context.startActivity(intent);
}
- class LanguageListAdapter extends BaseAdapter {
+ class IndexAdapter extends BaseAdapter {
// Visible for testing.
final LanguageData languageData;
- LanguageListAdapter(final LanguageData languageData) {
+ IndexAdapter(final LanguageData languageData) {
this.languageData = languageData;
}
private final class SearchOperation implements Runnable {
SearchOperation previousSearchOperation;
- final LanguageListAdapter listAdapter;
+ final IndexAdapter listAdapter;
final LanguageData languageData;
final String searchText;
final AtomicBoolean interrupted = new AtomicBoolean(false);
boolean searchFinished = false;
- SearchOperation(final LanguageListAdapter listAdapter,
+ SearchOperation(final IndexAdapter listAdapter,
final String searchText, final SearchOperation previousSearchOperation) {
this.listAdapter = listAdapter;
this.languageData = listAdapter.languageData;
+++ /dev/null
-package com.hughes.android.dictionary;\r
-\r
-import com.hughes.android.dictionary.engine.Language;\r
-\r
-import android.test.ActivityInstrumentationTestCase2;\r
-\r
-public class DictionaryActivityTest extends ActivityInstrumentationTestCase2<DictionaryActivity> {\r
-\r
- public DictionaryActivityTest() {\r
- super(DictionaryActivity.class.getPackage().getName(), DictionaryActivity.class);\r
- }\r
- \r
- public void testRunAndFinish() {\r
- final DictionaryActivity dict = getActivity();\r
- dict.finish();\r
- }\r
- \r
- abstract class NotifyRunnable implements Runnable {\r
- boolean finished = false;\r
- public final void run() {\r
- assertEquals(false, finished);\r
- run2();\r
- synchronized (this) {\r
- finished = true;\r
- this.notifyAll();\r
- }\r
- }\r
- public void waitForFinish() throws InterruptedException {\r
- synchronized (this) {\r
- while (!finished) {\r
- this.wait();\r
- }\r
- finished = false;\r
- }\r
- getActivity().waitForSearchEnd();\r
- }\r
- protected abstract void run2();\r
- }\r
-\r
- private void postAndWait(final NotifyRunnable notifyRunnable) throws Exception {\r
- getActivity().uiHandler.post(notifyRunnable);\r
- notifyRunnable.waitForFinish();\r
- }\r
-\r
- public void resetDictionary() throws Exception {\r
- final DictionaryActivity dict = getActivity();\r
- \r
- if (dict.languageList.languageData.language == Language.en) {\r
- postAndWait(switchLangRunnable());\r
- }\r
- assertEquals(Language.de, dict.languageList.languageData.language);\r
-\r
- postAndWait(new NotifyRunnable() {\r
- protected void run2() {\r
- dict.searchText.setText("");\r
- dict.onSearchTextChange("");\r
- }\r
- });\r
- }\r
-\r
- public void testSwitchLanguage() throws Exception {\r
- final DictionaryActivity dict = getActivity();\r
- resetDictionary();\r
-\r
- final NotifyRunnable switchLang = switchLangRunnable();\r
-\r
- postAndWait(switchLang);\r
- assertEquals(Language.en, dict.languageList.languageData.language);\r
- assertEquals("EN", dict.langButton.getText().toString());\r
-\r
- postAndWait(switchLang);\r
- assertEquals(Language.de, dict.languageList.languageData.language);\r
- assertEquals("DE", dict.langButton.getText().toString());\r
- \r
- dict.finish();\r
- }\r
-\r
- public void testUpDownArrows() throws Exception {\r
- final DictionaryActivity dict = getActivity();\r
- resetDictionary();\r
- assertEquals(0, dict.getSelectedItemPosition());\r
- \r
- final NotifyRunnable upButton = new NotifyRunnable() {\r
- protected void run2() {\r
- dict.onUpButton();\r
- }\r
- };\r
- final NotifyRunnable downButton = new NotifyRunnable() {\r
- protected void run2() {\r
- dict.onDownButton();\r
- }\r
- };\r
- \r
- dict.getListView().requestFocus();\r
- assertTrue(dict.getListView().isFocused());\r
- \r
- String word1 = "-1";\r
- String word2 = "-14";\r
- String word3 = "-15";\r
-\r
- postAndWait(upButton);\r
- assertEquals(0, dict.getSelectedItemPosition());\r
- assertEquals(word1, dict.searchText.getText().toString());\r
-\r
- postAndWait(downButton);\r
- assertEquals(2, dict.getSelectedItemPosition());\r
- assertEquals(word2, dict.searchText.getText().toString());\r
- \r
- postAndWait(downButton);\r
- assertEquals(4, dict.getSelectedItemPosition());\r
- assertEquals(word3, dict.searchText.getText().toString());\r
-\r
- postAndWait(upButton);\r
- assertEquals(2, dict.getSelectedItemPosition());\r
- assertEquals(word2, dict.searchText.getText().toString());\r
- \r
- postAndWait(upButton);\r
- assertEquals(0, dict.getSelectedItemPosition());\r
- assertEquals(word1, dict.searchText.getText().toString());\r
- \r
- postAndWait(upButton);\r
- assertEquals(0, dict.getSelectedItemPosition());\r
-\r
- postAndWait(downButton);\r
- assertEquals(2, dict.getSelectedItemPosition());\r
-\r
- dict.finish();\r
- }\r
-\r
- private NotifyRunnable switchLangRunnable() {\r
- final NotifyRunnable switchLang = new NotifyRunnable() {\r
- public void run2() {\r
- getActivity().onLanguageButton();\r
- }};\r
- return switchLang;\r
- }\r
-\r
-}\r
try {\r
destTmpFile = File.createTempFile("dictionaryDownload", "tmp", destFile\r
.getParentFile());\r
+ destTmpFile.deleteOnExit();\r
final URL uri = new URL(source);\r
final URLConnection connection = uri.openConnection();\r
contentLength = connection.getContentLength();\r
+++ /dev/null
-package com.hughes.android.dictionary;
-
-import java.io.IOException;
-import java.io.RandomAccessFile;
-
-import com.hughes.util.raf.RAFFactory;
-import com.hughes.util.raf.RAFSerializable;
-
-public interface Entry extends RAFSerializable<Entry> {
-
- public static final RAFFactory<Entry> RAF_FACTORY = new RAFFactory<Entry>() {
- public Entry create(RandomAccessFile raf) throws IOException {
- final byte type = raf.readByte();
- switch (type) {
- case 0:
- return SimpleEntry.RAF_FACTORY.create(raf);
- }
- throw new RuntimeException("Invalid entry type: " + type);
- }};
-
-
-}
+++ /dev/null
-package com.hughes.android.dictionary;\r
-\r
-import java.io.File;\r
-\r
-import android.app.Activity;\r
-import android.content.Intent;\r
-import android.content.SharedPreferences;\r
-import android.os.Bundle;\r
-import android.preference.PreferenceManager;\r
-import android.view.View;\r
-import android.view.View.OnClickListener;\r
-import android.widget.Button;\r
-import android.widget.TextView;\r
-\r
-public class NoDictionaryActivity extends Activity {\r
- \r
- /** Called when the activity is first created. */\r
- @Override\r
- public void onCreate(final Bundle savedInstanceState) {\r
- super.onCreate(savedInstanceState);\r
- setContentView(R.layout.no_dictionary);\r
- \r
- final Button downloadButton = (Button) findViewById(R.id.downloadDict);\r
- downloadButton.setOnClickListener(new OnClickListener() {\r
- public void onClick(View arg0) {\r
- DictionaryActivity.startDownloadDictActivity(NoDictionaryActivity.this);\r
- }});\r
-\r
- final Button prefsButton = (Button) findViewById(R.id.preferences);\r
- prefsButton.setOnClickListener(new OnClickListener() {\r
- public void onClick(View arg0) {\r
- startActivity(new Intent(NoDictionaryActivity.this, PreferenceActivity.class));\r
- }});\r
-\r
- final Button launchButton = (Button) findViewById(R.id.launchDict);\r
- launchButton.setOnClickListener(new OnClickListener() {\r
- public void onClick(View arg0) {\r
- startActivity(new Intent(NoDictionaryActivity.this, DictionaryActivity.class));\r
- }});\r
- }\r
-\r
- @Override\r
- protected void onResume() {\r
- super.onResume();\r
-\r
- final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);\r
- final String dictFile = prefs.getString(getString(R.string.dictFileKey), getString(R.string.dictFileDefault));\r
- final boolean canReadDict = new File(dictFile).canRead();\r
-\r
- final TextView statusText = (TextView) findViewById(R.id.statusTextId);\r
- if (!canReadDict) {\r
- statusText.setText(getString(R.string.unableToReadDictionaryFile, dictFile));\r
- } else {\r
- statusText.setText(getString(R.string.dictionaryFileExists, dictFile));\r
- }\r
-\r
- final Button launchButton = (Button) findViewById(R.id.launchDict);\r
- launchButton.setEnabled(canReadDict);\r
-\r
- }\r
- \r
-}\r
+++ /dev/null
-package com.hughes.android.dictionary;\r
-\r
-import java.io.IOException;\r
-import java.io.RandomAccessFile;\r
-import java.util.Arrays;\r
-import java.util.LinkedHashMap;\r
-import java.util.LinkedHashSet;\r
-import java.util.Map;\r
-import java.util.Set;\r
-import java.util.regex.Matcher;\r
-import java.util.regex.Pattern;\r
-\r
-import com.hughes.util.raf.RAFFactory;\r
-\r
-public final class SimpleEntry implements Entry {\r
-\r
- static final byte LANG1 = 0;\r
- static final byte LANG2 = 1;\r
-\r
- static final Pattern lineSplitPattern = Pattern.compile("\\s::\\s");\r
- static final Pattern sublineSplitPattern = Pattern.compile("\\s\\|\\s");\r
-\r
- final String[] lang1;\r
- final String[] lang2;\r
- \r
- SimpleEntry(final String[] lang1, final String[] lang2) {\r
- this.lang1 = lang1;\r
- this.lang2 = lang2;\r
- }\r
-\r
- public static final RAFFactory<SimpleEntry> RAF_FACTORY = new RAFFactory<SimpleEntry>() {\r
- public SimpleEntry create(RandomAccessFile raf) throws IOException {\r
- final int rows = raf.readByte();\r
- final String[] lang1 = new String[rows];\r
- final String[] lang2 = new String[rows];\r
- for (int i = 0; i < lang1.length; ++i) {\r
- lang1[i] = raf.readUTF();\r
- lang2[i] = raf.readUTF();\r
- }\r
- return new SimpleEntry(lang1, lang2);\r
- }};\r
- public void write(RandomAccessFile raf) throws IOException {\r
- assert lang1.length == (byte) lang1.length;\r
- raf.writeByte(lang1.length);\r
- for (int i = 0; i < lang1.length; ++i) {\r
- raf.writeUTF(lang1[i]);\r
- raf.writeUTF(lang2[i]);\r
- }\r
- }\r
-\r
- @Override\r
- public boolean equals(Object o) {\r
- if (!(o instanceof SimpleEntry)) {\r
- return false;\r
- }\r
- final SimpleEntry that = (SimpleEntry) o;\r
- return Arrays.deepEquals(this.lang1, that.lang1) && Arrays.deepEquals(this.lang2, that.lang2); \r
- }\r
-\r
- @Override\r
- public int hashCode() {\r
- return Arrays.deepHashCode(lang1) + Arrays.deepHashCode(lang2);\r
- }\r
-\r
- @Override\r
- public String toString() {\r
- return getRawText(false);\r
- }\r
-\r
- public int getRowCount() {\r
- assert lang1.length == lang2.length;\r
- return lang1.length;\r
- }\r
-\r
- String[] getAllText(final byte lang) {\r
- if (lang == LANG1) {\r
- return lang1;\r
- }\r
- assert lang == LANG2;\r
- return lang2;\r
- }\r
- \r
- String getRawText(boolean onlyFirstSubentry) {\r
- final StringBuilder result = new StringBuilder();\r
- for (int i = 0; i < (onlyFirstSubentry ? 1 : lang1.length); ++i) {\r
- result.append(i == 0 ? "" : " | ").append(lang1[i]);\r
- }\r
- result.append("\t");\r
- for (int i = 0; i < (onlyFirstSubentry ? 1 : lang2.length); ++i) {\r
- result.append(i == 0 ? "" : " | ").append(lang2[i]);\r
- }\r
- return result.toString();\r
- }\r
- \r
- static byte otherLang(final byte lang) {\r
- assert lang == LANG1 || lang == LANG2;\r
- return lang == LANG1 ? LANG2 : LANG1;\r
- }\r
- \r
-/*\r
-Lu Letter, Uppercase\r
-Ll Letter, Lowercase\r
-Lt Letter, Titlecase\r
-Lm Letter, Modifier\r
-Lo Letter, Other\r
-Mn Mark, Nonspacing\r
-Mc Mark, Spacing Combining\r
-Me Mark, Enclosing\r
-Nd Number, Decimal Digit\r
-Nl Number, Letter\r
-No Number, Other\r
-Pc Punctuation, Connector\r
-Pd Punctuation, Dash\r
-Ps Punctuation, Open\r
-Pe Punctuation, Close\r
-Pi Punctuation, Initial quote (may behave like Ps or Pe depending on usage)\r
-Pf Punctuation, Final quote (may behave like Ps or Pe depending on usage)\r
-Po Punctuation, Other\r
-Sm Symbol, Math\r
-Sc Symbol, Currency\r
-Sk Symbol, Modifier\r
-So Symbol, Other\r
-Zs Separator, Space\r
-Zl Separator, Line\r
-Zp Separator, Paragraph\r
-*/\r
-\r
- static Pattern htmlDecimalCode = Pattern.compile("&#([0-9]+);");\r
- static Pattern htmlCode = Pattern.compile("&#[^;]+;");\r
- \r
- static SimpleEntry parseFromLine(String line, final boolean hasMultipleSubentries) {\r
- \r
- line = line.replaceAll("<", "<");\r
- line = line.replaceAll(">", ">");\r
- Matcher matcher;\r
- while ((matcher = htmlDecimalCode.matcher(line)).find()) {\r
- final int intVal = Integer.parseInt(matcher.group(1));\r
- final String charCode = "" + ((char) intVal);\r
- System.out.println("Replacing " + matcher.group() + " with " + charCode);\r
- line = matcher.replaceAll(charCode);\r
- }\r
- if ((matcher = htmlCode.matcher(line)).find()) {\r
- System.err.println("HTML code: " + matcher.group());\r
- }\r
- \r
- final String[] parts = lineSplitPattern.split(line);\r
- if (parts.length != 2) {\r
- System.err.println("Entry:" + "Invalid line: " + line);\r
- return null;\r
- }\r
- if (!hasMultipleSubentries) {\r
- return new SimpleEntry(new String[] {parts[0].trim()}, new String[] {parts[1].trim()});\r
- }\r
- \r
- final String[] lang1 = sublineSplitPattern.split(" " + parts[0].trim() + " ");\r
- final String[] lang2 = sublineSplitPattern.split(" " + parts[1].trim() + " ");\r
- if (lang1.length != lang2.length) {\r
- System.err.println("Entry:" + "Invalid subline: " + line);\r
- return null;\r
- }\r
- for (int i = 0; i < lang1.length; ++i) {\r
- lang1[i] = lang1[i].trim();\r
- lang2[i] = lang2[i].trim();\r
- }\r
- return new SimpleEntry(lang1, lang2);\r
- }\r
- \r
- static final Map<String, String> bracketToClose = new LinkedHashMap<String, String>();\r
- static {\r
- bracketToClose.put("\"", "\"");\r
- bracketToClose.put(" '", "' ");\r
- }\r
- \r
- // This used to be called WHITESPACE.\r
- static final Pattern NON_TOKEN_CHAR = Pattern.compile("\\s+");\r
- \r
- public Set<String> getIndexableTokens(final byte lang) {\r
- final Set<String> result = new LinkedHashSet<String>();\r
- String text = " ";\r
- for (final String subentry : getAllText(lang)) {\r
- text += subentry + " ";\r
- }\r
-\r
- text = text.replaceAll("fig\\.", " ");\r
- text = text.replaceAll("\\{[^\\}]+}", " ");\r
- text = text.replaceAll("\"-", "-");\r
- text = text.replaceAll("-\"", "-");\r
- text = text.replaceAll("[\"/\\()<>\\[\\],;?!.]", " ");\r
- text = text.replaceAll("[-:] ", " ");\r
- text = text.replaceAll(" [-:]", " ");\r
- \r
- // Now be really conservative about what we allow inside a token:\r
- // See: http://unicode.org/Public/UNIDATA/UCD.html#General_Category_Values\r
- text = text.replaceAll("[^-:\\p{L}\\p{N}\\p{S}]", " ");\r
- result.addAll(Arrays.asList(NON_TOKEN_CHAR.split(text)));\r
-\r
- text = text.replaceAll("[-]", " ");\r
- result.addAll(Arrays.asList(NON_TOKEN_CHAR.split(text)));\r
- \r
- final Set<String> result2 = new LinkedHashSet<String>();\r
- for (final String token : result) {\r
- if (isIndexable(token)) {\r
- result2.add(token);\r
- }\r
- }\r
- return result2;\r
- }\r
-\r
- static boolean isIndexable(final String text) {\r
- // Does it have an alpha-numeric anywhere?\r
- return text.matches(".*\\w.*");\r
- }\r
- \r
-}
\ No newline at end of file
static final int CACHE_SIZE = 5000;
+ static final String END_OF_DICTIONARY = "END OF DICTIONARY";
+
// persisted
+ final int dictFileVersion;
final String dictInfo;
final List<PairEntry> pairEntries;
final List<TextEntry> textEntries;
final List<Index> indices;
public Dictionary(final String dictInfo) {
+ this.dictFileVersion = 0;
this.dictInfo = dictInfo;
pairEntries = new ArrayList<PairEntry>();
textEntries = new ArrayList<TextEntry>();
}
public Dictionary(final RandomAccessFile raf) throws IOException {
+ dictFileVersion = raf.readInt();
+ if (dictFileVersion != 0) {
+ throw new IOException("Invalid dictionary version: " + dictFileVersion);
+ }
dictInfo = raf.readUTF();
sources = CachingList.createFullyCached(RAFList.create(raf, EntrySource.SERIALIZER, raf.getFilePointer()));
pairEntries = CachingList.create(RAFList.create(raf, PairEntry.SERIALIZER, raf.getFilePointer()), CACHE_SIZE);
textEntries = CachingList.create(RAFList.create(raf, TextEntry.SERIALIZER, raf.getFilePointer()), CACHE_SIZE);
indices = CachingList.createFullyCached(RAFList.create(raf, indexSerializer, raf.getFilePointer()));
- }
-
- public void print(final PrintStream out) {
- out.println("dictInfo=" + dictInfo);
- for (final Index index : indices) {
- index.print(out);
- out.println();
+ final String end = raf.readUTF();
+ if (!end.equals(END_OF_DICTIONARY)) {
+ throw new IOException("Dictionary seems corrupt: " + end);
}
}
-
+
@Override
public void write(RandomAccessFile raf) throws IOException {
+ raf.writeInt(dictFileVersion);
raf.writeUTF(dictInfo);
RAFList.write(raf, sources, EntrySource.SERIALIZER);
RAFList.write(raf, pairEntries, PairEntry.SERIALIZER);
RAFList.write(raf, textEntries, TextEntry.SERIALIZER);
RAFList.write(raf, indices, indexSerializer);
+ raf.writeUTF(END_OF_DICTIONARY);
}
private final RAFListSerializer<Index> indexSerializer = new RAFListSerializer<Index>() {
public void write(RandomAccessFile raf, Index t) throws IOException {
t.write(raf);
}};
+
+ public void print(final PrintStream out) {
+ out.println("dictInfo=" + dictInfo);
+ for (final Index index : indices) {
+ index.print(out);
+ out.println();
+ }
+ }
+
}
\ No newline at end of file