]> gitweb.fperrin.net Git - Dictionary.git/commitdiff
go
authorThad Hughes <thad.hughes@gmail.com>
Tue, 8 Mar 2011 02:17:14 +0000 (18:17 -0800)
committerThad Hughes <thad.hughes@gmail.com>
Tue, 8 Mar 2011 02:17:14 +0000 (18:17 -0800)
24 files changed:
.classpath
AndroidManifest.xml
images/german_fuenf.png [new file with mode: 0644]
images/icon_big.png
images/italian_sogni.png [new file with mode: 0644]
res/layout/edit_activity.xml
res/values-de/strings.xml
res/values/arrays.xml [new file with mode: 0644]
res/values/strings.xml
res/values/themeDefault.xml [new file with mode: 0644]
res/values/themeLight.xml [moved from res/values/theme.xml with 82% similarity]
res/xml/preferences.xml
src/com/hughes/android/dictionary/AboutActivity.java
src/com/hughes/android/dictionary/DictionaryActivity.java
src/com/hughes/android/dictionary/DictionaryActivityOld.java.old [deleted file]
src/com/hughes/android/dictionary/DictionaryConfig.java
src/com/hughes/android/dictionary/DictionaryEditActivity.java
src/com/hughes/android/dictionary/DictionaryListActivity.java
src/com/hughes/android/dictionary/DownloadActivity.java
src/com/hughes/android/dictionary/PreferenceActivity.java
src/com/hughes/android/dictionary/QuickDicConfig.java
src/com/hughes/android/dictionary/engine/Index.java
src/com/hughes/android/dictionary/engine/TransliteratorManager.java
todo.txt

index 123204872d6a4462b988af6cbf7c9819213200a3..7f4fe45646204619889c9bc850abb42cc5a3903f 100644 (file)
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
        <classpathentry kind="src" path="src"/>
-       <classpathentry kind="src" path="gen"/>
        <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
        <classpathentry combineaccessrules="false" exported="true" kind="src" path="/Util"/>
        <classpathentry exported="true" kind="lib" path="jars/icu4j-4_4_2-src/out/module/lib/icu4j-module.jar"/>
+       <classpathentry kind="src" path="gen"/>
        <classpathentry kind="output" path="bin"/>
 </classpath>
index 091a0b092584ac86f37e427b76194fbec4654f46..34f5f804becb4669453f550da81fea1e4b09b86d 100644 (file)
@@ -4,40 +4,43 @@
  
  package="com.hughes.android.dictionary"
  
- android:versionCode="9"
- android:versionName="2.0"
+ android:versionCode="13"
+ android:versionName="2.0.4"
  android:installLocation="auto">
 
  <uses-sdk android:minSdkVersion="4" />
 
  <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.VIBRATE" />
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 
  <application 
   android:icon="@drawable/icon"
   android:label="@string/app_name"
-  android:backupAgent="DictionaryBackupAgent"
-  android:theme="@style/Theme.QuickDic">
+  android:theme="@style/Theme.Light"
+  android:name=".DictionaryApplication" >
+  
+<!--   
+  android:backupAgent="DictionaryBackupAgent" -->
 
   <meta-data android:name="com.google.android.backup.api_key"
    android:value="AEdPqrEAAAAIUa0cU0ZHbBpYXJqm0vVUP5IAjr5D4iUeX7UwiQ" />
 
   <activity android:name=".DictionaryListActivity"
    android:label="@string/app_name">
-   
-   <intent-filter>
-    <action android:name="android.intent.action.MAIN" />
-    <category android:name="android.intent.category.LAUNCHER" />
-   </intent-filter>
+
+    <intent-filter>
+      <action android:name="android.intent.action.MAIN" />
+      <category android:name="android.intent.category.LAUNCHER" />
+    </intent-filter>
   </activity>
 
-  <activity android:name="DictionaryActivity" />
-  <activity android:name="DictionaryEditActivity" />
-  <activity android:name="AboutActivity" />
-  <activity android:name="PreferenceActivity" />
-  <activity android:name="DownloadActivity" />
+  <activity android:name=".DictionaryActivity" />
+  <activity android:name=".DictionaryEditActivity" />
+  <activity android:name=".AboutActivity" />
+  <activity android:name=".PreferenceActivity" />
+  <activity android:name=".DownloadActivity"
+      android:configChanges="keyboardHidden|orientation"/>
 
  </application>
 
diff --git a/images/german_fuenf.png b/images/german_fuenf.png
new file mode 100644 (file)
index 0000000..24a7e1d
Binary files /dev/null and b/images/german_fuenf.png differ
index e7800b31475d3ea3a7f3bed13f3749579bd16581..b3c3e900e02e0ff1705bb3c033fdeba5c21e3095 100644 (file)
Binary files a/images/icon_big.png and b/images/icon_big.png differ
diff --git a/images/italian_sogni.png b/images/italian_sogni.png
new file mode 100644 (file)
index 0000000..41b5df1
Binary files /dev/null and b/images/italian_sogni.png differ
index 8c4282401699973df6913db0499931e3a5b80175..d1fb9900158e3adbe326e863b83de45bc4d99df0 100755 (executable)
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content" />
 
+ <LinearLayout 
+   android:id="@+id/LinearLayout03"
+   android:orientation="horizontal"
+   android:layout_width="wrap_content"
+   android:layout_height="wrap_content"
+   >
+
+  <Button
+    android:id="@+id/downloadButton"
+    android:text="@string/downloadButton"
+    android:layout_width="wrap_content" 
+    android:layout_height="wrap_content"
+   />
+  <Button
+    android:id="@+id/openButton"
+    android:text="@string/openButton"
+    android:layout_width="wrap_content" 
+    android:layout_height="wrap_content"
+   />
+ </LinearLayout>
+
   <TextView 
     android:id="@+id/dictionaryInfoTitle" 
     android:text="@string/dictionaryInfo"
index dd4f3560451bf31d31852f323c94d8924431eb4a..d1670c46da0c0c154f5910537f4f7e47d71440a2 100755 (executable)
        <string name="dictFileKey">dictFile</string>
        <string name="dictFileTitle">Wörterbuch Datei</string>
        <string name="dictFileSummary">Die Datei, die das Wörterbuch enthält (und worein das Wörterbuch heruntergeladen wird).</string>
-       <string name="dictFileDefault">/sdcard/quickdic/de-en.dict</string>
 
-       <string name="dictFetchUrlKey">dictFetchUrl</string>
        <string name="dictFetchUrlTitle">Wörterbuch URL</string>
        <string name="dictFetchUrlSummary">Das URL, wovon das Wörterbuch heruntergeladen wird.</string>
-       <string name="dictFetchUrlDefault">http://www.stanford.edu/~egirard/dict/de-en_2.0.dict</string>
        
 </resources>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
new file mode 100644 (file)
index 0000000..b9dc345
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+  <string-array name="themeKeys">
+    <item>themeLight</item>
+    <item>themeDefault</item>
+  </string-array>
+
+  <string-array name="themes">
+    <item>Light theme</item>
+    <item>Default theme</item>
+  </string-array>
+  
+</resources>
\ No newline at end of file
index 03d9cc57b9df6fccfc58f51a52f522610f05dc9f..aca53c136f232218616591a59243837affb862ec 100644 (file)
@@ -7,8 +7,9 @@
   <!-- DictionaryListActivity -->
   <string name="dictionaryList">Dictionary list</string>
   <string name="selectADictionary"><![CDATA[Select a dictionary.
-\nLong-press to edit the dictionary. Press "menu" to add a new dictionary.]]></string>
+\nLong-press to edit the dictionary config. Press "menu" to add a new dictionary.]]></string>
   <string name="addDictionary">Add dictionary</string>
+  <string name="addDefaultDictionaries">Add default dictionaries</string>
   <string name="editDictionary">Edit dictionary config</string>
   <string name="deleteDictionary">Delete dictionary</string>
   <string name="moveUp">Move up</string>
   <p> New features:
   <ul>
     <li> Easily work with multiple dictionaries.
-    <li> Wiktionary-based dictionaries for French, Italian, German, Spanish, Swedish.
-    <li> Create your own dictionaries.  Look in Menu...About for details.
   </ul>
-  <p>The new version requires you to re-download any dictionaries you want.<br/>
+  <p>The new version requires you to re-download dictionaries you want to use.<br/>
 </body>
 </html>
 ]]>
   <string name="dictionaryEdit">Edit dictionary config</string>
   <string name="dictionaryName">Dictionary name</string>
   <string name="downloadUrl">Dictionary download URL</string>
+  <string name="downloadButton">Download</string>
+  <string name="openButton">Open</string>
   <string name="dictionaryInfo">Dictionary info:</string>
   <string name="localFile">Dictionary file</string>
   <string name="wordListFile">Word list file</string>
   <string name="fileNotFound">File not found: \'%s\'</string>
   <string name="invalidDictionary">Invalid dictionary: file=%1$s, error=%2$s</string>
-  <string name="numPairEntries">Entries: %d</string>
-  <string name="numTokens">Tokens: %d</string>
-  <string name="numRows">Rows: %d</string>
+  <string name="numPairEntries">Entries: %,d</string>
+  <string name="numTokens">Tokens: %,d</string>
+  <string name="numRows">Rows: %,d</string>
 
  
        <!-- Main -->
        <string name="about">About...</string>
        <string name="addToWordList">Add to word list: %s</string>
   <string name="failedAddingToWordList">Failure adding to word list: %s</string>
+  <string name="unzippingDictionary">Unzipping dictionary...</string>
+  <string name="failedToUnzipDictionary">Failed to unzip dictionary...</string>
 
        <!-- About. -->
        <string name="titleWithVersion">QuickDic 2.0</string>
        <string name="thadHughes">Thad Hughes</string>
        <string name="contactMe">If you\'re using QuickDic, I\'d love to hear from you.  Please send comments, suggestions, bug reports, or just a quick hello to:</string>
-       <string name="myEmail">thad.hughes\+quickdic@gmail.com</string>
-  <string name="webPage">For more information, including how to make your own QuickDic dictionaries, see:</string>
+       <string name="myEmail" formatted="false">thad.hughes@gmail.com</string>
+  <string name="webPage">For more information, see:</string>
   <string name="webPageUrl">http://sites.google.com/site/quickdic/home</string>
  
        <!-- Download. -->
-       <string name="downloading">Downloading, %1$d of %2$d bytes.</string>
-       <string name="downloadFinished">Download finished, %d bytes downloaded.</string>
+  <string name="openingConnection">Opening connection...</string>
+       <string name="downloading">Downloading: %1$,d of %2$,d bytes.</string>
+  <string name="unzipping">Unzipping: %1$,d of %2$,d bytes.</string>
+       <string name="downloadFinished">Finished: %,d bytes.</string>
        <string name="errorDownloadingFile">"Error downloading file: \n%s"</string>
 
   <!-- NoDictionary. -->
@@ -84,9 +89,9 @@
   <string name="showClearSearchTextButtonKey">showClearSearchTextButton</string>
   <string name="showClearSearchTextButtonTitle">Show \'clear search text\' button</string>
   <string name="showClearSearchTextButtonSummary">Show the button to clear the search text. You can also just move focus away from search text and start typing.</string>
-  
-  <string name="vibrateOnFailedSearchKey">vibrateOnFailedSearch</string>
-  <string name="vibrateOnFailedSearchTitle">Vibrate on failed search.</string>
-  <string name="vibrateOnFailedSearchSummary">Vibrate the phone when invalid search text is entered.</string>
 
+  <string name="themeKey">theme</string>
+  <string name="themeTitle">UI theme</string>
+  <string name="themeSummary">User-interface color theme (restart required).</string>
+  
 </resources>
diff --git a/res/values/themeDefault.xml b/res/values/themeDefault.xml
new file mode 100644 (file)
index 0000000..dfdb04a
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <style name="Theme.Default" parent="@android:style/Theme">
+<!-- 
+  <item name="android:layout_width">fill_parent</item>
+  <item name="android:layout_height">wrap_content</item>
+  
+  <item name="android:colorForeground">#FFFFFF</item>
+  <item name="android:colorBackground">#000000</item>
+
+  <item name="android:textColorPrimary">#FFFFFF</item>
+ -->
+ </style>
+</resources>
similarity index 82%
rename from res/values/theme.xml
rename to res/values/themeLight.xml
index 720baa97c40d55779f025cf74272a95cb630c387..59f3d410a550702ae4d97fcbdf28cc80910a0280 100644 (file)
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
- <style name="Theme.QuickDic" parent="@android:style/Theme.Light">
+ <style name="Theme.Light" parent="@android:style/Theme.Light">
+<!-- 
   <item name="android:layout_width">fill_parent</item>
   <item name="android:layout_height">wrap_content</item>
   
@@ -8,6 +9,7 @@
   <item name="android:colorBackground">#FFFFFF</item>
 
   <item name="android:textColorPrimary">#000000</item>
-
+ -->
  </style>
 </resources>
index 7cf7652577249784e9ecc88c8c683699ad95a2a3..52cea010098175165baf25b74f7fab7b31eb5778 100755 (executable)
     android:persistent="true"\r
   />\r
 \r
+  <ListPreference \r
+    android:key="@string/themeKey"\r
+    android:title="@string/themeTitle"\r
+    android:summary="@string/themeSummary"\r
+    android:persistent="true"\r
+    android:defaultValue=""\r
+    android:entries="@array/themes"\r
+    android:entryValues="@array/themeKeys"\r
+  />\r
+\r
 </PreferenceScreen>  
\ No newline at end of file
index e3880f5985f78f4ef364e7df76ed79356cd8e3ed..b23a01a878c6f4e08dd24681fc4fbfbd1b9a908f 100755 (executable)
@@ -10,6 +10,8 @@ public final class AboutActivity extends Activity {
   /** Called when the activity is first created. */\r
   @Override\r
   public void onCreate(final Bundle savedInstanceState) {\r
+    ((DictionaryApplication)getApplication()).applyTheme(this);\r
+\r
     super.onCreate(savedInstanceState);\r
     setContentView(R.layout.about_activity);\r
   }\r
index 10b3cf6dc42be147f56b14e37f6376b24f3013ac..922b9728cda321c11c62614ba554414496ce8025 100644 (file)
@@ -119,10 +119,13 @@ public class DictionaryActivity extends ListActivity {
     prefs.remove(C.INDEX_INDEX);\r
     prefs.remove(C.SEARCH_TOKEN);\r
     prefs.commit();\r
+    Log.d(LOG, "Removed default dictionary prefs.");\r
   }\r
 \r
   @Override\r
   public void onCreate(Bundle savedInstanceState) {\r
+    ((DictionaryApplication)getApplication()).applyTheme(this);\r
+    \r
     super.onCreate(savedInstanceState);\r
     Log.d(LOG, "onCreate:" + this);\r
     \r
@@ -195,8 +198,10 @@ public class DictionaryActivity extends ListActivity {
     \r
     searchText.requestFocus();\r
     searchText.addTextChangedListener(searchTextWatcher);\r
-    searchText.setText(prefs.getString(C.SEARCH_TOKEN, ""));\r
-    Log.d(LOG, "Trying to restore searchText=" + searchText.getText());\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
     \r
     final Button clearSearchTextButton = (Button) findViewById(R.id.ClearSearchTextButton);\r
     clearSearchTextButton.setOnClickListener(new OnClickListener() {\r
@@ -254,18 +259,17 @@ public class DictionaryActivity extends ListActivity {
     wordList = new File(prefs.getString(getString(R.string.wordListFileKey),\r
         getString(R.string.wordListFileDefault)));\r
     saveOnlyFirstSubentry = prefs.getBoolean(getString(R.string.saveOnlyFirstSubentryKey), false);\r
-    if (prefs.getBoolean(getString(R.string.vibrateOnFailedSearchKey), true)) {\r
+    //if (prefs.getBoolean(getString(R.string.vibrateOnFailedSearchKey), true)) {\r
       // vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);\r
-    }\r
+    //}\r
     Log.d(LOG, "wordList=" + wordList + ", saveOnlyFirstSubentry=" + saveOnlyFirstSubentry);\r
   }\r
   \r
-  \r
   @Override\r
   protected void onResume() {\r
     super.onResume();\r
   }\r
-\r
+  \r
   @Override\r
   protected void onPause() {\r
     super.onPause();\r
@@ -278,11 +282,31 @@ public class DictionaryActivity extends ListActivity {
       return;\r
     }\r
     setDictionaryPrefs(this, dictIndex, indexIndex, searchText.getText().toString());\r
+    \r
+    // Before we close the RAF, we have to wind the current search down.\r
+    if (currentSearchOperation != null) {\r
+      Log.d(LOG, "Interrupting search to shut down.");\r
+      final SearchOperation searchOperation = currentSearchOperation;\r
+      currentSearchOperation = null;\r
+      searchOperation.interrupted.set(true);\r
+      synchronized (searchOperation) {\r
+        while (!searchOperation.done) {\r
+          try {\r
+            searchOperation.wait();\r
+          } catch (InterruptedException e) {\r
+            Log.d(LOG, "Interrupted.", e);\r
+          }\r
+        }\r
+      }\r
+    }\r
+    \r
     try {\r
+      Log.d(LOG, "Closing RAF.");\r
       dictRaf.close();\r
     } catch (IOException e) {\r
       Log.e(LOG, "Failed to close dictionary", e);\r
     }\r
+    dictRaf = null;\r
   }\r
 \r
   // --------------------------------------------------------------------------\r
@@ -348,37 +372,37 @@ public class DictionaryActivity extends ListActivity {
   public boolean onCreateOptionsMenu(final Menu menu) {\r
     \r
     {\r
-    final MenuItem preferences = menu.add(getString(R.string.preferences));\r
-    preferences.setOnMenuItemClickListener(new OnMenuItemClickListener() {\r
-      public boolean onMenuItemClick(final MenuItem menuItem) {\r
-        startActivity(new Intent(DictionaryActivity.this,\r
-            PreferenceActivity.class));\r
-        return false;\r
-      }\r
-    });\r
+      final MenuItem preferences = menu.add(getString(R.string.preferences));\r
+      preferences.setOnMenuItemClickListener(new OnMenuItemClickListener() {\r
+        public boolean onMenuItemClick(final MenuItem menuItem) {\r
+          startActivity(new Intent(DictionaryActivity.this,\r
+              PreferenceActivity.class));\r
+          return false;\r
+        }\r
+      });\r
     }\r
 \r
     {\r
-    final MenuItem dictionaryList = menu.add(getString(R.string.dictionaryList));\r
-    dictionaryList.setOnMenuItemClickListener(new OnMenuItemClickListener() {\r
-      public boolean onMenuItemClick(final MenuItem menuItem) {\r
-        startActivity(DictionaryListActivity.getIntent(DictionaryActivity.this));\r
-        startActivity(DictionaryListActivity.getIntent(DictionaryActivity.this));\r
-        return false;\r
-      }\r
-    });\r
+      final MenuItem dictionaryList = menu.add(getString(R.string.dictionaryList));\r
+      dictionaryList.setOnMenuItemClickListener(new OnMenuItemClickListener() {\r
+        public boolean onMenuItemClick(final MenuItem menuItem) {\r
+          startActivity(DictionaryListActivity.getIntent(DictionaryActivity.this));\r
+          finish();\r
+          return false;\r
+        }\r
+      });\r
     }\r
 \r
     {\r
-      final MenuItem dictionaryList = menu.add(getString(R.string.editDictionary));\r
-      dictionaryList.setOnMenuItemClickListener(new OnMenuItemClickListener() {\r
+      final MenuItem dictionaryEdit = menu.add(getString(R.string.editDictionary));\r
+      dictionaryEdit.setOnMenuItemClickListener(new OnMenuItemClickListener() {\r
         public boolean onMenuItemClick(final MenuItem menuItem) {\r
           final Intent intent = DictionaryEditActivity.getIntent(dictIndex);\r
           startActivity(intent);\r
           return false;\r
         }\r
       });\r
-      }\r
+    }\r
 \r
     return true;\r
   }\r
@@ -458,6 +482,10 @@ public class DictionaryActivity extends ListActivity {
       }\r
       return true;\r
     }\r
+    if (keyCode == KeyEvent.KEYCODE_BACK) {\r
+      Log.d(LOG, "Clearing dictionary prefs.");\r
+      DictionaryActivity.clearDictionaryPrefs(this);\r
+    }\r
     return super.onKeyDown(keyCode, event);\r
   }\r
 \r
@@ -518,6 +546,8 @@ public class DictionaryActivity extends ListActivity {
 \r
     Index.IndexEntry searchResult;\r
     \r
+    boolean done = false;\r
+    \r
     SearchOperation(final String searchText, final Index index) {\r
       this.searchText = searchText.trim();\r
       this.index = index;\r
@@ -529,18 +559,25 @@ public class DictionaryActivity extends ListActivity {
 \r
     @Override\r
     public void run() {\r
-      searchStartMillis = System.currentTimeMillis();\r
-      searchResult = index.findInsertionPoint(searchText, interrupted);\r
-      Log.d(LOG, "searchText=" + searchText + ", searchDuration="\r
-          + (System.currentTimeMillis() - searchStartMillis) + ", interrupted="\r
-          + interrupted.get());\r
-      if (!interrupted.get()) {\r
-        uiHandler.post(new Runnable() {\r
-          @Override\r
-          public void run() {            \r
-            searchFinished(SearchOperation.this);\r
-          }\r
-        });\r
+      try {\r
+        searchStartMillis = System.currentTimeMillis();\r
+        searchResult = index.findInsertionPoint(searchText, interrupted);\r
+        Log.d(LOG, "searchText=" + searchText + ", searchDuration="\r
+            + (System.currentTimeMillis() - searchStartMillis) + ", interrupted="\r
+            + interrupted.get());\r
+        if (!interrupted.get()) {\r
+          uiHandler.post(new Runnable() {\r
+            @Override\r
+            public void run() {            \r
+              searchFinished(SearchOperation.this);\r
+            }\r
+          });\r
+        }\r
+      } finally {\r
+        synchronized (this) {\r
+          done = true;\r
+          this.notifyAll();\r
+        }\r
       }\r
     }\r
   }\r
@@ -650,6 +687,10 @@ public class DictionaryActivity extends ListActivity {
   // --------------------------------------------------------------------------\r
 \r
   void onSearchTextChange(final String text) {\r
+    if (dictRaf == null) {\r
+      Log.d(LOG, "searchText changed during shutdown, doing nothing.");\r
+      return;\r
+    }\r
     if (!searchText.isFocused()) {\r
       Log.d(LOG, "searchText changed without focus, doing nothing.");\r
       return;\r
diff --git a/src/com/hughes/android/dictionary/DictionaryActivityOld.java.old b/src/com/hughes/android/dictionary/DictionaryActivityOld.java.old
deleted file mode 100644 (file)
index 662ed15..0000000
+++ /dev/null
@@ -1,739 +0,0 @@
-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 DictionaryActivityOld 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
index 3ef63332938de09493836946ec44214336ea28b2..8577e14f3cc9e7ba5298da628d843aafa78be632 100644 (file)
@@ -13,12 +13,4 @@ public class DictionaryConfig implements Serializable {
   int openIndex = 0;
   String openWord = "";
   
-  static DictionaryConfig defaultConfig() {
-    final DictionaryConfig result = new DictionaryConfig();
-    result.name = "DE<->EN";
-    result.downloadUrl = "http://www.stanford.edu/~egirard/dict/de-en.2.dict";
-    result.localFile = "/sdcard/quickDic/de-en.dict";
-    return result;
-  }
-  
 }
index cc21132c504d1d75a413cb662564b66c5ccdce90..9a450eef5444d6e7cbec90bf27b6178cc1a4cbf1 100644 (file)
@@ -8,12 +8,17 @@ import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
+import android.os.Handler;
 import android.text.Editable;
 import android.text.TextWatcher;
 import android.util.Log;
+import android.view.KeyEvent;
 import android.view.Menu;
 import android.view.MenuItem;
+import android.view.View;
 import android.view.MenuItem.OnMenuItemClickListener;
+import android.view.View.OnClickListener;
+import android.widget.Button;
 import android.widget.EditText;
 import android.widget.TextView;
 
@@ -27,6 +32,8 @@ public class DictionaryEditActivity extends Activity {
 
   QuickDicConfig quickDicConfig;
   private DictionaryConfig dictionaryConfig;
+  
+  final Handler uiHandler = new Handler();
 
   public static Intent getIntent(final int dictIndex) {
     final Intent intent = new Intent();
@@ -39,17 +46,20 @@ public class DictionaryEditActivity extends Activity {
   /** Called when the activity is first created. */
   @Override
   public void onCreate(final Bundle savedInstanceState) {
+    ((DictionaryApplication)getApplication()).applyTheme(this);
+
     super.onCreate(savedInstanceState);
     setContentView(R.layout.edit_activity);
 
     final Intent intent = getIntent();
 
+    final int dictIndex = intent.getIntExtra(C.DICT_INDEX, 0);
+      
     PersistentObjectCache.init(this);
     try {
       quickDicConfig = PersistentObjectCache.init(this).read(
           C.DICTIONARY_CONFIGS, QuickDicConfig.class);
-      dictionaryConfig = quickDicConfig.dictionaryConfigs.get(intent
-          .getIntExtra(C.DICT_INDEX, 0));
+      dictionaryConfig = quickDicConfig.dictionaryConfigs.get(dictIndex);
     } catch (Exception e) {
       Log.e(LOG, "Failed to read QuickDicConfig.", e);
       quickDicConfig = new QuickDicConfig();
@@ -62,29 +72,55 @@ public class DictionaryEditActivity extends Activity {
         .setText(dictionaryConfig.name);
     ((EditText) findViewById(R.id.localFile))
         .setText(dictionaryConfig.localFile);
-    ((EditText) findViewById(R.id.downloadUrl))
-        .setText(dictionaryConfig.downloadUrl);
 
-    updateDictInfo();
-    ((EditText) findViewById(R.id.localFile))
-        .addTextChangedListener(new TextWatcher() {
-          @Override
-          public void onTextChanged(CharSequence s, int start, int before,
-              int count) {
-          }
+    final TextWatcher textWatcher = new TextWatcher() {
+      @Override
+      public void onTextChanged(CharSequence s, int start, int before,
+          int count) {
+      }
 
-          @Override
-          public void beforeTextChanged(CharSequence s, int start, int count,
-              int after) {
-          }
+      @Override
+      public void beforeTextChanged(CharSequence s, int start, int count,
+          int after) {
+      }
 
-          @Override
-          public void afterTextChanged(Editable s) {
-            updateDictInfo();
-          }
-        });
+      @Override
+      public void afterTextChanged(Editable s) {
+        updateDictInfo();
+      }
+    };
+
+    ((EditText) findViewById(R.id.localFile)).addTextChangedListener(textWatcher);
+
+    final EditText downloadUrl = (EditText) findViewById(R.id.downloadUrl);
+    downloadUrl.setText(dictionaryConfig.downloadUrl);
+    downloadUrl.addTextChangedListener(textWatcher);
+    
+    final Button downloadButton = (Button) findViewById(R.id.downloadButton);
+    downloadButton.setOnClickListener(new OnClickListener() {
+      @Override
+      public void onClick(View v) {
+        startDownloadDictActivity(DictionaryEditActivity.this,
+            dictionaryConfig);
+      }
+    });
+
+    final Button openButton = (Button) findViewById(R.id.openButton);
+    openButton.setOnClickListener(new OnClickListener() {
+      @Override
+      public void onClick(View v) {
+        final Intent intent = DictionaryActivity.getIntent(DictionaryEditActivity.this, dictIndex, 0, "");
+        startActivity(intent);
+      }
+    });
 
   }
+  
+  protected void onResume() {
+    super.onResume();
+    
+    updateDictInfo();
+  }
 
   @Override
   protected void onPause() {
@@ -105,23 +141,39 @@ public class DictionaryEditActivity extends Activity {
   public boolean onCreateOptionsMenu(final Menu menu) {
     final MenuItem newDictionaryMenuItem = menu
         .add(R.string.downloadDictionary);
-    newDictionaryMenuItem
-        .setOnMenuItemClickListener(new OnMenuItemClickListener() {
+    newDictionaryMenuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() {
           public boolean onMenuItemClick(final MenuItem menuItem) {
             startDownloadDictActivity(DictionaryEditActivity.this,
                 dictionaryConfig);
             return false;
           }
         });
+    
+    final MenuItem dictionaryList = menu.add(getString(R.string.dictionaryList));
+    dictionaryList.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+      public boolean onMenuItemClick(final MenuItem menuItem) {
+        startActivity(DictionaryListActivity.getIntent(DictionaryEditActivity.this));
+        return false;
+      }
+    });
+
 
     return true;
   }
 
   void updateDictInfo() {
-    final TextView dictInfo = (TextView) findViewById(R.id.dictionaryInfo);
+    final String downloadUrl = ((EditText) findViewById(R.id.downloadUrl))
+        .getText().toString();
     final String localFile = ((EditText) findViewById(R.id.localFile))
         .getText().toString();
 
+    final Button downloadButton = (Button) findViewById(R.id.downloadButton);
+    downloadButton.setEnabled(downloadUrl.length() > 0 && localFile.length() > 0);
+
+    final Button openButton = (Button) findViewById(R.id.openButton);
+    openButton.setEnabled(false);
+
+    final TextView dictInfo = (TextView) findViewById(R.id.dictionaryInfo);
     if (!new File(localFile).canRead()) {
       dictInfo.setText(getString(R.string.fileNotFound, localFile));
       return;
@@ -146,6 +198,8 @@ public class DictionaryEditActivity extends Activity {
       }
       raf.close();
       dictInfo.setText(builder.toString());
+      openButton.setEnabled(true);
+      
     } catch (IOException e) {
       dictInfo.setText(getString(R.string.invalidDictionary, localFile, e
           .toString()));
@@ -156,8 +210,17 @@ public class DictionaryEditActivity extends Activity {
       final DictionaryConfig dictionaryConfig) {
     final Intent intent = new Intent(context, DownloadActivity.class);
     intent.putExtra(DownloadActivity.SOURCE, dictionaryConfig.downloadUrl);
-    intent.putExtra(DownloadActivity.DEST, dictionaryConfig.localFile);
+    intent.putExtra(DownloadActivity.DEST, dictionaryConfig.localFile + ".zip");
     context.startActivity(intent);
   }
+  
+  @Override
+  public boolean onKeyDown(final int keyCode, final KeyEvent event) {
+    if (keyCode == KeyEvent.KEYCODE_BACK) {
+      Log.d(LOG, "Clearing dictionary prefs.");
+      DictionaryActivity.clearDictionaryPrefs(this);
+    }
+    return super.onKeyDown(keyCode, event);
+  }
 
 }
index 29ec4b88f94475bfd8095f9c9ac44dd847deb676..286f2497e98e035d7255f6e3e90b675ef087ad70 100644 (file)
@@ -34,6 +34,8 @@ public class DictionaryListActivity extends ListActivity {
   
   
   public void onCreate(Bundle savedInstanceState) {
+    ((DictionaryApplication)getApplication()).applyTheme(this);
+
     super.onCreate(savedInstanceState);
     Log.d(LOG, "onCreate:" + this);
 
@@ -52,7 +54,7 @@ public class DictionaryListActivity extends ListActivity {
     registerForContextMenu(getListView());
 
     final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
-    final int introMessageId = 0;
+    final int introMessageId = -1;
     if (prefs.getInt(C.INTRO_MESSAGE_SHOWN, 0) < introMessageId) {
       final AlertDialog.Builder builder = new AlertDialog.Builder(this);
       builder.setCancelable(false);
@@ -81,8 +83,9 @@ public class DictionaryListActivity extends ListActivity {
     
     final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
     if (prefs.contains(C.DICT_INDEX) && prefs.contains(C.INDEX_INDEX)) {
+      Log.d(LOG, "Skipping Dictionary List, going straight to dictionary.");
       startActivity(DictionaryActivity.getIntent(this, prefs.getInt(C.DICT_INDEX, 0), prefs.getInt(C.INDEX_INDEX, 0), prefs.getString(C.SEARCH_TOKEN, "")));
-      finish();
+      //finish();
       return;
     }
 
@@ -91,6 +94,11 @@ public class DictionaryListActivity extends ListActivity {
       quickDicConfig = new QuickDicConfig();
       PersistentObjectCache.getInstance().write(C.DICTIONARY_CONFIGS, quickDicConfig);
     }
+    if (quickDicConfig.currentVersion < QuickDicConfig.LATEST_VERSION) {
+      Log.d(LOG, "Dictionary list is old, updating it.");
+      quickDicConfig.addDefaultDictionaries();
+      quickDicConfig.currentVersion = QuickDicConfig.LATEST_VERSION;
+    }
 
     setListAdapter(new Adapter());
     
@@ -107,6 +115,34 @@ public class DictionaryListActivity extends ListActivity {
             return false;
           }
         });
+
+    final MenuItem addDefaultDictionariesMenuItem = menu.add(R.string.addDefaultDictionaries);
+    addDefaultDictionariesMenuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+          public boolean onMenuItemClick(final MenuItem menuItem) {
+            quickDicConfig.addDefaultDictionaries();
+            dictionaryConfigsChanged();
+            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());
+        startActivity(intent);
+        return false;
+      }
+    });
+    
+    final MenuItem preferences = menu.add(getString(R.string.preferences));
+    preferences.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+      public boolean onMenuItemClick(final MenuItem menuItem) {
+        startActivity(new Intent(DictionaryListActivity.this,
+            PreferenceActivity.class));
+        return false;
+      }
+    });
     
     return true;
   }
index 9ad663ae3b84f5be31eae1117306369ba91668dc..a7834021c1bd6b098731568dfe11f56008bdbf93 100755 (executable)
@@ -4,11 +4,14 @@ import java.io.File;
 import java.io.FileOutputStream;\r
 import java.io.IOException;\r
 import java.io.InputStream;\r
+import java.io.OutputStream;\r
 import java.net.URL;\r
 import java.net.URLConnection;\r
 import java.util.concurrent.Executor;\r
 import java.util.concurrent.Executors;\r
 import java.util.concurrent.atomic.AtomicBoolean;\r
+import java.util.zip.ZipEntry;\r
+import java.util.zip.ZipFile;\r
 \r
 import android.app.Activity;\r
 import android.content.Intent;\r
@@ -25,7 +28,7 @@ public class DownloadActivity extends Activity {
 \r
   String source;\r
   String dest;\r
-  long bytesDownloaded = 0;\r
+  long bytesProcessed = 0;\r
   long contentLength = -1;\r
 \r
   private final Executor downloadExecutor = Executors.newSingleThreadExecutor();\r
@@ -36,6 +39,8 @@ public class DownloadActivity extends Activity {
   /** Called when the activity is first created. */\r
   @Override\r
   public void onCreate(final Bundle savedInstanceState) {\r
+    ((DictionaryApplication)getApplication()).applyTheme(this);\r
+\r
     super.onCreate(savedInstanceState);\r
     final Intent intent = getIntent();\r
     source = intent.getStringExtra(SOURCE);\r
@@ -54,57 +59,75 @@ public class DownloadActivity extends Activity {
     final ProgressBar progressBar = (ProgressBar) findViewById(R.id.downloadProgressBar);\r
     progressBar.setIndeterminate(false);\r
     progressBar.setMax(100);\r
-\r
-    final InputStream in;\r
-    final FileOutputStream out;\r
-\r
-    final File destFile = new File(dest);\r
-    final File destTmpFile;\r
-    try {\r
-      destTmpFile = File.createTempFile("dictionaryDownload", "tmp", destFile\r
-          .getParentFile());\r
-      destTmpFile.deleteOnExit();\r
-      final URL uri = new URL(source);\r
-      final URLConnection connection = uri.openConnection();\r
-      contentLength = connection.getContentLength();\r
-      in = connection.getInputStream();\r
-      out = new FileOutputStream(destTmpFile);\r
-    } catch (Exception e) {\r
-      Log.e("THAD", "Error downloading file", e);\r
-      setDownloadStatus(String.format(getString(R.string.errorDownloadingFile), e.getLocalizedMessage()));\r
-      return;\r
-    }\r
+    \r
+    bytesProcessed = 0;\r
+    contentLength = 100;\r
+    setDownloadStatus(getString(R.string.openingConnection));\r
 \r
     final Runnable runnable = new Runnable() {\r
       public void run() {\r
+\r
         try {\r
-          bytesDownloaded = 0;\r
-          int bytesRead;\r
-          final byte[] bytes = new byte[1024 * 8];\r
-          int count = 0;\r
-          while ((bytesRead = in.read(bytes)) != -1 && !stop.get()) {\r
-            out.write(bytes, 0, bytesRead);\r
-            bytesDownloaded += bytesRead;\r
-            if (count++ % 20 == 0) {\r
-              setDownloadStatus(getString(R.string.downloading,\r
-                  bytesDownloaded, contentLength));\r
-            }\r
-          }\r
-          in.close();\r
-          out.close();\r
+          final File destFile = new File(dest);\r
+          destFile.getParentFile().mkdirs();\r
+\r
+          final File destTmpFile = File.createTempFile("dictionaryDownload", "tmp", destFile\r
+              .getParentFile());\r
+          destTmpFile.deleteOnExit();\r
+\r
+          final URL uri = new URL(source);\r
+          final URLConnection connection = uri.openConnection();\r
+          contentLength = connection.getContentLength();\r
+          final InputStream in = connection.getInputStream();\r
+          final FileOutputStream out = new FileOutputStream(destTmpFile); \r
+          int bytesRead = copyStream(in, out, R.string.downloading);\r
+          \r
           if (bytesRead == -1 && !stop.get()) {\r
             destFile.delete();\r
             destTmpFile.renameTo(destFile);\r
           } else {\r
            Log.d("THAD", "Stopped downloading file.");\r
           }\r
+          \r
+          if (dest.toLowerCase().endsWith(".zip")) {\r
+            final ZipFile zipFile = new ZipFile(destFile);\r
+            final File destUnzipped = new File(dest.substring(0, dest.length() - 4));\r
+            final ZipEntry zipEntry = zipFile.getEntry(destUnzipped.getName());\r
+            if (zipEntry != null) {\r
+              destUnzipped.delete();\r
+              Log.d("THAD", "Unzipping entry: " + zipEntry.getName() + " to " + destUnzipped);\r
+              final InputStream zipIn = zipFile.getInputStream(zipEntry);\r
+              final OutputStream zipOut = new FileOutputStream(destUnzipped);\r
+              contentLength = zipEntry.getSize();\r
+              bytesRead = copyStream(zipIn, zipOut, R.string.unzipping);\r
+            }\r
+          }\r
+          \r
           setDownloadStatus(String.format(getString(R.string.downloadFinished),\r
-              bytesDownloaded));\r
+              bytesProcessed));\r
         } catch (IOException e) {\r
           Log.e("THAD", "Error downloading file", e);\r
           setDownloadStatus(String.format(getString(R.string.errorDownloadingFile), e.getLocalizedMessage()));\r
         }\r
       }\r
+\r
+      private int copyStream(final InputStream in, final OutputStream out, final int messageId)\r
+          throws IOException {\r
+        bytesProcessed = 0;\r
+        int bytesRead;\r
+        final byte[] bytes = new byte[1024 * 16];\r
+        int count = 0;\r
+        while ((bytesRead = in.read(bytes)) != -1 && !stop.get()) {\r
+          out.write(bytes, 0, bytesRead);\r
+          bytesProcessed += bytesRead;\r
+          if (count++ % 20 == 0) {\r
+            setDownloadStatus(getString(messageId, bytesProcessed, contentLength));\r
+          }\r
+        }\r
+        in.close();\r
+        out.close();\r
+        return bytesRead;\r
+      }\r
     };\r
 \r
     downloadExecutor.execute(runnable);\r
@@ -121,7 +144,7 @@ public class DownloadActivity extends Activity {
       public void run() {\r
         final ProgressBar progressBar = (ProgressBar) findViewById(R.id.downloadProgressBar);\r
         if (contentLength > 0) {\r
-          progressBar.setProgress((int) (bytesDownloaded * 100 / contentLength));\r
+          progressBar.setProgress((int) (bytesProcessed * 100 / contentLength));\r
         }\r
         \r
         final TextView downloadStatus = (TextView) findViewById(R.id.downloadStatus);\r
index 4863eafd0bdbff796cde80a0e38fac6ab86ecfc3..eae1497e40847626ce5dd6d8ca22145a40b6a2cd 100755 (executable)
@@ -5,7 +5,10 @@ import android.os.Bundle;
 public class PreferenceActivity extends android.preference.PreferenceActivity {\r
   @Override\r
   public void onCreate(Bundle savedInstanceState) {\r
+    ((DictionaryApplication)getApplication()).applyTheme(this);\r
+\r
     super.onCreate(savedInstanceState);\r
     addPreferencesFromResource(R.xml.preferences);\r
   }\r
+\r
 }\r
index 79f88ec0050b0a9621cf4877f4ce8a00295b9d5b..602fc24c54dcc5da48ed15b2f2d853d25d9b3113 100644 (file)
@@ -8,10 +8,41 @@ public final class QuickDicConfig implements Serializable {
   
   private static final long serialVersionUID = 6711617368780900979L;
   
+  static final int LATEST_VERSION = 1;
+  
   final List<DictionaryConfig> dictionaryConfigs = new ArrayList<DictionaryConfig>();
+  int currentVersion = LATEST_VERSION;
   
   public QuickDicConfig() {
-    dictionaryConfigs.add(DictionaryConfig.defaultConfig());
+    addDefaultDictionaries();
+  }
+
+  public void addDefaultDictionaries() {
+    {
+      final DictionaryConfig de_en_chemnitz = new DictionaryConfig();
+      de_en_chemnitz.name = "DE<->EN (Chemnitz)";
+      de_en_chemnitz.downloadUrl = "https://sites.google.com/site/quickdic/dictionaries-1/DE-EN_chemnitz.quickdic.zip?attredirects=0&d=1";
+      de_en_chemnitz.localFile = "/sdcard/quickDic/DE-EN_chemnitz.quickdic";
+      addOrReplace(de_en_chemnitz);
+    }
+
+    {
+      final DictionaryConfig en_it_wiktionary = new DictionaryConfig();
+      en_it_wiktionary.name = "EN<->IT (EN Wiktionary)";
+      en_it_wiktionary.downloadUrl = "https://sites.google.com/site/quickdic/dictionaries-1/EN-IT_enwiktionary.quickdic.zip?attredirects=0&d=1";
+      en_it_wiktionary.localFile = "/sdcard/quickDic/EN-IT_enwiktionary.quickdic";
+      addOrReplace(en_it_wiktionary);
+    }
+  }
+
+  private void addOrReplace(final DictionaryConfig dictionaryConfig) {
+    for (int i = 0; i < dictionaryConfigs.size(); ++i) {
+      if (dictionaryConfigs.get(i).name.equals(dictionaryConfig.name)) {
+        dictionaryConfigs.set(i, dictionaryConfig);
+        return;
+      }
+    }
+    dictionaryConfigs.add(dictionaryConfig);
   }
 
 }
index f05c0dc772dfe54f0f4d62e923e6475c04b5e140..6284f18e943d9c102526816e616fece1dbd6f0fb 100644 (file)
@@ -157,6 +157,9 @@ public final class Index implements RAFSerializable<Index> {
     final Transliterator normalizer = normalizer();
     if (TransliteratorManager.init(null)) {
       token = normalizer.transliterate(token);
+    } else {
+      // Do our best since the Transliterators aren't up yet.
+      token = token.toLowerCase();
     }
 
     int start = 0;
index 50a7ca6a4b3ed8a8bee0148d3913c1bffc5182a4..cbe6b89321692ea79e9b1fadbd2fa474940b8b53 100644 (file)
@@ -3,8 +3,6 @@ package com.hughes.android.dictionary.engine;
 import java.util.ArrayList;
 import java.util.List;
 
-import android.util.Log;
-
 import com.ibm.icu.text.Transliterator;
 
 public class TransliteratorManager {
index 31a41ffb1e7ed2dcb89e825cbb6b6213ccd8e78b..01ef3c9381a246b10b0de24f75a7ed9324954c57 100644 (file)
--- a/todo.txt
+++ b/todo.txt
@@ -1,10 +1,11 @@
+new version requires re-download of ~25MB dictionary file.
+
 * wiktionary
 * multi word search
 * source in context menu
 * quiz
 * link to leo, dict.cc
 * colorize things
-* better Row/Entry classes?
 * better tokenization?
 * test email
 * dict manager
@@ -13,3 +14,4 @@
 
 done:
 * sorting of entries
+* better Row/Entry classes?