]> gitweb.fperrin.net Git - Dictionary.git/blob - src/com/hughes/android/dictionary/Dictionary.java
go
[Dictionary.git] / src / com / hughes / android / dictionary / Dictionary.java
1 package com.hughes.android.dictionary;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.io.RandomAccessFile;
6 import java.util.ArrayList;
7 import java.util.Collections;
8 import java.util.LinkedHashSet;
9 import java.util.List;
10 import java.util.Set;
11 import java.util.concurrent.Executor;
12 import java.util.concurrent.Executors;
13 import java.util.concurrent.atomic.AtomicBoolean;
14
15 import android.app.ListActivity;
16 import android.os.Bundle;
17 import android.os.Handler;
18 import android.text.Editable;
19 import android.text.TextWatcher;
20 import android.util.Log;
21 import android.view.ContextMenu;
22 import android.view.KeyEvent;
23 import android.view.MenuItem;
24 import android.view.View;
25 import android.view.ViewGroup;
26 import android.view.Window;
27 import android.view.ContextMenu.ContextMenuInfo;
28 import android.view.MenuItem.OnMenuItemClickListener;
29 import android.view.View.OnLongClickListener;
30 import android.widget.AdapterView;
31 import android.widget.BaseAdapter;
32 import android.widget.EditText;
33 import android.widget.ListView;
34 import android.widget.TextView;
35 import android.widget.AdapterView.OnItemClickListener;
36 import android.widget.AdapterView.OnItemLongClickListener;
37
38 import com.hughes.util.FileUtil;
39
40 public class Dictionary extends ListActivity {
41
42   public static final String INDEX_FORMAT = "%s_index_%d";
43   private File dictionaryFile = new File("/sdcard/dict-de-en.txt");
44
45   private RandomAccessFile dictionaryRaf;
46   private final Index[] indexes = new Index[2];
47   private final byte lang = Entry.LANG1;
48
49   final Handler uiHandler = new Handler();
50
51   private final Object mutex = new Object();
52   private Executor searchExecutor = Executors.newSingleThreadExecutor();
53   private SearchOperation searchOperation = null;
54   private List<Entry> entries = Collections.emptyList();
55   private DictionaryListAdapter dictionaryListAdapter = new DictionaryListAdapter();
56   private int selectedItem = -1;
57
58   /** Called when the activity is first created. */
59   @Override
60   public void onCreate(Bundle savedInstanceState) {
61     Log.d("THAD", "onCreate");
62     super.onCreate(savedInstanceState);
63     setContentView(R.layout.main);
64
65     EditText searchText = (EditText) findViewById(R.id.SearchText);
66     searchText.addTextChangedListener(new DictionaryTextWatcher());
67
68     setListAdapter(dictionaryListAdapter);
69
70     try {
71       loadIndex();
72     } catch (Exception e) {
73       throw new RuntimeException(e);
74     }
75     onSearchTextChange("");
76
77     registerForContextMenu(getListView());
78     getListView().setOnItemLongClickListener((new OnItemLongClickListener() {
79       public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2,
80           long arg3) {
81         selectedItem = arg2;
82         return false;
83       }
84     }));
85   }
86
87   @Override
88   public void onCreateContextMenu(ContextMenu menu, View v,
89       ContextMenuInfo menuInfo) {
90     if (selectedItem == -1) {
91       return;
92     }
93     final MenuItem addToWordlist = menu.add("Add to wordlist.");
94     addToWordlist.setOnMenuItemClickListener(new OnMenuItemClickListener() {
95       public boolean onMenuItemClick(MenuItem item) {
96         Log
97             .d("THAD", "context menu: "
98                 + entries.get(selectedItem).getRawText());
99         return false;
100       }
101     });
102   }
103
104   @Override
105   protected void onListItemClick(ListView l, View v, int position, long id) {
106     Log.d("THAD", "Clicked: " + entries.get(position).getRawText());
107     selectedItem = position;
108     openContextMenu(getListView());
109   }
110
111   private void loadIndex() throws IOException, ClassNotFoundException {
112     Log.d("THAD", "enter loadIndex");
113     indexes[0] = new Index(String.format(INDEX_FORMAT, dictionaryFile
114         .getAbsolutePath(), Entry.LANG1));
115     dictionaryRaf = new RandomAccessFile(dictionaryFile, "r");
116     Log.d("THAD", "exit loadIndex");
117   }
118
119   void onSearchTextChange(final String searchText) {
120     Log.d("THAD", "onSearchTextChange: " + searchText);
121     synchronized (mutex) {
122       if (searchOperation != null) {
123         searchOperation.interrupted.set(true);
124       }
125       searchOperation = new SearchOperation(searchText);
126     }
127     searchExecutor.execute(searchOperation);
128   }
129
130   private final class SearchOperation implements Runnable {
131     final String searchText;
132     final int count = 100;
133     final AtomicBoolean interrupted = new AtomicBoolean(false);
134
135     public SearchOperation(final String searchText) {
136       this.searchText = searchText.toLowerCase(); // TODO: better
137     }
138
139     public void run() {
140       Log.d("THAD", "SearchOperation: " + searchText);
141       final List<Entry> newEntries = new ArrayList<Entry>(count);
142       try {
143         final Index.Node node = indexes[lang].lookup(searchText);
144         final Set<Integer> entryOffsets = new LinkedHashSet<Integer>(count);
145         node.getDescendantEntryOffsets(entryOffsets, count);
146         for (final int entryOffset : entryOffsets) {
147           if (interrupted.get()) {
148             Log.d("THAD", "Interrupted while parsing entries.");
149             return;
150           }
151           final String line = FileUtil.readLine(dictionaryRaf, entryOffset);
152           final Entry entry = new Entry(line);
153           newEntries.add(entry);
154         }
155       } catch (IOException e) {
156         Log.e("THAD", "Search failure.", e);
157       }
158
159       synchronized (mutex) {
160         if (interrupted.get()) {
161           return;
162         }
163         entries = newEntries;
164       }
165
166       uiHandler.post(new Runnable() {
167         public void run() {
168           synchronized (mutex) {
169             dictionaryListAdapter.notifyDataSetChanged();
170             if (entries.size() > 0) {
171               setSelection(0);
172             }
173           }
174         }
175       });
176     }
177   }
178
179   private class DictionaryListAdapter extends BaseAdapter {
180
181     public int getCount() {
182       synchronized (mutex) {
183         return entries.size();
184       }
185     }
186
187     public Object getItem(int position) {
188       synchronized (mutex) {
189         assert position < entries.size();
190         return entries.get(position).getFormattedEntry(lang);
191       }
192     }
193
194     public long getItemId(int position) {
195       return position;
196     }
197
198     public View getView(final int position, final View convertView,
199         final ViewGroup parent) {
200       TextView result = null;
201       if (convertView instanceof TextView) {
202         result = (TextView) convertView;
203       } else {
204         result = new TextView(parent.getContext());
205       }
206       result.setText((String) getItem(position));
207       return result;
208     }
209
210   }
211
212   private class DictionaryTextWatcher implements TextWatcher {
213     public void afterTextChanged(Editable searchText) {
214       onSearchTextChange(searchText.toString());
215     }
216
217     public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
218         int arg3) {
219     }
220
221     public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
222     }
223   }
224
225   public void run() {
226     // TODO Auto-generated method stub
227
228   }
229
230 }