]> gitweb.fperrin.net Git - Dictionary.git/blobdiff - src/com/hughes/android/dictionary/DictionaryApplication.java
Using external storage dir properly, better notifications when missing.
[Dictionary.git] / src / com / hughes / android / dictionary / DictionaryApplication.java
index 3670a1fd10dddf0598181da8260085fec6c15dc3..30d8067158303bf0d38b023e3f681a9c4da2904b 100644 (file)
 
 package com.hughes.android.dictionary;
 
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
 import android.app.Application;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
 import android.net.Uri;
+import android.os.Environment;
 import android.preference.PreferenceManager;
 import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MenuItem.OnMenuItemClickListener;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.ImageView.ScaleType;
+import android.widget.LinearLayout;
 
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuItem;
+import com.actionbarsherlock.view.MenuItem.OnMenuItemClickListener;
 import com.hughes.android.dictionary.DictionaryInfo.IndexInfo;
 import com.hughes.android.dictionary.engine.Dictionary;
 import com.hughes.android.dictionary.engine.Language;
 import com.hughes.android.dictionary.engine.TransliteratorManager;
+import com.hughes.android.dictionary.engine.Language.LanguageResources;
+import com.hughes.android.util.IntentLauncher;
 import com.hughes.android.util.PersistentObjectCache;
 import com.hughes.util.ListUtil;
 import com.ibm.icu.text.Collator;
 
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
 public class DictionaryApplication extends Application {
   
   static final String LOG = "QuickDicApp";
   
   // Static, determined by resources (and locale).
   // Unordered.
-  static Map<String,DictionaryInfo> DOWNLOADABLE_NAME_TO_INFO = null;
+  static Map<String,DictionaryInfo> DOWNLOADABLE_UNCOMPRESSED_FILENAME_NAME_TO_DICTIONARY_INFO = null;
   
   static final class DictionaryConfig implements Serializable {
     private static final long serialVersionUID = -1444177164708201263L;
     // User-ordered list, persisted, just the ones that are/have been present.
     final List<String> dictionaryFilesOrdered = new ArrayList<String>();
-    final Map<String, DictionaryInfo> dictionaryInfoCache = new LinkedHashMap<String, DictionaryInfo>();
+    
+    final Map<String, DictionaryInfo> uncompressedFilenameToDictionaryInfo = new LinkedHashMap<String, DictionaryInfo>();
   }
   DictionaryConfig dictionaryConfig = null;
-
-  static final class DictionaryHistory implements Serializable {
-    private static final long serialVersionUID = -4842995032541390284L;
-    // User-ordered list, persisted, just the ones that are/have been present.
-    final List<DictionaryLink> dictionaryLinks = new ArrayList<DictionaryLink>();
-  }
-  DictionaryHistory dictionaryHistory = null;
   
-  private File dictDir;
+  
+  int languageButtonPixels = 22;
 
+//  static final class DictionaryHistory implements Serializable {
+//    private static final long serialVersionUID = -4842995032541390284L;
+//    // User-ordered list, persisted, just the ones that are/have been present.
+//    final List<DictionaryLink> dictionaryLinks = new ArrayList<DictionaryLink>();
+//  }
+//  DictionaryHistory dictionaryHistory = null;
+  
   static synchronized void staticInit(final Context context) {
-    if (DOWNLOADABLE_NAME_TO_INFO != null) {
+    if (DOWNLOADABLE_UNCOMPRESSED_FILENAME_NAME_TO_DICTIONARY_INFO != null) {
       return;
     }
-    DOWNLOADABLE_NAME_TO_INFO = new LinkedHashMap<String,DictionaryInfo>();
-    final BufferedReader reader = new BufferedReader(new InputStreamReader(context.getResources().openRawResource(R.raw.dictionary_info)));
+    DOWNLOADABLE_UNCOMPRESSED_FILENAME_NAME_TO_DICTIONARY_INFO = new LinkedHashMap<String,DictionaryInfo>();
+    final BufferedReader reader = new BufferedReader(
+            new InputStreamReader(context.getResources().openRawResource(R.raw.dictionary_info)));
     try {
       String line;
       while ((line = reader.readLine()) != null) {
@@ -85,7 +99,8 @@ public class DictionaryApplication extends Application {
           continue;
         }
         final DictionaryInfo dictionaryInfo = new DictionaryInfo(line);
-        DOWNLOADABLE_NAME_TO_INFO.put(dictionaryInfo.uncompressedFilename, dictionaryInfo);
+        DOWNLOADABLE_UNCOMPRESSED_FILENAME_NAME_TO_DICTIONARY_INFO.put(
+                dictionaryInfo.uncompressedFilename, dictionaryInfo);
       }
       reader.close();
     } catch (IOException e) {
@@ -94,6 +109,8 @@ public class DictionaryApplication extends Application {
   }
 
   
+  private File dictDir;
+
   @Override
   public void onCreate() {
     super.onCreate();
@@ -101,8 +118,12 @@ public class DictionaryApplication extends Application {
     TransliteratorManager.init(null);
     staticInit(getApplicationContext());
     
+    languageButtonPixels = (int) TypedValue.applyDimension(
+            TypedValue.COMPLEX_UNIT_DIP, 60, getResources().getDisplayMetrics());
+    
     // Load the dictionaries we know about.
-    dictionaryConfig = PersistentObjectCache.init(getApplicationContext()).read(C.DICTIONARY_CONFIGS, DictionaryConfig.class);
+    dictionaryConfig = PersistentObjectCache.init(getApplicationContext()).read(
+            C.DICTIONARY_CONFIGS, DictionaryConfig.class);
     if (dictionaryConfig == null) {
       dictionaryConfig = new DictionaryConfig();
     }
@@ -125,6 +146,7 @@ public class DictionaryApplication extends Application {
   public void onCreateGlobalOptionsMenu(
       final Context context, final Menu menu) {
     final MenuItem about = menu.add(getString(R.string.about));
+    about.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
     about.setOnMenuItemClickListener(new OnMenuItemClickListener() {
       public boolean onMenuItemClick(final MenuItem menuItem) {
         final Intent intent = new Intent().setClassName(AboutActivity.class
@@ -135,14 +157,16 @@ public class DictionaryApplication extends Application {
     });
 
     final MenuItem help = menu.add(getString(R.string.help));
+    help.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
     help.setOnMenuItemClickListener(new OnMenuItemClickListener() {
       public boolean onMenuItemClick(final MenuItem menuItem) {
-        context.startActivity(HelpActivity.getLaunchIntent());
+        context.startActivity(HtmlDisplayActivity.getHelpLaunchIntent());
         return false;
       }
     });
 
-    final MenuItem preferences = menu.add(getString(R.string.preferences));
+    final MenuItem preferences = menu.add(getString(R.string.settings));
+    preferences.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
     preferences.setOnMenuItemClickListener(new OnMenuItemClickListener() {
       public boolean onMenuItemClick(final MenuItem menuItem) {
         PreferenceActivity.prefsMightHaveChanged = true;
@@ -155,6 +179,7 @@ public class DictionaryApplication extends Application {
     
     
     final MenuItem reportIssue = menu.add(getString(R.string.reportIssue));
+    reportIssue.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
     reportIssue.setOnMenuItemClickListener(new OnMenuItemClickListener() {
       public boolean onMenuItemClick(final MenuItem menuItem) {
         final Intent intent = new Intent(Intent.ACTION_VIEW);
@@ -166,14 +191,17 @@ public class DictionaryApplication extends Application {
   }
   
   public synchronized File getDictDir() {
-    // This metaphore doesn't work, because we've already reset prefsMightHaveChanged.
+    // This metaphor doesn't work, because we've already reset prefsMightHaveChanged.
 //    if (dictDir == null || PreferenceActivity.prefsMightHaveChanged) {
       final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
-      final String dir = prefs.getString(getString(R.string.quickdicDirectoryKey), getString(R.string.quickdicDirectoryDefault));
+      final File defaultDictDir = new File(Environment.getExternalStorageDirectory(), "quickDic");
+      String dir = prefs.getString(getString(R.string.quickdicDirectoryKey), defaultDictDir.getAbsolutePath());
+      if (dir.isEmpty()) {
+          dir = defaultDictDir.getAbsolutePath();
+      }
       dictDir = new File(dir);
       dictDir.mkdirs();
-//    }
-    return dictDir;
+      return dictDir;
   }
   
   public C.Theme getSelectedTheme() {
@@ -190,23 +218,38 @@ public class DictionaryApplication extends Application {
     return new File(getDictDir(), uncompressedFilename);
   }
   
-  
-  
+
   String defaultLangISO2 = Locale.getDefault().getLanguage().toLowerCase();
+  String defaultLangName = null;
   final Map<String, String> fileToNameCache = new LinkedHashMap<String, String>();
 
-  public String getLanguageName(final String isoCode) {
+  public String isoCodeToLocalizedLanguageName(final String isoCode) {
     final Language.LanguageResources languageResources = Language.isoCodeToResources.get(isoCode); 
     final String lang = languageResources != null ? getApplicationContext().getString(languageResources.nameId) : isoCode;
     return lang;
   }
   
+  public List<IndexInfo> sortedIndexInfos(List<IndexInfo> indexInfos) {
+      // Hack to put the default locale first in the name.
+      if (indexInfos.size() > 1 && 
+          indexInfos.get(1).shortName.toLowerCase().equals(defaultLangISO2)) {
+        List<IndexInfo> result = new ArrayList<DictionaryInfo.IndexInfo>(indexInfos);
+        ListUtil.swap(result, 0, 1);
+        return result;
+      }
+      return indexInfos;
+  }
+  
 
   public synchronized String getDictionaryName(final String uncompressedFilename) {
     final String currentLocale = Locale.getDefault().getLanguage().toLowerCase(); 
     if (!currentLocale.equals(defaultLangISO2)) {
       defaultLangISO2 = currentLocale;
       fileToNameCache.clear();
+      defaultLangName = null;
+    }
+    if (defaultLangName == null) {
+      defaultLangName = isoCodeToLocalizedLanguageName(defaultLangISO2);
     }
     
     String name = fileToNameCache.get(uncompressedFilename);
@@ -214,25 +257,16 @@ public class DictionaryApplication extends Application {
       return name;
     }
     
-    final DictionaryInfo dictionaryInfo = DOWNLOADABLE_NAME_TO_INFO.get(uncompressedFilename);
+    final DictionaryInfo dictionaryInfo = DOWNLOADABLE_UNCOMPRESSED_FILENAME_NAME_TO_DICTIONARY_INFO.get(uncompressedFilename);
     if (dictionaryInfo != null) {
       final StringBuilder nameBuilder = new StringBuilder();
 
-      // Hack to put the default locale first in the name.
-      boolean swapped = false;
-      if (dictionaryInfo.indexInfos.size() > 1 && 
-          dictionaryInfo.indexInfos.get(1).shortName.toLowerCase().equals(defaultLangISO2)) {
-        ListUtil.swap(dictionaryInfo.indexInfos, 0, 1);
-        swapped = true;
-      }
-      for (int i = 0; i < dictionaryInfo.indexInfos.size(); ++i) {
+      List<IndexInfo> sortedIndexInfos = sortedIndexInfos(dictionaryInfo.indexInfos);
+      for (int i = 0; i < sortedIndexInfos.size(); ++i) {
         if (i > 0) {
           nameBuilder.append("-");
         }
-        nameBuilder.append(getLanguageName(dictionaryInfo.indexInfos.get(i).shortName));
-      }
-      if (swapped) {
-        ListUtil.swap(dictionaryInfo.indexInfos, 0, 1);
+        nameBuilder.append(isoCodeToLocalizedLanguageName(sortedIndexInfos.get(i).shortName));
       }
       name = nameBuilder.toString();
     } else {
@@ -241,6 +275,28 @@ public class DictionaryApplication extends Application {
     fileToNameCache.put(uncompressedFilename, name);
     return name;
   }
+  
+  public View createButton(final Context context, final DictionaryInfo dictionaryInfo,
+          final IndexInfo indexInfo) {
+      LanguageResources languageResources = Language.isoCodeToResources.get(indexInfo.shortName);
+      View result;
+            
+      if (languageResources == null || languageResources.flagId <= 0) {
+          Button button = new Button(context);
+          button.setText(indexInfo.shortName);
+          result = button;
+      } else {
+          ImageButton button = new ImageButton(context);
+          button.setImageResource(languageResources.flagId);
+          button.setScaleType(ScaleType.FIT_CENTER);
+          result = button;
+      }
+      result.setMinimumWidth(languageButtonPixels);
+      result.setMinimumHeight(languageButtonPixels * 2 / 3);
+//      result.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+      return result;
+  }
+
 
   public synchronized void moveDictionaryToTop(final DictionaryInfo dictionaryInfo) {
     dictionaryConfig.dictionaryFilesOrdered.remove(dictionaryInfo.uncompressedFilename);
@@ -250,7 +306,7 @@ public class DictionaryApplication extends Application {
 
   public synchronized void deleteDictionary(final DictionaryInfo dictionaryInfo) {
     while (dictionaryConfig.dictionaryFilesOrdered.remove(dictionaryInfo.uncompressedFilename)) {};
-    dictionaryConfig.dictionaryInfoCache.remove(dictionaryInfo.uncompressedFilename);
+    dictionaryConfig.uncompressedFilenameToDictionaryInfo.remove(dictionaryInfo.uncompressedFilename);
     getPath(dictionaryInfo.uncompressedFilename).delete();
     PersistentObjectCache.getInstance().write(C.DICTIONARY_CONFIGS, dictionaryConfig);
   }
@@ -259,12 +315,25 @@ public class DictionaryApplication extends Application {
   final Comparator<String> uncompressedFilenameComparator = new Comparator<String>() {
     @Override
     public int compare(String uncompressedFilename1, String uncompressedFilename2) {
-      return collator.compare(getDictionaryName(uncompressedFilename1), getDictionaryName(uncompressedFilename2));
+      final String name1 = getDictionaryName(uncompressedFilename1);
+      final String name2 = getDictionaryName(uncompressedFilename2);
+      if (defaultLangName.length() > 0) {
+        if (name1.startsWith(defaultLangName + "-") && !name2.startsWith(defaultLangName + "-")) {
+          return -1;
+        } else if (name2.startsWith(defaultLangName + "-") && !name1.startsWith(defaultLangName + "-")) {
+          return 1;
+        }
+      }
+      return collator.compare(name1, name2);
     }
   };
   final Comparator<DictionaryInfo> dictionaryInfoComparator = new Comparator<DictionaryInfo>() {
     @Override
     public int compare(DictionaryInfo d1, DictionaryInfo d2) {
+      // Single-index dictionaries first.
+      if (d1.indexInfos.size() != d2.indexInfos.size()) {
+          return d1.indexInfos.size() - d2.indexInfos.size();
+      }
       return uncompressedFilenameComparator.compare(d1.uncompressedFilename, d2.uncompressedFilename);
     }
   };
@@ -283,7 +352,7 @@ public class DictionaryApplication extends Application {
           final DictionaryInfo dictionaryInfo = Dictionary.getDictionaryInfo(dictFile);
           if (dictionaryInfo != null) {
             newDictionaryConfig.dictionaryFilesOrdered.add(uncompressedFilename);
-            newDictionaryConfig.dictionaryInfoCache.put(uncompressedFilename, dictionaryInfo);
+            newDictionaryConfig.uncompressedFilenameToDictionaryInfo.put(uncompressedFilename, dictionaryInfo);
           }
         }
         
@@ -294,14 +363,14 @@ public class DictionaryApplication extends Application {
         if (dictDirFiles != null) {
           for (final File file : dictDirFiles) {
             if (file.getName().endsWith(".zip")) {
-              if (DOWNLOADABLE_NAME_TO_INFO.containsKey(file.getName().replace(".zip", ""))) {
+              if (DOWNLOADABLE_UNCOMPRESSED_FILENAME_NAME_TO_DICTIONARY_INFO.containsKey(file.getName().replace(".zip", ""))) {
                 file.delete();
               }
             }
             if (!file.getName().endsWith(".quickdic")) {
               continue;
             }
-            if (newDictionaryConfig.dictionaryInfoCache.containsKey(file.getName())) {
+            if (newDictionaryConfig.uncompressedFilenameToDictionaryInfo.containsKey(file.getName())) {
               // We have it in our list already.
               continue;
             }
@@ -312,7 +381,7 @@ public class DictionaryApplication extends Application {
             }
             
             toAddSorted.add(file.getName());
-            newDictionaryConfig.dictionaryInfoCache.put(file.getName(), dictionaryInfo);
+            newDictionaryConfig.uncompressedFilenameToDictionaryInfo.put(file.getName(), dictionaryInfo);
           }
         } else {
           Log.w(LOG, "dictDir is not a diretory: " + getDictDir().getPath());
@@ -334,42 +403,58 @@ public class DictionaryApplication extends Application {
         }
       }}).start();
   }
+  
+  public boolean matchesFilters(final DictionaryInfo dictionaryInfo, final String[] filters) {
+      if (filters == null) {
+          return true;
+      }
+      for (final String filter : filters) {
+          if (!getDictionaryName(dictionaryInfo.uncompressedFilename).toLowerCase().contains(filter)) {
+              return false;
+          }
+      }
+      return true;
+  }
 
-  public synchronized List<DictionaryInfo> getUsableDicts() {
+  public synchronized List<DictionaryInfo> getDictionariesOnDevice(String[] filters) {
     final List<DictionaryInfo> result = new ArrayList<DictionaryInfo>(dictionaryConfig.dictionaryFilesOrdered.size());
     for (final String uncompressedFilename : dictionaryConfig.dictionaryFilesOrdered) {
-      final DictionaryInfo dictionaryInfo = dictionaryConfig.dictionaryInfoCache.get(uncompressedFilename);
-      if (dictionaryInfo != null) {
+      final DictionaryInfo dictionaryInfo = dictionaryConfig.uncompressedFilenameToDictionaryInfo.get(uncompressedFilename);
+      if (dictionaryInfo != null && matchesFilters(dictionaryInfo, filters)) {
         result.add(dictionaryInfo);
       }
     }
     return result;
   }
-
-  public synchronized List<DictionaryInfo> getAllDictionaries() {
-    final List<DictionaryInfo> result = getUsableDicts();
-    
-    // The downloadable ones.
-    final Map<String,DictionaryInfo> remaining = new LinkedHashMap<String, DictionaryInfo>(DOWNLOADABLE_NAME_TO_INFO);
-    remaining.keySet().removeAll(dictionaryConfig.dictionaryFilesOrdered);
-    final List<DictionaryInfo> toAddSorted = new ArrayList<DictionaryInfo>(remaining.values());
-    Collections.sort(toAddSorted, dictionaryInfoComparator);
-    result.addAll(toAddSorted);
-    
-    return result;
+  
+  public List<DictionaryInfo> getDownloadableDictionaries(String[] filters) {
+      final List<DictionaryInfo> result = new ArrayList<DictionaryInfo>(dictionaryConfig.dictionaryFilesOrdered.size());
+      
+      final Map<String, DictionaryInfo> remaining = new LinkedHashMap<String, DictionaryInfo>(DOWNLOADABLE_UNCOMPRESSED_FILENAME_NAME_TO_DICTIONARY_INFO);
+      remaining.keySet().removeAll(dictionaryConfig.dictionaryFilesOrdered);
+      for (final DictionaryInfo dictionaryInfo : remaining.values()) {
+          if (matchesFilters(dictionaryInfo, filters)) {
+              result.add(dictionaryInfo);
+          }
+      }
+      Collections.sort(result, dictionaryInfoComparator);
+      return result;
   }
-
+  
   public synchronized boolean isDictionaryOnDevice(String uncompressedFilename) {
-    return dictionaryConfig.dictionaryInfoCache.get(uncompressedFilename) != null;
+    return dictionaryConfig.uncompressedFilenameToDictionaryInfo.get(uncompressedFilename) != null;
   }
 
   public boolean updateAvailable(final DictionaryInfo dictionaryInfo) {
-    final DictionaryInfo downloadable = DOWNLOADABLE_NAME_TO_INFO.get(dictionaryInfo.uncompressedFilename);
-    return downloadable != null && downloadable.creationMillis > dictionaryInfo.creationMillis;
+    final DictionaryInfo downloadable = 
+            DOWNLOADABLE_UNCOMPRESSED_FILENAME_NAME_TO_DICTIONARY_INFO.get(
+                    dictionaryInfo.uncompressedFilename);
+    return downloadable != null && 
+            downloadable.creationMillis > dictionaryInfo.creationMillis;
   }
 
   public DictionaryInfo getDownloadable(final String uncompressedFilename) {
-    final DictionaryInfo downloadable = DOWNLOADABLE_NAME_TO_INFO.get(uncompressedFilename);
+    final DictionaryInfo downloadable = DOWNLOADABLE_UNCOMPRESSED_FILENAME_NAME_TO_DICTIONARY_INFO.get(uncompressedFilename);
     return downloadable;
   }