1 package com.hughes.android.dictionary;
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;
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;
42 import com.hughes.android.dictionary.Dictionary.IndexEntry;
43 import com.hughes.android.dictionary.Dictionary.LanguageData;
44 import com.hughes.android.dictionary.Dictionary.Row;
46 public class DictionaryActivity extends ListActivity {
48 private RandomAccessFile dictRaf = null;
49 private Dictionary dictionary = null;
50 private LanguageData activeLangaugeData = null;
52 private File wordList = new File("/sdcard/wordList.txt");
54 final Handler uiHandler = new Handler();
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;
63 private final Intent aboutIntent = new Intent().setClassName(AboutActivity.class.getPackage().getName(), AboutActivity.class.getCanonicalName());
65 /** Called when the activity is first created. */
67 public void onCreate(Bundle savedInstanceState) {
68 Log.d("THAD", "onCreate");
69 super.onCreate(savedInstanceState);
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);
79 setContentView(R.layout.main);
81 getSearchText().addTextChangedListener(new DictionaryTextWatcher());
83 setListAdapter(dictionaryListAdapter);
85 onSearchTextChange("");
88 final Button langButton = (Button) findViewById(R.id.LangButton);
89 langButton.setOnClickListener(new OnClickListener() {
90 public void onClick(View v) {
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;
105 destRowIndex = selectedTokenRowIndex;
107 jumpToRow(destRowIndex);
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;
119 destRowIndex = activeLangaugeData.rows.size() - 1;
121 jumpToRow(destRowIndex);
125 registerForContextMenu(getListView());
127 // ItemSelectedListener.
128 getListView().setOnItemSelectedListener(new OnItemSelectedListener() {
129 public void onItemSelected(AdapterView<?> arg0, View arg1, int rowIndex,
131 Log.d("THAD", "onItemSelected: " + rowIndex);
132 selectedRowIndex = rowIndex;
133 selectedTokenRowIndex = activeLangaugeData.getIndexEntryForRow(rowIndex).startRow;
137 public void onNothingSelected(AdapterView<?> arg0) {
141 // LongClickListener.
142 getListView().setOnItemLongClickListener((new OnItemLongClickListener() {
143 public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int rowIndex,
145 selectedRowIndex = rowIndex;
151 public String getSelectedRowText() {
152 return activeLangaugeData.rowToString(activeLangaugeData.rows.get(selectedRowIndex));
155 public EditText getSearchText() {
156 return (EditText) findViewById(R.id.SearchText);
159 // ----------------------------------------------------------------
161 // ----------------------------------------------------------------
163 private MenuItem switchLanguageMenuItem = null;
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) {
174 final MenuItem about = menu.add("About...");
175 about.setOnMenuItemClickListener(new OnMenuItemClickListener(){
176 public boolean onMenuItemClick(final MenuItem menuItem) {
177 startActivity(aboutIntent);
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);
190 void switchLanguage() {
191 activeLangaugeData = dictionary.languageDatas[(activeLangaugeData == dictionary.languageDatas[0]) ? 1 : 0];
192 selectedRowIndex = 0;
193 selectedTokenRowIndex = 0;
195 dictionaryListAdapter.notifyDataSetChanged();
196 onSearchTextChange(getSearchText().getText().toString());
199 void updateLangButton() {
200 final Button langButton = (Button) findViewById(R.id.LangButton);
201 langButton.setText(activeLangaugeData.language.symbol);
204 // ----------------------------------------------------------------
206 // ----------------------------------------------------------------
209 public void onCreateContextMenu(ContextMenu menu, View v,
210 ContextMenuInfo menuInfo) {
211 if (selectedRowIndex == -1) {
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);
220 final OutputStream out = new FileOutputStream(wordList, true);
221 out.write((rawText + "\n").getBytes());
223 } catch (IOException e) {
224 throw new RuntimeException(e);
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();
242 return super.onKeyDown(keyCode, event);
246 protected void onListItemClick(ListView l, View v, int row, long id) {
247 selectedRowIndex = row;
248 Log.d("THAD", "Clicked: " + getSelectedRowText());
249 openContextMenu(getListView());
252 void onSearchTextChange(final String searchText) {
253 Log.d("THAD", "onSearchTextChange: " + searchText);
254 if (searchOperation != null) {
255 searchOperation.interrupted.set(true);
257 searchOperation = new SearchOperation(searchText);
258 searchExecutor.execute(searchOperation);
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?
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);
282 private final class SearchOperation implements Runnable {
283 final String searchText;
284 final AtomicBoolean interrupted = new AtomicBoolean(false);
286 public SearchOperation(final String searchText) {
287 this.searchText = searchText;
291 Log.d("THAD", "SearchOperation: " + searchText);
292 final int indexLocation = activeLangaugeData.lookup(searchText, interrupted);
293 if (interrupted.get()) {
296 final IndexEntry indexEntry = activeLangaugeData.sortedIndex
298 uiHandler.post(new Runnable() {
300 jumpToRow(indexEntry.startRow);
306 private class DictionaryListAdapter extends BaseAdapter {
308 public int getCount() {
309 return activeLangaugeData.rows.size();
312 public Dictionary.Row getItem(int rowIndex) {
313 assert rowIndex < activeLangaugeData.rows.size();
314 return activeLangaugeData.rows.get(rowIndex);
317 public long getItemId(int rowIndex) {
321 public View getView(final int rowIndex, final View convertView,
322 final ViewGroup parent) {
323 final Row row = getItem(rowIndex);
327 TextView result = null;
328 if (convertView instanceof TextView) {
329 result = (TextView) convertView;
331 result = new TextView(parent.getContext());
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);
342 final TableLayout result = new TableLayout(parent.getContext());
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());
349 // tableRow.setBackgroundColor(Color.DKGRAY);
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;
358 final TextView spacer = new TextView(tableRow.getContext());
359 spacer.setText(r == 0 ? "
\95 " : "
\95 ");
360 tableRow.addView(spacer);
362 tableRow.addView(column1, layoutParams);
364 final TextView spacer = new TextView(tableRow.getContext());
365 spacer.setText(r == 0 ? "
\95 " : "
\95 ");
366 tableRow.addView(spacer);
368 tableRow.addView(column2, layoutParams);
372 // column1.setTextAppearance(parent.getContext(), android.R.style.Text);
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();
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();
385 column2.setText(entry.getAllText(Entry.otherLang(activeLangaugeData.lang))[r], TextView.BufferType.NORMAL);
387 result.addView(tableRow);
392 } // DictionaryListAdapter
394 private class DictionaryTextWatcher implements TextWatcher {
395 public void afterTextChanged(Editable searchText) {
396 if (getSearchText().hasFocus()) {
397 onSearchTextChange(searchText.toString());
401 public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
405 public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {