]> gitweb.fperrin.net Git - Dictionary.git/commitdiff
a
authorthadh <thadh@THADH-LAPTOP.ad.corp.google.com>
Tue, 27 Oct 2009 15:01:00 +0000 (08:01 -0700)
committerthadh <thadh@THADH-LAPTOP.ad.corp.google.com>
Tue, 27 Oct 2009 15:01:00 +0000 (08:01 -0700)
res/layout/no_dictionary.xml
res/values-de/strings.xml
res/values/strings.xml
src/com/hughes/android/dictionary/Dictionary.java
src/com/hughes/android/dictionary/DictionaryActivity.java
src/com/hughes/android/dictionary/DictionaryActivityTest.java
src/com/hughes/android/dictionary/Entry.java
src/com/hughes/android/dictionary/NoDictionaryActivity.java

index 6bcf86ba5336897a2da499395bcad26835c667c5..9ab0b85c635ba5d9ddcf52e90c68c4e282183f51 100755 (executable)
@@ -11,7 +11,7 @@
        >
 
        <TextView 
-               android:id="@+id/noDictTextId" 
+               android:id="@+id/statusTextId" 
                android:layout_width="wrap_content" 
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical|fill_vertical"
     android:layout_height="wrap_content"
   />
 
+  <Button 
+    android:id="@+id/launchDict"
+    android:text="@string/launchDict"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+  />
+
 </LinearLayout>
 
 </ScrollView>
\ No newline at end of file
index b82a3afbdd78a04ab0bb5abebf6a7e2e67ad9bbf..a7662f69332d122fa9e727fccdbcf1d0a722609e 100755 (executable)
@@ -6,12 +6,12 @@
        
        <!-- Main -->
        <string name="searchText">Stichwort</string>
-       <string name="unableToReadDictionaryFile">Wörterbuch Datei existiert nicht: %s</string>
        <string name="downloadDictionary">Wörterbuch herunterladen...</string>
        <string name="switchToLanguage">Switch to %s</string>
        <string name="preferences">Einstellungen...</string>
        <string name="about">Über QuickDic...</string>
        <string name="addToWordList">Zu Wortliste hinzufugen: %s</string>
+  <string name="failedAddingToWordList">Fehler bei Wortliste hinzufugen: %s</string>
 
        <!-- About. -->
        <string name="titleWithVersion">QuickDic 1.2</string>
        <string name="downloadFinished">Herunterladen fertig, %d Bytes heruntergeladen.</string>
        <string name="errorDownloadingFile">"Fehler während des Herunterladens: \n%s"</string>
 
+  <!-- NoDictionary. -->
+  <string name="unableToReadDictionaryFile">Wörterbuch Datei existiert nicht: %s</string>
+  <string name="DictionaryFileExists">Wörterbuch Datei existiert: %s</string>
+  <string name="launchDict">"Launch dictionary."</string>
+
        <!-- Preferences -->
        <string name="wordListFileKey">wordListFile</string>
        <string name="wordListFileTitle">Wortliste Datei</string>
index db1481a27b3f7d3ee0ee5f96aa49e00fe701c70f..1a8a8f40675a2ea173ef2442b877c290bd1d64fa 100755 (executable)
@@ -6,12 +6,12 @@
        
        <!-- Main -->
        <string name="searchText">Search Text</string>
-       <string name="unableToReadDictionaryFile">Unable to read dictionary file: %s</string>
        <string name="downloadDictionary">Download dictionary...</string>
        <string name="switchToLanguage">Switch to %s</string>
        <string name="preferences">Preferences...</string>
        <string name="about">About...</string>
        <string name="addToWordList">Add to word list: %s</string>
+  <string name="failedAddingToWordList">Failure adding to word list: %s</string>
 
        <!-- About. -->
        <string name="titleWithVersion">QuickDic 1.2</string>
        <string name="downloadFinished">Download finished, %d bytes downloaded.</string>
        <string name="errorDownloadingFile">"Error downloading file: \n%s"</string>
 
+  <!-- NoDictionary. -->
+  <string name="unableToReadDictionaryFile">Unable to read dictionary file: %s</string>
+  <string name="dictionaryFileExists">Dictionary file exists: %s</string>
+  <string name="launchDict">Launch dictionary.</string>
+
        <!-- Preferences -->
        <string name="wordListFileKey">wordListFile</string>
        <string name="wordListFileTitle">Word list file</string>
index cc31105d2438f1fb533a5e426376f9bd47162d66..05881295287e4be5a1aecd0ae0027bc0ce4ec2ae 100755 (executable)
@@ -123,6 +123,28 @@ public final class Dictionary implements RAFSerializable<Dictionary> {
       }\r
       return Math.min(sortedIndex.size() - 1, start);\r
     }\r
+    \r
+    public int getPrevTokenRow(final int rowIndex) {\r
+      final IndexEntry indexEntry = getIndexEntryForRow(rowIndex);\r
+      final Row tokenRow = rows.get(indexEntry.startRow);\r
+      assert tokenRow.isToken();\r
+      final int prevTokenIndex = tokenRow.getIndex() - 1;\r
+      if (indexEntry.startRow == rowIndex && prevTokenIndex >= 0) {\r
+        return sortedIndex.get(prevTokenIndex).startRow;\r
+      }\r
+      return indexEntry.startRow;\r
+    }\r
+\r
+    public int getNextTokenRow(final int rowIndex) {\r
+      final IndexEntry indexEntry = getIndexEntryForRow(rowIndex);\r
+      final Row tokenRow = rows.get(indexEntry.startRow);\r
+      assert tokenRow.isToken();\r
+      final int nextTokenIndex = tokenRow.getIndex() + 1;\r
+      if (nextTokenIndex < sortedIndex.size()) {\r
+        return sortedIndex.get(nextTokenIndex).startRow;\r
+      }\r
+      return rows.size() - 1;\r
+    }\r
 \r
     public IndexEntry getIndexEntryForRow(final int rowIndex) {\r
       // TODO: this kinda blows.\r
index 0bfd39ac1c1687cc81586328e80bf9668f29791c..f1d529d2a593e8f0a9defbc4a498c08c227d1a14 100755 (executable)
@@ -11,7 +11,6 @@ import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import android.app.AlertDialog;
 import android.app.ListActivity;
 import android.content.Context;
 import android.content.Intent;
@@ -36,6 +35,7 @@ import android.view.ViewGroup;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.view.MenuItem.OnMenuItemClickListener;
 import android.view.View.OnClickListener;
+import android.widget.AdapterView;
 import android.widget.BaseAdapter;
 import android.widget.Button;
 import android.widget.EditText;
@@ -43,6 +43,7 @@ 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.Dictionary.IndexEntry;
 import com.hughes.android.dictionary.Dictionary.LanguageData;
@@ -51,10 +52,12 @@ import com.hughes.android.dictionary.Dictionary.Row;
 public class DictionaryActivity extends ListActivity {
   
   // TODO:
-  // * Only have one live SearchActivity, and a way to wait for it to die.
-  // * Don't destroy dict unless we're really shutting down (not on screen rotate).
-  // * Move (re-)init code to a method, set a flag if prefs might have changed, invoke re-init in onResume, which clears flag and reloads prefs.
+  // * Version magic number at end of dictionary, checked for correctness. (Throw exception in ctor, remember to check for it).
+  // * Localize "about" string if % codes
+  // * Toast when word gets added to word list.
   // * 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";
@@ -62,31 +65,28 @@ public class DictionaryActivity extends ListActivity {
 
   // package for test.
   final Handler uiHandler = new Handler();
+  private final Executor searchExecutor = Executors.newSingleThreadExecutor();
 
   EditText searchText;
+  Button langButton;
+  int lastSelectedRow = 0;
 
-  private final Executor searchExecutor = Executors.newSingleThreadExecutor();
+  private boolean prefsMightHaveChanged = true;
 
   // Never null.
-  private boolean prefsMightHaveChanged = true;
   private File wordList;
-
   private RandomAccessFile dictRaf = null;
   private Dictionary dictionary = null;
 
   // Visible for testing.
   LanguageListAdapter languageList = null;
-
   private SearchOperation searchOperation = null;
 
-  private int selectedRowIndex;
-  private int selectedTokenRowIndex;
-
   /** Called when the activity is first created. */
   @Override
   public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
-    Log.d(LOG, "onCreate");
+    Log.d(LOG, "onCreate:" + this);
 
     if (Language.EN.sortCollator.compare("pre-print", "preppy") >= 0) {
       Log
@@ -103,9 +103,20 @@ public class DictionaryActivity extends ListActivity {
 
     setContentView(R.layout.main);
     searchText = (EditText) findViewById(R.id.SearchText);
-
+    langButton = (Button) findViewById(R.id.LangButton);
+    
     Log.d(LOG, "adding text changed listener");
     searchText.addTextChangedListener(new SearchTextWatcher());
+    
+    getListView().setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+      public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2,
+          long arg3) {
+        lastSelectedRow = arg2;
+        updateSearchText();
+      }
+      public void onNothingSelected(AdapterView<?> arg0) {
+      }
+    });
 
     // Language button.
     final Button langButton = (Button) findViewById(R.id.LangButton);
@@ -132,7 +143,7 @@ public class DictionaryActivity extends ListActivity {
 
     updateLangButton();
   }
-
+  
   private void initDictionaryAndPrefs() {
     if (!prefsMightHaveChanged) {
       return;
@@ -158,7 +169,8 @@ public class DictionaryActivity extends ListActivity {
       dictRaf = new RandomAccessFile(dictFile, "r");
       dictionary = new Dictionary(dictRaf);
     } catch (Exception e) {
-      throw new RuntimeException(e);
+      Log.e(LOG, "Couldn't open dictionary.", e);
+      return;
     }
 
     final byte lang = prefs.getInt(PREF_DICT_ACTIVE_LANG, Entry.LANG1) == Entry.LANG1 ? Entry.LANG1
@@ -172,10 +184,9 @@ public class DictionaryActivity extends ListActivity {
   @Override
   public void onResume() {
     super.onResume();
-    
-    if (prefsMightHaveChanged) {
-      
-    }
+    Log.d(LOG, "onResume:" + this);
+
+    initDictionaryAndPrefs();
     
     final SharedPreferences prefs = PreferenceManager
         .getDefaultSharedPreferences(this);
@@ -183,11 +194,13 @@ public class DictionaryActivity extends ListActivity {
         .getString(PREF_ACTIVE_SEARCH_TEXT, "");
     searchText.setText(searchTextString);
     onSearchTextChange(searchTextString);
+    getListView().requestFocus();
   }
 
   @Override
   public void onPause() {
     super.onPause();
+    Log.d(LOG, "onPause:" + this);
     final Editor prefs = PreferenceManager.getDefaultSharedPreferences(this)
         .edit();
     prefs.putInt(PREF_DICT_ACTIVE_LANG, languageList.languageData.lang);
@@ -198,17 +211,16 @@ public class DictionaryActivity extends ListActivity {
   @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 (searchOperation != null) {
-      searchOperation.stopAndWait();
-      searchOperation = null;
-    }
+    waitForSearchEnd();
     languageList = null;
     setListAdapter(null);
     dictionary = null;
@@ -223,7 +235,7 @@ public class DictionaryActivity extends ListActivity {
   }
 
   public String getSelectedRowRawText() {
-    final int row = getSelectedItemPosition();
+    final int row = getSelectedRow();
     return row < 0 ? "" : languageList.languageData
         .rowToString(languageList.languageData.rows.get(row));
   }
@@ -297,14 +309,13 @@ public class DictionaryActivity extends ListActivity {
 
   @Override
   public boolean onPrepareOptionsMenu(final Menu menu) {
-    switchLanguageMenuItem.setTitle(String.format(
-        getString(R.string.switchToLanguage), dictionary.languageDatas[Entry
+    switchLanguageMenuItem.setTitle(getString(R.string.switchToLanguage,
+        dictionary.languageDatas[Entry
             .otherLang(languageList.languageData.lang)].language.symbol));
     return super.onPrepareOptionsMenu(menu);
   }
   
   void updateLangButton() {
-    final Button langButton = (Button) findViewById(R.id.LangButton);
     langButton.setText(languageList.languageData.language.symbol);
   }
 
@@ -313,6 +324,7 @@ public class DictionaryActivity extends ListActivity {
   // ----------------------------------------------------------------
   
   void onLanguageButton() {
+    waitForSearchEnd();
     languageList = new LanguageListAdapter(
         dictionary.languageDatas[(languageList.languageData == dictionary.languageDatas[0]) ? 1
             : 0]);
@@ -323,41 +335,19 @@ public class DictionaryActivity extends ListActivity {
   }
 
   void onUpButton() {
-    final int destRowIndex;
-    final Row tokenRow = languageList.languageData.rows
-        .get(selectedTokenRowIndex);
-    assert tokenRow.isToken();
-    final int prevTokenIndex = tokenRow.getIndex() - 1;
-    if (selectedRowIndex == selectedTokenRowIndex && selectedRowIndex > 0) {
-      destRowIndex = languageList.languageData.sortedIndex
-          .get(prevTokenIndex).startRow;
-      Log.d(LOG, "onUpButton, jumping back a word, destRowIndex=" + destRowIndex);
-    } else {
-      destRowIndex = selectedTokenRowIndex;
-      Log.d(LOG, "onUpButton, jumping to top of word, destRowIndex=" + destRowIndex);
-    }
+    final int destRowIndex = languageList.languageData.getPrevTokenRow(lastSelectedRow);
+    Log.d(LOG, "onUpButton, destRowIndex=" + destRowIndex);
     jumpToRow(languageList, destRowIndex);
   }
 
   void onDownButton() {
-    final Row tokenRow = languageList.languageData.rows
-        .get(selectedTokenRowIndex);
-    assert tokenRow.isToken();
-    final int nextTokenIndex = tokenRow.getIndex() + 1;
-    final int destRowIndex;
-    if (nextTokenIndex < languageList.languageData.sortedIndex.size()) {
-      destRowIndex = languageList.languageData.sortedIndex
-          .get(nextTokenIndex).startRow;
-      Log.d(LOG, "onDownButton, jumping down a word, destRowIndex=" + destRowIndex);
-    } else {
-      destRowIndex = languageList.languageData.rows.size() - 1;
-      Log.d(LOG, "onDownButton, jumping to end of dict, destRowIndex=" + destRowIndex);
-    }
+    final int destRowIndex = languageList.languageData.getNextTokenRow(lastSelectedRow);
+    Log.d(LOG, "onDownButton, destRowIndex=" + destRowIndex);
     jumpToRow(languageList, destRowIndex);
   }
 
   void onAppendToWordList() {
-    final int row = getSelectedItemPosition();
+    final int row = getSelectedRow();
     if (row < 0) {
       return;
     }
@@ -377,21 +367,17 @@ public class DictionaryActivity extends ListActivity {
       out.close();
     } catch (IOException e) {
       Log.e(LOG, "Unable to append to " + wordList.getAbsolutePath(), e);
-      final AlertDialog alert = new AlertDialog.Builder(
-          DictionaryActivity.this).create();
-      alert.setMessage("Failed to append to file: "
-          + wordList.getAbsolutePath());
-      alert.show();
+      Toast.makeText(this, getString(R.string.failedAddingToWordList, wordList.getAbsolutePath()), Toast.LENGTH_LONG);
     }
     return;
   }
 
   void onCopy() {
-    final int row = getSelectedItemPosition();
+    final int row = getSelectedRow();
     if (row < 0) {
       return;
     }
-    Log.d(LOG, "Copy." + DictionaryActivity.this.getSelectedItemPosition());
+    Log.d(LOG, "Copy." + DictionaryActivity.this.getSelectedRow());
     final StringBuilder result = new StringBuilder();
     result.append(getSelectedRowRawText());
     final ClipboardManager clipboardManager = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
@@ -420,10 +406,14 @@ public class DictionaryActivity extends ListActivity {
 
   void onSearchTextChange(final String searchText) {
     Log.d(LOG, "onSearchTextChange: " + searchText);
-    searchOperation = new SearchOperation(languageList, searchText, searchOperation);
-    searchExecutor.execute(searchOperation);
+    synchronized (this) {
+      searchOperation = new SearchOperation(languageList, searchText, searchOperation);
+      searchExecutor.execute(searchOperation);
+    }
   }
 
+  
+
   // ----------------------------------------------------------------
   // ContextMenu
   // ----------------------------------------------------------------
@@ -431,13 +421,12 @@ public class DictionaryActivity extends ListActivity {
   @Override
   public void onCreateContextMenu(ContextMenu menu, View v,
       ContextMenuInfo menuInfo) {
-    final int row = getSelectedItemPosition();
+    final int row = getSelectedRow();
     if (row < 0) {
       return;
     }
 
-    final MenuItem addToWordlist = menu.add(String.format(
-        getString(R.string.addToWordList), wordList.getName()));
+    final MenuItem addToWordlist = menu.add(getString(R.string.addToWordList, wordList.getName()));
     addToWordlist.setOnMenuItemClickListener(new OnMenuItemClickListener() {
       public boolean onMenuItemClick(MenuItem item) {
         onAppendToWordList();
@@ -462,21 +451,30 @@ public class DictionaryActivity extends ListActivity {
       Log.w(LOG, "skipping jumpToRow for old list adapter: " + rowIndex);
       return;
     }
-    // selectedTokenRowIndex =
-    // languageList.languageData.getIndexEntryForRow(rowIndex).startRow;
     setSelection(rowIndex);
-    getListView().setSelected(true); // TODO: is this doing anything?
+    lastSelectedRow = rowIndex;  // TODO: find a way to delete this.
     updateSearchText();
+    getListView().setSelected(true);
+  }
+  
+  // TODO: delete me somehow.
+  private int getSelectedRow() {
+    return lastSelectedRow;
   }
 
   private void updateSearchText() {
     Log.d(LOG, "updateSearchText");
+    final int selectedRowIndex = getSelectedRow();
     if (!searchText.hasFocus()) {
-      final String word = languageList.languageData
-          .getIndexEntryForRow(selectedRowIndex).word;
-      if (!word.equals(searchText.getText().toString())) {
-        Log.d(LOG, "updateSearchText: setText: " + word);
-        searchText.setText(word);
+      if (selectedRowIndex >= 0) {
+        final String word = languageList.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.");
       }
     }
   }
@@ -601,7 +599,7 @@ public class DictionaryActivity extends ListActivity {
     final LanguageData languageData;
     final String searchText;
     final AtomicBoolean interrupted = new AtomicBoolean(false);
-    boolean finished = false;
+    boolean searchFinished = false;
 
     SearchOperation(final LanguageListAdapter listAdapter,
         final String searchText, final SearchOperation previousSearchOperation) {
@@ -619,32 +617,34 @@ public class DictionaryActivity extends ListActivity {
       
       Log.d(LOG, "SearchOperation: " + searchText);
       final int indexLocation = languageData.lookup(searchText, interrupted);
-      if (interrupted.get()) {
-        return;
-      }
-      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);
+      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) {
-        finished = true;
+        searchFinished = true;
         this.notifyAll();
       }
     }
     
-    public void stopAndWait() {
+    private void stopAndWait() {
       interrupted.set(true);
       synchronized (this) {
-        while (!finished) {
+        while (!searchFinished) {
           Log.d(LOG, "stopAndWait: " + searchText);
           try {
             this.wait();
@@ -654,8 +654,18 @@ public class DictionaryActivity extends ListActivity {
         }
       }
     }
-
-
+  }  // SearchOperation
+
+  void waitForSearchEnd() {
+    synchronized (this) {
+      while (searchOperation != null) {
+        try {
+          this.wait();
+        } catch (InterruptedException e) {
+          Log.e(LOG, "Interrupted.", e);
+        }
+      }
+    }
   }
 
   private class SearchTextWatcher implements TextWatcher {
index 5afcb229d033c07313c1cee9eb6dfe66c1d22a04..ea6b692906343da6b481576cde1e3b2310435cae 100755 (executable)
@@ -12,32 +12,125 @@ public class DictionaryActivityTest extends ActivityInstrumentationTestCase2<Dic
     final DictionaryActivity dict = getActivity();\r
     dict.finish();\r
   }\r
+  \r
+  abstract class NotifyRunnable implements Runnable {\r
+    boolean finished = false;\r
+    public final void run() {\r
+      assertEquals(false, finished);\r
+      run2();\r
+      synchronized (this) {\r
+        finished = true;\r
+        this.notifyAll();\r
+      }\r
+    }\r
+    public void waitForFinish() throws InterruptedException {\r
+      synchronized (this) {\r
+        while (!finished) {\r
+          this.wait();\r
+        }\r
+        finished = false;\r
+      }\r
+      getActivity().waitForSearchEnd();\r
+    }\r
+    protected abstract void run2();\r
+  }\r
 \r
-  public void testSwitchLanguage() throws Exception {\r
+  private void postAndWait(final NotifyRunnable notifyRunnable) throws Exception {\r
+    getActivity().uiHandler.post(notifyRunnable);\r
+    notifyRunnable.waitForFinish();\r
+  }\r
 \r
+  public void resetDictionary() throws Exception {\r
     final DictionaryActivity dict = getActivity();\r
-\r
-    final Runnable switchLang = new Runnable() {\r
-      public void run() {\r
-        getActivity().onLanguageButton();\r
-      }};\r
-\r
+    \r
     if (dict.languageList.languageData.language == Language.EN) {\r
-      dict.uiHandler.post(switchLang);\r
-      Thread.sleep(100);\r
+      postAndWait(switchLangRunnable());\r
     }\r
-    \r
     assertEquals(Language.DE, dict.languageList.languageData.language);\r
-      \r
-    dict.uiHandler.post(switchLang);\r
-    Thread.sleep(100);\r
+\r
+    postAndWait(new NotifyRunnable() {\r
+      protected void run2() {\r
+        dict.searchText.setText("");\r
+        dict.onSearchTextChange("");\r
+      }\r
+    });\r
+  }\r
+\r
+  public void testSwitchLanguage() throws Exception {\r
+    final DictionaryActivity dict = getActivity();\r
+    resetDictionary();\r
+\r
+    final NotifyRunnable switchLang = switchLangRunnable();\r
+\r
+    postAndWait(switchLang);\r
     assertEquals(Language.EN, dict.languageList.languageData.language);\r
+    assertEquals("EN", dict.langButton.getText().toString());\r
 \r
-    dict.uiHandler.post(switchLang);\r
-    Thread.sleep(200);\r
+    postAndWait(switchLang);\r
     assertEquals(Language.DE, dict.languageList.languageData.language);\r
+    assertEquals("DE", dict.langButton.getText().toString());\r
     \r
     dict.finish();\r
   }\r
 \r
+  public void testUpDownArrows() throws Exception {\r
+    final DictionaryActivity dict = getActivity();\r
+    resetDictionary();\r
+    assertEquals(0, dict.getSelectedItemPosition());\r
+    \r
+    final NotifyRunnable upButton = new NotifyRunnable() {\r
+      protected void run2() {\r
+        dict.onUpButton();\r
+      }\r
+    };\r
+    final NotifyRunnable downButton = new NotifyRunnable() {\r
+      protected void run2() {\r
+        dict.onDownButton();\r
+      }\r
+    };\r
+    \r
+    dict.getListView().requestFocus();\r
+    assertTrue(dict.getListView().isFocused());\r
+    \r
+    String word1 = "-1";\r
+    String word2 = "-14";\r
+    String word3 = "-15";\r
+\r
+    postAndWait(upButton);\r
+    assertEquals(0, dict.getSelectedItemPosition());\r
+    assertEquals(word1, dict.searchText.getText().toString());\r
+\r
+    postAndWait(downButton);\r
+    assertEquals(2, dict.getSelectedItemPosition());\r
+    assertEquals(word2, dict.searchText.getText().toString());\r
+    \r
+    postAndWait(downButton);\r
+    assertEquals(4, dict.getSelectedItemPosition());\r
+    assertEquals(word3, dict.searchText.getText().toString());\r
+\r
+    postAndWait(upButton);\r
+    assertEquals(2, dict.getSelectedItemPosition());\r
+    assertEquals(word2, dict.searchText.getText().toString());\r
+    \r
+    postAndWait(upButton);\r
+    assertEquals(0, dict.getSelectedItemPosition());\r
+    assertEquals(word1, dict.searchText.getText().toString());\r
+    \r
+    postAndWait(upButton);\r
+    assertEquals(0, dict.getSelectedItemPosition());\r
+\r
+    postAndWait(downButton);\r
+    assertEquals(2, dict.getSelectedItemPosition());\r
+\r
+    dict.finish();\r
+  }\r
+\r
+  private NotifyRunnable switchLangRunnable() {\r
+    final NotifyRunnable switchLang = new NotifyRunnable() {\r
+      public void run2() {\r
+        getActivity().onLanguageButton();\r
+      }};\r
+    return switchLang;\r
+  }\r
+\r
 }\r
index b2f8c45261835bf91fe0dd4ccd620be6d698396f..87e87a307ef0d83e89f4229c375432aa3d432993 100755 (executable)
@@ -9,6 +9,7 @@ import java.util.LinkedHashSet;
 import java.util.List;\r
 import java.util.Map;\r
 import java.util.Set;\r
+import java.util.regex.Matcher;\r
 import java.util.regex.Pattern;\r
 \r
 import com.hughes.util.raf.RAFFactory;\r
@@ -104,10 +105,52 @@ public final class Entry implements RAFSerializable<Entry> {
     return lang == LANG1 ? LANG2 : LANG1;\r
   }\r
   \r
-\r
+/*\r
+Lu     Letter, Uppercase\r
+Ll  Letter, Lowercase\r
+Lt  Letter, Titlecase\r
+Lm  Letter, Modifier\r
+Lo  Letter, Other\r
+Mn  Mark, Nonspacing\r
+Mc  Mark, Spacing Combining\r
+Me  Mark, Enclosing\r
+Nd  Number, Decimal Digit\r
+Nl  Number, Letter\r
+No  Number, Other\r
+Pc  Punctuation, Connector\r
+Pd  Punctuation, Dash\r
+Ps  Punctuation, Open\r
+Pe  Punctuation, Close\r
+Pi  Punctuation, Initial quote (may behave like Ps or Pe depending on usage)\r
+Pf  Punctuation, Final quote (may behave like Ps or Pe depending on usage)\r
+Po  Punctuation, Other\r
+Sm  Symbol, Math\r
+Sc  Symbol, Currency\r
+Sk  Symbol, Modifier\r
+So  Symbol, Other\r
+Zs  Separator, Space\r
+Zl  Separator, Line\r
+Zp  Separator, Paragraph\r
+*/\r
+\r
+  static Pattern htmlDecimalCode = Pattern.compile("&#([0-9]+);");\r
+  static Pattern htmlCode = Pattern.compile("&#[^;]+;");\r
+  \r
   static Entry parseFromLine(String line, final boolean hasMultipleSubentries) {\r
+    \r
     line = line.replaceAll("&lt;", "<");\r
     line = line.replaceAll("&gt;", ">");\r
+    Matcher matcher;\r
+    while ((matcher = htmlDecimalCode.matcher(line)).find()) {\r
+      final int intVal = Integer.parseInt(matcher.group(1));\r
+      final String charCode = "" + ((char) intVal);\r
+      System.out.println("Replacing " + matcher.group() + " with " + charCode);\r
+      line = matcher.replaceAll(charCode);\r
+    }\r
+    if ((matcher = htmlCode.matcher(line)).find()) {\r
+      System.err.println("HTML code: " + matcher.group());\r
+    }\r
+    \r
     final String[] parts = lineSplitPattern.split(line);\r
     if (parts.length != 2) {\r
       System.err.println("Entry:" + "Invalid line: " + line);\r
@@ -136,7 +179,8 @@ public final class Entry implements RAFSerializable<Entry> {
     bracketToClose.put(" '", "' ");\r
   }\r
   \r
-  static final Pattern WHITESPACE = Pattern.compile("\\s+");\r
+  // This used to be called WHITESPACE.\r
+  static final Pattern NON_TOKEN_CHAR = Pattern.compile("\\s+");\r
   \r
   public Set<String> getIndexableTokens(final byte lang) {\r
     final Set<String> result = new LinkedHashSet<String>();\r
@@ -150,17 +194,16 @@ public final class Entry implements RAFSerializable<Entry> {
     text = text.replaceAll("\"-", "-");\r
     text = text.replaceAll("-\"", "-");\r
     text = text.replaceAll("[\"/\\()<>\\[\\],;?!.]", " ");\r
-    text = text.replaceAll("[:] ", " ");\r
-    text = text.replaceAll(" [:]", " ");\r
+    text = text.replaceAll("[-:] ", " ");\r
+    text = text.replaceAll(" [-:]", " ");\r
     \r
     // Now be really conservative about what we allow inside a token:\r
     // See: http://unicode.org/Public/UNIDATA/UCD.html#General_Category_Values\r
-    text = text.replaceAll("[^-:\\p{Lu}\\p{Ll}\\p{Lt}\\p{Lm}\\p{Lo}\\p{Nd}\\p{Nl}\\p{No}]", " ");\r
-    \r
-    result.addAll(Arrays.asList(WHITESPACE.split(text)));\r
+    text = text.replaceAll("[^-:\\p{L}\\p{N}\\p{S}]", " ");\r
+    result.addAll(Arrays.asList(NON_TOKEN_CHAR.split(text)));\r
 \r
     text = text.replaceAll("[-]", " ");\r
-    result.addAll(Arrays.asList(WHITESPACE.split(text)));\r
+    result.addAll(Arrays.asList(NON_TOKEN_CHAR.split(text)));\r
     \r
     final Set<String> result2 = new LinkedHashSet<String>();\r
     for (final String token : result) {\r
index 9633a689ad4fb85b934b27363ad2c97484ef4dca..c2093c6606b567091ea8c6abde33dc0afbc2ae5e 100755 (executable)
@@ -1,5 +1,7 @@
 package com.hughes.android.dictionary;\r
 \r
+import java.io.File;\r
+\r
 import android.app.Activity;\r
 import android.content.Intent;\r
 import android.content.SharedPreferences;\r
@@ -22,8 +24,14 @@ public class NoDictionaryActivity extends Activity {
       final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);\r
       final String dictFile = prefs.getString(getString(R.string.dictFileKey), getString(R.string.dictFileDefault));\r
 \r
-      final TextView noDictText = (TextView) findViewById(R.id.noDictTextId);\r
-      noDictText.setText(String.format(getString(R.string.unableToReadDictionaryFile), dictFile));\r
+      final boolean canReadDict = new File(dictFile).canRead();\r
+        \r
+      final TextView statusText = (TextView) findViewById(R.id.statusTextId);\r
+      if (!canReadDict) {\r
+        statusText.setText(String.format(getString(R.string.unableToReadDictionaryFile), dictFile));\r
+      } else {\r
+        statusText.setText(String.format(getString(R.string.unableToReadDictionaryFile), dictFile));\r
+      }\r
 \r
       final Button downloadButton = (Button) findViewById(R.id.downloadDict);\r
       downloadButton.setOnClickListener(new OnClickListener() {\r
@@ -36,6 +44,13 @@ public class NoDictionaryActivity extends Activity {
         public void onClick(View arg0) {\r
           startActivity(new Intent(NoDictionaryActivity.this, PreferenceActivity.class));\r
         }});\r
-  }\r
+\r
+      final Button launchButton = (Button) findViewById(R.id.launchDict);\r
+      launchButton.setEnabled(canReadDict);\r
+      launchButton.setOnClickListener(new OnClickListener() {\r
+        public void onClick(View arg0) {\r
+          startActivity(new Intent(NoDictionaryActivity.this, DictionaryActivity.class));\r
+        }});\r
+}\r
 \r
 }\r