<?xml version="1.0" encoding="utf-8"?>
-<manifest
- xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.hughes.android.dictionary"
- android:versionCode="8"
- android:versionName="1.8">
-
- <uses-sdk android:minSdkVersion="4" />
-
- <uses-permission android:name="android.permission.INTERNET"/>
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
-
- <application android:icon="@drawable/icon" android:label="@string/app_name">
-
- <activity android:name=".DictionaryActivity" android:label="@string/app_name">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.hughes.android.dictionary" android:versionCode="9"
+ android:versionName="2.0">
+
+ <uses-sdk android:minSdkVersion="4" />
+
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+
+ <application
+ android:icon="@drawable/icon"
+ android:label="@string/app_name"
+ android:backupAgent="DictionaryBackupAgent"
+ android:theme="@style/Theme.QuickDic">
+
+ <meta-data android:name="com.google.android.backup.api_key"
+ android:value="AEdPqrEAAAAIUa0cU0ZHbBpYXJqm0vVUP5IAjr5D4iUeX7UwiQ" />
+
+ <activity android:name=".DictionaryListActivity"
+ android:label="@string/app_name">
+
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <activity android:name="AboutActivity"/>
- <activity android:name="PreferenceActivity"/>
- <activity android:name="DownloadActivity"/>
- <activity android:name="NoDictionaryActivity"/>
+ <activity android:name="DictionaryActivity" />
+ <activity android:name="DictionaryEditActivity" />
+ <activity android:name="AboutActivity" />
+ <activity android:name="PreferenceActivity" />
+ <activity android:name="DownloadActivity" />
+ <activity android:name="NoDictionaryActivity" />
</application>
# Indicates whether an apk should be generated for each density.
split.density=false
# Project target.
-target=android-3
+target=android-4
--- /dev/null
+<ScrollView android:id="@+id/ScrollView01"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+<LinearLayout
+ android:id="@+id/LinearLayout01"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ >
+
+<!-- android:textAppearance="?android:attr/textAppearanceLarge" -->
+
+ <!-- Name. -->
+ <TextView
+ android:id="@+id/dictionaryNameTitle"
+ android:text="@string/dictionaryName"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+ <EditText
+ android:id="@+id/dictionaryName"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content" />
+
+ <!-- Local file. -->
+ <TextView
+ android:id="@+id/localFileTitle"
+ android:text="@string/localFile"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dip" />
+ <EditText
+ android:id="@+id/localFile"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content" />
+
+ <!-- Local file. -->
+ <TextView
+ android:id="@+id/wordListFileTitle"
+ android:text="@string/wordListFile"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dip" />
+ <EditText
+ android:id="@+id/wordListFile"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content" />
+
+ <!-- Download URL. -->
+ <TextView
+ android:id="@+id/downloadUrlTitle"
+ android:text="@string/downloadUrl"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dip" />
+ <EditText
+ android:id="@+id/downloadUrl"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content" />
+
+
+ String localFile = "";
+ String wordList = "";
+
+ int openIndex = 0;
+ String openWord = "";
+
+</LinearLayout>
+
+</ScrollView>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical" android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <ListView
+ android:id="@id/android:list"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:choiceMode="singleChoice"
+ android:clickable="true"
+ android:focusable="true"
+ android:layout_weight="1.0"
+ />
+
+ <LinearLayout
+ android:id="@+id/LinearLayout01"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+ <TextView
+ android:id="@+id/DictionaryListHeader"
+ android:hint="@string/selectADictionary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:imeOptions="actionSearch|flagNoEnterAction|flagNoExtractUi"
+ android:layout_weight="1.0" android:inputType="text"/>
+ </LinearLayout>
+
+</LinearLayout>
<string name="app_name">QuickDic</string>
<string name="about_text">QuickDic\nby Thad Hughes</string>
-
+
+ <!-- DictionaryListActivity -->
+ <string name="selectADictionary"><![CDATA[Select a dictionary.
+\nLong-press to edit the dictionary. Press "menu" to add a new dictionary.]]></string>
+ <string name="addDictionary">Add dictionary</string>
+ <string name="editDictionary">Edit dictionary config</string>
+ <string name="deleteDictionary">Delete dictionary</string>
+ <string name="moveUp">Move up</string>
+ <string name="newDictionary">New Dictionary</string>
+
+ <!-- DictionaryEditActivity -->
+ <string name="dictionaryName">Dictionary name</string>
+ <string name="downloadUrl">Dictionary download URL</string>
+ <string name="localFile">Dictionary file</string>
+ <string name="wordListFile">Word list file</string>
+
<!-- Main -->
<string name="searchText">Search Text</string>
<string name="downloadDictionary">Download dictionary...</string>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <style name="Theme.QuickDic" parent="@android:style/Theme.Light">
+ <item name="android:layout_width">fill_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+
+ <item name="android:colorForeground">#000000</item>
+ <item name="android:colorBackground">#FFFFFF</item>
+
+ <item name="android:textColorPrimary">#000000</item>
+
+ </style>
+</resources>
import android.widget.TextView;\r
\r
public final class AboutActivity extends Activity {\r
- \r
+\r
public static final String CURRENT_DICT_INFO = "currentDictInfo";\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.about);\r
- \r
- final Intent intent = getIntent();\r
- \r
- final TextView currentDictInfo = (TextView) findViewById(R.id.currentDictInfo);\r
- currentDictInfo.setText(intent.getStringExtra(CURRENT_DICT_INFO));\r
+ super.onCreate(savedInstanceState);\r
+ setContentView(R.layout.about_activity);\r
+\r
+ final Intent intent = getIntent();\r
+\r
+ final TextView currentDictInfo = (TextView) findViewById(R.id.currentDictInfo);\r
+ currentDictInfo.setText(intent.getStringExtra(CURRENT_DICT_INFO));\r
}\r
\r
}\r
\r
private static final String VERSION_CODE = "DictionaryVersion=2.0";\r
\r
- static final RAFSerializer<SimpleEntry> ENTRY_SERIALIZER = new RAFSerializableSerializer<SimpleEntry>(\r
- SimpleEntry.RAF_FACTORY);\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
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 = CachingList.create(RAFList.create(raf, ENTRY_SERIALIZER, raf\r
- .getFilePointer()), 10000);\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
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
+ //RAFList.write(raf, entries, ENTRY_SERIALIZER);\r
languageDatas[0].write(raf);\r
languageDatas[1].write(raf);\r
raf.writeUTF(VERSION_CODE);\r
}\r
\r
String rowToString(final Row row, final boolean onlyFirstSubentry) {\r
- return row.isToken() ? sortedIndex.get(row.getIndex()).word : entries\r
- .get(row.getIndex()).getRawText(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
public class DictionaryActivity extends ListActivity {
// TO DO:
+ // * Easy reverse lookup.
// * Download latest dicts.
// * http://ftp.tu-chemnitz.de/pub/Local/urz/ding/de-en-devel/
// * http://www1.dict.cc/translation_file_request.php?l=e
// UI init.
- setContentView(R.layout.main);
+ setContentView(R.layout.dictionary_activity);
searchText = (EditText) findViewById(R.id.SearchText);
langButton = (Button) findViewById(R.id.LangButton);
// Entry row(s).
final TableLayout result = new TableLayout(parent.getContext());
- final SimpleEntry entry = dictionary.entries.get(row.getIndex());
+ final SimpleEntry entry = new SimpleEntry(null, null);//.entries.get(row.getIndex());
final int rowCount = entry.getRowCount();
for (int r = 0; r < rowCount; ++r) {
final TableRow tableRow = new TableRow(result.getContext());
--- /dev/null
+package com.hughes.android.dictionary;
+
+import java.io.Serializable;
+
+public class DictionaryConfig implements Serializable {
+
+ private static final long serialVersionUID = -6850863377577700387L;
+
+ String name = "";
+ String localFile = "/sdcard/quickDic/";
+ String wordList = "/sdcard/quickDic/";
+ String downloadUrl = "http://";
+
+ int openIndex = 0;
+ String openWord = "";
+
+ static DictionaryConfig defaultConfig() {
+ final DictionaryConfig result = new DictionaryConfig();
+ result.name = "DE<->EN";
+ result.downloadUrl = "http://www.stanford.edu/~egirard/dict/de-en.2.dict";
+ result.localFile = "/sdcard/quickDic/de-en.dict";
+ result.wordList = "/sdcard/quickDict/wordlist_de-en.txt";
+ return result;
+ }
+
+}
--- /dev/null
+package com.hughes.android.dictionary;
+
+import java.util.List;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MenuItem.OnMenuItemClickListener;
+import android.widget.EditText;
+
+import com.hughes.android.util.PersistentObjectCache;
+
+public class DictionaryEditActivity extends Activity {
+
+ List<DictionaryConfig> dictionaryConfigs;
+ private DictionaryConfig dictionaryConfig;
+
+ public static final String DICT_INDEX = "dictIndex";
+
+ /** Called when the activity is first created. */
+ @SuppressWarnings("unchecked")
+ @Override
+ public void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.edit_activity);
+
+ PersistentObjectCache.init(this);
+ dictionaryConfigs = (List<DictionaryConfig>) PersistentObjectCache.init(
+ this).read(DictionaryListActivity.DICTIONARY_CONFIGS);
+
+ final Intent intent = getIntent();
+ dictionaryConfig = dictionaryConfigs.get(intent.getIntExtra(DICT_INDEX, 0));
+
+ // Write stuff from object into fields.
+
+ ((EditText) findViewById(R.id.dictionaryName)).setText(dictionaryConfig.name);
+ ((EditText) findViewById(R.id.localFile)).setText(dictionaryConfig.localFile);
+ ((EditText) findViewById(R.id.wordListFile)).setText(dictionaryConfig.wordList);
+ ((EditText) findViewById(R.id.downloadUrl)).setText(dictionaryConfig.downloadUrl);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ // Read stuff from fields into object.
+ dictionaryConfig.name = ((EditText) findViewById(R.id.dictionaryName)).getText().toString();
+ dictionaryConfig.localFile = ((EditText) findViewById(R.id.localFile)).getText().toString();
+ dictionaryConfig.wordList = ((EditText) findViewById(R.id.wordListFile)).getText().toString();
+ dictionaryConfig.downloadUrl = ((EditText) findViewById(R.id.downloadUrl)).getText().toString();
+
+ PersistentObjectCache.getInstance().write(
+ DictionaryListActivity.DICTIONARY_CONFIGS, dictionaryConfigs);
+ }
+
+ public boolean onCreateOptionsMenu(final Menu menu) {
+ final MenuItem newDictionaryMenuItem = menu.add(R.string.downloadDictionary);
+ newDictionaryMenuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ public boolean onMenuItemClick(final MenuItem menuItem) {
+ startDownloadDictActivity(DictionaryEditActivity.this, dictionaryConfig);
+ return false;
+ }
+ });
+
+ return true;
+ }
+
+ static void startDownloadDictActivity(final Context context, final DictionaryConfig dictionaryConfig) {
+ final Intent intent = new Intent(context, DownloadActivity.class);
+ intent.putExtra(DownloadActivity.SOURCE, dictionaryConfig.downloadUrl);
+ intent.putExtra(DownloadActivity.DEST, dictionaryConfig.localFile);
+ context.startActivity(intent);
+ }
+
+
+}
--- /dev/null
+package com.hughes.android.dictionary;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.ListActivity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.MenuItem.OnMenuItemClickListener;
+import android.view.View.OnFocusChangeListener;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.EditText;
+import android.widget.ListView;
+import android.widget.TableLayout;
+import android.widget.TextView;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+
+import com.hughes.android.util.PersistentObjectCache;
+
+public class DictionaryListActivity extends ListActivity {
+
+ static final String LOG = "QuickDic";
+
+ static final String DICTIONARY_CONFIGS = "dictionaryConfigs";
+
+ List<DictionaryConfig> dictionaries = new ArrayList<DictionaryConfig>();
+
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Log.d(LOG, "onCreate:" + this);
+
+ // UI init.
+ setContentView(R.layout.list_activity);
+
+ getListView().setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
+ public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int row,
+ long arg3) {
+ return false;
+ }
+ });
+
+ // ContextMenu.
+ registerForContextMenu(getListView());
+
+ getListView().setItemsCanFocus(true);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ dictionaries = (List<DictionaryConfig>) PersistentObjectCache.init(this).read(DICTIONARY_CONFIGS);
+ if (dictionaries == null) {
+ dictionaries = new ArrayList<DictionaryConfig>();
+ }
+ if (dictionaries.size() == 0) {
+ final DictionaryConfig dictionaryConfig = DictionaryConfig.defaultConfig();
+ dictionaries.add(dictionaryConfig);
+ PersistentObjectCache.getInstance().write(DICTIONARY_CONFIGS, dictionaries);
+ }
+
+ setListAdapter(new Adapter());
+ }
+
+ public boolean onCreateOptionsMenu(final Menu menu) {
+ final MenuItem newDictionaryMenuItem = menu.add(R.string.addDictionary);
+ newDictionaryMenuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ public boolean onMenuItemClick(final MenuItem menuItem) {
+ final DictionaryConfig dictionaryConfig = new DictionaryConfig();
+ dictionaryConfig.name = getString(R.string.newDictionary);
+ dictionaries.add(0, dictionaryConfig);
+ dictionaryConfigsChanged();
+ return false;
+ }
+ });
+
+ return true;
+ }
+
+
+ @Override
+ public void onCreateContextMenu(final ContextMenu menu, final View view,
+ final ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, view, menuInfo);
+
+ final AdapterContextMenuInfo adapterContextMenuInfo = (AdapterContextMenuInfo) menuInfo;
+
+ final MenuItem editMenuItem = menu.add(R.string.editDictionary);
+ editMenuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ final Intent intent = new Intent(DictionaryListActivity.this, DictionaryEditActivity.class);
+ intent.putExtra(DictionaryEditActivity.DICT_INDEX, adapterContextMenuInfo.position);
+ startActivity(intent);
+ return true;
+ }
+ });
+
+ if (adapterContextMenuInfo.position > 0) {
+ final MenuItem moveUpMenuItem = menu.add(R.string.moveUp);
+ moveUpMenuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ final DictionaryConfig dictionaryConfig = dictionaries.remove(adapterContextMenuInfo.position);
+ dictionaries.add(adapterContextMenuInfo.position - 1, dictionaryConfig);
+ dictionaryConfigsChanged();
+ return true;
+ }
+ });
+ }
+
+ final MenuItem deleteMenuItem = menu.add(R.string.deleteDictionary);
+ deleteMenuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ dictionaries.remove(adapterContextMenuInfo.position);
+ dictionaryConfigsChanged();
+ return true;
+ }
+ });
+
+ }
+
+ private void dictionaryConfigsChanged() {
+ PersistentObjectCache.getInstance().write(DICTIONARY_CONFIGS, dictionaries);
+ setListAdapter(getListAdapter());
+ }
+
+ static final OnFocusChangeListener focusListener = new OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ final TextView textView = (TextView) v;
+ if (hasFocus) {
+ textView.setTextAppearance(v.getContext(), R.style.Theme_QuickDic);
+ } else {
+ //textView.setTextAppearance(v.getContext(), android.R.style.TextAppearance_Medium);
+ }
+ }
+ };
+
+
+ class Adapter extends BaseAdapter {
+
+ @Override
+ public int getCount() {
+ return dictionaries.size();
+ }
+
+ @Override
+ public DictionaryConfig getItem(int position) {
+ return dictionaries.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ final DictionaryConfig dictionaryConfig = getItem(position);
+ final TableLayout tableLayout = new TableLayout(parent.getContext());
+ final TextView view = new TextView(parent.getContext());
+
+ view.setText(dictionaryConfig.name);
+ view.setTextSize(20);
+ view.setFocusable(true);
+ view.setOnFocusChangeListener(focusListener);
+ tableLayout.addView(view);
+
+ final EditText view2 = new EditText(parent.getContext());
+ view2.setText(dictionaryConfig.name + "2");
+ view2.setFocusable(true);
+ view2.setOnFocusChangeListener(focusListener);
+ tableLayout.addView(view2);
+
+ return tableLayout;
+ }
+
+ }
+
+
+}
if (source == null || dest == null) {\r
throw new RuntimeException("null source or dest.");\r
}\r
- setContentView(R.layout.download);\r
+ setContentView(R.layout.download_activity);\r
\r
final TextView sourceTextView = (TextView) findViewById(R.id.source);\r
sourceTextView.setText(source);\r
import com.hughes.util.raf.RAFFactory;
import com.hughes.util.raf.RAFSerializable;
-public abstract class Entry implements RAFSerializable<Entry> {
+public interface Entry extends RAFSerializable<Entry> {
public static final RAFFactory<Entry> RAF_FACTORY = new RAFFactory<Entry>() {
public Entry create(RandomAccessFile raf) throws IOException {
\r
static final Map<String, Language> symbolToLangauge = new LinkedHashMap<String, Language>();\r
\r
- \r
final String symbol;\r
final Locale locale;\r
\r
return symbol;\r
}\r
\r
- synchronized Collator getFindCollator() {\r
+ public synchronized Collator getFindCollator() {\r
if (findCollator == null) {\r
findCollator = Collator.getInstance(locale);\r
findCollator.setDecomposition(Collator.CANONICAL_DECOMPOSITION);\r
return findCollator;\r
}\r
\r
- synchronized Collator getSortCollator() {\r
+ public synchronized Collator getSortCollator() {\r
if (sortCollator == null) {\r
sortCollator = Collator.getInstance(locale);\r
sortCollator.setDecomposition(Collator.CANONICAL_DECOMPOSITION);\r
\r
// ----------------------------------------------------------------\r
\r
- static Language lookup(final String symbol) {\r
+ public static Language lookup(final String symbol) {\r
return symbolToLangauge.get(symbol.toLowerCase());\r
}\r
\r
\r
import java.io.IOException;\r
import java.io.RandomAccessFile;\r
-import java.util.ArrayList;\r
import java.util.Arrays;\r
import java.util.LinkedHashMap;\r
import java.util.LinkedHashSet;\r
-import java.util.List;\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
-import com.hughes.util.raf.RAFSerializable;\r
\r
public final class SimpleEntry implements Entry {\r
\r
// This used to be called WHITESPACE.\r
static final Pattern NON_TOKEN_CHAR = Pattern.compile("\\s+");\r
\r
- public Map<String,Integer> getIndexableTokens(final byte lang) {\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
package com.hughes.android.dictionary.engine;
import java.io.IOException;
+import java.io.PrintStream;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;
+import com.hughes.util.CachingList;
import com.hughes.util.raf.RAFList;
-import com.hughes.util.raf.RAFSerializer;
+import com.hughes.util.raf.RAFListSerializer;
+import com.hughes.util.raf.RAFSerializable;
-public class Dictionary {
+public class Dictionary implements RAFSerializable<Dictionary> {
// persisted
+ final String dictInfo;
final List<PairEntry> pairEntries;
-
- // persisted
+ final List<TextEntry> textEntries;
final List<EntrySource> sources;
-
- // persisted
final List<Index> indices;
- public Dictionary() {
+ public Dictionary(final String dictInfo) {
+ this.dictInfo = dictInfo;
pairEntries = new ArrayList<PairEntry>();
+ textEntries = new ArrayList<TextEntry>();
sources = new ArrayList<EntrySource>();
indices = new ArrayList<Index>();
}
public Dictionary(final RandomAccessFile raf) throws IOException {
- pairEntries = RAFList.create(raf, PairEntry.SERIALIZER, raf.getFilePointer());
- sources = new ArrayList<EntrySource>();
+ dictInfo = raf.readUTF();
- final RAFSerializer<Index> indexSerializer = new RAFSerializer<Index>() {
+ sources = RAFList.create(raf, EntrySource.SERIALIZER, raf.getFilePointer());
- @Override
- public Index read(RandomAccessFile raf) throws IOException {
- return new Index(Dictionary.this, raf);
- }
+ // TODO: caching
+ pairEntries = RAFList.create(raf, PairEntry.SERIALIZER, raf.getFilePointer());
- @Override
- public void write(RandomAccessFile raf, Index t) throws IOException {
- t.write(raf);
-
- }};
- indices = RAFList.create(raf, indexSerializer, raf.getFilePointer());
+ // TODO: caching
+ textEntries = RAFList.create(raf, TextEntry.SERIALIZER, raf.getFilePointer());
+
+ final List<Index> rawIndices = RAFList.create(raf, indexSerializer, raf.getFilePointer());
+ indices = CachingList.create(rawIndices, rawIndices.size());
}
+ public void print(final PrintStream out) {
+ out.println("dictInfo=" + dictInfo);
+ for (final Index index : indices) {
+ index.print(out);
+ out.println();
+ }
+ }
+
+ @Override
+ public void write(RandomAccessFile raf) throws IOException {
+ 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);
+ }
+
+ private final RAFListSerializer<Index> indexSerializer = new RAFListSerializer<Index>() {
+ @Override
+ public Index read(RandomAccessFile raf, final int readIndex) throws IOException {
+ return new Index(Dictionary.this, raf);
+ }
+ @Override
+ public void write(RandomAccessFile raf, Index t) throws IOException {
+ t.write(raf);
+ }};
+
}
\ No newline at end of file
package com.hughes.android.dictionary.engine;
-import java.util.List;
public abstract class Entry {
EntrySource entrySource;
-
- abstract List<String> getMainTokens();
- abstract List<String> getOtherTokens();
-
+
}
package com.hughes.android.dictionary.engine;
+import java.io.IOException;
+import java.io.RandomAccessFile;
import java.io.Serializable;
import com.hughes.util.IndexedObject;
+import com.hughes.util.raf.RAFListSerializer;
public class EntrySource extends IndexedObject implements Serializable {
final String name;
- public EntrySource(final String name) {
+ public EntrySource(final int index, final String name) {
+ super(index);
this.name = name;
}
+ public static RAFListSerializer<EntrySource> SERIALIZER = new RAFListSerializer<EntrySource>() {
+
+ @Override
+ public EntrySource read(RandomAccessFile raf, int readIndex)
+ throws IOException {
+ final String name = raf.readUTF();
+ return new EntrySource(readIndex, name);
+ }
+
+ @Override
+ public void write(RandomAccessFile raf, EntrySource t) throws IOException {
+ raf.writeUTF(t.name);
+ }
+
+ };
+
}
--- /dev/null
+package com.hughes.android.dictionary.engine;
+
+
+public enum EntryTypeName {
+
+ NOUN(0),
+ VERB(0),
+ ADJ(0),
+ ADV(0),
+ ONE_WORD(0),
+ MULTIROW_HEAD_ONE_WORD(0),
+ MULTIROW_TAIL_ONE_WORD(0),
+
+ TWO_WORDS(0),
+ THREE_WORDS(0),
+ FOUR_WORDS(0),
+ FIVE_OR_MORE_WORDS(0),
+
+ WIKTIONARY_DE_MAIN(0),
+ MULTIROW_HEAD_MANY_WORDS(0),
+ MULTIROW_TAIL_MANY_WORDS(0),
+ PART_OF_HYPHENATED(0),
+ BRACKETED(0),
+ PARENTHESIZED(0),
+ SEE_ALSO(0),
+ ;
+
+ final int nameResId;
+
+ private EntryTypeName(final int nameResId) {
+ this.nameResId = nameResId;
+ }
+
+}
package com.hughes.android.dictionary.engine;
import java.io.IOException;
+import java.io.PrintStream;
import java.io.RandomAccessFile;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import com.hughes.android.dictionary.Language;
import com.hughes.util.raf.RAFList;
import com.hughes.util.raf.RAFSerializable;
import com.hughes.util.raf.RAFSerializer;
import com.hughes.util.raf.UniformRAFList;
-final class Index implements RAFSerializable<Index> {
+public final class Index implements RAFSerializable<Index> {
final Dictionary dict;
final String shortName;
final String longName;
+
+ // persisted: tells how the entries are sorted.
+ final Language sortLanguage;
// persisted
- final List<Index.IndexEntry> sortedIndexEntries;
+ final List<IndexEntry> sortedIndexEntries;
// One big list!
// Various sub-types.
// --------------------------------------------------------------------------
+ public Index(final Dictionary dict, final String shortName, final String longName, final Language sortLanguage) {
+ this.dict = dict;
+ this.shortName = shortName;
+ this.longName = longName;
+ this.sortLanguage = sortLanguage;
+ sortedIndexEntries = new ArrayList<IndexEntry>();
+ rows = new ArrayList<RowBase>();
+ }
+
public Index(final Dictionary dict, final RandomAccessFile raf) throws IOException {
this.dict = dict;
shortName = raf.readUTF();
longName = raf.readUTF();
+ final String languageCode = raf.readUTF();
+ sortLanguage = Language.lookup(languageCode);
+ if (sortLanguage == null) {
+ throw new IOException("Unsupported language: " + languageCode);
+ }
// TODO: caching
sortedIndexEntries = RAFList.create(raf, IndexEntry.SERIALIZER, raf.getFilePointer());
rows = UniformRAFList.create(raf, new RowBase.Serializer(this), raf.getFilePointer());
}
+
+ public void print(final PrintStream out) {
+ for (final RowBase row : rows) {
+ row.print(out);
+ }
+ }
+
@Override
public void write(final RandomAccessFile raf) throws IOException {
raf.writeUTF(shortName);
raf.writeUTF(longName);
+ raf.writeUTF(sortLanguage.getSymbol());
RAFList.write(raf, sortedIndexEntries, IndexEntry.SERIALIZER);
UniformRAFList.write(raf, (Collection<RowBase>) rows, new RowBase.Serializer(this), 5);
}
static final class IndexEntry implements RAFSerializable<Index.IndexEntry> {
String token;
int startRow;
+
static final RAFSerializer<IndexEntry> SERIALIZER = new RAFSerializer<IndexEntry> () {
@Override
public IndexEntry read(RandomAccessFile raf) throws IOException {
public void write(RandomAccessFile raf, IndexEntry t) throws IOException {
t.write(raf);
}};
+
+ public IndexEntry(final String token, final int startRow) {
+ assert token.equals(token.trim());
+ assert token.length() > 0;
+ this.token = token;
+ this.startRow = startRow;
+ }
+
public IndexEntry(final RandomAccessFile raf) throws IOException {
token = raf.readUTF();
startRow = raf.readInt();
}
+
public void write(RandomAccessFile raf) throws IOException {
raf.writeUTF(token);
raf.write(startRow);
package com.hughes.android.dictionary.engine;
import java.io.IOException;
+import java.io.PrintStream;
import java.io.RandomAccessFile;
-import java.util.List;
import com.hughes.util.raf.RAFSerializable;
import com.hughes.util.raf.RAFSerializer;
public class PairEntry extends Entry implements RAFSerializable<PairEntry> {
- public PairEntry(final RandomAccessFile raf) {
+ public static final class Pair {
+ final String lang1;
+ final String lang2;
+ public Pair(final String lang1, final String lang2) {
+ this.lang1 = lang1;
+ this.lang2 = lang2;
+ }
+ public String toString() {
+ return lang1 + "\t" + lang2;
+ }
+ }
+
+ final Pair[] pairs;
+
+ public PairEntry(final Pair[] pairs) {
+ this.pairs = pairs;
+ }
+
+ public PairEntry(final RandomAccessFile raf) throws IOException {
+ pairs = new Pair[raf.readInt()];
+ for (int i = 0; i < pairs.length; ++i) {
+ pairs[i] = new Pair(raf.readUTF(), raf.readUTF());
+ }
}
@Override
public void write(RandomAccessFile raf) throws IOException {
+ // TODO: this couls be a short.
+ raf.writeInt(pairs.length);
+ for (int i = 0; i < pairs.length; ++i) {
+ raf.writeUTF(pairs[i].lang1);
+ raf.writeUTF(pairs[i].lang2);
+ }
}
static final RAFSerializer<PairEntry> SERIALIZER = new RAFSerializer<PairEntry>() {
};
- @Override
- List<String> getMainTokens() {
- return null;
- }
-
- @Override
- List<String> getOtherTokens() {
- return null;
- }
-
-
-
-
public static class Row extends RowBase {
Row(final RandomAccessFile raf, final int thisRowIndex,
final Index index) throws IOException {
super(raf, thisRowIndex, index);
}
-
+
+ Row(final int referenceIndex, final int thisRowIndex,
+ final Index index) {
+ super(referenceIndex, thisRowIndex, index);
+ }
+
public PairEntry getEntry() {
return index.dict.pairEntries.get(referenceIndex);
}
// TODO Auto-generated method stub
return null;
}
+
+ @Override
+ public void print(PrintStream out) {
+ final PairEntry pairEntry = getEntry();
+ for (int i = 0; i < pairEntry.pairs.length; ++i) {
+ out.println((i == 0 ? " " : " ") + pairEntry.pairs[i]);
+ }
+ }
}
package com.hughes.android.dictionary.engine;
import java.io.IOException;
+import java.io.PrintStream;
import java.io.RandomAccessFile;
+import com.hughes.util.IndexedObject;
import com.hughes.util.raf.RAFListSerializer;
-public abstract class RowBase {
+public abstract class RowBase extends IndexedObject {
/**
* the Index owning this RowBase.
*/
final Index index;
- /**
- * Where this row lives within the list of Rows.
- */
- int thisRowIndex;
-
/**
* Where this RowBase points to.
*/
TokenRow tokenRow = null;
RowBase(final RandomAccessFile raf, final int thisRowIndex, final Index index) throws IOException {
+ super(thisRowIndex);
this.index = index;
- this.thisRowIndex = thisRowIndex; // where this was inside the list.
this.referenceIndex = raf.readInt(); // what this points to.
}
- public void write(RandomAccessFile raf) throws IOException {
- raf.writeInt(referenceIndex);
+ public RowBase(final int referenceIndex, final int thisRowIndex, final Index index) {
+ super(thisRowIndex);
+ this.index = index;
+ this.referenceIndex = referenceIndex;
}
-
+
/**
* @return the TokenRow that this row is "filed under".
*/
public TokenRow getTokenRow(final boolean search) {
if (tokenRow == null && search) {
- int r = thisRowIndex - 1;
+ int r = index() - 1;
while (r >= 0) {
final RowBase row = index.rows.get(r);
final TokenRow candidate = row.getTokenRow(false);
if (candidate != null) {
- for (++r; r <= thisRowIndex; ++r) {
+ for (++r; r <= index(); ++r) {
index.rows.get(r).setTokenRow(candidate);
}
}
this.tokenRow = tokenRow;
}
+
+ public abstract void print(PrintStream out);
public abstract Object draw(final String searchText);
} else if (t instanceof TokenRow) {
raf.writeByte(1);
}
- t.write(raf);
+ raf.writeInt(t.referenceIndex);
}
- };
+ }
}
--- /dev/null
+package com.hughes.android.dictionary.engine;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.RandomAccessFile;
+
+import com.hughes.util.raf.RAFSerializable;
+import com.hughes.util.raf.RAFSerializer;
+
+public class TextEntry extends Entry implements RAFSerializable<TextEntry> {
+
+ final String text;
+
+ public TextEntry(final RandomAccessFile raf) throws IOException {
+ text = raf.readUTF();
+ }
+ @Override
+ public void write(RandomAccessFile raf) throws IOException {
+ raf.writeUTF(text);
+ }
+
+ static final RAFSerializer<TextEntry> SERIALIZER = new RAFSerializer<TextEntry>() {
+ @Override
+ public TextEntry read(RandomAccessFile raf) throws IOException {
+ return new TextEntry(raf);
+ }
+
+ @Override
+ public void write(RandomAccessFile raf, TextEntry t) throws IOException {
+ t.write(raf);
+ }
+ };
+
+
+ public static class Row extends RowBase {
+
+ Row(final RandomAccessFile raf, final int thisRowIndex,
+ final Index index) throws IOException {
+ super(raf, thisRowIndex, index);
+ }
+
+ public TextEntry getEntry() {
+ return index.dict.textEntries.get(referenceIndex);
+ }
+
+ @Override
+ public Object draw(String searchText) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void print(PrintStream out) {
+ out.println(" " + getEntry().text);
+ }
+ }
+
+
+
+}
package com.hughes.android.dictionary.engine;
import java.io.IOException;
+import java.io.PrintStream;
import java.io.RandomAccessFile;
public class TokenRow extends RowBase {
super(raf, thisRowIndex, index);
}
+ TokenRow(final int referenceIndex, final int thisRowIndex, final Index index) {
+ super(referenceIndex, thisRowIndex, index);
+ }
+
@Override
public TokenRow getTokenRow(final boolean search) {
return this;
return null;
}
+ @Override
+ public void print(final PrintStream out) {
+ out.println(getToken());
+ }
+
}
--- /dev/null
+package com.hughes.android.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import android.content.Context;
+import android.util.Log;
+
+public class PersistentObjectCache {
+
+ private final File dir;
+ private final Map<String, Object> objects = new LinkedHashMap<String, Object>();
+
+ public synchronized Object read(final String filename) {
+ Object object = (objects.get(filename));
+ if (object != null) {
+ return object;
+ }
+ Log.d(getClass().getSimpleName(), "Cache miss.");
+ final File src = new File(dir, filename);
+ if (!src.canRead()) {
+ Log.d(getClass().getSimpleName(), "File empty: " + src);
+ return null;
+ }
+ try {
+ final ObjectInputStream in = new ObjectInputStream(new FileInputStream(src));
+ object = in.readObject();
+ in.close();
+ } catch (Exception e) {
+ Log.e(getClass().getSimpleName(), "Deserialization failed: " + src, e);
+ return null;
+ }
+ objects.put(filename, object);
+ return object;
+ }
+
+ public synchronized void write(final String filename, final Object object) {
+ objects.put(filename, object);
+ final File dest = new File(dir, filename);
+ try {
+ final ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(dest));
+ out.writeObject(object);
+ out.close();
+ } catch (Exception e) {
+ Log.e(getClass().getSimpleName(), "Serialization failed: " + dest, e);
+ }
+ }
+
+ private PersistentObjectCache(final Context context) {
+ dir = context.getFilesDir();
+ }
+
+ public static synchronized PersistentObjectCache getInstance() {
+ if (instance == null) {
+ throw new RuntimeException("getInstance called before init.");
+ }
+ return instance;
+ }
+
+ public static synchronized PersistentObjectCache init(final Context context) {
+ if (instance == null) {
+ instance = new PersistentObjectCache(context);
+ } else {
+ if (!instance.dir.equals(context.getFilesDir())) {
+ throw new RuntimeException("File dir changed. old=" + instance.dir + ", new=" + context.getFilesDir());
+ }
+ }
+ return instance;
+ }
+
+ private static PersistentObjectCache instance = null;
+
+}