/**
* @ClassName:QueryProcessCenter.java
*/
package com.zhan_dui.dictionary.datacenter;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.holoeverywhere.preference.PreferenceManager;
import org.holoeverywhere.preference.SharedPreferences;
import org.xml.sax.SAXException;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Color;
import android.os.Environment;
import android.os.Handler;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.CharacterStyle;
import android.text.style.ForegroundColorSpan;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import com.zhan_dui.dictionary.datacenter.DictionaryParseInfomation.EchoViews;
import com.zhan_dui.dictionary.datacenter.DictionaryParseInfomation.TextArg;
import com.zhan_dui.dictionary.db.DictionaryDB;
import com.zhan_dui.dictionary.handlers.DictionaryXMLHandler;
import com.zhan_dui.dictionary.utils.Constants;
import com.zhan_dui.dictionary.utils.DisplayUtils;
/**
* @Description:负责整个词典单词的查询和排版工作
*
*/
public class QueryProcessor {
private static QueryProcessor mQueryProcessor;
/**
* 缓存所有的XML转换信息
*/
private static HashMap<String, DictionaryParseInfomation> mCacheXMLInformation = new HashMap<String, DictionaryParseInfomation>();
/**
* 缓存所有正在启用的字典
*/
private static ArrayList<DictionaryInfo> mCacheUsingDictionaries = new ArrayList<QueryProcessor.DictionaryInfo>();
/**
* 缓存所有的查询过的单词ID,这样,二次查询会极速无比
*/
private static HashMap<String, Integer> mCacheWordID = new HashMap<String, Integer>();
private static final int mCacheCountForWordsID = 60;
private final static String DB_PATH = Environment
.getExternalStorageDirectory()
+ File.separator
+ Constants.SAVE_DIRECTORY + File.separator;
public final static String DB_BASE_DIC = "dictionary_word.sqlite";
private static Boolean mIsGlobal = false;
private static Boolean mIsIndividual = false;
private static Boolean mIsIndividualTermNum = false;
private static Boolean mIsIndividualProperty = false;
private static Boolean mIsIndividualChinese = false;
private static Boolean mIsIndividualEnglish = false;
private static Boolean mIsIndividualExample = false;
private static class DictionaryInfo {
public DictionaryInfo(String DicName, String DicFileName,
String DicConfigFileName, String DicSaveDir) {
mDicDir = DicSaveDir;
mDicFileName = DicFileName;
mDicConfigFileName = DicConfigFileName;
mDicName = DicName;
}
/***
* 词典所在子目录,所有词典都会被解压在sdcard/dictionary下,mDicDir只是该字典的目录
*/
public String mDicDir;
/**
* 字典的名称 如 collins.dic 实际是一个sqlite文件
*/
public String mDicFileName;
/**
* 字典的配置文件 config-[字典名称]
*/
public String mDicConfigFileName;
/**
* 字典的中文名
*/
public String mDicName;
}
public class QueryResult {
private String DictionaryName;
private ScrollView DictionaryView;
public QueryResult(String dictionaryName, ScrollView dictionaryView) {
DictionaryName = dictionaryName;
DictionaryView = dictionaryView;
}
public String getDictionaryName() {
return DictionaryName;
}
public ScrollView getDictionaryView() {
return DictionaryView;
}
}
private static int mGlobalSize, mGlobalColor, mTermNumSize, mTermNumColor,
mPropertySize, mPropertyColor, mChineseSize, mChineseColor,
mEnglishSize, mEnglishColor, mExampleSize, mExampleColor;
// 更新排版的偏好设置
public static void updateFromPreference(Context context) {
SharedPreferences sharedPreferences = PreferenceManager
.getDefaultSharedPreferences(context);
mIsGlobal = sharedPreferences.getBoolean("global_effect", false);
mIsIndividual = sharedPreferences.getBoolean("individual", false);
mIsIndividualTermNum = sharedPreferences.getBoolean("term_number",
false);
mIsIndividualProperty = sharedPreferences.getBoolean(
"individual_property", false);
mIsIndividualChinese = sharedPreferences.getBoolean(
"chinese_explanation", false);
mIsIndividualEnglish = sharedPreferences.getBoolean(
"english_explanation", false);
mIsIndividualExample = sharedPreferences.getBoolean("example", false);
mGlobalSize = sharedPreferences.getInt("global_effect_size", 14);
mGlobalColor = sharedPreferences.getInt("global_effect_color",
Color.WHITE);
mPropertySize = sharedPreferences
.getInt("individual_property_size", 14);
mPropertyColor = sharedPreferences.getInt("individual_property_color",
Color.WHITE);
mChineseSize = sharedPreferences.getInt("chinese_explanation_size", 14);
mChineseColor = sharedPreferences.getInt("chinese_explanation_color",
Color.WHITE);
mEnglishSize = sharedPreferences.getInt("english_explanation_size", 14);
mEnglishColor = sharedPreferences.getInt("english_explanation_color",
Color.WHITE);
mExampleSize = sharedPreferences.getInt("example_size", 12);
mExampleColor = sharedPreferences.getInt("example_color", Color.WHITE);
}
private QueryProcessor(Context context) {
updateFromPreference(context);
updateCacheDictionaryList(context);
}
public static QueryProcessor instance(Context context) {
if (mQueryProcessor == null) {
mQueryProcessor = new QueryProcessor(context);
}
return mQueryProcessor;
}
public static void updateCacheDictionaryList(Context context) {
mCacheUsingDictionaries.clear();
DictionaryDB dictionaryDB = new DictionaryDB(context,
DictionaryDB.DB_NAME, null, DictionaryDB.DB_VERSION);
SQLiteDatabase sqLiteDatabase = dictionaryDB.getReadableDatabase();
Cursor cursor = sqLiteDatabase
.rawQuery(
"select * from `dictionary_list` where `dictionary_show`='1' and `dictionary_downloaded`='1' order by `dictionary_order` asc",
null);
while (cursor.moveToNext()) {
String dicname = cursor.getString(cursor
.getColumnIndex("dictionary_name"));
String filename = cursor.getString(
cursor.getColumnIndex("dictionary_save_name")).replace(
"zip", "dic");
String dirname = filename.substring(0, filename.length() - 4);
String configFileName = "config-" + filename;
DictionaryInfo dictionaryInfo = new DictionaryInfo(dicname,
filename, configFileName, dirname);
mCacheUsingDictionaries.add(dictionaryInfo);
}
sqLiteDatabase.close();
}
public int getDictionaryUsingCount() {
return mCacheUsingDictionaries.size();
}
public QueryResult query(Context context, String word, int position,
Handler eHandler) throws ParserConfigurationException,
SAXException, IOException {
int id = getWordID(word);
if (id == MSG_WORD_NOT_EXISIT) {
eHandler.sendEmptyMessage(MSG_WORD_NOT_EXISIT);
return null;
} else {
DictionaryInfo dictionaryInfo = mCacheUsingDictionaries
.get(position);
ScrollView dictionaryView = query(context, word,
dictionaryInfo.mDicDir, dictionaryInfo.mDicFileName,
dictionaryInfo.mDicConfigFileName);
String dictionaryName = mCacheUsingDictionaries.get(position).mDicName;
return new QueryResult(dictionaryName, dictionaryView);
}
}
/**
* 查询并且生成scrollView排版
*
* @param context
* 不解释
* @param word
* 要查询的单词
* @param filePath
* sqlite文件地址
* @param xmlPath
* 对应该sqlite的配置文件地址
* @return
* @throws ParserConfigurationException
* @throws SAXException
* @throws IOException
*/
private ScrollView query(Context context, String word, String saveDir,
String filePath, String xmlPath)
throws ParserConfigurationException, SAXException, IOException {
// start parse the dictionary config-xml
DictionaryParseInfomation dictionaryParseInfomation = parseConfigureXML(
saveDir, xmlPath);
// end parse
// Prepare some query variables
SQLiteDatabase sqLiteDatabase = SQLiteDatabase.openDatabase(
Constants.getSaveDirectory() + File.separator + saveDir
+ File.separator + filePath, null,
SQLiteDatabase.OPEN_READWRITE);
int word_id = getWordID(word);
if (word_id == MSG_WORD_NOT_EXISIT) {
// 单词不存在时候返回null
return null;
} else {
String table = dictionaryParseInfomation.table;
String[] columns = (String[]) (dictionaryParseInfomation.queryWords
.toArray(new String[0]));
String[] selectionArgs = { word_id + "" };
Cursor cursor = sqLiteDatabase.query(table, columns, "word_id=?",
selectionArgs, null, null, null);
// end prepare some query variables
int index = 1;
LinearLayout wrapperLinearLayout = new LinearLayout(context);
wrapperLinearLayout.setOrientation(LinearLayout.VERTICAL);
ViewGroup.LayoutParams layoutParams = new LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
wrapperLinearLayout.setLayoutParams(layoutParams);
TextView textView = null;
while (cursor.moveToNext()) {
textView = processOneItem(context, cursor,
dictionaryParseInfomation, index++);
wrapperLinearLayout.addView(textView);
}
cursor.close();
sqLiteDatabase.close();
ScrollView scrollView = new ScrollView(context);
scrollView.setLayoutParams(new LayoutParams(
android.view.ViewGroup.LayoutParams.MATCH_PARENT,
android.view.ViewGroup.LayoutParams.WRAP_CONTENT));
scrollView.addView(wrapperLinearLayout);
return scrollView;
}
}
/**
* 对每一个单词条目生成textview
*
* @param context
* @param cursor
* @param dictionaryParseInfomation
* @param index
* @return
*/
private TextView processOneItem(Context context, Cursor cursor,
DictionaryParseInfomation dictionaryParseInfomation, int index) {
LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
TextView textView = new TextView(context);
for (EchoViews echoView : dictionaryParseInfomation.echoViews) {
textView.setLayoutParams(layoutParams);
textView.setPadding(
DisplayUtils.dip2px(context, echoView.view_padding_left),
DisplayUtils.dip2px(context, echoView.view_padding_top),
DisplayUtils.dip2px(context, echoView.view_padding_right),
DisplayUtils.dip2px(context, echoView.view_padding_bottom));
ArrayList<SpannableString> contents = new ArrayList<SpannableString>();
CharacterStyle colorCharacterStyle = null, sizeCharacterStyle = null;
for (TextArg textArg : echoView.sprintfArgs) {
String content = cursor.getString(cursor
.getColumnIndex(textArg.argContent)) + " ";
SpannableString partString = dealAction(textArg, content);
colorCharacterStyle = null;
sizeCharacterStyle = null;
if (mIsGlobal) {
colorCharacterStyle = new ForegroundColorSpan(mGlobalColor);
sizeCharacterStyle = new AbsoluteSizeSpan(mGlobalSize);
}
if (mIsIndividual) {
if (mIsIndividualProperty
&& textArg.type.equalsIgnoreCase("property")) {
colorCharacterStyle = new ForegroundColorSpan(
mPropertyColor);
sizeCharacterStyle = new AbsoluteSizeSpan(mPropertySize);
} else if (mIsIndividualEnglish
&& textArg.type.equalsIgnoreCase("english")) {
colorCharacterStyle = new ForegroundColorSpan(
mEnglishColor);
sizeCharacterStyle = new AbsoluteSizeSpan(mEnglishSize);
} else if (mIsIndividualChinese
&& textArg.type.equalsIgnoreCase("chinese")) {
colorCharacterStyle = new ForegroundColorSpan(
mChineseColor);
sizeCharacterStyle = new AbsoluteSizeSpan(mChineseSize);
} else if (mIsIndividualExample
&& textArg.type.equalsIgnoreCase("example")) {
colorCharacterStyle = new ForegroundColorSpan(
mExampleColor);
sizeCharacterStyle = new AbsoluteSizeSpan(mExampleSize);
}
}
if (colorCharacterStyle == null || sizeCharacterStyle == null) {
if (mIsGlobal) {
colorCharacterStyle = new ForegroundColorSpan(
mGlobalColor);
sizeCharacterStyle = new AbsoluteSizeSpan(mGlobalSize);
} else {
// theme style
}
}
partString.setSpan(colorCharacterStyle, 0, partString.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
partString.setSpan(sizeCharacterStyle, 0, partString.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
contents.add(partString);
}
CharSequence resultContent = TextUtils.concat(contents
.toArray(new SpannableString[0]));
SpannableString IndexSpannableString = new SpannableString(index
+ ".");
if (mIsIndividual && mIsIndividualTermNum) {
colorCharacterStyle = new ForegroundColorSpan(mTermNumColor);
sizeCharacterStyle = new AbsoluteSizeSpan(mTermNumSize);
} else if (mIsGlobal) {
colorCharacterStyle = new ForegroundColorSpan(mGlobalColor);
sizeCharacterStyle = new AbsoluteSizeSpan(mGlobalSize);
} else {
// Theme style
}
IndexSpannableString.setSpan(colorCharacterStyle, 0,
IndexSpannableString.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
IndexSpannableString.setSpan(sizeCharacterStyle, 0,
IndexSpannableString.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
resultContent = TextUtils.concat(IndexSpannableString,
resultContent);
textView.setText(resultContent);
}
return textView;
}
// 解决XML中的行为属性
private SpannableString dealAction(TextArg arg, String content) {
if (arg.action != null) {
if (arg.action.equals("split")) {
// |||
String[] examples = content.split("\\|\\|\\|");
content = "\n";
for (String example : examples) {
content += example + "\n";
}
content = "\n" + content;
}
}
return new SpannableString(content);
}
private DictionaryParseInfomation parseConfigureXML(String childDir,
String xmlPath) throws ParserConfigurationException, SAXException,
IOException {
DictionaryParseInfomation dictionaryParseInfomation;
if (mCacheXMLInformation.containsKey(xmlPath)) {
dictionaryParseInfomation = mCacheXMLInformation.get(xmlPath);
} else {
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
SAXParser saxParser = saxParserFactory.newSAXParser();
DictionaryXMLHandler dictionaryXMLHandler = new DictionaryXMLHandler();
String xmlFilePath = Constants.getSaveDirectory() + File.separator
+ childDir + File.separator + xmlPath;
saxParser.parse(new File(xmlFilePath), dictionaryXMLHandler);
dictionaryParseInfomation = dictionaryXMLHandler.getResults();
mCacheXMLInformation.put(xmlPath, dictionaryParseInfomation);
}
return dictionaryParseInfomation;
}
public static final int MSG_WORD_NOT_EXISIT = -1;
// 获取单词在快表中的ID
public int getWordID(String word) {
if (mCacheWordID.containsKey(word)) {
return mCacheWordID.get(word);
}
SQLiteDatabase iddatabase = SQLiteDatabase.openDatabase(DB_PATH
+ DB_BASE_DIC, null, SQLiteDatabase.OPEN_READWRITE);
String[] tableStrings = { "id" };
Cursor cursor = iddatabase.query("word", tableStrings, "word='" + word
+ "'", null, null, null, null);
int id = MSG_WORD_NOT_EXISIT;
if (cursor.getCount() > 0) {
cursor.moveToNext();
id = cursor.getInt(0);
} else {
id = MSG_WORD_NOT_EXISIT;
}
iddatabase.close();
if (mCacheWordID.size() == mCacheCountForWordsID) {
mCacheWordID.clear();
} else {
mCacheWordID.put(word, id);
}
return id;
}
}