X-Git-Url: http://gitweb.fperrin.net/?a=blobdiff_plain;f=src%2Fcom%2Fhughes%2Fandroid%2Fdictionary%2FDictionaryActivity.java;h=7f156cfea69d776c5c927da37223c06712fe76a6;hb=d3d2ec689514a90d73e35ddb6fb832fb42e3990d;hp=f1699f1eb6b0f5c594a0e09e453ad0283f3cdeee;hpb=222581b90556e065e4c9efcb819101b333f9b863;p=Dictionary.git diff --git a/src/com/hughes/android/dictionary/DictionaryActivity.java b/src/com/hughes/android/dictionary/DictionaryActivity.java index f1699f1..7f156cf 100644 --- a/src/com/hughes/android/dictionary/DictionaryActivity.java +++ b/src/com/hughes/android/dictionary/DictionaryActivity.java @@ -1,739 +1,330 @@ -package com.hughes.android.dictionary; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.RandomAccessFile; -import java.text.SimpleDateFormat; -import java.util.Arrays; -import java.util.Date; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicBoolean; - -import android.app.ListActivity; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.SharedPreferences.Editor; -import android.graphics.Typeface; -import android.os.Bundle; -import android.os.Handler; -import android.preference.PreferenceManager; -import android.text.ClipboardManager; -import android.text.Editable; -import android.text.Spannable; -import android.text.TextWatcher; -import android.text.style.StyleSpan; -import android.util.Log; -import android.view.ContextMenu; -import android.view.KeyEvent; -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.view.inputmethod.InputMethodManager; -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.Toast; - -import com.hughes.android.dictionary.engine.Dictionary; -import com.hughes.android.dictionary.engine.Language; -import com.ibm.icu.text.Collator; - -public class DictionaryActivity extends ListActivity { - - // TO DO: - // * Easy reverse lookup. - // * Download latest dicts. - // * http://ftp.tu-chemnitz.de/pub/Local/urz/ding/de-en-devel/ - // * http://www1.dict.cc/translation_file_request.php?l=e - // * Compress all the strings everywhere, put compression table in file. - // Done: - // * Only one way to way for current search to end. (won't do). - - static final String LOG = "QuickDic"; - static final String PREF_DICT_ACTIVE_LANG = "DICT_DIR_PREF"; - static final String PREF_ACTIVE_SEARCH_TEXT = "ACTIVE_WORD_PREF"; - - // package for test. - final Handler uiHandler = new Handler(); - private final Executor searchExecutor = Executors.newSingleThreadExecutor(); - - EditText searchText; - Button langButton; - int lastSelectedRow = 0; // TODO: I'm evil. - - private boolean prefsMightHaveChanged = true; - - // Never null. - private File wordList = null; - private RandomAccessFile dictRaf = null; - private Dictionary dictionary = null; - private boolean saveOnlyFirstSubentry = false; - - // Visible for testing. - IndexAdapter indexAdapter = null; - private SearchOperation searchOperation = null; - - public DictionaryActivity() { - - searchExecutor.execute(new Runnable() { - public void run() { - final long startMillis = System.currentTimeMillis(); - for (final String lang : Arrays.asList("EN", "DE")) { - Language.lookup(lang).getFindCollator(); - final Collator c = Language.lookup(lang).getSortCollator(); - if (c.compare("pre-print", "preppy") >= 0) { - Log.e(LOG, c.getClass() + " is buggy, lookups may not work properly."); - } - } - Log.d(LOG, "Loading collators took:" + (System.currentTimeMillis() - startMillis)); - } - }); - - } - - /** Called when the activity is first created. */ - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - Log.d(LOG, "onCreate:" + this); - - try { - initDictionaryAndPrefs(); - } catch (Exception e) { - return; - } - - // UI init. - - setContentView(R.layout.dictionary_activity); - searchText = (EditText) findViewById(R.id.SearchText); - langButton = (Button) findViewById(R.id.LangButton); - - searchText.addTextChangedListener(new SearchTextWatcher()); - - getListView().setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { - public void onItemSelected(AdapterView arg0, View arg1, int row, - long arg3) { - setSelectedRow(row); - } - public void onNothingSelected(AdapterView arg0) { - } - }); - - getListView().setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { - public boolean onItemLongClick(AdapterView arg0, View arg1, int row, - long arg3) { - setSelectedRow(row); - return false; - } - }); - - final Button clearSearchTextButton = (Button) findViewById(R.id.ClearSearchTextButton); - clearSearchTextButton.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - onClearSearchTextButton(clearSearchTextButton); - } - }); - clearSearchTextButton.setVisibility(PreferenceManager.getDefaultSharedPreferences(this).getBoolean( - getString(R.string.showClearSearchTextButtonKey), true) ? View.VISIBLE - : View.GONE); - - final Button langButton = (Button) findViewById(R.id.LangButton); - langButton.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - onLanguageButton(); - } - }); - - final Button upButton = (Button) findViewById(R.id.UpButton); - upButton.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - onUpButton(); - } - }); - final Button downButton = (Button) findViewById(R.id.DownButton); - downButton.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - onDownButton(); - } - }); - - // ContextMenu. - registerForContextMenu(getListView()); - - updateLangButton(); - } - - private void initDictionaryAndPrefs() throws Exception { - if (!prefsMightHaveChanged) { - return; - } - closeCurrentDictionary(); - - final SharedPreferences prefs = PreferenceManager - .getDefaultSharedPreferences(this); - wordList = new File(prefs.getString(getString(R.string.wordListFileKey), - getString(R.string.wordListFileDefault))); - Log.d(LOG, "wordList=" + wordList); - - saveOnlyFirstSubentry = prefs.getBoolean(getString(R.string.saveOnlyFirstSubentryKey), false); - - final File dictFile = new File(prefs.getString(getString(R.string.dictFileKey), - getString(R.string.dictFileDefault))); - Log.d(LOG, "dictFile=" + dictFile); - - try { - if (!dictFile.canRead()) { - throw new IOException("Unable to read dictionary file."); - } - - dictRaf = new RandomAccessFile(dictFile, "r"); - final long startMillis = System.currentTimeMillis(); - dictionary = new Dictionary(dictRaf); - Log.d(LOG, "Read dictionary millis: " + (System.currentTimeMillis() - startMillis)); - } catch (IOException e) { - Log.e(LOG, "Couldn't open dictionary.", e); - - this.startActivity(new asdfIntent(this, DictionaryEditActivity.class)); - finish(); - } - - final byte lang = prefs.getInt(PREF_DICT_ACTIVE_LANG, SimpleEntry.LANG1) == SimpleEntry.LANG1 ? SimpleEntry.LANG1 - : SimpleEntry.LANG2; - - indexAdapter = new IndexAdapter(dictionary.languageDatas[lang]); - setListAdapter(indexAdapter); - prefsMightHaveChanged = false; - } - - @Override - public void onResume() { - super.onResume(); - Log.d(LOG, "onResume:" + this); - - try { - initDictionaryAndPrefs(); - } catch (Exception e) { - return; - } - - final SharedPreferences prefs = PreferenceManager - .getDefaultSharedPreferences(this); - final String searchTextString = prefs - .getString(PREF_ACTIVE_SEARCH_TEXT, ""); - searchText.setText(searchTextString); - getListView().requestFocus(); - onSearchTextChange(searchTextString); - } - - @Override - public void onPause() { - super.onPause(); - Log.d(LOG, "onPause:" + this); - final Editor prefs = PreferenceManager.getDefaultSharedPreferences(this) - .edit(); - prefs.putInt(PREF_DICT_ACTIVE_LANG, indexAdapter.languageData.lang); - prefs.putString(PREF_ACTIVE_SEARCH_TEXT, searchText.getText().toString()); - prefs.commit(); - } - - @Override - public void onStop() { - super.onStop(); - Log.d(LOG, "onStop:" + this); - if (isFinishing()) { - Log.i(LOG, "isFinishing()==true, closing dictionary."); - closeCurrentDictionary(); - } - } - - private void closeCurrentDictionary() { - Log.i(LOG, "closeCurrentDictionary"); - if (dictionary == null) { - return; - } - waitForSearchEnd(); - indexAdapter = null; - setListAdapter(null); - Log.d(LOG, "setListAdapter finished."); - dictionary = null; - try { - if (dictRaf != null) { - dictRaf.close(); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - dictRaf = null; - } - - public String getSelectedRowRawText(final boolean onlyFirstSubentry) { - final Row row = indexAdapter.languageData.rows.get(getSelectedRow()); - return indexAdapter.languageData.rowToString(row, onlyFirstSubentry); - } - - // ---------------------------------------------------------------- - // OptionsMenu - // ---------------------------------------------------------------- - - private MenuItem switchLanguageMenuItem = null; - - @Override - public boolean onCreateOptionsMenu(final Menu menu) { - switchLanguageMenuItem = menu.add(getString(R.string.switchToLanguage)); - switchLanguageMenuItem - .setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(final MenuItem menuItem) { - onLanguageButton(); - return false; - } - }); - - final MenuItem preferences = menu.add(getString(R.string.preferences)); - preferences.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(final MenuItem menuItem) { - prefsMightHaveChanged = true; - startActivity(new Intent(DictionaryActivity.this, - PreferenceActivity.class)); - return false; - } - }); - - final MenuItem about = menu.add(getString(R.string.about)); - about.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(final MenuItem menuItem) { - final Intent intent = new Intent().setClassName(AboutActivity.class - .getPackage().getName(), AboutActivity.class.getCanonicalName()); - final String currentDictInfo; - if (dictionary == null) { - currentDictInfo = getString(R.string.noDictLoaded); - } else { - final LanguageData lang0 = dictionary.languageDatas[0]; - final LanguageData lang1 = dictionary.languageDatas[1]; - currentDictInfo = getString(R.string.aboutText, dictionary.dictionaryInfo, dictionary.entries.size(), - lang0.language.symbol, lang0.sortedIndex.size(), lang0.rows.size(), - lang1.language.symbol, lang1.sortedIndex.size(), lang1.rows.size()); - } - intent.putExtra(AboutActivity.CURRENT_DICT_INFO, currentDictInfo - .toString()); - startActivity(intent); - return false; - } - }); - - final MenuItem download = menu.add(getString(R.string.downloadDictionary)); - download.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(final MenuItem menuItem) { - prefsMightHaveChanged = true; - startDownloadDictActivity(DictionaryActivity.this); - return false; - } - }); - - return true; - } - - @Override - public boolean onPrepareOptionsMenu(final Menu menu) { - switchLanguageMenuItem.setTitle(getString(R.string.switchToLanguage, - dictionary.languageDatas[SimpleEntry - .otherLang(indexAdapter.languageData.lang)].language.symbol)); - return super.onPrepareOptionsMenu(menu); - } - - void updateLangButton() { - langButton.setText(indexAdapter.languageData.language.symbol); - } - - // ---------------------------------------------------------------- - // Event handlers. - // ---------------------------------------------------------------- - - void onLanguageButton() { - waitForSearchEnd(); - indexAdapter = new IndexAdapter( - dictionary.languageDatas[(indexAdapter.languageData == dictionary.languageDatas[0]) ? 1 - : 0]); - Log.d(LOG, "onLanguageButton, newLang=" + indexAdapter.languageData.language.symbol); - setListAdapter(indexAdapter); - updateLangButton(); - onSearchTextChange(searchText.getText().toString()); - } - - void onUpButton() { - final int destRowIndex = indexAdapter.languageData.getPrevTokenRow(getSelectedRow()); - Log.d(LOG, "onUpButton, destRowIndex=" + destRowIndex); - jumpToRow(indexAdapter, destRowIndex); - } - - void onDownButton() { - final int destRowIndex = indexAdapter.languageData.getNextTokenRow(getSelectedRow()); - Log.d(LOG, "onDownButton, destRowIndex=" + destRowIndex); - jumpToRow(indexAdapter, destRowIndex); - } - - void onAppendToWordList() { - final int row = getSelectedRow(); - if (row < 0) { - return; - } - final StringBuilder rawText = new StringBuilder(); - final String word = indexAdapter.languageData.getIndexEntryForRow(row).word; - rawText.append( - new SimpleDateFormat("yyyy.MM.dd HH:mm:ss").format(new Date())) - .append("\t"); - rawText.append(word).append("\t"); - rawText.append(getSelectedRowRawText(saveOnlyFirstSubentry)); - Log.d(LOG, "Writing : " + rawText); - try { - wordList.getParentFile().mkdirs(); - final PrintWriter out = new PrintWriter( - new FileWriter(wordList, true)); - out.println(rawText.toString()); - out.close(); - } catch (IOException e) { - Log.e(LOG, "Unable to append to " + wordList.getAbsolutePath(), e); - Toast.makeText(this, getString(R.string.failedAddingToWordList, wordList.getAbsolutePath()), Toast.LENGTH_LONG); - } - return; - } - - void onCopy() { - final int row = getSelectedRow(); - if (row < 0) { - return; - } - Log.d(LOG, "Copy." + DictionaryActivity.this.getSelectedRow()); - final StringBuilder result = new StringBuilder(); - result.append(getSelectedRowRawText(false)); - final ClipboardManager clipboardManager = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); - clipboardManager.setText(result.toString()); - Log.d(LOG, "Copied: " + result); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (event.getUnicodeChar() != 0) { - if (!searchText.hasFocus()) { - searchText.setText("" + (char) event.getUnicodeChar()); - onSearchTextChange(searchText.getText().toString()); - searchText.requestFocus(); - } - return true; - } - return super.onKeyDown(keyCode, event); - } - - @Override - protected void onListItemClick(ListView l, View v, int row, long id) { - setSelectedRow(row); - openContextMenu(getListView()); - } - - void onSearchTextChange(final String searchText) { - Log.d(LOG, "onSearchTextChange: " + searchText); - synchronized (this) { - searchOperation = new SearchOperation(indexAdapter, searchText.trim(), searchOperation); - searchExecutor.execute(searchOperation); - } - } - - private void onClearSearchTextButton(final Button clearSearchTextButton) { - clearSearchTextButton.requestFocus(); - searchText.setText(""); - searchText.requestFocus(); - Log.d(LOG, "Trying to show soft keyboard."); - final InputMethodManager manager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - manager.showSoftInput(searchText, InputMethodManager.SHOW_IMPLICIT); - } - - // ---------------------------------------------------------------- - // ContextMenu - // ---------------------------------------------------------------- - - @Override - public void onCreateContextMenu(ContextMenu menu, View v, - ContextMenuInfo menuInfo) { - final int row = getSelectedRow(); - if (row < 0) { - return; - } - - final MenuItem addToWordlist = menu.add(getString(R.string.addToWordList, wordList.getName())); - addToWordlist.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - onAppendToWordList(); - return false; - } - }); - - final MenuItem copy = menu.add(android.R.string.copy); - copy.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - onCopy(); - return false; - } - }); - - } - - private void jumpToRow(final IndexAdapter dictionaryListAdapter, - final int rowIndex) { - Log.d(LOG, "jumpToRow: " + rowIndex); - if (dictionaryListAdapter != this.indexAdapter) { - Log.w(LOG, "skipping jumpToRow for old list adapter: " + rowIndex); - return; - } - setSelection(rowIndex); - setSelectedRow(rowIndex); - getListView().setSelected(true); - } - - // TODO: delete me somehow. - private int getSelectedRow() { - return lastSelectedRow; - } - private void setSelectedRow(final int row) { - lastSelectedRow = row; - Log.d(LOG, "Selected: " + getSelectedRowRawText(true)); - updateSearchText(); - } - - private void updateSearchText() { - Log.d(LOG, "updateSearchText"); - final int selectedRowIndex = getSelectedRow(); - if (!searchText.hasFocus()) { - if (selectedRowIndex >= 0) { - final String word = indexAdapter.languageData - .getIndexEntryForRow(selectedRowIndex).word; - if (!word.equals(searchText.getText().toString())) { - Log.d(LOG, "updateSearchText: setText: " + word); - searchText.setText(word); - } - } else { - Log.w(LOG, "updateSearchText: nothing selected."); - } - } - } - - static void startDownloadDictActivity(final Context context) { - final Intent intent = new Intent(context, DownloadActivity.class); - final SharedPreferences prefs = PreferenceManager - .getDefaultSharedPreferences(context); - final String dictFetchUrl = prefs.getString(context - .getString(R.string.dictFetchUrlKey), context - .getString(R.string.dictFetchUrlDefault)); - final String dictFileName = prefs.getString(context - .getString(R.string.dictFileKey), context - .getString(R.string.dictFileDefault)); - intent.putExtra(DownloadActivity.SOURCE, dictFetchUrl); - intent.putExtra(DownloadActivity.DEST, dictFileName); - context.startActivity(intent); - } - - class IndexAdapter extends BaseAdapter { - - // Visible for testing. - final LanguageData languageData; - - IndexAdapter(final LanguageData languageData) { - this.languageData = languageData; - } - - public int getCount() { - return languageData.rows.size(); - } - - public Dictionary.Row getItem(int rowIndex) { - assert rowIndex < languageData.rows.size(); - return languageData.rows.get(rowIndex); - } - - public long getItemId(int rowIndex) { - return rowIndex; - } - - public View getView(final int rowIndex, final View convertView, - final ViewGroup parent) { - final Row row = getItem(rowIndex); - - // Token row. - if (row.isToken()) { - TextView result = null; - if (convertView instanceof TextView) { - result = (TextView) convertView; - } else { - result = new TextView(parent.getContext()); - } - if (row == null) { - return result; - } - result.setText(languageData.rowToString(row, false)); - result.setTextAppearance(parent.getContext(), - android.R.style.TextAppearance_Large); - result.setClickable(false); - return result; - } - - // Entry row(s). - final TableLayout result = new TableLayout(parent.getContext()); - - final SimpleEntry entry = new SimpleEntry(null, null);//.entries.get(row.getIndex()); - final int rowCount = entry.getRowCount(); - for (int r = 0; r < rowCount; ++r) { - final TableRow tableRow = new TableRow(result.getContext()); - - TextView column1 = new TextView(tableRow.getContext()); - TextView column2 = new TextView(tableRow.getContext()); - final TableRow.LayoutParams layoutParams = new TableRow.LayoutParams(); - layoutParams.weight = 0.5f; - - if (r > 0) { - final TextView spacer = new TextView(tableRow.getContext()); - spacer.setText(r == 0 ? "� " : " � "); - tableRow.addView(spacer); - } - tableRow.addView(column1, layoutParams); - if (r > 0) { - final TextView spacer = new TextView(tableRow.getContext()); - spacer.setText(r == 0 ? "� " : " � "); - tableRow.addView(spacer); - } - tableRow.addView(column2, layoutParams); - - column1.setWidth(1); - column2.setWidth(1); - // column1.setTextAppearance(parent.getContext(), android.R.style.Text); - - // TODO: color words by gender - final String col1Text = entry.getAllText(languageData.lang)[r]; - column1.setText(col1Text, TextView.BufferType.SPANNABLE); - final Spannable col1Spannable = (Spannable) column1.getText(); - int startPos = 0; - final String token = languageData.getIndexEntryForRow(rowIndex).word; - while ((startPos = col1Text.indexOf(token, startPos)) != -1) { - col1Spannable.setSpan(new StyleSpan(Typeface.BOLD), startPos, - startPos + token.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); - startPos += token.length(); - } - - column2.setText( - entry.getAllText(SimpleEntry.otherLang(languageData.lang))[r], - TextView.BufferType.NORMAL); - - result.addView(tableRow); - } - - return result; - } - - } // DictionaryListAdapter - - private final class SearchOperation implements Runnable { - SearchOperation previousSearchOperation; - - final IndexAdapter listAdapter; - final LanguageData languageData; - final String searchText; - final AtomicBoolean interrupted = new AtomicBoolean(false); - boolean searchFinished = false; - - SearchOperation(final IndexAdapter listAdapter, - final String searchText, final SearchOperation previousSearchOperation) { - this.listAdapter = listAdapter; - this.languageData = listAdapter.languageData; - this.searchText = searchText; - this.previousSearchOperation = previousSearchOperation; - } - - public void run() { - if (previousSearchOperation != null) { - previousSearchOperation.stopAndWait(); - } - previousSearchOperation = null; - - Log.d(LOG, "SearchOperation: " + searchText); - final int indexLocation = languageData.lookup(searchText, interrupted); - if (!interrupted.get()) { - final IndexEntry indexEntry = languageData.sortedIndex.get(indexLocation); - - Log.d(LOG, "SearchOperation completed: " + indexEntry.toString()); - uiHandler.post(new Runnable() { - public void run() { - // Check is just a performance operation. - if (!interrupted.get()) { - // This is safe, because it checks that the listAdapter hasn't changed. - jumpToRow(listAdapter, indexEntry.startRow); - } - synchronized (DictionaryActivity.this) { - searchOperation = null; - DictionaryActivity.this.notifyAll(); - } - } - }); - } - synchronized (this) { - searchFinished = true; - this.notifyAll(); - } - } - - private void stopAndWait() { - interrupted.set(true); - synchronized (this) { - while (!searchFinished) { - Log.d(LOG, "stopAndWait: " + searchText); - try { - this.wait(); - } catch (InterruptedException e) { - Log.e(LOG, "Interrupted", e); - } - } - } - } - } // SearchOperation - - void waitForSearchEnd() { - synchronized (this) { - while (searchOperation != null) { - Log.d(LOG, "waitForSearchEnd"); - try { - this.wait(); - } catch (InterruptedException e) { - Log.e(LOG, "Interrupted.", e); - } - } - } - } - - private class SearchTextWatcher implements TextWatcher { - public void afterTextChanged(final Editable searchTextEditable) { - Log.d(LOG, "Search text changed: " + searchText.getText().toString()); - if (searchText.hasFocus()) { - // If they were typing to cause the change, update the UI. - onSearchTextChange(searchText.getText().toString()); - } - } - - public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, - int arg3) { - } - - public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { - } - } - -} \ No newline at end of file +package com.hughes.android.dictionary; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicBoolean; + +import android.app.ListActivity; +import android.content.Intent; +import android.graphics.Typeface; +import android.os.Bundle; +import android.os.Handler; +import android.preference.PreferenceManager; +import android.text.Editable; +import android.text.Spannable; +import android.text.TextWatcher; +import android.text.style.StyleSpan; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.view.View.OnClickListener; +import android.widget.BaseAdapter; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ListAdapter; +import android.widget.TableLayout; +import android.widget.TableRow; +import android.widget.TextView; + +import com.hughes.android.dictionary.engine.Dictionary; +import com.hughes.android.dictionary.engine.Index; +import com.hughes.android.dictionary.engine.PairEntry; +import com.hughes.android.dictionary.engine.RowBase; +import com.hughes.android.dictionary.engine.TokenRow; +import com.hughes.android.util.PersistentObjectCache; + +public class DictionaryActivity extends ListActivity { + + static final String LOG = "QuickDic"; + + RandomAccessFile dictRaf = null; + Dictionary dictionary = null; + int indexIndex = 0; + Index index = null; + + // package for test. + final Handler uiHandler = new Handler(); + private final Executor searchExecutor = Executors.newSingleThreadExecutor(); + private SearchOperation currentSearchOperation = null; + + EditText searchText; + Button langButton; + + // Never null. + private File wordList = null; + private boolean saveOnlyFirstSubentry = false; + + // Visible for testing. + ListAdapter indexAdapter = null; + + + public static Intent getIntent(final int dictIndex, final int indexIndex, final String searchToken) { + final Intent intent = new Intent(); + intent.setClassName(DictionaryActivity.class.getPackage().getName(), DictionaryActivity.class.getName()); + intent.putExtra(C.DICT_INDEX, dictIndex); + intent.putExtra(C.INDEX_INDEX, indexIndex); + intent.putExtra(C.SEARCH_TOKEN, searchToken); + return intent; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + PersistentObjectCache.init(this); + QuickDicConfig quickDicConfig = PersistentObjectCache.init( + this).read(C.DICTIONARY_CONFIGS, QuickDicConfig.class); + + final Intent intent = getIntent(); + + final DictionaryConfig dictionaryConfig = quickDicConfig.dictionaryConfigs.get(intent.getIntExtra(C.DICT_INDEX, 0)); + try { + dictRaf = new RandomAccessFile(dictionaryConfig.localFile, "r"); + dictionary = new Dictionary(dictRaf); + } catch (IOException e) { + Log.e(LOG, "Unable to load dictionary.", e); + // TODO: Start up the editor. + finish(); + return; + } + + indexIndex = intent.getIntExtra(C.INDEX_INDEX, 0); + index = dictionary.indices.get(indexIndex); + setListAdapter(new IndexAdapter(index)); + + setContentView(R.layout.dictionary_activity); + searchText = (EditText) findViewById(R.id.SearchText); + langButton = (Button) findViewById(R.id.LangButton); + + searchText.addTextChangedListener(new SearchTextWatcher()); + + + final Button clearSearchTextButton = (Button) findViewById(R.id.ClearSearchTextButton); + clearSearchTextButton.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + //onClearSearchTextButton(clearSearchTextButton); + } + }); + clearSearchTextButton.setVisibility(PreferenceManager.getDefaultSharedPreferences(this).getBoolean( + getString(R.string.showClearSearchTextButtonKey), true) ? View.VISIBLE + : View.GONE); + + final Button langButton = (Button) findViewById(R.id.LangButton); + langButton.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + onLanguageButton(); + } + }); + + final Button upButton = (Button) findViewById(R.id.UpButton); + upButton.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + //onUpButton(); + } + }); + final Button downButton = (Button) findViewById(R.id.DownButton); + downButton.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + //onDownButton(); + } + }); + + // ContextMenu. + registerForContextMenu(getListView()); + + updateLangButton(); + + } + + void updateLangButton() { + langButton.setText(index.shortName.toUpperCase()); + } + + + + + void onLanguageButton() { + // TODO: synchronized, stop search. + + indexIndex = (indexIndex + 1) % dictionary.indices.size(); + index = dictionary.indices.get(indexIndex); + indexAdapter = new IndexAdapter(index); + Log.d(LOG, "onLanguageButton, newLang=" + index.longName); + setListAdapter(indexAdapter); + updateLangButton(); + onSearchTextChange(searchText.getText().toString()); + } + + // -------------------------------------------------------------------------- + // SearchOperation + // -------------------------------------------------------------------------- + + private void searchFinished(final SearchOperation searchOperation) { + if (searchOperation == this.currentSearchOperation) { + setSelection(searchOperation.tokenRow.index()); + getListView().setSelected(true); + } + } + + final class SearchOperation implements Runnable { + + final AtomicBoolean interrupted = new AtomicBoolean(false); + final String searchText; + final Index index; + + boolean failed = false; + TokenRow tokenRow; + + SearchOperation(final String searchText, final Index index) { + this.searchText = searchText.trim(); + this.index = index; + } + + @Override + public void run() { + tokenRow = index.findInsertionPoint(searchText, interrupted); + failed = false; // TODO + if (!interrupted.get()) { + uiHandler.post(new Runnable() { + @Override + public void run() { + searchFinished(SearchOperation.this); + } + }); + } + } + } + + + // -------------------------------------------------------------------------- + // IndexAdapter + // -------------------------------------------------------------------------- + + static final class IndexAdapter extends BaseAdapter { + + final Index index; + + IndexAdapter(final Index index) { + this.index = index; + } + + @Override + public int getCount() { + return index.rows.size(); + } + + @Override + public Object getItem(int position) { + return index.rows.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + final RowBase row = index.rows.get(position); + if (row instanceof PairEntry.Row) { + return getView((PairEntry.Row) row, parent); + } else if (row instanceof TokenRow) { + return getView((TokenRow) row, parent); + } else { + throw new IllegalArgumentException("Unsupported Row type: " + row.getClass()); + } + } + + private View getView(PairEntry.Row row, ViewGroup parent) { + final TableLayout result = new TableLayout(parent.getContext()); + final PairEntry entry = row.getEntry(); + final int rowCount = entry.pairs.length; + for (int r = 0; r < rowCount; ++r) { + final TableRow tableRow = new TableRow(result.getContext()); + + TextView column1 = new TextView(tableRow.getContext()); + TextView column2 = new TextView(tableRow.getContext()); + final TableRow.LayoutParams layoutParams = new TableRow.LayoutParams(); + layoutParams.weight = 0.5f; + + if (r > 0) { + final TextView spacer = new TextView(tableRow.getContext()); + spacer.setText(" • "); + tableRow.addView(spacer); + } + tableRow.addView(column1, layoutParams); + if (r > 0) { + final TextView spacer = new TextView(tableRow.getContext()); + spacer.setText(" • "); + tableRow.addView(spacer); + } + tableRow.addView(column2, layoutParams); + + column1.setWidth(1); + column2.setWidth(1); + + // TODO: color words by gender + final String col1Text = index.swapPairEntries ? entry.pairs[r].lang2 : entry.pairs[r].lang1; + column1.setText(col1Text, TextView.BufferType.SPANNABLE); + final Spannable col1Spannable = (Spannable) column1.getText(); + + int startPos = 0; + final String token = row.getTokenRow(true).getToken(); + while ((startPos = col1Text.indexOf(token, startPos)) != -1) { + col1Spannable.setSpan(new StyleSpan(Typeface.BOLD), startPos, + startPos + token.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + startPos += token.length(); + } + + final String col2Text = index.swapPairEntries ? entry.pairs[r].lang1 : entry.pairs[r].lang2; + column2.setText(col2Text, TextView.BufferType.NORMAL); + + result.addView(tableRow); + } + + return result; + } + + private View getView(TokenRow row, ViewGroup parent) { + final TextView textView = new TextView(parent.getContext()); + textView.setText(row.getToken()); + textView.setTextSize(20); + return textView; + } + + } + + // -------------------------------------------------------------------------- + // SearchText + // -------------------------------------------------------------------------- + + void onSearchTextChange(final String searchText) { + Log.d(LOG, "onSearchTextChange: " + searchText); + if (currentSearchOperation != null) { + currentSearchOperation.interrupted.set(true); + } + currentSearchOperation = new SearchOperation(searchText, index); + searchExecutor.execute(currentSearchOperation); + } + + private class SearchTextWatcher implements TextWatcher { + public void afterTextChanged(final Editable searchTextEditable) { + Log.d(LOG, "Search text changed: " + searchText.getText()); + if (searchText.hasFocus()) { + // If they were typing to cause the change, update the UI. + onSearchTextChange(searchText.getText().toString()); + } + } + + public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, + int arg3) { + } + + public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { + } + } + +}