From: thadh Date: Wed, 18 Mar 2009 05:49:04 +0000 (-0700) Subject: go X-Git-Url: http://gitweb.fperrin.net/?a=commitdiff_plain;h=29fd21b2158ad639439df7097a51cfbd003ef049;p=Dictionary.git go --- diff --git a/res/layout/main.xml b/res/layout/main.xml index 80dee91..e1e4a89 100755 --- a/res/layout/main.xml +++ b/res/layout/main.xml @@ -3,12 +3,16 @@ android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> - + + + + + + + diff --git a/src/com/hughes/android/dictionary/Dictionary.java b/src/com/hughes/android/dictionary/Dictionary.java index f0efe82..6645c9c 100755 --- a/src/com/hughes/android/dictionary/Dictionary.java +++ b/src/com/hughes/android/dictionary/Dictionary.java @@ -3,7 +3,9 @@ package com.hughes.android.dictionary; import java.io.IOException; import java.io.RandomAccessFile; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; import com.hughes.util.CachingList; import com.hughes.util.raf.FileList; @@ -11,78 +13,139 @@ import com.hughes.util.raf.RAFFactory; import com.hughes.util.raf.RAFSerializable; import com.hughes.util.raf.RAFSerializableSerializer; import com.hughes.util.raf.RAFSerializer; +import com.hughes.util.raf.UniformFileList; public final class Dictionary implements RAFSerializable { - - static final RAFSerializer ENTRY_SERIALIZER = new RAFSerializableSerializer(Entry.RAF_FACTORY); - static final RAFSerializer ROW_SERIALIZER = new RAFSerializableSerializer(Row.RAF_FACTORY); - static final RAFSerializer INDEX_ENTRY_SERIALIZER = new RAFSerializableSerializer(IndexEntry.RAF_FACTORY); + + static final RAFSerializer ENTRY_SERIALIZER = new RAFSerializableSerializer( + Entry.RAF_FACTORY); + static final RAFSerializer ROW_SERIALIZER = new RAFSerializableSerializer( + Row.RAF_FACTORY); + static final RAFSerializer INDEX_ENTRY_SERIALIZER = new RAFSerializableSerializer( + IndexEntry.RAF_FACTORY); final List entries; final Language[] languages = new Language[2]; - - Language activeLanguage = null; public Dictionary(final String lang0, final String lang1) { - languages[0] = new Language(lang0); - languages[1] = new Language(lang1); + languages[0] = new Language(lang0, Entry.LANG1); + languages[1] = new Language(lang1, Entry.LANG2); entries = new ArrayList(); } - + public Dictionary(final RandomAccessFile raf) throws IOException { - entries = CachingList.create(FileList.create(raf, ENTRY_SERIALIZER, raf.getFilePointer()), 10000); - languages[0] = new Language(raf); - languages[1] = new Language(raf); + entries = CachingList.create(FileList.create(raf, ENTRY_SERIALIZER, raf + .getFilePointer()), 10000); + languages[0] = new Language(raf, Entry.LANG1); + languages[1] = new Language(raf, Entry.LANG2); } + public void write(RandomAccessFile raf) throws IOException { FileList.write(raf, entries, ENTRY_SERIALIZER); languages[0].write(raf); languages[1].write(raf); } - - static final class Language implements RAFSerializable { + + final class Language implements RAFSerializable { + final byte lang; final String symbol; final List rows; final List sortedIndex; - - public Language(final String symbol) { + final Comparator comparator = EntryFactory.entryFactory + .getEntryComparator(); + + Language(final String symbol, final byte lang) { + this.lang = lang; this.symbol = symbol; rows = new ArrayList(); sortedIndex = new ArrayList(); } - public Language(final RandomAccessFile raf) throws IOException { + Language(final RandomAccessFile raf, final byte lang) throws IOException { + this.lang = lang; symbol = raf.readUTF(); - rows = CachingList.create(FileList.create(raf, ROW_SERIALIZER, raf.getFilePointer()), 10000); - sortedIndex = CachingList.create(FileList.create(raf, INDEX_ENTRY_SERIALIZER, raf.getFilePointer()), 10000); + rows = CachingList.create(UniformFileList.create(raf, ROW_SERIALIZER, raf + .getFilePointer()), 10000); + sortedIndex = CachingList.create(FileList.create(raf, + INDEX_ENTRY_SERIALIZER, raf.getFilePointer()), 10000); } + public void write(final RandomAccessFile raf) throws IOException { raf.writeUTF(symbol); - FileList.write(raf, rows, ROW_SERIALIZER); + UniformFileList.write(raf, rows, ROW_SERIALIZER, 4); FileList.write(raf, sortedIndex, INDEX_ENTRY_SERIALIZER); } + + String rowToString(final Row row) { + return row.isToken() ? sortedIndex.get(row.getIndex()).word : entries + .get(row.getIndex()).toString(); + } + + int lookup(String word, final AtomicBoolean interrupted) { + word = word.toLowerCase(); + + int start = 0; + int end = sortedIndex.size(); + while (start < end) { + final int mid = (start + end) / 2; + if (interrupted.get()) { + return mid; + } + final IndexEntry midEntry = sortedIndex.get(mid); + + final int comp = comparator.compare(word, midEntry.word.toLowerCase()); + if (comp == 0) { + int result = mid; + while (result > 0 && comparator.compare(word, sortedIndex.get(result - 1).word.toLowerCase()) == 0) { + --result; + if (interrupted.get()) { + return result; + } + } + return result; + } else if (comp < 0) { + end = mid; + } else { + start = mid + 1; + } + } + return start; + } } - + public static final class Row implements RAFSerializable { final int index; - public Row(int index) { + public Row(final int index) { this.index = index; } static final RAFFactory RAF_FACTORY = new RAFFactory() { public Row create(RandomAccessFile raf) throws IOException { return new Row(raf.readInt()); - }}; + } + }; + public void write(RandomAccessFile raf) throws IOException { raf.writeInt(index); } + + boolean isToken() { + return index < 0; + } + + public int getIndex() { + if (index >= 0) { + return index; + } + return -index - 1; + } } public static final class IndexEntry implements RAFSerializable { final String word; final int startRow; - + public IndexEntry(final String word, final int startRow) { this.word = word; this.startRow = startRow; @@ -93,7 +156,9 @@ public final class Dictionary implements RAFSerializable { final String word = raf.readUTF(); final int startRow = raf.readInt(); return new IndexEntry(word, startRow); - }}; + } + }; + public void write(final RandomAccessFile raf) throws IOException { raf.writeUTF(word); raf.writeInt(startRow); @@ -103,8 +168,7 @@ public final class Dictionary implements RAFSerializable { public String toString() { return word + "@" + startRow; } - - + } } diff --git a/src/com/hughes/android/dictionary/DictionaryActivity.java b/src/com/hughes/android/dictionary/DictionaryActivity.java index 6d1abb9..0e30086 100755 --- a/src/com/hughes/android/dictionary/DictionaryActivity.java +++ b/src/com/hughes/android/dictionary/DictionaryActivity.java @@ -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 entries = Collections.emptyList(); + // private List 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; + } } diff --git a/src/com/hughes/android/dictionary/Entry.java b/src/com/hughes/android/dictionary/Entry.java index bd000f4..6d85764 100755 --- a/src/com/hughes/android/dictionary/Entry.java +++ b/src/com/hughes/android/dictionary/Entry.java @@ -67,19 +67,19 @@ public final class Entry implements RAFSerializable { return text; } - public String getFormattedEntry(final byte lang) { - return getAllText(lang) + "\n" + getAllText(OtherLang(lang)); + String getFormattedEntry(final byte lang) { + return getAllText(lang) + "\n" + getAllText(otherLang(lang)); } - private byte OtherLang(final byte lang) { + String getRawText() { + return getAllText(LANG1) + " :: " + getAllText(LANG2); + } + + static byte otherLang(final byte lang) { assert lang == LANG1 || lang == LANG2; return lang == LANG1 ? LANG2 : LANG1; } - public String getRawText() { - return getAllText(LANG1) + " :: " + getAllText(LANG2); - } - static Entry parseFromLine(final String line) { diff --git a/src/com/hughes/android/dictionary/R.java b/src/com/hughes/android/dictionary/R.java index a74f949..2a750f4 100755 --- a/src/com/hughes/android/dictionary/R.java +++ b/src/com/hughes/android/dictionary/R.java @@ -14,7 +14,13 @@ public final class R { public static final int icon=0x7f020000; } public static final class id { - public static final int SearchText=0x7f050000; + public static final int DownButton=0x7f050005; + public static final int LangButton=0x7f050004; + public static final int SearchBarLinearLayout=0x7f050000; + public static final int SearchBarTableLayout=0x7f050001; + public static final int SearchBarTableRow=0x7f050002; + public static final int SearchText=0x7f050003; + public static final int UpButton=0x7f050006; } public static final class layout { public static final int main=0x7f030000;