]> gitweb.fperrin.net Git - Dictionary.git/commitdiff
Lots of bug fixes! Workaround for ICS OOM, background loading of which
authorThad Hughes <thad.hughes@gmail.com>
Fri, 3 Feb 2012 23:44:05 +0000 (15:44 -0800)
committerThad Hughes <thad.hughes@gmail.com>
Fri, 3 Feb 2012 23:44:05 +0000 (15:44 -0800)
dictionaries are available.  New screenshots.

21 files changed:
images/dictionary_list.png
images/german_fuenf.png [deleted file]
images/italian_sogni.png [deleted file]
images/nihao_hello.png [new file with mode: 0644]
images/q128x128.png
images/search_zh_shia_shia_thank_you.png [new file with mode: 0644]
images/switch_dictionary_quick.png [new file with mode: 0644]
images/v3.1_multi_search_train_station.png [new file with mode: 0644]
images/v3.1_search_selected.png [new file with mode: 0644]
res/layout/thadolina_dialog.xml
res/raw-de/whats_new.html
res/raw/help.html
res/raw/whats_new.html
res/values-de/languages.xml [new file with mode: 0644]
res/values-de/strings.xml
res/values/strings.xml
res/xml/preferences.xml
src/com/hughes/android/dictionary/DictionaryActivity.java
src/com/hughes/android/dictionary/DictionaryApplication.java
src/com/hughes/android/dictionary/DictionaryManagerActivity.java
src/com/hughes/android/dictionary/PreferenceActivity.java

index eff48de90aa85a92c38780f668914fe2e6cff30b..c57b778e5732251316431767c6c7fa87aab308cc 100644 (file)
Binary files a/images/dictionary_list.png and b/images/dictionary_list.png differ
diff --git a/images/german_fuenf.png b/images/german_fuenf.png
deleted file mode 100644 (file)
index 24a7e1d..0000000
Binary files a/images/german_fuenf.png and /dev/null differ
diff --git a/images/italian_sogni.png b/images/italian_sogni.png
deleted file mode 100644 (file)
index 6f0e647..0000000
Binary files a/images/italian_sogni.png and /dev/null differ
diff --git a/images/nihao_hello.png b/images/nihao_hello.png
new file mode 100644 (file)
index 0000000..b417463
Binary files /dev/null and b/images/nihao_hello.png differ
index ceb74665dc26b35c34c53c06d5c949e6cbebb7a9..738a7e3ab509fd433a3f418df877696c956ed3f1 100644 (file)
Binary files a/images/q128x128.png and b/images/q128x128.png differ
diff --git a/images/search_zh_shia_shia_thank_you.png b/images/search_zh_shia_shia_thank_you.png
new file mode 100644 (file)
index 0000000..6af4762
Binary files /dev/null and b/images/search_zh_shia_shia_thank_you.png differ
diff --git a/images/switch_dictionary_quick.png b/images/switch_dictionary_quick.png
new file mode 100644 (file)
index 0000000..da151c4
Binary files /dev/null and b/images/switch_dictionary_quick.png differ
diff --git a/images/v3.1_multi_search_train_station.png b/images/v3.1_multi_search_train_station.png
new file mode 100644 (file)
index 0000000..e1f93f0
Binary files /dev/null and b/images/v3.1_multi_search_train_station.png differ
diff --git a/images/v3.1_search_selected.png b/images/v3.1_search_selected.png
new file mode 100644 (file)
index 0000000..4da612c
Binary files /dev/null and b/images/v3.1_search_selected.png differ
index 440d8fc68118f941bd377400cdeb280ae1b4a334..e81ccd9c73cf70b39133f883a122b9db88ba032b 100644 (file)
@@ -6,26 +6,49 @@
     <LinearLayout
         android:id="@+id/linearLayout1"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
+        android:layout_height="wrap_content"
         android:orientation="vertical" >
 
+       <TextView
+         android:layout_marginTop="20dip"
+         android:id="@+id/text_quote_flower"
+         android:layout_width="wrap_content"
+         android:layout_height="wrap_content"
+         android:layout_gravity="center_horizontal"
+         android:text="There is a flower... I think that she has tamed me..."
+         android:layout_marginBottom="20dip"
+          />
+        
+        
+
         <ImageView
-            android:id="@+id/ImageView01"
+            android:id="@+id/thadolina_image"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="center_horizontal"
             android:background="@drawable/thadolina"
-            android:layout_marginTop="20dip"
             android:layout_marginBottom="20dip"
              />
 
         <TextView
-            android:id="@+id/text1"
+            android:id="@+id/text_message"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal"
+            android:text="Happy Valentine's Day, amore mio!  And happy every other day, too!" 
+            android:textAppearance="@android:style/TextAppearance.Large"
+            android:layout_marginBottom="20dip"
+            />
+        
+        <TextView
+            android:id="@+id/text_quote"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="center_horizontal"
             android:text="It is only with the heart that one can see rightly; what is essential is invisible to the eye."
-            android:textAppearance="@android:style/TextAppearance.Large" />
+             />
+
+        
     </LinearLayout>
 
 </ScrollView>
\ No newline at end of file
index dcb9326fbe25e7ab692f615e87f2b990c54cc9aa..73c35beeaf8874387aa6e6c5cbf3c445da527133 100644 (file)
@@ -10,7 +10,7 @@
   <ul>
     <li> Suche nach mehreren Begriffen gleichzeitig (durch Leerzeichen getrennt).
     <li> Alle Wörter sind Hyperlinks: long-drücken jedes Wort in einem Wörterbuch, um dieses Wort zu suchen.
-    <li> Long-drücken den Sprache-Taste, um das aktuelle Wörterbuch zu wechseln.
+    <li> Wörterbuch wechseln ist einfacher: Long-drücken den Sprache-Taste.
     <li> New English Wörterbücher: Azeri, Basque, Breton, Burmese, Faroese, Galician, Georgian, Haitian Creole, Luxembourgish, Macedonian, Tagalog, Urdu. (von enwiktionary.com Daten).
     <li> Alle Wörterbücher aktualisiert (vor allem mit einer besseren Formatierung), und können in Ihrer Freizeit (zuvor heruntergeladene Wörterbücher wird immer noch funktionieren) erneut heruntergeladen werden.  </ul>
 </body>
index ac9362cad368669b754e092cd4920826ab92813c..82e4ac3d9ed363f1c3ac3e1ed654c7fcf4fec4dd 100644 (file)
   under all the relevant words.
   <h3>Searching</h3>
   <ul>
-    <li> Type a single word to search for it.  QuickDic searches as you type, jumping to the relevant position in the list.
-    <li> (NEW) Type multiple words separated by spaces.  QuickDic finds all the rows containing all of the words and displays them.
-    <li> QuickDic tries to sort words using a romanized transliteration, so you can try searching for non-Latin words using the Latin alphabet.
-    <li> If the search text box isn't focused, you can start typing and its contents will be replaced.
+    <li> Type a single word to search for it.  QuickDic searches as you type, 
+         jumping to the relevant position in the list.
+    <li> (NEW) Type multiple words separated by spaces.  QuickDic finds all 
+         the rows containing all of the words and displays them.
+    <li> QuickDic tries to sort words using a romanized transliteration, 
+         so you can try searching for non-Latin words using the Latin alphabet.
+    <li> If the search text box isn't focused, you can start typing and its 
+         contents will be replaced.
   </ul>
-  <h3>Other</h3>
+  <h3>Tricks</h3>
   <ul>
     <li> Click the button to the right of the search box to switch dictionary directions: EN-&gt;DE to DE-&gt;EN.
     <li> (NEW) Long-click the button to the right of the search box to pick a new dictionary.
     <li> Long-click any entry to bring up the context menu, from which you can:
     <ul>
+      <li> (NEW) Long-click a particular word to jump to that word in the 
+           dictionary.  This is a great way to quickly lookup words that
+           are part of definitions (especially if they're in a language that's
+           tough to type in!)
       <li> Add the current row to the wordList.txt file for later study.
       <li> Copy the current row to the clipboard.
-      <li> (NEW) Long-click a particular word to jump to that word in the dictionary.
     </ul>
     <!-- Long-click in the search text to open the search history. -->
   </ul>
index 85d2e92c6f82ace28ad49757ecf56e83069ac1d5..5ae4cd8f738fdc1a5043362bb4b83c4c994e2c45 100644 (file)
@@ -10,7 +10,7 @@
   <ul>
     <li> Search for multiple words at once (separated by spaces).
     <li> All words are hyperlinks: long-press any word in a dictionary to lookup that word.
-    <li> Long-press the switch-language button to switch the current dictionary.
+    <li> Easier dictionary switching: long-press the switch-language button.
     <li> New English dictionaries: Azeri, Basque, Breton, Burmese, Faroese, Galician, Georgian, Haitian Creole, Luxembourgish, Macedonian, Tagalog, Urdu. (from enwiktionary.com data).
     <li> All dictionaries updated (mostly with better formatting), and can be re-downloaded at your leisure (previously downloaded dictionaries will still work).
   </ul>
diff --git a/res/values-de/languages.xml b/res/values-de/languages.xml
new file mode 100644 (file)
index 0000000..274120d
--- /dev/null
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+  <string name="AF">Afrikaans</string>
+  <string name="SQ">Albanisch</string>
+  <string name="AR">Arabisch</string>
+  <string name="HY">Armenisch</string>
+  <string name="BE">Belarussisch</string>
+  <string name="BN">Bengali</string>
+  <string name="BS">Bosnisch</string>
+  <string name="BG">Bulgarisch</string>
+  <string name="CA">Katalanisch</string>
+  <string name="HR">Kroatisch</string>
+  <string name="CS">Tschechisch</string>
+  <string name="ZH">Chinesisch (Mandarin, Kantonesisch)</string>
+  <string name="DA">Dänisch</string>
+  <string name="NL">Niederländisch</string>
+  <string name="EN">Englisch</string>
+  <string name="EO">Esperanto</string>
+  <string name="ET">Estnisch</string>
+  <string name="FI">Finnisch</string>
+  <string name="FR">Französisch</string>
+  <string name="DE">Deutsch</string>
+  <string name="EL">Griechisch</string>
+  <string name="haw">Hawaiian</string>
+  <string name="HE">Hebräisch</string>
+  <string name="HI">Hindi</string>
+  <string name="HU">Ungarisch</string>
+  <string name="IS">Isländisch</string>
+  <string name="ID">Indonesisch</string>
+  <string name="GA">Gälisch (Irisch, Schottisch)</string>
+  <string name="IT">Italienisch</string>
+  <string name="LA">Latin</string>
+  <string name="LV">Lettisch</string>
+  <string name="LT">Litauisch</string>
+  <string name="JA">Japanisch</string>
+  <string name="KO">Korean</string>
+  <string name="KU">Kurdisch</string>
+  <string name="MS">Malay</string>
+  <string name="MI">Maori</string>
+  <string name="MN">Mongolisch</string>
+  <string name="NE">Nepali</string>
+  <string name="NO">Norwegisch</string>
+  <string name="FA">Persisch</string>
+  <string name="PL">Polnisch</string>
+  <string name="PT">Portugiesisch</string>
+  <string name="PA">Punjabi</string>
+  <string name="RO">Rumänisch</string>
+  <string name="RU">Russisch</string>
+  <string name="SA">Sanskrit</string>
+  <string name="SR">Serbisch</string>
+  <string name="SK">Slowakisch</string>
+  <string name="SO">Somali</string>
+  <string name="ES">Spanisch</string>
+  <string name="SW">Swahili</string>
+  <string name="SV">Schwedisch</string>
+  <string name="TL">Tagalog</string>
+  <string name="TG">Tadschikisch</string>
+  <string name="TH">Thailändisch</string>
+  <string name="BO">Tibetisch</string>
+  <string name="TR">Türkisch</string>
+  <string name="UK">Ukrainisch</string>
+  <string name="UR">Urdu</string>
+  <string name="VI">Vietnamesisch</string>
+  <string name="CI">Walisisch</string>
+  <string name="YI">Jiddisch</string>
+  <string name="ZU">Zulu</string>
+
+  
+  <string name="AZ">Azeri</string>
+  <string name="EU">Baskisch</string>
+  <string name="BR">Breton</string>
+  <string name="MR">Birmanisch</string>
+  <string name="FO">Färöisch</string>
+  <string name="GL">Galizisch</string>
+  <string name="KA">Georgisch</string>
+  <string name="HT">Haitian Creole</string>
+  <string name="LB">Luxemburgisch</string>
+  <string name="MK">Mazedonisch</string>  
+</resources>
\ No newline at end of file
index 97f92faa06e6aab56d97f5e7e5b208e08f623052..311b56b5350bd036fb31fd5ba2c8eaa7346bf5a5 100644 (file)
@@ -12,8 +12,8 @@
   <!-- DictionaryManagerActivity -->
   <string name="dictionaryManager">Wörterbuch-Liste</string>
   <string name="helpText">Long-drücken, um weitere Möglichkeiten zu sehen.</string>
-  <string name="downloadButton">Herunterladen</string>
-  <string name="updateButton">Neuladen</string>
+  <string name="downloadButton">Herunterladen (%.1fMB)</string>
+  <string name="updateButton">Neuladen (%.1fMB)</string>
   <string name="moveToTop">Nach Anfang ziehen</string>
   <string name="deleteDictionary">Wörterbuch entfernen</string>
   <string name="indexInfo">%1$s: %2$,d Wörter</string>
   <string name="errorDownloadingFile">"Fehler beim Herunterladen: \n%s"</string>
 
        <!-- Preferences -->
+  <string name="quickdicDirectoryKey">quickdicDirectory</string>
+  <string name="quickdicDirectoryTitle">QuickDic Verzeichnis</string>
+  <string name="quickdicDirectorySummary">Das Verzeichnis, in dem QuickDic speichert Wörterbücher.</string>
+  <string name="quickdicDirectoryDefault">/sdcard/quickDic/</string>
+  
        <string name="wordListFileKey">wordListFile</string>
        <string name="wordListFileTitle">Wortlist Datei</string>
        <string name="wordListFileSummary">Die lokale Datei, wo das Wortliste hinzugefügt wird.</string>
index 779d3b9cf1931606ce32133e8fa5fe593ace859c..e7d97dd3696ea49a94365edf00201f724f149885 100644 (file)
 
 
        <!-- Preferences -->
+
+  <string name="quickdicDirectoryKey">quickdicDirectory</string>
+  <string name="quickdicDirectoryTitle">QuickDic directory</string>
+  <string name="quickdicDirectorySummary">The directory where QuickDic stores dictionaries.</string>
+  <string name="quickdicDirectoryDefault">/sdcard/quickDic/</string>
+  
        <string name="wordListFileKey">wordListFile</string>
        <string name="wordListFileTitle">Word list file</string>
        <string name="wordListFileSummary">The local file where the word list will be appended.</string>
index 30a60660584b11041af55eb0c4b294c35e547080..23a7a03babc8de343a4e867189a567021464590f 100644 (file)
@@ -1,5 +1,14 @@
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">\r
 \r
+  <EditTextPreference\r
+    android:key="@string/quickdicDirectoryKey"\r
+    android:title="@string/quickdicDirectoryTitle" \r
+    android:summary="@string/quickdicDirectorySummary"\r
+    android:defaultValue="@string/quickdicDirectoryDefault"\r
+    android:persistent="true"\r
+  />\r
+\r
+    \r
        <EditTextPreference\r
          android:key="@string/wordListFileKey"\r
     android:title="@string/wordListFileTitle" \r
index 63284ecb25c0f66f4f8e44453658b023a32e9284..6bfb379dd3bc6b54dccd2ee104bf7f5ac4a39a07 100644 (file)
@@ -39,6 +39,7 @@ import android.content.Context;
 import android.content.Intent;\r
 import android.content.SharedPreferences;\r
 import android.graphics.Typeface;\r
+import android.net.Uri;\r
 import android.os.Bundle;\r
 import android.os.Handler;\r
 import android.preference.PreferenceManager;\r
@@ -69,6 +70,7 @@ import android.widget.AdapterView.AdapterContextMenuInfo;
 import android.widget.BaseAdapter;\r
 import android.widget.Button;\r
 import android.widget.EditText;\r
+import android.widget.ImageView;\r
 import android.widget.LinearLayout;\r
 import android.widget.ListAdapter;\r
 import android.widget.ListView;\r
@@ -81,8 +83,8 @@ import com.hughes.android.dictionary.DictionaryInfo.IndexInfo;
 import com.hughes.android.dictionary.engine.Dictionary;\r
 import com.hughes.android.dictionary.engine.EntrySource;\r
 import com.hughes.android.dictionary.engine.Index;\r
-import com.hughes.android.dictionary.engine.PairEntry;\r
 import com.hughes.android.dictionary.engine.Index.IndexEntry;\r
+import com.hughes.android.dictionary.engine.PairEntry;\r
 import com.hughes.android.dictionary.engine.PairEntry.Pair;\r
 import com.hughes.android.dictionary.engine.RowBase;\r
 import com.hughes.android.dictionary.engine.TokenRow;\r
@@ -128,6 +130,14 @@ public class DictionaryActivity extends ListActivity {
   ListAdapter indexAdapter = null;\r
   \r
   final SearchTextWatcher searchTextWatcher = new SearchTextWatcher();\r
+  \r
+  /**\r
+   * For some languages, loading the transliterators used in this search takes\r
+   * a long time, so we fire it up on a different thread, and don't invoke it\r
+   * from the main thread until it's already finished once.\r
+   */\r
+  private volatile boolean indexPrepFinished = false;\r
+\r
 \r
 \r
   public DictionaryActivity() {\r
@@ -146,6 +156,7 @@ public class DictionaryActivity extends ListActivity {
   protected void onSaveInstanceState(final Bundle outState) {\r
     super.onSaveInstanceState(outState);\r
     Log.d(LOG, "onSaveInstanceState: " + searchText.getText().toString());\r
+    outState.putInt(C.INDEX_INDEX, indexIndex);\r
     outState.putString(C.SEARCH_TOKEN, searchText.getText().toString());\r
   }\r
 \r
@@ -153,7 +164,7 @@ public class DictionaryActivity extends ListActivity {
   protected void onRestoreInstanceState(final Bundle outState) {\r
     super.onRestoreInstanceState(outState);\r
     Log.d(LOG, "onRestoreInstanceState: " + outState.getString(C.SEARCH_TOKEN));\r
-    initialSearchText = outState.getString(C.SEARCH_TOKEN);\r
+    onCreate(outState);\r
   }\r
 \r
   @Override\r
@@ -187,47 +198,52 @@ public class DictionaryActivity extends ListActivity {
         }\r
         dictRaf = null;\r
       }\r
-      Toast.makeText(this, getString(R.string.invalidDictionary, "", e.getMessage()), Toast.LENGTH_LONG);\r
+      Toast.makeText(this, getString(R.string.invalidDictionary, "", e.getMessage()), Toast.LENGTH_LONG).show();\r
       startActivity(DictionaryManagerActivity.getLaunchIntent());\r
       finish();\r
       return;\r
     }\r
-\r
-    indexIndex = intent.getIntExtra(C.INDEX_INDEX, 0) % dictionary.indices.size();\r
+    indexIndex = intent.getIntExtra(C.INDEX_INDEX, 0);\r
+    if (savedInstanceState != null) {\r
+      indexIndex = savedInstanceState.getInt(C.INDEX_INDEX, indexIndex);\r
+    }\r
+    indexIndex %= dictionary.indices.size();\r
     Log.d(LOG, "Loading index " + indexIndex);\r
     index = dictionary.indices.get(indexIndex);\r
     setListAdapter(new IndexAdapter(index));\r
     \r
     // Pre-load the collators.\r
-    searchExecutor.execute(new Runnable() {\r
+    new Thread(new Runnable() {\r
       public void run() {\r
         final long startMillis = System.currentTimeMillis();\r
-        \r
-        TransliteratorManager.init(new TransliteratorManager.Callback() {\r
-          @Override\r
-          public void onTransliteratorReady() {\r
-            uiHandler.post(new Runnable() {\r
-              @Override\r
-              public void run() {\r
-                onSearchTextChange(searchText.getText().toString());\r
-              }\r
-            });\r
-          }\r
-        });\r
-        \r
-        for (final Index index : dictionary.indices) {\r
-          Log.d(LOG, "Starting collator load for lang=" + index.sortLanguage.getIsoCode());\r
+        try {\r
+          TransliteratorManager.init(new TransliteratorManager.Callback() {\r
+            @Override\r
+            public void onTransliteratorReady() {\r
+              uiHandler.post(new Runnable() {\r
+                @Override\r
+                public void run() {\r
+                  onSearchTextChange(searchText.getText().toString());\r
+                }\r
+              });\r
+            }\r
+          });\r
           \r
-          final com.ibm.icu.text.Collator c = index.sortLanguage.getCollator();          \r
-          if (c.compare("pre-print", "preppy") >= 0) {\r
-            Log.e(LOG, c.getClass()\r
-                + " is buggy, lookups may not work properly.");\r
+          for (final Index index : dictionary.indices) {\r
+            final String searchToken = index.sortedIndexEntries.get(0).token;\r
+            final IndexEntry entry = index.findExact(searchToken);\r
+            if (!searchToken.equals(entry.token)) {\r
+              Log.e(LOG, "Couldn't find token: " + searchToken + ", " + entry.token);\r
+            }\r
           }\r
+          indexPrepFinished = true;\r
+        } catch (Exception e) {\r
+          Log.w(LOG, "Exception while prepping.  This can happen if dictionary is closed while search is happening.");\r
         }\r
-        Log.d(LOG, "Loading collators took:"\r
-            + (System.currentTimeMillis() - startMillis));\r
+          Log.d(LOG, "Prepping indices took:"\r
+              + (System.currentTimeMillis() - startMillis));\r
       }\r
-    });\r
+    }).start();\r
     \r
     final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);\r
     \r
@@ -246,10 +262,15 @@ public class DictionaryActivity extends ListActivity {
     \r
     searchText.requestFocus();\r
     searchText.addTextChangedListener(searchTextWatcher);\r
-    final String search = prefs.getString(C.SEARCH_TOKEN, "");\r
-    searchText.setText(search);\r
-    searchText.setSelection(0, search.length());\r
-    Log.d(LOG, "Trying to restore searchText=" + search);\r
+    String text = "";\r
+    if (savedInstanceState != null) {\r
+      text = savedInstanceState.getString(C.SEARCH_TOKEN);\r
+      if (text == null) {\r
+        text = "";\r
+      }\r
+    }\r
+    setSearchText(text, true);\r
+    Log.d(LOG, "Trying to restore searchText=" + text);\r
     \r
     final Button clearSearchTextButton = (Button) findViewById(R.id.ClearSearchTextButton);\r
     clearSearchTextButton.setOnClickListener(new OnClickListener() {\r
@@ -333,7 +354,7 @@ public class DictionaryActivity extends ListActivity {
       startActivity(getIntent());\r
     }\r
     if (initialSearchText != null) {\r
-      setSearchText(initialSearchText);\r
+      setSearchText(initialSearchText, true);\r
     }\r
   }\r
   \r
@@ -421,7 +442,7 @@ public class DictionaryActivity extends ListActivity {
       currentSearchOperation.interrupted.set(true);\r
       currentSearchOperation = null;\r
     }\r
-    changeIndex((indexIndex + 1)% dictionary.indices.size());\r
+    changeIndexGetFocusAndResearch((indexIndex + 1)% dictionary.indices.size());\r
   }\r
   \r
   void onLanguageButtonLongClick(final Context context) {\r
@@ -477,7 +498,7 @@ public class DictionaryActivity extends ListActivity {
   }\r
 \r
 \r
-  private void changeIndex(final int newIndex) {\r
+  private void changeIndexGetFocusAndResearch(final int newIndex) {\r
     indexIndex = newIndex;\r
     index = dictionary.indices.get(indexIndex);\r
     indexAdapter = new IndexAdapter(index);\r
@@ -565,9 +586,10 @@ public class DictionaryActivity extends ListActivity {
             for (final EntrySource source : dictionary.sources) {\r
               builder.append(getString(R.string.sourceInfo, source.getName(), source.getNumEntries())).append("\n");\r
             }\r
-          } else {\r
-            builder.append(getString(R.string.invalidDictionary));\r
           }\r
+//          } else {\r
+//            builder.append(getString(R.string.invalidDictionary));\r
+//          }\r
           textView.setText(builder.toString());\r
           \r
           dialog.show();\r
@@ -618,20 +640,30 @@ public class DictionaryActivity extends ListActivity {
           int indexToUse = -1;\r
           for (int i = 0; i < dictionary.indices.size(); ++i) {\r
             final Index index = dictionary.indices.get(i);\r
-            final IndexEntry indexEntry = index.findExact(selectedText); \r
-            final TokenRow tokenRow = index.rows.get(indexEntry.startRow).getTokenRow(false);\r
-            if (tokenRow != null && tokenRow.hasMainEntry) {\r
-              indexToUse = i;\r
-              break;\r
+            if (indexPrepFinished) {\r
+              System.out.println("Doing index lookup: on " + selectedText);\r
+              final IndexEntry indexEntry = index.findExact(selectedText);\r
+              if (indexEntry != null) {\r
+                final TokenRow tokenRow = index.rows.get(indexEntry.startRow).getTokenRow(false);\r
+                if (tokenRow != null && tokenRow.hasMainEntry) {\r
+                  indexToUse = i;\r
+                  break;\r
+                }\r
+              }\r
+            } else {\r
+              Log.w(LOG, "Skipping findExact on index " + index.shortName);\r
             }\r
           }\r
           if (indexToUse == -1) {\r
             indexToUse = selectedSpannableIndex;\r
           }\r
-          if (indexIndex != indexToUse) {\r
-            changeIndex(indexToUse);\r
+          final boolean changeIndex = indexIndex != indexToUse;\r
+          setSearchText(selectedText, !changeIndex);  // If we're not changing index, we have to triggerSearch.\r
+          if (changeIndex) {\r
+            changeIndexGetFocusAndResearch(indexToUse);\r
           }\r
-          setSearchText(selectedText);\r
+          // Give focus back to list view because typing is done.\r
+          getListView().requestFocus();\r
           return false;\r
         }\r
       });\r
@@ -701,7 +733,7 @@ public class DictionaryActivity extends ListActivity {
   public boolean onKeyDown(final int keyCode, final KeyEvent event) {\r
     if (event.getUnicodeChar() != 0) {\r
       if (!searchText.hasFocus()) {\r
-        setSearchText("" + (char) event.getUnicodeChar());\r
+        setSearchText("" + (char) event.getUnicodeChar(), true);\r
       }\r
       return true;\r
     }\r
@@ -718,14 +750,19 @@ public class DictionaryActivity extends ListActivity {
     return super.onKeyDown(keyCode, event);\r
   }\r
 \r
-  private void setSearchText(final String text) {\r
+  private void setSearchText(final String text, final boolean triggerSearch) {\r
+    if (!triggerSearch) {\r
+      getListView().requestFocus();\r
+    }\r
     searchText.setText(text);\r
     searchText.requestFocus();\r
-    onSearchTextChange(searchText.getText().toString());\r
     if (searchText.getLayout() != null) {\r
       // Surprising, but this can crash when you rotate...\r
       Selection.moveToRightEdge(searchText.getText(), searchText.getLayout());\r
     }\r
+    if (triggerSearch) {\r
+      onSearchTextChange(text);\r
+    }\r
   }\r
 \r
 \r
@@ -869,28 +906,36 @@ public class DictionaryActivity extends ListActivity {
     }\r
 \r
     @Override\r
-    public View getView(int position, final View convertView, ViewGroup parent) {\r
+    public TableLayout getView(int position, View convertView, ViewGroup parent) {\r
+      final TableLayout result;\r
+      if (convertView instanceof TableLayout) {\r
+        result = (TableLayout) convertView;\r
+        result.removeAllViews();\r
+      } else {\r
+        result = new TableLayout(parent.getContext());\r
+      }\r
       final RowBase row = getItem(position);\r
       if (row instanceof PairEntry.Row) {\r
-        return getView(position, (PairEntry.Row) row, parent, convertView);\r
+        return getView(position, (PairEntry.Row) row, parent, result);\r
       } else if (row instanceof TokenRow) {\r
-        return getView((TokenRow) row, parent, convertView);\r
+        return getView((TokenRow) row, parent, result);\r
       } else {\r
         throw new IllegalArgumentException("Unsupported Row type: " + row.getClass());\r
       }\r
     }\r
 \r
-    private View getView(final int position, PairEntry.Row row, ViewGroup parent, final View convertView) {\r
-      final TableLayout result = new TableLayout(parent.getContext());\r
+    private TableLayout getView(final int position, PairEntry.Row row, ViewGroup parent, final TableLayout result) {\r
       final PairEntry entry = row.getEntry();\r
       final int rowCount = entry.pairs.size();\r
+      \r
+      final TableRow.LayoutParams layoutParams = new TableRow.LayoutParams();\r
+      layoutParams.weight = 0.5f;\r
+      \r
       for (int r = 0; r < rowCount; ++r) {\r
         final TableRow tableRow = new TableRow(result.getContext());\r
 \r
         final TextView col1 = new TextView(tableRow.getContext());\r
         final TextView col2 = new TextView(tableRow.getContext());\r
-        final TableRow.LayoutParams layoutParams = new TableRow.LayoutParams();\r
-        layoutParams.weight = 0.5f;\r
 \r
         // Set the columns in the table.\r
         if (r > 0) {\r
@@ -913,7 +958,6 @@ public class DictionaryActivity extends ListActivity {
         \r
         // Set what's in the columns.\r
 \r
-        // TODO: color words by gender\r
         final Pair pair = entry.pairs.get(r);\r
         final String col1Text = index.swapPairEntries ? pair.lang2 : pair.lang1;\r
         final String col2Text = index.swapPairEntries ? pair.lang1 : pair.lang2;\r
@@ -948,86 +992,40 @@ public class DictionaryActivity extends ListActivity {
           col2.setOnLongClickListener(textViewLongClickListenerIndex1);\r
         }\r
         \r
-        // Because we have a Button inside a ListView row:\r
-        // http://groups.google.com/group/android-developers/browse_thread/thread/3d96af1530a7d62a?pli=1\r
-        result.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);\r
-        result.setClickable(true);\r
-        result.setFocusable(true);\r
-        result.setLongClickable(true);\r
-        result.setBackgroundResource(android.R.drawable.menuitem_background);\r
-        result.setOnClickListener(new TextView.OnClickListener() {\r
-          @Override\r
-          public void onClick(View v) {\r
-            DictionaryActivity.this.onListItemClick(null, v, position, position);\r
-          }\r
-        });\r
-        \r
         result.addView(tableRow);\r
       }\r
 \r
-      return result;\r
+      // Because we have a Button inside a ListView row:\r
+      // http://groups.google.com/group/android-developers/browse_thread/thread/3d96af1530a7d62a?pli=1\r
+      result.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);\r
+      result.setClickable(true);\r
+      result.setFocusable(true);\r
+      result.setLongClickable(true);\r
+      result.setBackgroundResource(android.R.drawable.menuitem_background);\r
+      result.setOnClickListener(new TextView.OnClickListener() {\r
+        @Override\r
+        public void onClick(View v) {\r
+          DictionaryActivity.this.onListItemClick(getListView(), v, position, position);\r
+        }\r
+      });\r
 \r
-      \r
-//      final WebView result = (WebView) (convertView instanceof WebView ? convertView : new WebView(parent.getContext()));\r
-//        \r
-//      final PairEntry entry = row.getEntry();\r
-//      final int rowCount = entry.pairs.size();\r
-//      final StringBuilder html = new StringBuilder();\r
-//      html.append("<html><body><table width=\"100%\">");\r
-//      for (int r = 0; r < rowCount; ++r) {\r
-//        html.append("<tr>");\r
-//\r
-//        final Pair pair = entry.pairs.get(r);\r
-//        // TODO: escape both the token and the text.\r
-//        final String token = row.getTokenRow(true).getToken();\r
-//        final String col1Text = index.swapPairEntries ? pair.lang2 : pair.lang1;\r
-//        final String col2Text = index.swapPairEntries ? pair.lang1 : pair.lang2;\r
-//        \r
-//        col1Text.replaceAll(token, String.format("<b>%s</b>", token));\r
-//\r
-//        // Column1\r
-//        html.append("<td width=\"50%\">");\r
-//        if (r > 0) {\r
-//          html.append("<li>");\r
-//        }\r
-//        html.append(col1Text);\r
-//        html.append("</td>");\r
-//\r
-//        // Column2\r
-//        html.append("<td width=\"50%\">");\r
-//        if (r > 0) {\r
-//          html.append("<li>");\r
-//        }\r
-//        html.append(col2Text);\r
-//        html.append("</td>");\r
-//\r
-////        column1.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSizeSp);\r
-////        column2.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSizeSp);\r
-//\r
-//        html.append("</tr>");\r
-//      }\r
-//      html.append("</table></body></html>");\r
-//      \r
-//      Log.i(LOG, html.toString());\r
-//      \r
-//      result.getSettings().setRenderPriority(RenderPriority.HIGH);\r
-//      result.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);\r
-//      \r
-//      result.loadData("<html><body><table><tr><td>line (connected series of public conveyances, and hence, an established arrangement for forwarding merchandise, etc.) (noun)</td><td>verbinding</td></tr></table></body></html>", "text/html", "utf-8");\r
-//\r
-//      return result;\r
+      return result;\r
     }\r
 \r
-    private View getView(TokenRow row, ViewGroup parent, final View convertView) {\r
+    private TableLayout getView(TokenRow row, ViewGroup parent, final TableLayout result) {\r
       final Context context = parent.getContext();\r
       final TextView textView = new TextView(context);\r
       textView.setText(row.getToken());\r
-      textView.setBackgroundResource(row.hasMainEntry ? theme.tokenRowMainBg : theme.tokenRowOtherBg);\r
       // Doesn't work:\r
       //textView.setTextColor(android.R.color.secondary_text_light);\r
       textView.setTextAppearance(context, theme.tokenRowFg);\r
       textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 5 * fontSizeSp / 4);\r
-      return textView;\r
+      \r
+      final TableRow tableRow = new TableRow(result.getContext());\r
+      tableRow.addView(textView);\r
+      tableRow.setBackgroundResource(row.hasMainEntry ? theme.tokenRowMainBg : theme.tokenRowOtherBg);\r
+      result.addView(tableRow);\r
+      return result;\r
     }\r
     \r
   }\r
@@ -1087,6 +1085,15 @@ public class DictionaryActivity extends ListActivity {
       final Dialog dialog = new Dialog(getListView().getContext());\r
       dialog.setContentView(R.layout.thadolina_dialog);\r
       dialog.setTitle("Ti amo, amore mio!");\r
+      final ImageView imageView = (ImageView) dialog.findViewById(R.id.thadolina_image);\r
+      imageView.setOnClickListener(new OnClickListener() {\r
+        @Override\r
+        public void onClick(View v) {\r
+          final Intent intent = new Intent(Intent.ACTION_VIEW);\r
+          intent.setData(Uri.parse("https://sites.google.com/site/cfoxroxvday/vday2012"));\r
+          startActivity(intent);\r
+        }\r
+      });\r
       dialog.show();\r
     }\r
     if (dictRaf == null) {\r
index fc80df6d854a5d6d74f51003ded40933906bb2ad..d36e99d718cdbfe77f7438b622668b6d89384132 100644 (file)
@@ -23,17 +23,14 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 import android.app.Application;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
-import android.os.Environment;
 import android.preference.PreferenceManager;
 import android.util.Log;
 import android.view.Menu;
@@ -50,17 +47,15 @@ public class DictionaryApplication extends Application {
   
   static final String LOG = "QuickDicApp";
   
-  private static final File DICT_DIR = new File(Environment.getExternalStorageDirectory().getName(), "quickdic");
-
   // Static, determined by resources (and locale).
   // Unordered.
   static Map<String,DictionaryInfo> DOWNLOADABLE_NAME_TO_INFO = null;
   
   static final class DictionaryConfig implements Serializable {
-    private static final long serialVersionUID = -1444177164708201262L;
+    private static final long serialVersionUID = -1444177164708201263L;
     // User-ordered list, persisted, just the ones that are/have been present.
-    final List<DictionaryInfo> dictionaryFilesOrdered = new ArrayList<DictionaryInfo>();
-    final Set<String> invalidatedFilenames = new LinkedHashSet<String>();
+    final List<String> dictionaryFilesOrdered = new ArrayList<String>();
+    final Map<String, DictionaryInfo> dictionaryInfoCache = new LinkedHashMap<String, DictionaryInfo>();
   }
   DictionaryConfig dictionaryConfig = null;
 
@@ -70,6 +65,29 @@ public class DictionaryApplication extends Application {
     final List<DictionaryLink> dictionaryLinks = new ArrayList<DictionaryLink>();
   }
   DictionaryHistory dictionaryHistory = null;
+  
+  private File dictDir;
+
+  static synchronized void staticInit(final Context context) {
+    if (DOWNLOADABLE_NAME_TO_INFO != null) {
+      return;
+    }
+    DOWNLOADABLE_NAME_TO_INFO = new LinkedHashMap<String,DictionaryInfo>();
+    final BufferedReader reader = new BufferedReader(new InputStreamReader(context.getResources().openRawResource(R.raw.dictionary_info)));
+    try {
+      String line;
+      while ((line = reader.readLine()) != null) {
+        if (line.startsWith("#") || line.length() == 0) {
+          continue;
+        }
+        final DictionaryInfo dictionaryInfo = new DictionaryInfo(line);
+        DOWNLOADABLE_NAME_TO_INFO.put(dictionaryInfo.uncompressedFilename, dictionaryInfo);
+      }
+      reader.close();
+    } catch (IOException e) {
+      Log.e(LOG, "Failed to load downloadable dictionary lists.", e);
+    }
+  }
 
   
   @Override
@@ -85,7 +103,6 @@ public class DictionaryApplication extends Application {
       dictionaryConfig = new DictionaryConfig();
     }
     
-
     // Theme stuff.
     setTheme(getSelectedTheme().themeId);
     final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
@@ -101,6 +118,49 @@ public class DictionaryApplication extends Application {
     });
   }
   
+  public void onCreateGlobalOptionsMenu(
+      final Context context, final Menu menu) {
+    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());
+        context.startActivity(intent);
+        return false;
+      }
+    });
+
+    final MenuItem help = menu.add(getString(R.string.help));
+    help.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+      public boolean onMenuItemClick(final MenuItem menuItem) {
+        context.startActivity(HelpActivity.getLaunchIntent());
+        return false;
+      }
+    });
+
+    final MenuItem preferences = menu.add(getString(R.string.preferences));
+    preferences.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+      public boolean onMenuItemClick(final MenuItem menuItem) {
+        PreferenceActivity.prefsMightHaveChanged = true;
+        final Intent intent = new Intent().setClassName(PreferenceActivity.class
+            .getPackage().getName(), PreferenceActivity.class.getCanonicalName());
+        context.startActivity(intent);
+        return false;
+      }
+    });
+  }
+  
+  public synchronized File getDictDir() {
+    // This metaphore doesn't work, because we've already reset prefsMightHaveChanged.
+//    if (dictDir == null || PreferenceActivity.prefsMightHaveChanged) {
+      final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+      final String dir = prefs.getString(getString(R.string.quickdicDirectoryKey), getString(R.string.quickdicDirectoryDefault));
+      dictDir = new File(dir);
+      dictDir.mkdirs();
+//    }
+    return dictDir;
+  }
+  
   public C.Theme getSelectedTheme() {
     final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
     final String theme = prefs.getString(getString(R.string.themeKey), "themeLight");
@@ -111,60 +171,19 @@ public class DictionaryApplication extends Application {
     }
   }
     
-  static synchronized void staticInit(final Context context) {
-    if (DOWNLOADABLE_NAME_TO_INFO != null) {
-      return;
-    }
-    DOWNLOADABLE_NAME_TO_INFO = new LinkedHashMap<String,DictionaryInfo>();
-    final BufferedReader reader = new BufferedReader(new InputStreamReader(context.getResources().openRawResource(R.raw.dictionary_info)));
-    try {
-      String line;
-      while ((line = reader.readLine()) != null) {
-        if (line.startsWith("#") || line.length() == 0) {
-          continue;
-        }
-        final DictionaryInfo dictionaryInfo = new DictionaryInfo(line);
-        DOWNLOADABLE_NAME_TO_INFO.put(dictionaryInfo.uncompressedFilename, dictionaryInfo);
-      }
-      reader.close();
-    } catch (IOException e) {
-      Log.e(LOG, "Failed to load downloadable dictionary lists.", e);
-    }
-  }
-
   public File getPath(String uncompressedFilename) {
-    return new File(DICT_DIR, uncompressedFilename);
-  }
-
-
-  public List<DictionaryInfo> getUsableDicts() {
-    final List<DictionaryInfo> result = new ArrayList<DictionaryInfo>(dictionaryConfig.dictionaryFilesOrdered.size());
-    for (int i = 0; i < dictionaryConfig.dictionaryFilesOrdered.size(); ++i) {
-      DictionaryInfo dictionaryInfo = dictionaryConfig.dictionaryFilesOrdered.get(i);
-      if (dictionaryConfig.invalidatedFilenames.contains(dictionaryInfo.uncompressedFilename)) {
-        dictionaryInfo = Dictionary.getDictionaryInfo(getPath(dictionaryInfo.uncompressedFilename));
-        if (dictionaryInfo != null) {
-          dictionaryConfig.dictionaryFilesOrdered.set(i, dictionaryInfo);
-        }
-      }
-      if (dictionaryInfo != null) {
-        result.add(dictionaryInfo);
-      }
-    }
-    if (!dictionaryConfig.invalidatedFilenames.isEmpty()) {
-      dictionaryConfig.invalidatedFilenames.clear();
-      PersistentObjectCache.getInstance().write(C.DICTIONARY_CONFIGS, dictionaryConfig);
-    }
-    return result;
+    return new File(getDictDir(), uncompressedFilename);
   }
   
+  
+  final Map<String, String> fileToNameCache = new LinkedHashMap<String, String>();
+
   public String getLanguageName(final String isoCode) {
     final Language.LanguageResources languageResources = Language.isoCodeToResources.get(isoCode); 
     final String lang = languageResources != null ? getApplicationContext().getString(languageResources.nameId) : isoCode;
     return lang;
   }
 
-  final Map<String, String> fileToNameCache = new LinkedHashMap<String, String>();
   public synchronized String getDictionaryName(final String uncompressedFilename) {
     String name = fileToNameCache.get(uncompressedFilename);
     if (name != null) {
@@ -188,81 +207,121 @@ public class DictionaryApplication extends Application {
     return name;
   }
 
-  public void moveDictionaryToTop(final DictionaryInfo dictionaryInfo) {
-    dictionaryConfig.dictionaryFilesOrdered.remove(dictionaryInfo);
-    dictionaryConfig.dictionaryFilesOrdered.add(0, dictionaryInfo);
+  public synchronized void moveDictionaryToTop(final DictionaryInfo dictionaryInfo) {
+    dictionaryConfig.dictionaryFilesOrdered.remove(dictionaryInfo.uncompressedFilename);
+    dictionaryConfig.dictionaryFilesOrdered.add(0, dictionaryInfo.uncompressedFilename);
     PersistentObjectCache.getInstance().write(C.DICTIONARY_CONFIGS, dictionaryConfig);
   }
 
-  public void deleteDictionary(final DictionaryInfo dictionaryInfo) {
-    while (dictionaryConfig.dictionaryFilesOrdered.remove(dictionaryInfo)) {};
+  public synchronized void deleteDictionary(final DictionaryInfo dictionaryInfo) {
+    while (dictionaryConfig.dictionaryFilesOrdered.remove(dictionaryInfo.uncompressedFilename)) {};
+    dictionaryConfig.dictionaryInfoCache.remove(dictionaryInfo.uncompressedFilename);
     getPath(dictionaryInfo.uncompressedFilename).delete();
     PersistentObjectCache.getInstance().write(C.DICTIONARY_CONFIGS, dictionaryConfig);
   }
 
   final Collator collator = Collator.getInstance();
-  final Comparator<DictionaryInfo> comparator = new Comparator<DictionaryInfo>() {
+  final Comparator<String> uncompressedFilenameComparator = new Comparator<String>() {
     @Override
-    public int compare(DictionaryInfo object1, DictionaryInfo object2) {
-      return collator.compare(getDictionaryName(object1.uncompressedFilename), getDictionaryName(object2.uncompressedFilename));
+    public int compare(String uncompressedFilename1, String uncompressedFilename2) {
+      return collator.compare(getDictionaryName(uncompressedFilename1), getDictionaryName(uncompressedFilename2));
     }
   };
-
-  public List<DictionaryInfo> getAllDictionaries() {
-    final List<DictionaryInfo> result = getUsableDicts();
-    
-    // The ones we knew about...
-    final Set<String> known = new LinkedHashSet<String>();
-    for (final DictionaryInfo usable : result) {
-      known.add(usable.uncompressedFilename);
-    }
-    if (!dictionaryConfig.invalidatedFilenames.isEmpty()) {
-      dictionaryConfig.invalidatedFilenames.clear();
+  final Comparator<DictionaryInfo> dictionaryInfoComparator = new Comparator<DictionaryInfo>() {
+    @Override
+    public int compare(DictionaryInfo d1, DictionaryInfo d2) {
+      return uncompressedFilenameComparator.compare(d1.uncompressedFilename, d2.uncompressedFilename);
     }
-    
-    // Are there dictionaries on the device that we didn't know about already?
-    // Pick them up and put them at the end of the list.
-    final List<DictionaryInfo> toAddSorted = new ArrayList<DictionaryInfo>();
-    final File[] dictDirFiles = DICT_DIR.listFiles();
-    for (final File file : dictDirFiles) {
-      // TODO: delete zip files here.
-      if (!file.getName().endsWith(".quickdic")) {
-        continue;
-      }
-      if (known.contains(file.getName())) {
-        // We have it in our list already.
-        continue;
-      }
-      final DictionaryInfo dictionaryInfo = Dictionary.getDictionaryInfo(file);
-      if (dictionaryInfo == null) {
-        Log.e(LOG, "Unable to parse dictionary: " + file.getPath());
-        continue;
+  };
+  
+  public void backgroundUpdateDictionaries(final Runnable onUpdateFinished) {
+    new Thread(new Runnable() {
+      @Override
+      public void run() {
+        final DictionaryConfig oldDictionaryConfig = new DictionaryConfig();
+        synchronized(this) {
+          oldDictionaryConfig.dictionaryFilesOrdered.addAll(dictionaryConfig.dictionaryFilesOrdered);
+        }
+        final DictionaryConfig newDictionaryConfig = new DictionaryConfig();
+        for (final String uncompressedFilename : oldDictionaryConfig.dictionaryFilesOrdered) {
+          final File dictFile = getPath(uncompressedFilename);
+          final DictionaryInfo dictionaryInfo = Dictionary.getDictionaryInfo(dictFile);
+          if (dictionaryInfo != null) {
+            newDictionaryConfig.dictionaryFilesOrdered.add(uncompressedFilename);
+            newDictionaryConfig.dictionaryInfoCache.put(uncompressedFilename, dictionaryInfo);
+          }
+        }
+        
+        // Are there dictionaries on the device that we didn't know about already?
+        // Pick them up and put them at the end of the list.
+        final List<String> toAddSorted = new ArrayList<String>();
+        final File[] dictDirFiles = getDictDir().listFiles();
+        for (final File file : dictDirFiles) {
+          if (file.getName().endsWith(".zip")) {
+            if (DOWNLOADABLE_NAME_TO_INFO.containsKey(file.getName().replace(".zip", ""))) {
+              file.delete();
+            }
+          }
+          if (!file.getName().endsWith(".quickdic")) {
+            continue;
+          }
+          if (newDictionaryConfig.dictionaryInfoCache.containsKey(file.getName())) {
+            // We have it in our list already.
+            continue;
+          }
+          final DictionaryInfo dictionaryInfo = Dictionary.getDictionaryInfo(file);
+          if (dictionaryInfo == null) {
+            Log.e(LOG, "Unable to parse dictionary: " + file.getPath());
+            continue;
+          }
+          
+          toAddSorted.add(file.getName());
+          newDictionaryConfig.dictionaryInfoCache.put(file.getName(), dictionaryInfo);
+        }
+        if (!toAddSorted.isEmpty()) {
+          Collections.sort(toAddSorted, uncompressedFilenameComparator);
+          newDictionaryConfig.dictionaryFilesOrdered.addAll(toAddSorted);
+        }
+
+        PersistentObjectCache.getInstance().write(C.DICTIONARY_CONFIGS, newDictionaryConfig);
+        synchronized (this) {
+          dictionaryConfig = newDictionaryConfig;
+        }
+        
+        try {
+          onUpdateFinished.run();
+        } catch (Exception e) {
+          Log.e(LOG, "Exception running callback.", e);
+        }
+      }}).start();
+  }
+
+  public synchronized List<DictionaryInfo> getUsableDicts() {
+    final List<DictionaryInfo> result = new ArrayList<DictionaryInfo>(dictionaryConfig.dictionaryFilesOrdered.size());
+    for (final String uncompressedFilename : dictionaryConfig.dictionaryFilesOrdered) {
+      final DictionaryInfo dictionaryInfo = dictionaryConfig.dictionaryInfoCache.get(uncompressedFilename);
+      if (dictionaryInfo != null) {
+        result.add(dictionaryInfo);
       }
-      known.add(file.getName());
-      toAddSorted.add(dictionaryInfo);
-    }
-    if (!toAddSorted.isEmpty()) {
-      Collections.sort(toAddSorted, comparator);
-      result.addAll(toAddSorted);
-//      for (final DictionaryInfo dictionaryInfo : toAddSorted) {
-//        dictionaryConfig.dictionaryFilesOrdered.add(dictionaryInfo.uncompressedFilename);
-//      }
-      dictionaryConfig.dictionaryFilesOrdered.addAll(toAddSorted);
-      PersistentObjectCache.getInstance().write(C.DICTIONARY_CONFIGS, dictionaryConfig);
     }
+    return result;
+  }
 
+  public synchronized List<DictionaryInfo> getAllDictionaries() {
+    final List<DictionaryInfo> result = getUsableDicts();
+    
     // The downloadable ones.
     final Map<String,DictionaryInfo> remaining = new LinkedHashMap<String, DictionaryInfo>(DOWNLOADABLE_NAME_TO_INFO);
-    remaining.keySet().removeAll(known);
-    toAddSorted.clear();
-    toAddSorted.addAll(remaining.values());
-    Collections.sort(toAddSorted, comparator);
+    remaining.keySet().removeAll(dictionaryConfig.dictionaryFilesOrdered);
+    final List<DictionaryInfo> toAddSorted = new ArrayList<DictionaryInfo>(remaining.values());
+    Collections.sort(toAddSorted, dictionaryInfoComparator);
     result.addAll(toAddSorted);
+    
     return result;
   }
 
-  public boolean isDictionaryOnDevice(String uncompressedFilename) {
-    return getPath(uncompressedFilename).canRead();
+  public synchronized boolean isDictionaryOnDevice(String uncompressedFilename) {
+    return dictionaryConfig.dictionaryInfoCache.get(uncompressedFilename) != null;
   }
 
   public boolean updateAvailable(final DictionaryInfo dictionaryInfo) {
@@ -275,41 +334,4 @@ public class DictionaryApplication extends Application {
     return downloadable;
   }
 
-  public void invalidateDictionaryInfo(final String uncompressedFilename) {
-    dictionaryConfig.invalidatedFilenames.add(uncompressedFilename);
-    PersistentObjectCache.getInstance().write(C.DICTIONARY_CONFIGS, dictionaryConfig);
-  }
-
-  public void onCreateGlobalOptionsMenu(
-      final Context context, final Menu menu) {
-    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());
-        context.startActivity(intent);
-        return false;
-      }
-    });
-
-    final MenuItem help = menu.add(getString(R.string.help));
-    help.setOnMenuItemClickListener(new OnMenuItemClickListener() {
-      public boolean onMenuItemClick(final MenuItem menuItem) {
-        context.startActivity(HelpActivity.getLaunchIntent());
-        return false;
-      }
-    });
-
-    final MenuItem preferences = menu.add(getString(R.string.preferences));
-    preferences.setOnMenuItemClickListener(new OnMenuItemClickListener() {
-      public boolean onMenuItemClick(final MenuItem menuItem) {
-        PreferenceActivity.prefsMightHaveChanged = true;
-        final Intent intent = new Intent().setClassName(PreferenceActivity.class
-            .getPackage().getName(), PreferenceActivity.class.getCanonicalName());
-        context.startActivity(intent);
-        return false;
-      }
-    });
-  }
-  
 }
index 44d764165e0395f2b8d4648fcb31b3614c9ae50e..f7db7de6cd886223fd0d2e81e619445fea89dcd1 100644 (file)
@@ -23,6 +23,7 @@ import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.os.Bundle;
+import android.os.Handler;
 import android.preference.PreferenceManager;
 import android.util.Log;
 import android.util.TypedValue;
@@ -44,6 +45,7 @@ import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import com.hughes.android.dictionary.C.Theme;
 import com.hughes.android.dictionary.DictionaryInfo.IndexInfo;
 import com.hughes.android.util.IntentLauncher;
 import com.hughes.util.StringUtil;
@@ -56,6 +58,8 @@ public class DictionaryManagerActivity extends ListActivity {
   DictionaryApplication application;
   Adapter adapter;
   
+  Handler uiHandler;
+  
   public static Intent getLaunchIntent() {
     final Intent intent = new Intent();
     intent.setClassName(DictionaryManagerActivity.class.getPackage().getName(),
@@ -117,14 +121,23 @@ public class DictionaryManagerActivity extends ListActivity {
     }
   }
   
+  @Override
+  protected void onStart() {
+    super.onStart();
+    uiHandler = new Handler();
+  }
+  
+  @Override
+  protected void onStop() {
+    super.onStop();
+    uiHandler = null;
+  }
+
   private void onClick(int index) {
     final DictionaryInfo dictionaryInfo = adapter.getItem(index);
     final DictionaryInfo downloadable = application.getDownloadable(dictionaryInfo.uncompressedFilename);
     if (!application.isDictionaryOnDevice(dictionaryInfo.uncompressedFilename) && downloadable != null) {
-      final Intent intent = DownloadActivity
-          .getLaunchIntent(downloadable.downloadUrl,
-              application.getPath(dictionaryInfo.uncompressedFilename).getPath() + ".zip",
-              dictionaryInfo.dictInfo);
+      final Intent intent = getDownloadIntent(downloadable);
       startActivity(intent);
     } else {
       final Intent intent = DictionaryActivity.getLaunchIntent(application.getPath(dictionaryInfo.uncompressedFilename), 0, "");
@@ -151,6 +164,21 @@ public class DictionaryManagerActivity extends ListActivity {
       //finish();
       return;
     }
+    
+    application.backgroundUpdateDictionaries(new Runnable() {
+      @Override
+      public void run() {
+        if (uiHandler == null) {
+          return;
+        }
+        uiHandler.post(new Runnable() {
+          @Override
+          public void run() {
+            setListAdapter(adapter = new Adapter());
+          }
+        });
+      }
+    });
 
     setListAdapter(adapter = new Adapter());
   }
@@ -170,7 +198,7 @@ public class DictionaryManagerActivity extends ListActivity {
     final int position = adapterContextMenuInfo.position;
     final DictionaryInfo dictionaryInfo = adapter.getItem(position);
     
-    if (position > 0) {
+    if (position > 0 && application.isDictionaryOnDevice(dictionaryInfo.uncompressedFilename)) {
       final MenuItem moveToTopMenuItem = menu.add(R.string.moveToTop);
       moveToTopMenuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() {
         @Override
@@ -192,6 +220,28 @@ public class DictionaryManagerActivity extends ListActivity {
       }
     });
 
+    final DictionaryInfo downloadable = application.getDownloadable(dictionaryInfo.uncompressedFilename);
+    if (downloadable != null) {
+      final MenuItem downloadMenuItem = menu.add(getString(R.string.downloadButton, downloadable.zipBytes/1024.0/1024.0));
+      downloadMenuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+        @Override
+        public boolean onMenuItemClick(MenuItem item) {
+          final Intent intent = getDownloadIntent(downloadable);
+          startActivity(intent);
+          setListAdapter(adapter = new Adapter());
+          return true;
+        }
+
+      });
+    }
+
+  }
+
+  private Intent getDownloadIntent(final DictionaryInfo downloadable) {
+    final Intent intent = DownloadActivity.getLaunchIntent(downloadable.downloadUrl,
+        application.getPath(downloadable.uncompressedFilename).getPath() + ".zip",
+        downloadable.dictInfo);
+    return intent;
   }
 
   class Adapter extends BaseAdapter {
@@ -215,8 +265,16 @@ public class DictionaryManagerActivity extends ListActivity {
     
     @Override
     public View getView(final int position, final View convertView, final ViewGroup parent) {
+      final LinearLayout result;
+      // Android 4.0.3 leaks memory like crazy if we don't do this.
+      if (convertView instanceof LinearLayout) {
+        result = (LinearLayout) convertView;
+        result.removeAllViews();
+      } else {
+        result = new LinearLayout(parent.getContext());
+      }
+      
       final DictionaryInfo dictionaryInfo = getItem(position);
-      final LinearLayout result = new LinearLayout(parent.getContext());
       result.setOrientation(LinearLayout.VERTICAL);
 
       final LinearLayout row = new LinearLayout(parent.getContext());
@@ -239,15 +297,8 @@ public class DictionaryManagerActivity extends ListActivity {
       if ((!application.isDictionaryOnDevice(dictionaryInfo.uncompressedFilename) || updateAvailable) && downloadable != null) {
         final Button downloadButton = new Button(parent.getContext());
         downloadButton.setText(getString(updateAvailable ? R.string.updateButton : R.string.downloadButton, downloadable.zipBytes / 1024.0 / 1024.0));
-        downloadButton.setOnClickListener(new IntentLauncher(parent.getContext(), DownloadActivity
-            .getLaunchIntent(downloadable.downloadUrl,
-                application.getPath(dictionaryInfo.uncompressedFilename).getPath() + ".zip",
-                dictionaryInfo.dictInfo)) {
-          @Override
-          protected void onGo() {
-            application.invalidateDictionaryInfo(dictionaryInfo.uncompressedFilename);
-          }
-        });
+        final Intent intent = getDownloadIntent(downloadable);
+        downloadButton.setOnClickListener(new IntentLauncher(parent.getContext(), intent));
         WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
         layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
         layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
@@ -290,7 +341,7 @@ public class DictionaryManagerActivity extends ListActivity {
           DictionaryManagerActivity.this.onClick(position);
         }
       });
-
+      
       return result;
     }
   }
index 96a1b7d1c6cc12ae62e597e1d7d7a1b02b7814af..b933382408038e1d517d300ee20b93991939b5c3 100644 (file)
@@ -32,7 +32,5 @@ public class PreferenceActivity extends android.preference.PreferenceActivity {
   public void onContentChanged() {\r
     super.onContentChanged();\r
   }\r
-  \r
-  \r
 \r
 }\r