]> gitweb.fperrin.net Git - Dictionary.git/commitdiff
go
authorThad Hughes <thad.hughes@gmail.com>
Fri, 8 Oct 2010 22:15:14 +0000 (15:15 -0700)
committerThad Hughes <thad.hughes@gmail.com>
Fri, 8 Oct 2010 22:15:14 +0000 (15:15 -0700)
29 files changed:
AndroidManifest.xml
default.properties
res/layout/about_activity.xml [moved from res/layout/about.xml with 100% similarity]
res/layout/dictionary_activity.xml [moved from res/layout/main.xml with 100% similarity]
res/layout/download_activity.xml [moved from res/layout/download.xml with 100% similarity]
res/layout/edit_activity.xml [new file with mode: 0755]
res/layout/list_activity.xml [new file with mode: 0644]
res/values/strings.xml
res/values/theme.xml [new file with mode: 0644]
src/com/hughes/android/dictionary/AboutActivity.java
src/com/hughes/android/dictionary/Dictionary.java
src/com/hughes/android/dictionary/DictionaryActivity.java
src/com/hughes/android/dictionary/DictionaryConfig.java [new file with mode: 0644]
src/com/hughes/android/dictionary/DictionaryEditActivity.java [new file with mode: 0644]
src/com/hughes/android/dictionary/DictionaryListActivity.java [new file with mode: 0644]
src/com/hughes/android/dictionary/DownloadActivity.java
src/com/hughes/android/dictionary/Entry.java
src/com/hughes/android/dictionary/Language.java
src/com/hughes/android/dictionary/SimpleEntry.java
src/com/hughes/android/dictionary/engine/Dictionary.java
src/com/hughes/android/dictionary/engine/Entry.java
src/com/hughes/android/dictionary/engine/EntrySource.java
src/com/hughes/android/dictionary/engine/EntryTypeName.java [new file with mode: 0644]
src/com/hughes/android/dictionary/engine/Index.java
src/com/hughes/android/dictionary/engine/PairEntry.java
src/com/hughes/android/dictionary/engine/RowBase.java
src/com/hughes/android/dictionary/engine/TextEntry.java [new file with mode: 0644]
src/com/hughes/android/dictionary/engine/TokenRow.java
src/com/hughes/android/util/PersistentObjectCache.java [new file with mode: 0644]

index 5bff2e3ec1c51bd2205518e03e1c4696f2c7c4cc..17f77d08f0d7862f6a42faff0362f53456bb8b08 100644 (file)
@@ -1,30 +1,39 @@
 <?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>
 
index a1ef8e9ff47020568453aecb2452fa624961b326..19c96655d772aa6da4be76417b997aa63fa6cfcb 100644 (file)
@@ -10,4 +10,4 @@
 # Indicates whether an apk should be generated for each density.
 split.density=false
 # Project target.
-target=android-3
+target=android-4
diff --git a/res/layout/edit_activity.xml b/res/layout/edit_activity.xml
new file mode 100755 (executable)
index 0000000..58e4b35
--- /dev/null
@@ -0,0 +1,71 @@
+<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
diff --git a/res/layout/list_activity.xml b/res/layout/list_activity.xml
new file mode 100644 (file)
index 0000000..037e137
--- /dev/null
@@ -0,0 +1,31 @@
+<?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>
index 3b2e929233aa502a75dc8cef8952626a265e077f..c7925a1de0138b3f031216de27ef30ed5d45284a 100644 (file)
@@ -3,7 +3,22 @@
 
        <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>
diff --git a/res/values/theme.xml b/res/values/theme.xml
new file mode 100644 (file)
index 0000000..720baa9
--- /dev/null
@@ -0,0 +1,13 @@
+<?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>
index 065b0c48739f9cfe76c0424137667e5278d3206e..9697ae6bdb571fbba2696e281ed6ec00b639df89 100755 (executable)
@@ -6,19 +6,19 @@ import android.os.Bundle;
 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
index 3133e281dcdd82b33436361ede4f92939ec40296..c0a35880879a86649be99a2841f092f8f95e7be5 100755 (executable)
@@ -18,8 +18,7 @@ public final class Dictionary implements RAFSerializable<Dictionary> {
   \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
@@ -41,8 +40,7 @@ public final class Dictionary implements RAFSerializable<Dictionary> {
   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
@@ -54,7 +52,7 @@ public final class Dictionary implements RAFSerializable<Dictionary> {
   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
@@ -95,8 +93,9 @@ public final class Dictionary implements RAFSerializable<Dictionary> {
     }\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
index e8d188f4b9974adb5442f3962d980e4b9c9dfc21..d6a6ff10d7a0cb0a0fc24ad7f195adb7455f0df1 100644 (file)
@@ -55,6 +55,7 @@ import com.ibm.icu.text.Collator;
 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
@@ -118,7 +119,7 @@ public class DictionaryActivity extends ListActivity {
 
     // UI init.
 
-    setContentView(R.layout.main);
+    setContentView(R.layout.dictionary_activity);
     searchText = (EditText) findViewById(R.id.SearchText);
     langButton = (Button) findViewById(R.id.LangButton);
     
@@ -592,7 +593,7 @@ public class DictionaryActivity extends ListActivity {
       // 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());
diff --git a/src/com/hughes/android/dictionary/DictionaryConfig.java b/src/com/hughes/android/dictionary/DictionaryConfig.java
new file mode 100644 (file)
index 0000000..1c2458b
--- /dev/null
@@ -0,0 +1,26 @@
+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;
+  }
+  
+}
diff --git a/src/com/hughes/android/dictionary/DictionaryEditActivity.java b/src/com/hughes/android/dictionary/DictionaryEditActivity.java
new file mode 100644 (file)
index 0000000..3c2f5a0
--- /dev/null
@@ -0,0 +1,79 @@
+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);
+  }
+
+
+}
diff --git a/src/com/hughes/android/dictionary/DictionaryListActivity.java b/src/com/hughes/android/dictionary/DictionaryListActivity.java
new file mode 100644 (file)
index 0000000..faeb8fe
--- /dev/null
@@ -0,0 +1,192 @@
+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;
+    }
+    
+  }
+
+
+}
index cff7463e83d5b262c1e3e795f08c88637977e629..fca603a8860b809591c0e4dc9c27611eae58500b 100755 (executable)
@@ -43,7 +43,7 @@ public class DownloadActivity extends Activity {
     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
index fb95f4ce2bb6c34b7b48bf4cf4cc49c95a531460..b5ba715512666ddfd7748b4c0e8f9aef4f5102e7 100644 (file)
@@ -6,7 +6,7 @@ import java.io.RandomAccessFile;
 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 {
index 0f53d7ff4f0fe90700145a315402935d1f4af2fe..9732efad221f93378fa017e3578f3e276d5c6cbc 100755 (executable)
@@ -11,7 +11,6 @@ public class Language {
 \r
   static final Map<String, Language> symbolToLangauge = new LinkedHashMap<String, Language>();\r
 \r
-  \r
   final String symbol;\r
   final Locale locale;\r
 \r
@@ -53,7 +52,7 @@ public class Language {
     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
@@ -62,7 +61,7 @@ public class Language {
     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
@@ -113,7 +112,7 @@ public class Language {
 \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
index d90d51fc78224a4934e0a731b3497b6269095cfd..4ee8dd41199616e1a9839059fce2cb6110955bd9 100755 (executable)
@@ -2,18 +2,15 @@ package com.hughes.android.dictionary;
 \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
@@ -177,7 +174,7 @@ Zp  Separator, Paragraph
   // 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
index cea0c7d22aa64a3ee4b957faee9200149a2ac78e..1472d310623de67fcc369d96c3f28bc7351e4947 100644 (file)
@@ -1,48 +1,74 @@
 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
index af279c1f3058b6e6000fe0c2d6429d6e67aaef59..9efd1f535d5eef63d0a2a0cfde4c430845b72249 100644 (file)
@@ -1,12 +1,8 @@
 package com.hughes.android.dictionary.engine;
 
-import java.util.List;
 
 public abstract class Entry {
   
   EntrySource entrySource;
-  
-  abstract List<String> getMainTokens();
-  abstract List<String> getOtherTokens();
-  
+    
 }
index f773f6096fe2b3b60223e3bf7d89e98e9797305b..914cf8f5f7578c34678d27a0c83eb6a673f03112 100644 (file)
@@ -1,8 +1,11 @@
 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 {
   
@@ -10,8 +13,25 @@ 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);
+    }
+    
+  };
+  
 }
diff --git a/src/com/hughes/android/dictionary/engine/EntryTypeName.java b/src/com/hughes/android/dictionary/engine/EntryTypeName.java
new file mode 100644 (file)
index 0000000..008da6a
--- /dev/null
@@ -0,0 +1,34 @@
+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;
+  }
+
+}
index 9185d9d4623a32378eb8b40bf9a7cc352d412f9f..49536003bf29502a9e953302139d271b65bf9002 100644 (file)
@@ -4,23 +4,29 @@
 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.
@@ -29,18 +35,40 @@ final class Index implements RAFSerializable<Index> {
   
   // --------------------------------------------------------------------------
   
+  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);
   }
@@ -49,6 +77,7 @@ final class Index implements RAFSerializable<Index> {
   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 {
@@ -58,10 +87,19 @@ final class Index implements RAFSerializable<Index> {
       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);
index e22969e3fe21dc1b41ea13fa4f7af32b07892057..55c32d0dbb8d8d0d90902b5f4fcc64f4a63158e1 100644 (file)
@@ -1,18 +1,46 @@
 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>() {
@@ -28,26 +56,18 @@ public class PairEntry extends Entry implements RAFSerializable<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);
     }
@@ -57,6 +77,14 @@ public class PairEntry extends Entry implements RAFSerializable<PairEntry> {
       // 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]);
+      }
+    }
   }
 
 
index 95c226761121cd977a4babef10a810fd987f89c2..61ff4e078d464e26dcd0130109683199924be44f 100644 (file)
@@ -1,21 +1,18 @@
 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.
    */
@@ -27,26 +24,28 @@ public abstract class RowBase {
   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);
           }
         }
@@ -62,6 +61,8 @@ public abstract class RowBase {
     this.tokenRow = tokenRow;
   }
 
+
+  public abstract void print(PrintStream out);
   
   public abstract Object draw(final String searchText);
 
@@ -94,9 +95,9 @@ public abstract class RowBase {
       } else if (t instanceof TokenRow) {
         raf.writeByte(1);
       }
-      t.write(raf);
+      raf.writeInt(t.referenceIndex);
     }
-  };
+  }
 
 
 }
diff --git a/src/com/hughes/android/dictionary/engine/TextEntry.java b/src/com/hughes/android/dictionary/engine/TextEntry.java
new file mode 100644 (file)
index 0000000..87d29d7
--- /dev/null
@@ -0,0 +1,60 @@
+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);
+    }
+  }
+
+
+
+}
index 7a9f5d977f886b39121959e013b0bca17fce4b34..06a1aa8a891ee272561534a6023937b09e507c21 100644 (file)
@@ -1,6 +1,7 @@
 package com.hughes.android.dictionary.engine;
 
 import java.io.IOException;
+import java.io.PrintStream;
 import java.io.RandomAccessFile;
 
 public class TokenRow extends RowBase {
@@ -9,6 +10,10 @@ 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;
@@ -29,5 +34,10 @@ public class TokenRow extends RowBase {
     return null;
   }
 
+  @Override
+  public void print(final PrintStream out) {
+    out.println(getToken());
+  }
+
 
 }
diff --git a/src/com/hughes/android/util/PersistentObjectCache.java b/src/com/hughes/android/util/PersistentObjectCache.java
new file mode 100644 (file)
index 0000000..2d9d2ff
--- /dev/null
@@ -0,0 +1,78 @@
+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;
+
+}