1 package com.hughes.android.dictionary;
4 import java.io.FileNotFoundException;
5 import java.io.FileOutputStream;
6 import java.io.IOException;
7 import java.io.OutputStream;
8 import java.io.RandomAccessFile;
9 import java.util.ArrayList;
10 import java.util.Collections;
11 import java.util.LinkedHashSet;
12 import java.util.List;
14 import java.util.concurrent.Executor;
15 import java.util.concurrent.Executors;
16 import java.util.concurrent.atomic.AtomicBoolean;
18 import android.app.AlertDialog;
19 import android.app.ListActivity;
20 import android.os.Bundle;
21 import android.os.Handler;
22 import android.text.Editable;
23 import android.text.TextWatcher;
24 import android.util.Log;
25 import android.view.ContextMenu;
26 import android.view.MenuItem;
27 import android.view.View;
28 import android.view.ViewGroup;
29 import android.view.ContextMenu.ContextMenuInfo;
30 import android.view.MenuItem.OnMenuItemClickListener;
31 import android.widget.AdapterView;
32 import android.widget.BaseAdapter;
33 import android.widget.EditText;
34 import android.widget.ListView;
35 import android.widget.TextView;
36 import android.widget.AdapterView.OnItemLongClickListener;
38 import com.hughes.util.FileUtil;
40 public class Dictionary extends ListActivity {
42 public static final String INDEX_FORMAT = "%s_index_%d";
43 private File dictionaryFile = new File("/sdcard/dict-de-en.txt");
44 private File wordList = new File("/sdcard/wordList.txt");
46 private RandomAccessFile dictionaryRaf;
47 private final Index[] indexes = new Index[2];
48 private final byte lang = Entry.LANG1;
50 final Handler uiHandler = new Handler();
52 private final Object mutex = new Object();
53 private Executor searchExecutor = Executors.newSingleThreadExecutor();
54 private SearchOperation searchOperation = null;
55 private List<Entry> entries = Collections.emptyList();
56 private DictionaryListAdapter dictionaryListAdapter = new DictionaryListAdapter();
57 private int selectedItem = -1;
59 /** Called when the activity is first created. */
61 public void onCreate(Bundle savedInstanceState) {
62 Log.d("THAD", "onCreate");
63 super.onCreate(savedInstanceState);
64 setContentView(R.layout.main);
66 EditText searchText = (EditText) findViewById(R.id.SearchText);
67 searchText.addTextChangedListener(new DictionaryTextWatcher());
69 setListAdapter(dictionaryListAdapter);
73 } catch (Exception e) {
74 throw new RuntimeException(e);
76 onSearchTextChange("");
78 registerForContextMenu(getListView());
79 getListView().setOnItemLongClickListener((new OnItemLongClickListener() {
80 public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2,
88 private void loadIndex() throws IOException, ClassNotFoundException {
89 Log.d("THAD", "enter loadIndex");
90 indexes[0] = new Index(String.format(INDEX_FORMAT, dictionaryFile
91 .getAbsolutePath(), Entry.LANG1));
92 dictionaryRaf = new RandomAccessFile(dictionaryFile, "r");
93 Log.d("THAD", "exit loadIndex");
97 public void onCreateContextMenu(ContextMenu menu, View v,
98 ContextMenuInfo menuInfo) {
99 if (selectedItem == -1) {
102 final MenuItem addToWordlist = menu.add("Add to wordlist.");
103 addToWordlist.setOnMenuItemClickListener(new OnMenuItemClickListener() {
104 public boolean onMenuItemClick(MenuItem item) {
105 final String rawText = entries.get(selectedItem).getRawText();
106 Log.d("THAD", "Writing : "
109 final OutputStream out = new FileOutputStream(wordList, true);
110 out.write((rawText + "\n").getBytes());
112 } catch (IOException e) {
113 throw new RuntimeException(e);
121 protected void onListItemClick(ListView l, View v, int position, long id) {
122 Log.d("THAD", "Clicked: " + entries.get(position).getRawText());
123 selectedItem = position;
124 openContextMenu(getListView());
127 void onSearchTextChange(final String searchText) {
128 Log.d("THAD", "onSearchTextChange: " + searchText);
129 synchronized (mutex) {
130 if (searchOperation != null) {
131 searchOperation.interrupted.set(true);
133 searchOperation = new SearchOperation(searchText);
135 searchExecutor.execute(searchOperation);
138 private final class SearchOperation implements Runnable {
139 final String searchText;
140 final int count = 100;
141 final AtomicBoolean interrupted = new AtomicBoolean(false);
143 public SearchOperation(final String searchText) {
144 this.searchText = searchText.toLowerCase(); // TODO: better
148 Log.d("THAD", "SearchOperation: " + searchText);
149 final List<Entry> newEntries = new ArrayList<Entry>(count);
151 final Index.Node node = indexes[lang].lookup(searchText);
152 final Set<Integer> entryOffsets = new LinkedHashSet<Integer>(count);
153 node.getDescendantEntryOffsets(entryOffsets, count);
154 for (final int entryOffset : entryOffsets) {
155 if (interrupted.get()) {
156 Log.d("THAD", "Interrupted while parsing entries.");
159 final String line = FileUtil.readLine(dictionaryRaf, entryOffset);
160 final Entry entry = new Entry(line);
161 newEntries.add(entry);
163 } catch (IOException e) {
164 Log.e("THAD", "Search failure.", e);
167 synchronized (mutex) {
168 if (interrupted.get()) {
171 entries = newEntries;
174 uiHandler.post(new Runnable() {
176 synchronized (mutex) {
177 dictionaryListAdapter.notifyDataSetChanged();
178 if (entries.size() > 0) {
187 private class DictionaryListAdapter extends BaseAdapter {
189 public int getCount() {
190 synchronized (mutex) {
191 return entries.size();
195 public Object getItem(int position) {
196 synchronized (mutex) {
197 assert position < entries.size();
198 return entries.get(position).getFormattedEntry(lang);
202 public long getItemId(int position) {
206 public View getView(final int position, final View convertView,
207 final ViewGroup parent) {
208 TextView result = null;
209 if (convertView instanceof TextView) {
210 result = (TextView) convertView;
212 result = new TextView(parent.getContext());
214 result.setText((String) getItem(position));
220 private class DictionaryTextWatcher implements TextWatcher {
221 public void afterTextChanged(Editable searchText) {
222 onSearchTextChange(searchText.toString());
225 public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
229 public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {