]> gitweb.fperrin.net Git - Dictionary.git/blob - src/com/hughes/android/dictionary/DictionaryActivity.java
daa79dd2f7dedaadc0c894d7d68bb36271f86c10
[Dictionary.git] / src / com / hughes / android / dictionary / DictionaryActivity.java
1 package com.hughes.android.dictionary;
2
3 import java.io.File;
4 import java.io.FileOutputStream;
5 import java.io.IOException;
6 import java.io.OutputStream;
7 import java.io.RandomAccessFile;
8 import java.util.concurrent.Executor;
9 import java.util.concurrent.Executors;
10 import java.util.concurrent.atomic.AtomicBoolean;
11
12 import android.app.ListActivity;
13 import android.content.Intent;
14 import android.graphics.Typeface;
15 import android.os.Bundle;
16 import android.os.Handler;
17 import android.text.Editable;
18 import android.text.Spannable;
19 import android.text.TextWatcher;
20 import android.text.style.StyleSpan;
21 import android.util.Log;
22 import android.view.ContextMenu;
23 import android.view.KeyEvent;
24 import android.view.Menu;
25 import android.view.MenuItem;
26 import android.view.View;
27 import android.view.ViewGroup;
28 import android.view.ContextMenu.ContextMenuInfo;
29 import android.view.MenuItem.OnMenuItemClickListener;
30 import android.view.View.OnClickListener;
31 import android.widget.AdapterView;
32 import android.widget.BaseAdapter;
33 import android.widget.Button;
34 import android.widget.EditText;
35 import android.widget.ListView;
36 import android.widget.TableLayout;
37 import android.widget.TableRow;
38 import android.widget.TextView;
39 import android.widget.AdapterView.OnItemLongClickListener;
40 import android.widget.AdapterView.OnItemSelectedListener;
41
42 import com.hughes.android.dictionary.Dictionary.IndexEntry;
43 import com.hughes.android.dictionary.Dictionary.LanguageData;
44 import com.hughes.android.dictionary.Dictionary.Row;
45
46 public class DictionaryActivity extends ListActivity {
47
48   private RandomAccessFile dictRaf = null;
49   private Dictionary dictionary = null;
50   private LanguageData activeLangaugeData = null;
51
52   private File wordList = new File("/sdcard/wordList.txt");
53
54   final Handler uiHandler = new Handler();
55
56   private Executor searchExecutor = Executors.newSingleThreadExecutor();
57   private SearchOperation searchOperation = null;
58   // private List<Entry> entries = Collections.emptyList();
59   private DictionaryListAdapter dictionaryListAdapter = new DictionaryListAdapter();
60   private int selectedRowIndex = -1;
61   private int selectedTokenRowIndex = -1;
62   
63   private final Intent aboutIntent = new Intent().setClassName(AboutActivity.class.getPackage().getName(), AboutActivity.class.getCanonicalName());
64
65   /** Called when the activity is first created. */
66   @Override
67   public void onCreate(Bundle savedInstanceState) {
68     Log.d("THAD", "onCreate");
69     super.onCreate(savedInstanceState);
70
71     try {
72       dictRaf = new RandomAccessFile("/sdcard/de-en.dict", "r");
73       dictionary = new Dictionary(dictRaf);
74       activeLangaugeData = dictionary.languageDatas[Entry.LANG1];
75     } catch (Exception e) {
76       throw new RuntimeException(e);
77     }
78
79     setContentView(R.layout.main);
80
81     getSearchText().addTextChangedListener(new DictionaryTextWatcher());
82
83     setListAdapter(dictionaryListAdapter);
84
85     onSearchTextChange("");
86     
87     // Language button.
88     final Button langButton = (Button) findViewById(R.id.LangButton);
89     langButton.setOnClickListener(new OnClickListener() {
90       public void onClick(View v) {
91         switchLanguage();
92       }});
93     updateLangButton();
94
95     final Button upButton = (Button) findViewById(R.id.UpButton);
96     upButton.setOnClickListener(new OnClickListener() {
97       public void onClick(View v) {
98         final int destRowIndex;
99         final Row tokenRow = activeLangaugeData.rows.get(selectedTokenRowIndex);
100         assert tokenRow.isToken();
101         final int prevTokenIndex = tokenRow.getIndex() - 1;
102         if (selectedRowIndex == selectedTokenRowIndex && selectedRowIndex > 0) {
103           destRowIndex = activeLangaugeData.sortedIndex.get(prevTokenIndex).startRow;
104         } else {
105           destRowIndex = selectedTokenRowIndex;
106         }
107         jumpToRow(destRowIndex);
108       }});
109     final Button downButton = (Button) findViewById(R.id.DownButton);
110     downButton.setOnClickListener(new OnClickListener() {
111       public void onClick(View v) {
112         final Row tokenRow = activeLangaugeData.rows.get(selectedTokenRowIndex);
113         assert tokenRow.isToken();
114         final int nextTokenIndex = tokenRow.getIndex() + 1;
115         final int destRowIndex;
116         if (nextTokenIndex < activeLangaugeData.sortedIndex.size()) {
117           destRowIndex = activeLangaugeData.sortedIndex.get(nextTokenIndex).startRow;
118         } else {
119           destRowIndex = activeLangaugeData.rows.size() - 1;
120         }
121         jumpToRow(destRowIndex);
122       }});
123
124     // ContextMenu.
125     registerForContextMenu(getListView());
126
127     // ItemSelectedListener.
128     getListView().setOnItemSelectedListener(new OnItemSelectedListener() {
129       public void onItemSelected(AdapterView<?> arg0, View arg1, int rowIndex,
130           long arg3) {
131         Log.d("THAD", "onItemSelected: " + rowIndex);
132         selectedRowIndex = rowIndex;
133         selectedTokenRowIndex = activeLangaugeData.getIndexEntryForRow(rowIndex).startRow;
134         updateSearchText();
135       }
136
137       public void onNothingSelected(AdapterView<?> arg0) {
138       }});
139     
140
141     // LongClickListener.
142     getListView().setOnItemLongClickListener((new OnItemLongClickListener() {
143       public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int rowIndex,
144           long arg3) {
145         selectedRowIndex = rowIndex;
146         return false;
147       }
148     }));
149   }
150   
151   public String getSelectedRowText() {
152     return activeLangaugeData.rowToString(activeLangaugeData.rows.get(selectedRowIndex));
153   }
154   
155   public EditText getSearchText() {
156     return (EditText) findViewById(R.id.SearchText);
157   }
158   
159   // ----------------------------------------------------------------
160   // OptionsMenu
161   // ----------------------------------------------------------------
162
163   private MenuItem switchLanguageMenuItem = null;
164   
165   @Override
166   public boolean onCreateOptionsMenu(final Menu menu) {
167     switchLanguageMenuItem = menu.add("Switch to language.");
168     switchLanguageMenuItem.setOnMenuItemClickListener(new OnMenuItemClickListener(){
169       public boolean onMenuItemClick(final MenuItem menuItem) {
170         switchLanguage();
171         return false;
172       }});
173
174     final MenuItem about = menu.add("About...");
175     about.setOnMenuItemClickListener(new OnMenuItemClickListener(){
176       public boolean onMenuItemClick(final MenuItem menuItem) {
177         startActivity(aboutIntent);
178         return false;
179       }});
180
181     return true;
182   }
183   
184   @Override
185   public boolean onPrepareOptionsMenu(final Menu menu) {
186     switchLanguageMenuItem.setTitle(String.format("Switch to %s", dictionary.languageDatas[Entry.otherLang(activeLangaugeData.lang)].language.symbol));
187     return super.onPrepareOptionsMenu(menu);
188   }
189
190   void switchLanguage() {
191     activeLangaugeData = dictionary.languageDatas[(activeLangaugeData == dictionary.languageDatas[0]) ? 1 : 0];
192     selectedRowIndex = 0;
193     selectedTokenRowIndex = 0;
194     updateLangButton();
195     dictionaryListAdapter.notifyDataSetChanged();
196     onSearchTextChange(getSearchText().getText().toString());
197   }
198   
199   void updateLangButton() {
200     final Button langButton = (Button) findViewById(R.id.LangButton);
201     langButton.setText(activeLangaugeData.language.symbol);
202   }
203   
204   // ----------------------------------------------------------------
205   // ContextMenu
206   // ----------------------------------------------------------------
207   
208   @Override
209   public void onCreateContextMenu(ContextMenu menu, View v,
210       ContextMenuInfo menuInfo) {
211     if (selectedRowIndex == -1) {
212       return;
213     }
214     final MenuItem addToWordlist = menu.add("Add to wordlist: " + wordList.getName());
215     addToWordlist.setOnMenuItemClickListener(new OnMenuItemClickListener() {
216       public boolean onMenuItemClick(MenuItem item) {
217         final String rawText = getSelectedRowText();
218         Log.d("THAD", "Writing : " + rawText);
219         try {
220           final OutputStream out = new FileOutputStream(wordList, true);
221           out.write((rawText + "\n").getBytes());
222           out.close();
223         } catch (IOException e) {
224           throw new RuntimeException(e);
225         }
226         return false;
227       }
228     });
229   }
230   
231   @Override
232   public boolean onKeyDown(int keyCode, KeyEvent event) {
233     if (event.getUnicodeChar() != 0) {
234       final EditText searchText = getSearchText();
235       if (!searchText.hasFocus()) {
236         searchText.setText("" + (char)event.getUnicodeChar());
237         onSearchTextChange(searchText.getText().toString());
238         searchText.requestFocus();
239       }
240       return true;
241     }
242     return super.onKeyDown(keyCode, event);
243   }
244
245   @Override
246   protected void onListItemClick(ListView l, View v, int row, long id) {
247     selectedRowIndex = row;
248     Log.d("THAD", "Clicked: " + getSelectedRowText());
249     openContextMenu(getListView());
250   }
251
252   void onSearchTextChange(final String searchText) {
253     Log.d("THAD", "onSearchTextChange: " + searchText);
254     if (searchOperation != null) {
255       searchOperation.interrupted.set(true);
256     }
257     searchOperation = new SearchOperation(searchText);
258     searchExecutor.execute(searchOperation);
259   }
260   
261   private void jumpToRow(final int rowIndex) {
262     Log.d("THAD", "jumpToRow: " + rowIndex);
263     selectedRowIndex = rowIndex;
264     selectedTokenRowIndex = activeLangaugeData.getIndexEntryForRow(rowIndex).startRow;
265     getListView().setSelection(rowIndex);
266     getListView().setSelected(true);  // TODO: is this doing anything?
267     updateSearchText();
268   }
269
270   private void updateSearchText() {
271     final EditText searchText = getSearchText();
272     if (!searchText.hasFocus()) {
273       // TODO: Not so nice:
274       final String word = activeLangaugeData.getIndexEntryForRow(selectedRowIndex).word;
275       if (!word.equals(searchText.getText().toString())) {
276         Log.d("THAD", "updateSearchText: setText: " + word);
277         searchText.setText(word);
278       }
279     }
280   }
281
282   private final class SearchOperation implements Runnable {
283     final String searchText;
284     final AtomicBoolean interrupted = new AtomicBoolean(false);
285
286     public SearchOperation(final String searchText) {
287       this.searchText = searchText;
288     }
289
290     public void run() {
291       Log.d("THAD", "SearchOperation: " + searchText);
292       final int indexLocation = activeLangaugeData.lookup(searchText, interrupted);
293       if (interrupted.get()) {
294         return;
295       }
296       final IndexEntry indexEntry = activeLangaugeData.sortedIndex
297           .get(indexLocation);
298       uiHandler.post(new Runnable() {
299         public void run() {
300           jumpToRow(indexEntry.startRow);
301         }
302       });
303     }
304   }
305
306   private class DictionaryListAdapter extends BaseAdapter {
307
308     public int getCount() {
309       return activeLangaugeData.rows.size();
310     }
311
312     public Dictionary.Row getItem(int rowIndex) {
313       assert rowIndex < activeLangaugeData.rows.size();
314       return activeLangaugeData.rows.get(rowIndex);
315     }
316
317     public long getItemId(int rowIndex) {
318       return rowIndex;
319     }
320
321     public View getView(final int rowIndex, final View convertView,
322         final ViewGroup parent) {
323       final Row row = getItem(rowIndex);
324       
325       // Token row.
326       if (row.isToken()) {
327         TextView result = null;
328         if (convertView instanceof TextView) {
329           result = (TextView) convertView;
330         } else {
331           result = new TextView(parent.getContext());
332         }
333 //        result.setBackgroundColor(Color.WHITE);
334         result.setText(activeLangaugeData.rowToString(row));
335         result.setTextAppearance(parent.getContext(),
336             android.R.style.TextAppearance_Large);
337         result.setClickable(false);
338         return result;
339       }
340
341       // Entry row(s).
342       final TableLayout result = new TableLayout(parent.getContext());
343
344       final Entry entry = dictionary.entries.get(row.getIndex());
345       final int rowCount = entry.getRowCount();
346       for (int r = 0; r < rowCount; ++r) {
347         final TableRow tableRow = new TableRow(result.getContext());
348 //        if (r > 0) {
349 //          tableRow.setBackgroundColor(Color.DKGRAY);  
350 //        }
351         
352         TextView column1 = new TextView(tableRow.getContext());
353         TextView column2 = new TextView(tableRow.getContext());
354         final TableRow.LayoutParams layoutParams = new TableRow.LayoutParams();
355         layoutParams.weight = 0.5f;
356         
357         if (r>0){
358           final TextView spacer = new TextView(tableRow.getContext());
359           spacer.setText(r == 0 ? "\95 " : " \95 ");
360           tableRow.addView(spacer);
361         }
362         tableRow.addView(column1, layoutParams);
363         if (r>0){
364           final TextView spacer = new TextView(tableRow.getContext());
365           spacer.setText(r == 0 ? "\95 " : " \95 ");
366           tableRow.addView(spacer);
367         }
368         tableRow.addView(column2, layoutParams);
369         
370         column1.setWidth(1);
371         column2.setWidth(1);
372         // column1.setTextAppearance(parent.getContext(), android.R.style.Text);
373         
374         // TODO: highlight query word in entries.
375         final String col1Text = entry.getAllText(activeLangaugeData.lang)[r]; 
376         column1.setText(col1Text, TextView.BufferType.SPANNABLE);
377         final Spannable col1Spannable = (Spannable) column1.getText();
378         int startPos = 0;
379         final String token = activeLangaugeData.getIndexEntryForRow(rowIndex).word;
380         while ((startPos = col1Text.indexOf(token, startPos)) != -1) {
381           col1Spannable.setSpan(new StyleSpan(Typeface.BOLD), startPos, startPos + token.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
382          startPos += token.length();
383         }
384         
385         column2.setText(entry.getAllText(Entry.otherLang(activeLangaugeData.lang))[r], TextView.BufferType.NORMAL);
386         
387         result.addView(tableRow);
388       }
389       
390       return result;
391     }
392   }  // DictionaryListAdapter
393
394   private class DictionaryTextWatcher implements TextWatcher {
395     public void afterTextChanged(Editable searchText) {
396       if (getSearchText().hasFocus()) {
397         onSearchTextChange(searchText.toString());
398       }
399     }
400
401     public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
402         int arg3) {
403     }
404
405     public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
406     }
407   }
408
409 }