]> gitweb.fperrin.net Git - Dictionary.git/commitdiff
go
authorthadh <thadh@THADH-MTV.ad.corp.google.com>
Wed, 18 Mar 2009 05:49:04 +0000 (22:49 -0700)
committerthadh <thadh@THADH-MTV.ad.corp.google.com>
Wed, 18 Mar 2009 05:49:04 +0000 (22:49 -0700)
res/layout/main.xml
src/com/hughes/android/dictionary/Dictionary.java
src/com/hughes/android/dictionary/DictionaryActivity.java
src/com/hughes/android/dictionary/Entry.java
src/com/hughes/android/dictionary/R.java

index 80dee9162a584917af3d1e94f8ebfeea9227ccd1..e1e4a89481cd31f2bbdd17d79c8592a759c3cc5f 100755 (executable)
@@ -3,12 +3,16 @@
        android:orientation="vertical" android:layout_width="fill_parent"
        android:layout_height="fill_parent">
 
-       <EditText android:layout_width="fill_parent"
-               android:layout_height="wrap_content" android:id="@+id/SearchText"
-               android:hint="Search Text"></EditText>
+       <LinearLayout android:layout_height="wrap_content" android:id="@+id/SearchBarLinearLayout" android:layout_width="wrap_content">
+
+
+</LinearLayout><TableLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/SearchBarTableLayout" android:stretchColumns="0">
+<TableRow android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/SearchBarTableRow"><EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/SearchText" android:hint="Search Text"></EditText><Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/LangButton" android:text="LANG"></Button><Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/DownButton" android:text="v"></Button><Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/UpButton" android:text="^"></Button></TableRow>
+</TableLayout>
 
        <ListView android:id="@id/android:list"
                android:layout_width="fill_parent" android:layout_height="fill_parent"
                android:choiceMode="singleChoice" android:clickable="true"></ListView>
 
+
 </LinearLayout>
index f0efe823eeac3abfde9248afed284073824600ce..6645c9c5fd4f6ac64590b644aff4c38a2f7c5c7d 100755 (executable)
@@ -3,7 +3,9 @@ package com.hughes.android.dictionary;
 import java.io.IOException;\r
 import java.io.RandomAccessFile;\r
 import java.util.ArrayList;\r
+import java.util.Comparator;\r
 import java.util.List;\r
+import java.util.concurrent.atomic.AtomicBoolean;\r
 \r
 import com.hughes.util.CachingList;\r
 import com.hughes.util.raf.FileList;\r
@@ -11,78 +13,139 @@ import com.hughes.util.raf.RAFFactory;
 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.UniformFileList;\r
 \r
 public final class Dictionary implements RAFSerializable<Dictionary> {\r
-  \r
-  static final RAFSerializer<Entry> ENTRY_SERIALIZER = new RAFSerializableSerializer<Entry>(Entry.RAF_FACTORY);\r
-  static final RAFSerializer<Row> ROW_SERIALIZER = new RAFSerializableSerializer<Row>(Row.RAF_FACTORY);\r
-  static final RAFSerializer<IndexEntry> INDEX_ENTRY_SERIALIZER = new RAFSerializableSerializer<IndexEntry>(IndexEntry.RAF_FACTORY);\r
+\r
+  static final RAFSerializer<Entry> ENTRY_SERIALIZER = new RAFSerializableSerializer<Entry>(\r
+      Entry.RAF_FACTORY);\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 List<Entry> entries;\r
   final Language[] languages = new Language[2];\r
-  \r
-  Language activeLanguage = null;\r
 \r
   public Dictionary(final String lang0, final String lang1) {\r
-    languages[0] = new Language(lang0);\r
-    languages[1] = new Language(lang1);\r
+    languages[0] = new Language(lang0, Entry.LANG1);\r
+    languages[1] = new Language(lang1, Entry.LANG2);\r
     entries = new ArrayList<Entry>();\r
   }\r
-  \r
+\r
   public Dictionary(final RandomAccessFile raf) throws IOException {\r
-    entries = CachingList.create(FileList.create(raf, ENTRY_SERIALIZER, raf.getFilePointer()), 10000);\r
-    languages[0] = new Language(raf);\r
-    languages[1] = new Language(raf);\r
+    entries = CachingList.create(FileList.create(raf, ENTRY_SERIALIZER, raf\r
+        .getFilePointer()), 10000);\r
+    languages[0] = new Language(raf, Entry.LANG1);\r
+    languages[1] = new Language(raf, Entry.LANG2);\r
   }\r
+\r
   public void write(RandomAccessFile raf) throws IOException {\r
     FileList.write(raf, entries, ENTRY_SERIALIZER);\r
     languages[0].write(raf);\r
     languages[1].write(raf);\r
   }\r
-  \r
-  static final class Language implements RAFSerializable<Language> {\r
+\r
+  final class Language implements RAFSerializable<Language> {\r
+    final byte lang;\r
     final String symbol;\r
     final List<Row> rows;\r
     final List<IndexEntry> sortedIndex;\r
-    \r
-    public Language(final String symbol) {\r
+    final Comparator<String> comparator = EntryFactory.entryFactory\r
+        .getEntryComparator();\r
+\r
+    Language(final String symbol, final byte lang) {\r
+      this.lang = lang;\r
       this.symbol = symbol;\r
       rows = new ArrayList<Row>();\r
       sortedIndex = new ArrayList<IndexEntry>();\r
     }\r
 \r
-    public Language(final RandomAccessFile raf) throws IOException {\r
+    Language(final RandomAccessFile raf, final byte lang) throws IOException {\r
+      this.lang = lang;\r
       symbol = raf.readUTF();\r
-      rows = CachingList.create(FileList.create(raf, ROW_SERIALIZER, raf.getFilePointer()), 10000);\r
-      sortedIndex = CachingList.create(FileList.create(raf, INDEX_ENTRY_SERIALIZER, raf.getFilePointer()), 10000);\r
+      rows = CachingList.create(UniformFileList.create(raf, ROW_SERIALIZER, raf\r
+          .getFilePointer()), 10000);\r
+      sortedIndex = CachingList.create(FileList.create(raf,\r
+          INDEX_ENTRY_SERIALIZER, raf.getFilePointer()), 10000);\r
     }\r
+\r
     public void write(final RandomAccessFile raf) throws IOException {\r
       raf.writeUTF(symbol);\r
-      FileList.write(raf, rows, ROW_SERIALIZER);\r
+      UniformFileList.write(raf, rows, ROW_SERIALIZER, 4);\r
       FileList.write(raf, sortedIndex, INDEX_ENTRY_SERIALIZER);\r
     }\r
+\r
+    String rowToString(final Row row) {\r
+      return row.isToken() ? sortedIndex.get(row.getIndex()).word : entries\r
+          .get(row.getIndex()).toString();\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
+\r
+        final int comp = comparator.compare(word, midEntry.word.toLowerCase());\r
+        if (comp == 0) {\r
+          int result = mid;\r
+          while (result > 0 && comparator.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
+          end = mid;\r
+        } else {\r
+          start = mid + 1;\r
+        }\r
+      }\r
+      return start;\r
+    }\r
   }\r
-  \r
+\r
   public static final class Row implements RAFSerializable<Row> {\r
     final int index;\r
 \r
-    public Row(int index) {\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
+\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
+\r
     public IndexEntry(final String word, final int startRow) {\r
       this.word = word;\r
       this.startRow = startRow;\r
@@ -93,7 +156,9 @@ public final class Dictionary implements RAFSerializable<Dictionary> {
         final String word = raf.readUTF();\r
         final int startRow = raf.readInt();\r
         return new IndexEntry(word, startRow);\r
-      }};\r
+      }\r
+    };\r
+\r
     public void write(final RandomAccessFile raf) throws IOException {\r
       raf.writeUTF(word);\r
       raf.writeInt(startRow);\r
@@ -103,8 +168,7 @@ public final class Dictionary implements RAFSerializable<Dictionary> {
     public String toString() {\r
       return word + "@" + startRow;\r
     }\r
-    \r
-    \r
+\r
   }\r
 \r
 }\r
index 6d1abb9ff2daa8bb2a5b11843f1d06c45fe6d1b9..0e300865af98d474c3a28b9cdf2c8623bf239ac8 100755 (executable)
@@ -4,14 +4,11 @@ import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
+import java.io.RandomAccessFile;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import com.hughes.android.dictionary.Dictionary.Row;
-
 import android.app.ListActivity;
 import android.os.Bundle;
 import android.os.Handler;
@@ -19,76 +16,119 @@ import android.text.Editable;
 import android.text.TextWatcher;
 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.OnClickListener;
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
+import android.widget.Button;
 import android.widget.EditText;
 import android.widget.ListView;
+import android.widget.TableLayout;
+import android.widget.TableRow;
 import android.widget.TextView;
 import android.widget.AdapterView.OnItemLongClickListener;
 
+import com.hughes.android.dictionary.Dictionary.IndexEntry;
+import com.hughes.android.dictionary.Dictionary.Language;
+import com.hughes.android.dictionary.Dictionary.Row;
+
 public class DictionaryActivity extends ListActivity {
 
+  private RandomAccessFile dictRaf = null;
   private Dictionary dictionary = null;
-  
+  private Language activeLanguge = null;
+
   private File wordList = new File("/sdcard/wordList.txt");
 
   final Handler uiHandler = new Handler();
 
-  private final Object mutex = new Object();
   private Executor searchExecutor = Executors.newSingleThreadExecutor();
   private SearchOperation searchOperation = null;
-//  private List<Entry> entries = Collections.emptyList();
+  // private List<Entry> entries = Collections.emptyList();
   private DictionaryListAdapter dictionaryListAdapter = new DictionaryListAdapter();
-  private int selectedItem = -1;
+  private int selectedRow = -1;
 
   /** Called when the activity is first created. */
   @Override
   public void onCreate(Bundle savedInstanceState) {
     Log.d("THAD", "onCreate");
     super.onCreate(savedInstanceState);
-    
+
     try {
-      dictionary = new Dictionary("/sdcard/dict-de-en.txt", Entry.LANG1);
+      dictRaf = new RandomAccessFile("/sdcard/de-en.dict", "r");
+      dictionary = new Dictionary(dictRaf);
+      activeLanguge = dictionary.languages[Entry.LANG1];
     } catch (Exception e) {
       throw new RuntimeException(e);
     }
-    
+
     setContentView(R.layout.main);
 
-    EditText searchText = (EditText) findViewById(R.id.SearchText);
+    final EditText searchText = (EditText) findViewById(R.id.SearchText);
     searchText.addTextChangedListener(new DictionaryTextWatcher());
 
     setListAdapter(dictionaryListAdapter);
 
     onSearchTextChange("");
+    final Button langButton = (Button) findViewById(R.id.LangButton);
+    langButton.setOnClickListener(new OnClickListener() {
+      public void onClick(View v) {
+        switchLanguage();
+      }});
+    updateLangButton();
 
     registerForContextMenu(getListView());
     getListView().setOnItemLongClickListener((new OnItemLongClickListener() {
       public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2,
           long arg3) {
-        selectedItem = arg2;
+        selectedRow = arg2;
         return false;
       }
     }));
   }
+  
+  public String getSelectedRowText() {
+    return activeLanguge.rowToString(activeLanguge.rows.get(selectedRow));
+  }
+
+  private MenuItem switchLanguageMenuItem = null;
+  
+  @Override
+  public boolean onCreateOptionsMenu(final Menu menu) {
+    switchLanguageMenuItem = menu.add("Switch to language.");
+    return true;
+  }
+  
+  @Override
+  public boolean onPrepareOptionsMenu(final Menu menu) {
+    switchLanguageMenuItem.setTitle(String.format("Switch to %s", dictionary.languages[Entry.otherLang(activeLanguge.lang)].symbol));
+    return super.onPrepareOptionsMenu(menu);
+  }
+  
+  @Override
+  public boolean onOptionsItemSelected(final MenuItem item) {
+    if (item == switchLanguageMenuItem) {
+      switchLanguage();
+    }
+    return super.onOptionsItemSelected(item);
+  }
 
   @Override
   public void onCreateContextMenu(ContextMenu menu, View v,
       ContextMenuInfo menuInfo) {
-    if (selectedItem == -1) {
+    if (selectedRow == -1) {
       return;
     }
     final MenuItem addToWordlist = menu.add("Add to wordlist.");
     addToWordlist.setOnMenuItemClickListener(new OnMenuItemClickListener() {
       public boolean onMenuItemClick(MenuItem item) {
-        final String rawText = "";//entries.get(selectedItem).getRawText();
-        Log.d("THAD", "Writing : "
-                + rawText);
+        final String rawText = getSelectedRowText();
+        Log.d("THAD", "Writing : " + rawText);
         try {
           final OutputStream out = new FileOutputStream(wordList, true);
           out.write((rawText + "\n").getBytes());
@@ -100,47 +140,60 @@ public class DictionaryActivity extends ListActivity {
       }
     });
   }
+  
+  void switchLanguage() {
+    activeLanguge = dictionary.languages[(activeLanguge == dictionary.languages[0]) ? 1 : 0];
+    updateLangButton();
+    dictionaryListAdapter.notifyDataSetChanged();
+    final EditText searchText = (EditText) findViewById(R.id.SearchText);
+    onSearchTextChange(searchText.getText().toString());
+  }
+  
+  void updateLangButton() {
+    final Button langButton = (Button) findViewById(R.id.LangButton);
+    langButton.setText(dictionary.languages[activeLanguge.lang].symbol.toUpperCase());
+  }
 
   @Override
-  protected void onListItemClick(ListView l, View v, int position, long id) {
-    try {
-      Log.d("THAD", "Clicked: " + dictionary.getRow(position));
-    } catch (IOException e) {
-      throw new RuntimeException(e);
-    }
-    selectedItem = position;
+  protected void onListItemClick(ListView l, View v, int row, long id) {
+    selectedRow = row;
+    Log.d("THAD", "Clicked: " + getSelectedRowText());
     openContextMenu(getListView());
   }
 
   void onSearchTextChange(final String searchText) {
     Log.d("THAD", "onSearchTextChange: " + searchText);
-    if (1==1) return;
-    synchronized (mutex) {
-      if (searchOperation != null) {
-        searchOperation.interrupted.set(true);
-      }
-      searchOperation = new SearchOperation(searchText);
+    if (searchOperation != null) {
+      searchOperation.interrupted.set(true);
     }
+    searchOperation = new SearchOperation(searchText);
     searchExecutor.execute(searchOperation);
   }
+  
+  private void jumpToRow(final int row) {
+    selectedRow = row;
+    getListView().setSelection(row);
+  }
 
   private final class SearchOperation implements Runnable {
     final String searchText;
-    final int count = 100;
     final AtomicBoolean interrupted = new AtomicBoolean(false);
 
     public SearchOperation(final String searchText) {
-      this.searchText = searchText.toLowerCase(); // TODO: better
+      this.searchText = searchText;
     }
 
     public void run() {
       Log.d("THAD", "SearchOperation: " + searchText);
+      final int indexLocation = activeLanguge.lookup(searchText, interrupted);
+      if (interrupted.get()) {
+        return;
+      }
+      final IndexEntry indexEntry = activeLanguge.sortedIndex
+          .get(indexLocation);
       uiHandler.post(new Runnable() {
         public void run() {
-          synchronized (mutex) {
-            dictionaryListAdapter.notifyDataSetChanged();
-          }
+          jumpToRow(indexEntry.startRow);
         }
       });
     }
@@ -149,16 +202,12 @@ public class DictionaryActivity extends ListActivity {
   private class DictionaryListAdapter extends BaseAdapter {
 
     public int getCount() {
-      return dictionary.numRows();
+      return activeLanguge.rows.size();
     }
 
     public Dictionary.Row getItem(int position) {
-      assert position < dictionary.numRows();
-      try {
-        return dictionary.getRow(position);
-      } catch (IOException e) {
-        throw new RuntimeException(e);
-      }
+      assert position < activeLanguge.rows.size();
+      return activeLanguge.rows.get(position);
     }
 
     public long getItemId(int position) {
@@ -167,16 +216,59 @@ public class DictionaryActivity extends ListActivity {
 
     public View getView(final int position, final View convertView,
         final ViewGroup parent) {
-      TextView result = null;
-      if (convertView instanceof TextView) {
-        result = (TextView) convertView;
+      final Row row = getItem(position);
+      if (row.isToken()) {
+        TextView result = null;
+        if (convertView instanceof TextView) {
+          result = (TextView) convertView;
+        } else {
+          result = new TextView(parent.getContext());
+        }
+        result.setText(activeLanguge.rowToString(row));
+        result.setTextAppearance(parent.getContext(),
+            android.R.style.TextAppearance_Large);
+        return result;
+      }
+
+      TableLayout result = null;
+      if (convertView instanceof TableLayout) {
+        result = (TableLayout) convertView;
       } else {
-        result = new TextView(parent.getContext());
+        result = new TableLayout(parent.getContext());
       }
-      final Row row = getItem(position);
-      result.setText(row.text);
-      result.setBackgroundColor(row.isWord ? );
+
+      TableRow tableRow = null;
+      if (result.getChildCount() != 1) {
+        result.removeAllViews();
+        tableRow = new TableRow(result.getContext());
+        result.addView(tableRow);
+      } else {
+        tableRow = (TableRow) result.getChildAt(0);
+      }
+      TextView column1 = null;
+      TextView column2 = null;
+      if (tableRow.getChildCount() != 2
+          || !(tableRow.getChildAt(0) instanceof TextView)
+          || !(tableRow.getChildAt(1) instanceof TextView)) {
+        tableRow.removeAllViews();
+        column1 = new TextView(tableRow.getContext());
+        column2 = new TextView(tableRow.getContext());
+        tableRow.addView(column1);
+        tableRow.addView(column2);
+      } else {
+        column1 = (TextView) tableRow.getChildAt(0);
+        column2 = (TextView) tableRow.getChildAt(1);
+      }
+      column1.setWidth(100);
+      column2.setWidth(100);
+      // column1.setTextAppearance(parent.getContext(), android.R.style.Text);
+      final Entry entry = dictionary.entries.get(row.getIndex());
+      column1.setText(entry.getAllText(activeLanguge.lang));
+      column2.setText(entry.getAllText(Entry.otherLang(activeLanguge.lang)));
+      // result.setTextAppearance(parent.getContext(),
+      // android.R.style.TextAppearance_Small);
       return result;
+
     }
   }
 
index bd000f408b5c5cbef114c5e57831471ca14cc9fd..6d8576477029d939a0813e5cfc0d4526efd2242c 100755 (executable)
@@ -67,19 +67,19 @@ public final class Entry implements RAFSerializable<Entry> {
     return text;\r
   }\r
 \r
-  public String getFormattedEntry(final byte lang) {\r
-    return getAllText(lang) + "\n" + getAllText(OtherLang(lang));\r
+  String getFormattedEntry(final byte lang) {\r
+    return getAllText(lang) + "\n" + getAllText(otherLang(lang));\r
   }\r
 \r
-  private byte OtherLang(final byte lang) {\r
+  String getRawText() {\r
+    return getAllText(LANG1) + " :: " + getAllText(LANG2);\r
+  }\r
+  \r
+  static byte otherLang(final byte lang) {\r
     assert lang == LANG1 || lang == LANG2;\r
     return lang == LANG1 ? LANG2 : LANG1;\r
   }\r
 \r
-  public String getRawText() {\r
-    return getAllText(LANG1) + " :: " + getAllText(LANG2);\r
-  }\r
-  \r
   \r
 \r
   static Entry parseFromLine(final String line) {\r
index a74f9490e2332335619467d8dee3e83a0bcfd6e0..2a750f4dc41761ebacc910d0a1075b415185b775 100755 (executable)
@@ -14,7 +14,13 @@ public final class R {
         public static final int icon=0x7f020000;\r
     }\r
     public static final class id {\r
-        public static final int SearchText=0x7f050000;\r
+        public static final int DownButton=0x7f050005;\r
+        public static final int LangButton=0x7f050004;\r
+        public static final int SearchBarLinearLayout=0x7f050000;\r
+        public static final int SearchBarTableLayout=0x7f050001;\r
+        public static final int SearchBarTableRow=0x7f050002;\r
+        public static final int SearchText=0x7f050003;\r
+        public static final int UpButton=0x7f050006;\r
     }\r
     public static final class layout {\r
         public static final int main=0x7f030000;\r