]> gitweb.fperrin.net Git - Dictionary.git/blob - src/com/hughes/android/dictionary/DictionaryActivity.java
go
[Dictionary.git] / src / com / hughes / android / dictionary / DictionaryActivity.java
1 package com.hughes.android.dictionary;\r
2 \r
3 import java.io.File;\r
4 import java.io.IOException;\r
5 import java.io.RandomAccessFile;\r
6 import java.util.concurrent.Executor;\r
7 import java.util.concurrent.Executors;\r
8 import java.util.concurrent.atomic.AtomicBoolean;\r
9 \r
10 import android.app.ListActivity;\r
11 import android.content.Intent;\r
12 import android.graphics.Typeface;\r
13 import android.os.Bundle;\r
14 import android.os.Handler;\r
15 import android.preference.PreferenceManager;\r
16 import android.text.Editable;\r
17 import android.text.Spannable;\r
18 import android.text.TextWatcher;\r
19 import android.text.style.StyleSpan;\r
20 import android.util.Log;\r
21 import android.view.View;\r
22 import android.view.ViewGroup;\r
23 import android.view.View.OnClickListener;\r
24 import android.widget.BaseAdapter;\r
25 import android.widget.Button;\r
26 import android.widget.EditText;\r
27 import android.widget.ListAdapter;\r
28 import android.widget.TableLayout;\r
29 import android.widget.TableRow;\r
30 import android.widget.TextView;\r
31 \r
32 import com.hughes.android.dictionary.engine.Dictionary;\r
33 import com.hughes.android.dictionary.engine.Index;\r
34 import com.hughes.android.dictionary.engine.PairEntry;\r
35 import com.hughes.android.dictionary.engine.RowBase;\r
36 import com.hughes.android.dictionary.engine.TokenRow;\r
37 import com.hughes.android.util.PersistentObjectCache;\r
38 \r
39 public class DictionaryActivity extends ListActivity {\r
40 \r
41   static final String LOG = "QuickDic";\r
42 \r
43   RandomAccessFile dictRaf = null;\r
44   Dictionary dictionary = null;\r
45   int indexIndex = 0;\r
46   Index index = null;\r
47   \r
48   // package for test.\r
49   final Handler uiHandler = new Handler();\r
50   private final Executor searchExecutor = Executors.newSingleThreadExecutor();\r
51   private SearchOperation currentSearchOperation = null;\r
52 \r
53   EditText searchText;\r
54   Button langButton;\r
55 \r
56   // Never null.\r
57   private File wordList = null;\r
58   private boolean saveOnlyFirstSubentry = false;\r
59 \r
60   // Visible for testing.\r
61   ListAdapter indexAdapter = null;\r
62 \r
63   \r
64   public static Intent getIntent(final int dictIndex, final int indexIndex, final String searchToken) {\r
65     final Intent intent = new Intent();\r
66     intent.setClassName(DictionaryActivity.class.getPackage().getName(), DictionaryActivity.class.getName());\r
67     intent.putExtra(C.DICT_INDEX, dictIndex);\r
68     intent.putExtra(C.INDEX_INDEX, indexIndex);\r
69     intent.putExtra(C.SEARCH_TOKEN, searchToken);\r
70     return intent;\r
71   }\r
72 \r
73   @Override\r
74   public void onCreate(Bundle savedInstanceState) {\r
75     super.onCreate(savedInstanceState);\r
76     \r
77     PersistentObjectCache.init(this);\r
78     QuickDicConfig quickDicConfig = PersistentObjectCache.init(\r
79         this).read(C.DICTIONARY_CONFIGS, QuickDicConfig.class);\r
80     \r
81     final Intent intent = getIntent();\r
82     \r
83     final DictionaryConfig dictionaryConfig = quickDicConfig.dictionaryConfigs.get(intent.getIntExtra(C.DICT_INDEX, 0));\r
84     try {\r
85       dictRaf = new RandomAccessFile(dictionaryConfig.localFile, "r");\r
86       dictionary = new Dictionary(dictRaf); \r
87     } catch (IOException e) {\r
88       Log.e(LOG, "Unable to load dictionary.", e);\r
89       // TODO: Start up the editor.\r
90       finish();\r
91       return;\r
92     }\r
93     \r
94     indexIndex = intent.getIntExtra(C.INDEX_INDEX, 0);\r
95     index = dictionary.indices.get(indexIndex);\r
96     setListAdapter(new IndexAdapter(index));\r
97     \r
98     setContentView(R.layout.dictionary_activity);\r
99     searchText = (EditText) findViewById(R.id.SearchText);\r
100     langButton = (Button) findViewById(R.id.LangButton);\r
101     \r
102     searchText.addTextChangedListener(new SearchTextWatcher());\r
103     \r
104     \r
105     final Button clearSearchTextButton = (Button) findViewById(R.id.ClearSearchTextButton);\r
106     clearSearchTextButton.setOnClickListener(new OnClickListener() {\r
107       public void onClick(View v) {\r
108         //onClearSearchTextButton(clearSearchTextButton);\r
109       }\r
110     });\r
111     clearSearchTextButton.setVisibility(PreferenceManager.getDefaultSharedPreferences(this).getBoolean(\r
112         getString(R.string.showClearSearchTextButtonKey), true) ? View.VISIBLE\r
113         : View.GONE);\r
114     \r
115     final Button langButton = (Button) findViewById(R.id.LangButton);\r
116     langButton.setOnClickListener(new OnClickListener() {\r
117       public void onClick(View v) {\r
118         onLanguageButton();\r
119       }\r
120     });\r
121     \r
122     final Button upButton = (Button) findViewById(R.id.UpButton);\r
123     upButton.setOnClickListener(new OnClickListener() {\r
124       public void onClick(View v) {\r
125         //onUpButton();\r
126       }\r
127     });\r
128     final Button downButton = (Button) findViewById(R.id.DownButton);\r
129     downButton.setOnClickListener(new OnClickListener() {\r
130       public void onClick(View v) {\r
131         //onDownButton();\r
132       }\r
133     });\r
134 \r
135     // ContextMenu.\r
136     registerForContextMenu(getListView());\r
137 \r
138     updateLangButton();\r
139 \r
140   }\r
141   \r
142   void updateLangButton() {\r
143     langButton.setText(index.shortName.toUpperCase());\r
144   }\r
145 \r
146 \r
147   \r
148   \r
149   void onLanguageButton() {\r
150     // TODO: synchronized, stop search.\r
151     \r
152     indexIndex = (indexIndex + 1) % dictionary.indices.size();\r
153     index = dictionary.indices.get(indexIndex);\r
154     indexAdapter = new IndexAdapter(index);\r
155     Log.d(LOG, "onLanguageButton, newLang=" + index.longName);\r
156     setListAdapter(indexAdapter);\r
157     updateLangButton();\r
158     onSearchTextChange(searchText.getText().toString());\r
159   }\r
160   \r
161   // --------------------------------------------------------------------------\r
162   // SearchOperation\r
163   // --------------------------------------------------------------------------\r
164 \r
165   private void searchFinished(final SearchOperation searchOperation) {\r
166     if (searchOperation == this.currentSearchOperation) {\r
167       setSelection(searchOperation.tokenRow.index());\r
168       getListView().setSelected(true);\r
169     }\r
170   }\r
171 \r
172   final class SearchOperation implements Runnable {\r
173     \r
174     final AtomicBoolean interrupted = new AtomicBoolean(false);\r
175     final String searchText;\r
176     final Index index;\r
177     \r
178     boolean failed = false;\r
179     TokenRow tokenRow;\r
180     \r
181     SearchOperation(final String searchText, final Index index) {\r
182       this.searchText = searchText.trim();\r
183       this.index = index;\r
184     }\r
185 \r
186     @Override\r
187     public void run() {\r
188       tokenRow = index.findInsertionPoint(searchText, interrupted);\r
189       failed = false; // TODO\r
190       if (!interrupted.get()) {\r
191         uiHandler.post(new Runnable() {\r
192           @Override\r
193           public void run() {            \r
194             searchFinished(SearchOperation.this);\r
195           }\r
196         });\r
197       }\r
198     }\r
199   }\r
200 \r
201   \r
202   // --------------------------------------------------------------------------\r
203   // IndexAdapter\r
204   // --------------------------------------------------------------------------\r
205 \r
206   static final class IndexAdapter extends BaseAdapter {\r
207     \r
208     final Index index;\r
209 \r
210     IndexAdapter(final Index index) {\r
211       this.index = index;\r
212     }\r
213 \r
214     @Override\r
215     public int getCount() {\r
216       return index.rows.size();\r
217     }\r
218 \r
219     @Override\r
220     public Object getItem(int position) {\r
221       return index.rows.get(position);\r
222     }\r
223 \r
224     @Override\r
225     public long getItemId(int position) {\r
226       return position;\r
227     }\r
228 \r
229     @Override\r
230     public View getView(int position, View convertView, ViewGroup parent) {\r
231       final RowBase row = index.rows.get(position);\r
232       if (row instanceof PairEntry.Row) {\r
233         return getView((PairEntry.Row) row, parent);\r
234       } else if (row instanceof TokenRow) {\r
235         return getView((TokenRow) row, parent);\r
236       } else {\r
237         throw new IllegalArgumentException("Unsupported Row type: " + row.getClass());\r
238       }\r
239     }\r
240 \r
241     private View getView(PairEntry.Row row, ViewGroup parent) {\r
242       final TableLayout result = new TableLayout(parent.getContext());\r
243       final PairEntry entry = row.getEntry();\r
244       final int rowCount = entry.pairs.length;\r
245       for (int r = 0; r < rowCount; ++r) {\r
246         final TableRow tableRow = new TableRow(result.getContext());\r
247 \r
248         TextView column1 = new TextView(tableRow.getContext());\r
249         TextView column2 = new TextView(tableRow.getContext());\r
250         final TableRow.LayoutParams layoutParams = new TableRow.LayoutParams();\r
251         layoutParams.weight = 0.5f;\r
252 \r
253         if (r > 0) {\r
254           final TextView spacer = new TextView(tableRow.getContext());\r
255           spacer.setText(" • ");\r
256           tableRow.addView(spacer);\r
257         }\r
258         tableRow.addView(column1, layoutParams);\r
259         if (r > 0) {\r
260           final TextView spacer = new TextView(tableRow.getContext());\r
261           spacer.setText(" • ");\r
262           tableRow.addView(spacer);\r
263         }\r
264         tableRow.addView(column2, layoutParams);\r
265 \r
266         column1.setWidth(1);\r
267         column2.setWidth(1);\r
268 \r
269         // TODO: color words by gender\r
270         final String col1Text = index.swapPairEntries ? entry.pairs[r].lang2 : entry.pairs[r].lang1;\r
271         column1.setText(col1Text, TextView.BufferType.SPANNABLE);\r
272         final Spannable col1Spannable = (Spannable) column1.getText();\r
273         \r
274         int startPos = 0;\r
275         final String token = row.getTokenRow(true).getToken();\r
276         while ((startPos = col1Text.indexOf(token, startPos)) != -1) {\r
277           col1Spannable.setSpan(new StyleSpan(Typeface.BOLD), startPos,\r
278               startPos + token.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);\r
279           startPos += token.length();\r
280         }\r
281 \r
282         final String col2Text = index.swapPairEntries ? entry.pairs[r].lang1 : entry.pairs[r].lang2;\r
283         column2.setText(col2Text, TextView.BufferType.NORMAL);\r
284 \r
285         result.addView(tableRow);\r
286       }\r
287 \r
288       return result;\r
289     }\r
290 \r
291     private View getView(TokenRow row, ViewGroup parent) {\r
292       final TextView textView = new TextView(parent.getContext());\r
293       textView.setText(row.getToken());\r
294       textView.setTextSize(20);\r
295       return textView;\r
296     }\r
297     \r
298   }\r
299 \r
300   // --------------------------------------------------------------------------\r
301   // SearchText\r
302   // --------------------------------------------------------------------------\r
303 \r
304   void onSearchTextChange(final String searchText) {\r
305     Log.d(LOG, "onSearchTextChange: " + searchText);\r
306     if (currentSearchOperation != null) {\r
307       currentSearchOperation.interrupted.set(true);\r
308     }\r
309     currentSearchOperation = new SearchOperation(searchText, index);\r
310     searchExecutor.execute(currentSearchOperation);\r
311   }\r
312   \r
313   private class SearchTextWatcher implements TextWatcher {\r
314     public void afterTextChanged(final Editable searchTextEditable) {\r
315       Log.d(LOG, "Search text changed: " + searchText.getText());\r
316       if (searchText.hasFocus()) {\r
317         // If they were typing to cause the change, update the UI.\r
318         onSearchTextChange(searchText.getText().toString());\r
319       }\r
320     }\r
321 \r
322     public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,\r
323         int arg3) {\r
324     }\r
325 \r
326     public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {\r
327     }\r
328   }\r
329 \r
330 }\r