]> gitweb.fperrin.net Git - Dictionary.git/blobdiff - src/com/hughes/android/dictionary/DictionaryActivity.java
Remove some margins that seem a bit overkill.
[Dictionary.git] / src / com / hughes / android / dictionary / DictionaryActivity.java
index d2b4a923623fa4534151baca54ce25655b220604..7517441d49c034cce939e2f661c894a4140e44c2 100644 (file)
@@ -42,6 +42,7 @@ import android.text.Spannable;
 import android.text.method.LinkMovementMethod;
 import android.text.style.ClickableSpan;
 import android.text.style.StyleSpan;
+import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.TypedValue;
 import android.view.ContextMenu;
@@ -98,6 +99,7 @@ import java.io.FileWriter;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.RandomAccessFile;
+import java.nio.channels.FileChannel;
 import java.text.SimpleDateFormat;
 import java.util.Arrays;
 import java.util.Collections;
@@ -123,7 +125,8 @@ public class DictionaryActivity extends ActionBarActivity {
     DictionaryApplication application;
 
     File dictFile = null;
-    RandomAccessFile dictRaf = null;
+    FileChannel dictRaf = null;
+    String dictFileTitleName = null;
 
     Dictionary dictionary = null;
 
@@ -223,12 +226,30 @@ public class DictionaryActivity extends ActionBarActivity {
         return search.length();
     }
 
+    private void dictionaryOpenFail(Exception e) {
+        Log.e(LOG, "Unable to load dictionary.", e);
+        if (dictRaf != null) {
+            try {
+                dictRaf.close();
+            } catch (IOException e1) {
+                Log.e(LOG, "Unable to close dictRaf.", e1);
+            }
+            dictRaf = null;
+        }
+        Toast.makeText(this, getString(R.string.invalidDictionary, "", e.getMessage()),
+                       Toast.LENGTH_LONG).show();
+        startActivity(DictionaryManagerActivity.getLaunchIntent(getApplicationContext()));
+        finish();
+    }
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
+        DictionaryApplication.INSTANCE.init(getApplicationContext());
+        application = DictionaryApplication.INSTANCE;
         // This needs to be before super.onCreate, otherwise ActionbarSherlock
         // doesn't makes the background of the actionbar white when you're
         // in the dark theme.
-        setTheme(((DictionaryApplication) getApplication()).getSelectedTheme().themeId);
+        setTheme(application.getSelectedTheme().themeId);
 
         Log.d(LOG, "onCreate:" + this);
         super.onCreate(savedInstanceState);
@@ -236,14 +257,22 @@ public class DictionaryActivity extends ActionBarActivity {
         final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
 
         // Don't auto-launch if this fails.
-        prefs.edit().remove(C.DICT_FILE).commit();
+        prefs.edit().remove(C.DICT_FILE).remove(C.INDEX_SHORT_NAME).commit();
 
         setContentView(R.layout.dictionary_activity);
 
-        application = (DictionaryApplication) getApplication();
         theme = application.getSelectedTheme();
         textColorFg = getResources().getColor(theme.tokenRowFgColor);
 
+        if (dictRaf != null) {
+            try {
+                dictRaf.close();
+            } catch (IOException e) {
+                Log.e(LOG, "Failed to close dictionary", e);
+            }
+            dictRaf = null;
+        }
+
         final Intent intent = getIntent();
         String intentAction = intent.getAction();
         /**
@@ -320,6 +349,18 @@ public class DictionaryActivity extends ActionBarActivity {
                 getIntent().putExtra(C.SEARCH_TOKEN, query);
             }
         }
+        // Support opening dictionary file directly
+        if (intentAction != null && intentAction.equals(Intent.ACTION_VIEW)) {
+            Uri uri = intent.getData();
+            intent.putExtra(C.DICT_FILE, uri.toString());
+            dictFileTitleName = uri.getLastPathSegment();
+            try {
+                dictRaf = getContentResolver().openAssetFileDescriptor(uri, "r").createInputStream().getChannel();
+            } catch (Exception e) {
+                dictionaryOpenFail(e);
+                return;
+            }
+        }
         /**
          * @author Dominik Köppl If no dictionary is chosen, use the default
          *         dictionary specified in the preferences If this step does
@@ -343,7 +384,7 @@ public class DictionaryActivity extends ActionBarActivity {
                 try {
                     Log.d(LOG, "Checking dictionary " + dics.get(i).uncompressedFilename);
                     final File dictfile = application.getPath(dics.get(i).uncompressedFilename);
-                    Dictionary dic = new Dictionary(new RandomAccessFile(dictfile, "r"));
+                    Dictionary dic = new Dictionary(new RandomAccessFile(dictfile, "r").getChannel());
                     for (int j = 0; j < dic.indices.size(); ++j) {
                         Index idx = dic.indices.get(j);
                         Log.d(LOG, "Checking index " + idx.shortName);
@@ -375,7 +416,7 @@ public class DictionaryActivity extends ActionBarActivity {
             finish();
             return;
         }
-        if (dictFilename != null)
+        if (dictRaf == null && dictFilename != null)
             dictFile = new File(dictFilename);
 
         ttsReady = false;
@@ -388,24 +429,14 @@ public class DictionaryActivity extends ActionBarActivity {
         });
 
         try {
-            final String name = application.getDictionaryName(dictFile.getName());
-            this.setTitle("QuickDic: " + name);
-            dictRaf = new RandomAccessFile(dictFile, "r");
+            if (dictRaf == null) {
+                dictFileTitleName = application.getDictionaryName(dictFile.getName());
+                dictRaf = new RandomAccessFile(dictFile, "r").getChannel();
+            }
+            this.setTitle("QuickDic: " + dictFileTitleName);
             dictionary = new Dictionary(dictRaf);
         } catch (Exception e) {
-            Log.e(LOG, "Unable to load dictionary.", e);
-            if (dictRaf != null) {
-                try {
-                    dictRaf.close();
-                } catch (IOException e1) {
-                    Log.e(LOG, "Unable to close dictRaf.", e1);
-                }
-                dictRaf = null;
-            }
-            Toast.makeText(this, getString(R.string.invalidDictionary, "", e.getMessage()),
-                           Toast.LENGTH_LONG).show();
-            startActivity(DictionaryManagerActivity.getLaunchIntent(getApplicationContext()));
-            finish();
+            dictionaryOpenFail(e);
             return;
         }
         String targetIndex = intent.getStringExtra(C.INDEX_SHORT_NAME);
@@ -421,27 +452,36 @@ public class DictionaryActivity extends ActionBarActivity {
         }
         Log.d(LOG, "Loading index " + indexIndex);
         index = dictionary.indices.get(indexIndex);
+        getListView().setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
         getListView().setEmptyView(findViewById(android.R.id.empty));
+        getListView().setOnItemClickListener(new OnItemClickListener() {
+            @Override
+            public void onItemClick(AdapterView<?> parent, View view, int row, long id) {
+                onListItemClick(getListView(), view, row, id);
+            }
+        });
+
         setListAdapter(new IndexAdapter(index));
 
+        // Pre-load the Transliterator (will spawn its own thread)
+        TransliteratorManager.init(new TransliteratorManager.Callback() {
+            @Override
+            public void onTransliteratorReady() {
+                uiHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        onSearchTextChange(searchView.getQuery().toString());
+                    }
+                });
+            }
+        }, DictionaryApplication.threadBackground);
+
         // Pre-load the collators.
         new Thread(new Runnable() {
             public void run() {
-                android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
+                android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_LESS_FAVORABLE);
                 final long startMillis = System.currentTimeMillis();
                 try {
-                    TransliteratorManager.init(new TransliteratorManager.Callback() {
-                        @Override
-                        public void onTransliteratorReady() {
-                            uiHandler.post(new Runnable() {
-                                @Override
-                                public void run() {
-                                    onSearchTextChange(searchView.getQuery().toString());
-                                }
-                            });
-                        }
-                    });
-
                     for (final Index index : dictionary.indices) {
                         final String searchToken = index.sortedIndexEntries.get(0).token;
                         final IndexEntry entry = index.findExact(searchToken);
@@ -523,7 +563,7 @@ public class DictionaryActivity extends ActionBarActivity {
         setSearchText(text, true);
         Log.d(LOG, "Trying to restore searchText=" + text);
 
-        setDictionaryPrefs(this, dictFile, index.shortName, searchView.getQuery().toString());
+        setDictionaryPrefs(this, dictFile, index.shortName);
 
         updateLangButton();
         searchView.requestFocus();
@@ -544,13 +584,6 @@ public class DictionaryActivity extends ActionBarActivity {
             ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
         customSearchView.setLayoutParams(layoutParams);
 
-        listView.setOnItemClickListener(new OnItemClickListener() {
-            @Override
-            public void onItemClick(AdapterView<?> parent, View view, int row, long id) {
-                onListItemClick(getListView(), view, row, id);
-            }
-        });
-
         languageButton = new ImageButton(customSearchView.getContext());
         languageButton.setId(R.id.languageButton);
         languageButton.setScaleType(ScaleType.FIT_CENTER);
@@ -645,12 +678,14 @@ public class DictionaryActivity extends ActionBarActivity {
     }
 
     private static void setDictionaryPrefs(final Context context, final File dictFile,
-                                           final String indexShortName, final String searchToken) {
+                                           final String indexShortName) {
         final SharedPreferences.Editor prefs = PreferenceManager.getDefaultSharedPreferences(
                 context).edit();
-        prefs.putString(C.DICT_FILE, dictFile.getPath());
-        prefs.putString(C.INDEX_SHORT_NAME, indexShortName);
-        prefs.putString(C.SEARCH_TOKEN, ""); // Don't need to save search token.
+        if (dictFile != null) {
+            prefs.putString(C.DICT_FILE, dictFile.getPath());
+            prefs.putString(C.INDEX_SHORT_NAME, indexShortName);
+        }
+        prefs.remove(C.SEARCH_TOKEN); // Don't need to save search token.
         prefs.commit();
     }
 
@@ -716,10 +751,9 @@ public class DictionaryActivity extends ActionBarActivity {
     }
 
     void updateLangButton() {
-        final LanguageResources languageResources =
-            DictionaryApplication.isoCodeToResources.get(index.shortName);
-        if (languageResources != null && languageResources.flagId != 0) {
-            languageButton.setImageResource(languageResources.flagId);
+        final int flagId = IsoUtils.INSTANCE.getFlagIdForIsoCode(index.shortName);
+        if (flagId != 0) {
+            languageButton.setImageResource(flagId);
         } else {
             if (indexIndex % 2 == 0) {
                 languageButton.setImageResource(android.R.drawable.ic_media_next);
@@ -802,10 +836,10 @@ public class DictionaryActivity extends ActionBarActivity {
 
                 final LinearLayout result = new LinearLayout(parent.getContext());
 
-                for (int i = 0; i < dictionaryInfo.indexInfos.size(); ++i) {
+                for (int i = 0; dictionaryInfo.indexInfos != null && i < dictionaryInfo.indexInfos.size(); ++i) {
                     final IndexInfo indexInfo = dictionaryInfo.indexInfos.get(i);
-                    final View button = application.createButton(parent.getContext(),
-                                        dictionaryInfo, indexInfo);
+                    final View button = IsoUtils.INSTANCE.createButton(parent.getContext(),
+                                        dictionaryInfo, indexInfo, application.languageButtonPixels);
                     final IntentLauncher intentLauncher = new IntentLauncher(parent.getContext(),
                             getLaunchIntent(getApplicationContext(),
                                             application.getPath(dictionaryInfo.uncompressedFilename),
@@ -958,16 +992,20 @@ public class DictionaryActivity extends ActionBarActivity {
                     dialog.setContentView(R.layout.about_dictionary_dialog);
                     final TextView textView = (TextView) dialog.findViewById(R.id.text);
 
-                    final String name = application.getDictionaryName(dictFile.getName());
-                    dialog.setTitle(name);
+                    dialog.setTitle(dictFileTitleName);
 
                     final StringBuilder builder = new StringBuilder();
                     final DictionaryInfo dictionaryInfo = dictionary.getDictionaryInfo();
-                    dictionaryInfo.uncompressedBytes = dictFile.length();
                     if (dictionaryInfo != null) {
+                        try {
+                            dictionaryInfo.uncompressedBytes = dictRaf.size();
+                        } catch (IOException e) {
+                        }
                         builder.append(dictionaryInfo.dictInfo).append("\n\n");
-                        builder.append(getString(R.string.dictionaryPath, dictFile.getPath()))
-                        .append("\n");
+                        if (dictFile != null) {
+                            builder.append(getString(R.string.dictionaryPath, dictFile.getPath()))
+                            .append("\n");
+                        }
                         builder.append(
                             getString(R.string.dictionarySize, dictionaryInfo.uncompressedBytes))
                         .append("\n");
@@ -1011,9 +1049,22 @@ public class DictionaryActivity extends ActionBarActivity {
 
     @Override
     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
-        AdapterContextMenuInfo adapterContextMenuInfo = (AdapterContextMenuInfo) menuInfo;
+        final AdapterContextMenuInfo adapterContextMenuInfo = (AdapterContextMenuInfo) menuInfo;
         final RowBase row = (RowBase) getListAdapter().getItem(adapterContextMenuInfo.position);
 
+        if (clickOpensContextMenu && (row instanceof HtmlEntry.Row ||
+            (row instanceof TokenRow && ((TokenRow)row).getIndexEntry().htmlEntries.size() > 0))) {
+            final List<HtmlEntry> html = row instanceof TokenRow ? ((TokenRow)row).getIndexEntry().htmlEntries : Collections.singletonList(((HtmlEntry.Row)row).getEntry());
+            final String highlight = row instanceof HtmlEntry.Row ? ((HtmlEntry.Row)row).getTokenRow(true).getToken() : null;
+            final MenuItem open = menu.add("Open");
+            open.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+                public boolean onMenuItemClick(MenuItem item) {
+                    showHtml(html, highlight);
+                    return false;
+                }
+            });
+        }
+
         final android.view.MenuItem addToWordlist = menu.add(getString(R.string.addToWordList,
                 wordList.getName()));
         addToWordlist
@@ -1075,6 +1126,37 @@ public class DictionaryActivity extends ActionBarActivity {
                 }
             });
         }
+        if (row instanceof PairEntry.Row && ttsReady) {
+            final List<Pair> pairs = ((PairEntry.Row)row).getEntry().pairs;
+            final MenuItem speakLeft = menu.add(R.string.speak_left);
+            speakLeft.setOnMenuItemClickListener(new android.view.MenuItem.OnMenuItemClickListener() {
+                @Override
+                public boolean onMenuItemClick(android.view.MenuItem item) {
+                    int idx = index.swapPairEntries ? 1 : 0;
+                    updateTTSLanguage(idx);
+                    String text = "";
+                    for (Pair p : pairs) text += p.get(idx);
+                    text = text.replaceAll("\\{[^{}]*\\}", "").replace("{", "").replace("}", "");
+                    textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH,
+                                       new HashMap<String, String>());
+                    return false;
+                }
+            });
+            final MenuItem speakRight = menu.add(R.string.speak_right);
+            speakRight.setOnMenuItemClickListener(new android.view.MenuItem.OnMenuItemClickListener() {
+                @Override
+                public boolean onMenuItemClick(android.view.MenuItem item) {
+                    int idx = index.swapPairEntries ? 0 : 1;
+                    updateTTSLanguage(idx);
+                    String text = "";
+                    for (Pair p : pairs) text += p.get(idx);
+                    text = text.replaceAll("\\{[^{}]*\\}", "").replace("{", "").replace("}", "");
+                    textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH,
+                                       new HashMap<String, String>());
+                    return false;
+                }
+            });
+        }
     }
 
     private void jumpToTextFromHyperLink(
@@ -1127,10 +1209,15 @@ public class DictionaryActivity extends ActionBarActivity {
         // searchView.selectAll();
     }
 
-    protected void onListItemClick(ListView l, View v, int row, long id) {
+    protected void onListItemClick(ListView l, View v, int rowIdx, long id) {
         defocusSearchText();
         if (clickOpensContextMenu && dictRaf != null) {
             openContextMenu(v);
+        } else {
+            final RowBase row = (RowBase)getListAdapter().getItem(rowIdx);
+            if (!(row instanceof PairEntry.Row)) {
+                v.performClick();
+            }
         }
     }
 
@@ -1211,7 +1298,7 @@ public class DictionaryActivity extends ActionBarActivity {
             indexAdapter = new IndexAdapter(index);
             setListAdapter(indexAdapter);
             Log.d(LOG, "changingIndex, newLang=" + index.longName);
-            setDictionaryPrefs(this, dictFile, index.shortName, searchView.getQuery().toString());
+            setDictionaryPrefs(this, dictFile, index.shortName);
             updateLangButton();
         }
         setSearchText(newSearchText, true, hideKeyboard);
@@ -1374,6 +1461,16 @@ public class DictionaryActivity extends ActionBarActivity {
     // IndexAdapter
     // --------------------------------------------------------------------------
 
+    private void showHtml(final List<HtmlEntry> htmlEntries, final String htmlTextToHighlight) {
+        String html = HtmlEntry.htmlBody(htmlEntries, index.shortName);
+        // Log.d(LOG, "html=" + html);
+        startActivityForResult(
+            HtmlDisplayActivity.getHtmlIntent(getApplicationContext(), String.format(
+                    "<html><head><meta name=\"viewport\" content=\"width=device-width\"></head><body>%s</body></html>", html),
+                                              htmlTextToHighlight, false),
+            0);
+    }
+
     static ViewGroup.LayoutParams WEIGHT_1 = new LinearLayout.LayoutParams(
         ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT, 1.0f);
 
@@ -1411,8 +1508,18 @@ public class DictionaryActivity extends ActionBarActivity {
         }
 
         private void getMetrics() {
+            float scale = 1;
             // Get the screen's density scale
-            final float scale = getResources().getDisplayMetrics().density;
+            // The previous method getResources().getDisplayMetrics()
+            // used to occasionally trigger a null pointer exception,
+            // so try this instead.
+            // As it still crashes, add a fallback
+            try {
+                DisplayMetrics dm = new DisplayMetrics();
+                getWindowManager().getDefaultDisplay().getMetrics(dm);
+                scale = dm.density;
+            } catch (NullPointerException e)
+            {}
             // Convert the dps to pixels, based on density scale
             mPaddingDefault = (int) (PADDING_DEFAULT_DP * scale + 0.5f);
             mPaddingLarge = (int) (PADDING_LARGE_DP * scale + 0.5f);
@@ -1476,16 +1583,13 @@ public class DictionaryActivity extends ActionBarActivity {
                 // Set the columns in the table.
                 if (r > 0) {
                     final TextView bullet = new TextView(tableRow.getContext());
-                    bullet.setText(" • ");
+                    bullet.setText(" •");
                     tableRow.addView(bullet);
                 }
                 tableRow.addView(col1, layoutParams);
-                final TextView margin = new TextView(tableRow.getContext());
-                margin.setText(" ");
-                tableRow.addView(margin);
                 if (r > 0) {
                     final TextView bullet = new TextView(tableRow.getContext());
-                    bullet.setText(" • ");
+                    bullet.setText(" •");
                     tableRow.addView(bullet);
                 }
                 tableRow.addView(col2, layoutParams);
@@ -1538,7 +1642,7 @@ public class DictionaryActivity extends ActionBarActivity {
             // http://groups.google.com/group/android-developers/browse_thread/thread/3d96af1530a7d62a?pli=1
             result.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
             result.setClickable(true);
-            result.setFocusable(true);
+            result.setFocusable(false);
             result.setLongClickable(true);
 //            result.setBackgroundResource(android.R.drawable.menuitem_background);
 
@@ -1605,16 +1709,17 @@ public class DictionaryActivity extends ActionBarActivity {
                 textView.setOnClickListener(new OnClickListener() {
                     @Override
                     public void onClick(View v) {
-                        String html = HtmlEntry.htmlBody(htmlEntries, index.shortName);
-                        // Log.d(LOG, "html=" + html);
-                        startActivityForResult(
-                            HtmlDisplayActivity.getHtmlIntent(getApplicationContext(), String.format(
-                                    "<html><head></head><body>%s</body></html>", html),
-                                                              htmlTextToHighlight, false),
-                            0);
+                        showHtml(htmlEntries, htmlTextToHighlight);
+                    }
+                });
+                result.setOnClickListener(new OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        textView.performClick();
                     }
                 });
             }
+            result.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
             return result;
         }