View Javadoc

1   /***
2    *     Aedict - an EDICT browser for Android
3    Copyright (C) 2009 Martin Vysny
4    
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation, either version 3 of the License, or
8    (at your option) any later version.
9    
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14  
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17   */
18  package sk.baka.aedict;
19  
20  import java.io.Serializable;
21  import java.util.ArrayList;
22  import java.util.Iterator;
23  import java.util.List;
24  
25  import sk.baka.aedict.dict.DictEntry;
26  import sk.baka.aedict.dict.DictTypeEnum;
27  import sk.baka.aedict.dict.Dictionary;
28  import sk.baka.aedict.dict.EdictEntry;
29  import sk.baka.aedict.dict.LuceneSearch;
30  import sk.baka.aedict.dict.MatcherEnum;
31  import sk.baka.aedict.dict.SearchQuery;
32  import sk.baka.aedict.dict.TanakaDictEntry;
33  import sk.baka.aedict.util.DictEntryListActions;
34  import sk.baka.aedict.util.ShowRomaji;
35  import sk.baka.autils.AbstractTask;
36  import sk.baka.autils.MiscUtils;
37  import sk.baka.autils.Progress;
38  import android.app.Activity;
39  import android.app.ListActivity;
40  import android.content.Intent;
41  import android.os.Bundle;
42  import android.view.Menu;
43  import android.view.View;
44  import android.view.ViewGroup;
45  import android.widget.ArrayAdapter;
46  import android.widget.ListView;
47  import android.widget.TextView;
48  
49  /***
50   * Perform analysis of the Tanaka sentence.
51   * 
52   * @author Martin Vysny
53   */
54  public class TanakaAnalyzeActivity extends ListActivity {
55  	/***
56  	 * The {@link TanakaDictEntry} to analyze.
57  	 */
58  	static final String INTENTKEY_TANAKADICTENTRY = "tanakaDictEntry";
59  	private static final String INTENTKEY_STATE = "state";
60  
61  	public static void launch(final Activity activity, final TanakaDictEntry td) {
62  		if (td == null || td.wordList == null || td.wordList.isEmpty()) {
63  			throw new IllegalArgumentException("word is null");
64  		}
65  		if (!AedictApp.getDownloader().checkDictionary(activity, new Dictionary(DictTypeEnum.Tanaka, null), null, false)) {
66  			return;
67  		}
68  		final Intent i = new Intent(activity, TanakaAnalyzeActivity.class);
69  		i.putExtra(INTENTKEY_TANAKADICTENTRY, td);
70  		activity.startActivity(i);
71  	}
72  
73  	private ShowRomaji showRomaji;
74  	private List<DictEntry> model = null;
75  	private TanakaDictEntry tanaka;
76  
77  	@SuppressWarnings("unchecked")
78  	@Override
79  	protected void onRestoreInstanceState(Bundle savedInstanceState) {
80  		model = (List<DictEntry>) savedInstanceState.getSerializable(INTENTKEY_STATE);
81  		showRomaji.loadState(savedInstanceState);
82  		setListAdapter(newAdapter());
83  	}
84  
85  	private ArrayAdapter<DictEntry> newAdapter() {
86  		return new ArrayAdapter<DictEntry>(this, R.layout.kanjidic_list_item, model) {
87  
88  			@Override
89  			public View getView(int position, View convertView, ViewGroup parent) {
90  				View v = convertView;
91  				if (v == null) {
92  					v = getLayoutInflater().inflate(R.layout.kanjidic_list_item, getListView(), false);
93  				}
94  				final DictEntry e = model.get(position);
95  				((TextView) v.findViewById(android.R.id.text1)).setText(showRomaji.romanize(e.reading));
96  				final StringBuilder sb = new StringBuilder();
97  				sb.insert(0, e.english);
98  				((TextView) v.findViewById(android.R.id.text2)).setText(sb.toString());
99  				final TextView tv = (TextView) v.findViewById(R.id.kanjiBig);
100 				// if the japanese word is too big the reading and the
101 				// translation is not shown anymore
102 				// workaround: add \n character after each third char
103 				tv.setText(splitToRows(e.getJapanese()));
104 				return v;
105 			}
106 
107 			private String splitToRows(final String str) {
108 				if (str == null) {
109 					return "";
110 				}
111 				final StringBuilder sb = new StringBuilder(str.length() * 4 / 3);
112 				for (int i = 0; i < str.length(); i++) {
113 					if ((i > 0) && (i % 3 == 0)) {
114 						sb.append('\n');
115 					}
116 					sb.append(str.charAt(i));
117 				}
118 				return sb.toString();
119 			}
120 		};
121 	}
122 
123 	@Override
124 	protected void onSaveInstanceState(Bundle outState) {
125 		showRomaji.saveState(outState);
126 		outState.putSerializable(INTENTKEY_STATE, (Serializable) model);
127 	}
128 
129 	@Override
130 	protected void onListItemClick(ListView l, View v, int position, long id) {
131 		final DictEntry e = model.get(position);
132 		if (!e.isValid()) {
133 			return;
134 		}
135 		if (e instanceof EdictEntry) {
136 			EdictEntryDetailActivity.launch(this, (EdictEntry) e);
137 		}
138 	}
139 
140 	@Override
141 	protected void onCreate(Bundle savedInstanceState) {
142 		super.onCreate(savedInstanceState);
143 		showRomaji = new ShowRomaji() {
144 
145 			@Override
146 			protected void show(boolean romaji) {
147 				if (getListAdapter() != null) {
148 					((ArrayAdapter<?>) getListAdapter()).notifyDataSetChanged();
149 				}
150 			}
151 		};
152 		tanaka = (TanakaDictEntry) getIntent().getSerializableExtra(INTENTKEY_TANAKADICTENTRY);
153 		new DictEntryListActions(this, true, true, false, true).register(getListView());
154 	}
155 
156 	@Override
157 	protected void onResume() {
158 		super.onResume();
159 		showRomaji.onResume();
160 		if(model==null){
161 			recomputeModel();
162 		}
163 	}
164 
165 	@Override
166 	public boolean onPrepareOptionsMenu(Menu menu) {
167 		menu.clear();
168 		showRomaji.register(this, menu);
169 		return true;
170 	}
171 
172 	private void recomputeModel() {
173 		new RecomputeModel().execute(AedictApp.isInstrumentation, this, tanaka);
174 	}
175 
176 	private class RecomputeModel extends AbstractTask<TanakaDictEntry, List<DictEntry>> {
177 
178 		@Override
179 		protected void cleanupAfterError(Exception ex) {
180 			// nothing to do
181 		}
182 
183 		@Override
184 		protected void onSucceeded(List<DictEntry> result) {
185 			model = result;
186 			model.add(0, new DictEntry("", tanaka.kanji + "\n" + tanaka.reading, tanaka.english));
187 			setListAdapter(newAdapter());
188 		}
189 
190 		@Override
191 		public List<DictEntry> impl(TanakaDictEntry... params) throws Exception {
192 			publish(new Progress(AedictApp.getStr(R.string.analyzing), 0, 100));
193 			final List<DictEntry> result = new ArrayList<DictEntry>();
194 			final LuceneSearch lsEdict = new LuceneSearch(DictTypeEnum.Edict, AedictApp.getConfig().getDictionaryLoc(), true);
195 			try {
196 				final TanakaDictEntry e = params[0];
197 				for (int i = 0; i < e.wordList.size(); i++) {
198 					publish(new Progress(null, i, e.wordList.size()));
199 					if (isCancelled()) {
200 						return null;
201 					}
202 					final String kanji = e.wordList.get(i);
203 					final SearchQuery q = SearchQuery.searchJpEdict(kanji, MatcherEnum.Exact);
204 					final List<DictEntry> matches = lsEdict.search(q, 10);
205 					for (Iterator<DictEntry> it = matches.iterator(); it.hasNext();) {
206 						final DictEntry ee = it.next();
207 						if (!ee.getJapanese().equals(kanji)) {
208 							it.remove();
209 						}
210 					}
211 					DictEntry.removeInvalid(matches);
212 					final DictEntry ee;
213 					if (!matches.isEmpty()) {
214 						ee = matches.get(0);
215 					} else {
216 						// no luck. Just add the kanji
217 						ee = new DictEntry(kanji, "", "");
218 					}
219 					result.add(ee);
220 				}
221 				return result;
222 			} finally {
223 				MiscUtils.closeQuietly(lsEdict);
224 			}
225 		}
226 	}
227 }