package maigosoft.mcpdict; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.HashMap; import java.util.Map; import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.ListFragment; import android.text.ClipboardManager; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.SubMenu; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import com.mobiRic.ui.widget.Boast; @SuppressWarnings("deprecation") public class SearchResultFragment extends ListFragment implements Masks { @SuppressLint("UseSparseArrays") private static final Map<Integer, Integer> COPY_MENU_ITEM_TO_MASK = new HashMap<Integer, Integer>(); static { COPY_MENU_ITEM_TO_MASK.put(R.id.menu_item_copy_hz, MASK_HZ); COPY_MENU_ITEM_TO_MASK.put(R.id.menu_item_copy_unicode, MASK_UNICODE); COPY_MENU_ITEM_TO_MASK.put(R.id.menu_item_copy_all, MASK_ALL_READINGS); COPY_MENU_ITEM_TO_MASK.put(R.id.menu_item_copy_mc, MASK_MC); COPY_MENU_ITEM_TO_MASK.put(R.id.menu_item_copy_pu, MASK_PU); COPY_MENU_ITEM_TO_MASK.put(R.id.menu_item_copy_ct, MASK_CT); COPY_MENU_ITEM_TO_MASK.put(R.id.menu_item_copy_sh, MASK_SH); COPY_MENU_ITEM_TO_MASK.put(R.id.menu_item_copy_mn, MASK_MN); COPY_MENU_ITEM_TO_MASK.put(R.id.menu_item_copy_kr, MASK_KR); COPY_MENU_ITEM_TO_MASK.put(R.id.menu_item_copy_vn, MASK_VN); COPY_MENU_ITEM_TO_MASK.put(R.id.menu_item_copy_jp_all, MASK_JP_ALL); COPY_MENU_ITEM_TO_MASK.put(R.id.menu_item_copy_jp_go, MASK_JP_GO); COPY_MENU_ITEM_TO_MASK.put(R.id.menu_item_copy_jp_kan, MASK_JP_KAN); COPY_MENU_ITEM_TO_MASK.put(R.id.menu_item_copy_jp_tou, MASK_JP_TOU); COPY_MENU_ITEM_TO_MASK.put(R.id.menu_item_copy_jp_kwan, MASK_JP_KWAN); COPY_MENU_ITEM_TO_MASK.put(R.id.menu_item_copy_jp_other, MASK_JP_OTHER); } private static final int[] DICT_LINK_MASKS = { MASK_MC, MASK_PU, MASK_CT, MASK_SH, MASK_MN, MASK_KR, MASK_VN }; private static final String[] DICT_LINK_BASES = { "http://ytenx.org/zim?kyonh=1&dzih=", // plus UTF-8 encoded string "http://www.zdic.net/sousuo/?q=", // plus UTF-8 encoded string "http://humanum.arts.cuhk.edu.hk/Lexis/lexi-can/search.php?q=", // plus Big5 encoded string "http://www.wu-chinese.com/minidict/search.php?searchlang=zaonhe&searchkey=", // plus UTF-8 encoded string "http://twblg.dict.edu.tw/holodict_new/result.jsp?querytarget=1&radiobutton=0&limit=20&sample=", // plus UTF-8 encoded string "http://hanja.naver.com/hanja?q=", // plus UTF-8 encoded string "http://hanviet.org/hv_timchu.php?unichar=", // plus UTF-8 encoded string }; // Bases of links to external dictionaries private View selfView; private ListView listView; private SearchResultCursorAdapter adapter; private boolean showFavoriteButton; private View selectedEntry; private static SearchResultFragment selectedFragment; public SearchResultFragment() { this(true); } public SearchResultFragment(boolean showFavoriteButton) { super(); this.showFavoriteButton = showFavoriteButton; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // A hack to avoid nested fragments from being inflated twice // Reference: http://stackoverflow.com/a/14695397 if (selfView != null) { ViewGroup parent = (ViewGroup) selfView.getParent(); if (parent != null) parent.removeView(selfView); return selfView; } // Inflate the fragment view selfView = inflater.inflate(R.layout.search_result_fragment, container, false); // Get a reference to the ListView listView = (ListView) selfView.findViewById(android.R.id.list); // Set up a context menu for each item of the search result registerForContextMenu(listView); return selfView; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // Set up the adapter if (adapter == null) { adapter = new SearchResultCursorAdapter( getActivity(), R.layout.search_result_item, null, showFavoriteButton ); setListAdapter(adapter); } } @Override public void onListItemClick(ListView list, View view, int position, long id) { // Show context menu on short clicks, too list.showContextMenuForChild(view); } @Override public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) { selectedFragment = this; // This is a bug with Android: when a context menu item is clicked, // all fragments of this class receive a call to onContextItemSelected. // Therefore we need to remember which fragment created the context menu. // Find the Chinese character in the view being clicked ListView list = (ListView) view; AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; int position = info.position - list.getFirstVisiblePosition(); // info.position is the position of the item in the entire list // but list.getChildAt() on the next line requires the position of the item in currently visible items selectedEntry = list.getChildAt(position); TextView text = (TextView) selectedEntry.findViewById(R.id.text_hz); String hanzi = text.getText().toString(); char unicode = hanzi.charAt(0); int tag = (Integer) selectedEntry.getTag(); // Inflate the context menu getActivity().getMenuInflater().inflate(R.menu.search_result_context_menu, menu); SubMenu menuCopy = menu.getItem(0).getSubMenu(); SubMenu menuDictLinks = menu.getItem(1).getSubMenu(); MenuItem item; // Determine whether to retain each item in the "copy" sub-menu for (int i = menuCopy.size() - 1; i >= 0; i--) { int id = menuCopy.getItem(i).getItemId(); int mask = COPY_MENU_ITEM_TO_MASK.get(id); if ((tag & mask) == 0) menuCopy.removeItem(id); } // Determine whether to enable each item in the sub-menu of external dictionaries, // and generate links for enabled items String utf8 = null; String big5 = null; try {utf8 = URLEncoder.encode(hanzi, "utf-8");} catch (UnsupportedEncodingException e) {} try {big5 = URLEncoder.encode(hanzi, "big5");} catch (UnsupportedEncodingException e) {} if (big5.equals("%3F")) big5 = null; // Unsupported character String[] linkArgs = {utf8, utf8, big5, utf8, utf8, utf8, utf8}; for (int i = 0; i < menuDictLinks.size(); i++) { item = menuDictLinks.getItem(i); if ((tag & DICT_LINK_MASKS[i]) != 0) { item.setEnabled(true); item.setIntent(new Intent(Intent.ACTION_VIEW, Uri.parse(DICT_LINK_BASES[i] + linkArgs[i]))); } else { item.setEnabled(false); } } // Determine the functionality of the "favorite" item item = menu.getItem(2); item.setTitle((tag & MASK_FAVORITE) == 0 ? R.string.favorite_add : R.string.favorite_view_or_edit); // Replace the placeholders in the menu items with the character selected for (Menu m : new Menu[] {menu, menuCopy, menuDictLinks}) { for (int i = 0; i < m.size(); i++) { item = m.getItem(i); item.setTitle(String.format(item.getTitle().toString(), unicode)); } } } @Override public boolean onContextItemSelected(MenuItem item) { if (selectedFragment != this) return false; if (COPY_MENU_ITEM_TO_MASK.containsKey(item.getItemId())) { // Generate the text to copy to the clipboard String text = getCopyText(selectedEntry, COPY_MENU_ITEM_TO_MASK.get(item.getItemId())); ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE); clipboard.setText(text); String label = item.getTitle().toString().substring(2); // this is ugly String message = String.format(getString(R.string.copy_done), label); Boast.showText(getActivity(), message, Toast.LENGTH_SHORT); return true; } else if (item.getItemId() == R.id.menu_item_favorite) { selectedEntry.findViewById(R.id.button_favorite).performClick(); return true; } else { // Fall back to default behavior return false; } } private String getCopyText(View entry, int mask) { int tag = (Integer) entry.getTag(); if ((tag & mask) == 0) return null; TextView[] textViewJPExtras = { (TextView) entry.findViewById(R.id.text_jp_extra_1), (TextView) entry.findViewById(R.id.text_jp_extra_2), (TextView) entry.findViewById(R.id.text_jp_extra_3) }; StringBuilder sb; switch (mask) { case MASK_HZ: return ((TextView) entry.findViewById(R.id.text_hz)).getText().toString(); case MASK_UNICODE: return ((TextView) entry.findViewById(R.id.text_unicode)).getText().toString(); case MASK_MC: String[] readings = ((TextView) entry.findViewById(R.id.text_mc)).getText().toString().split("\n"); String[] details = ((TextView) entry.findViewById(R.id.text_mc_detail)).getText().toString().split("\n"); String text = ""; for (int i = 0; i < readings.length; i++) { if (i > 0) text += "\n"; text += readings[i] + details[i]; } return text; case MASK_PU: return ((TextView) entry.findViewById(R.id.text_pu)).getText().toString(); case MASK_CT: return ((TextView) entry.findViewById(R.id.text_ct)).getText().toString(); case MASK_SH: return ((TextView) entry.findViewById(R.id.text_sh)).getText().toString(); case MASK_MN: return ((TextView) entry.findViewById(R.id.text_mn)).getText().toString(); case MASK_KR: return ((TextView) entry.findViewById(R.id.text_kr)).getText().toString(); case MASK_VN: return ((TextView) entry.findViewById(R.id.text_vn)).getText().toString(); case MASK_JP_GO: return ((TextView) entry.findViewById(R.id.text_jp_go)).getText().toString(); case MASK_JP_KAN: return ((TextView) entry.findViewById(R.id.text_jp_kan)).getText().toString(); case MASK_JP_TOU: return textViewJPExtras[0].getText().toString(); case MASK_JP_KWAN: return textViewJPExtras[(tag & MASK_JP_TOU) > 0 ? 1 : 0].getText().toString(); case MASK_JP_OTHER: return textViewJPExtras[((tag & MASK_JP_TOU) > 0 ? 1 : 0) + ((tag & MASK_JP_KWAN) > 0 ? 1 : 0)].getText().toString(); case MASK_JP_ALL: sb = new StringBuilder(); if ((tag & MASK_JP_GO) > 0) sb.append(formatReading("吳", getCopyText(entry, MASK_JP_GO))); if ((tag & MASK_JP_KAN) > 0) sb.append(formatReading("漢", getCopyText(entry, MASK_JP_KAN))); if ((tag & MASK_JP_TOU) > 0) sb.append(formatReading("唐", getCopyText(entry, MASK_JP_TOU))); if ((tag & MASK_JP_KWAN) > 0) sb.append(formatReading("慣", getCopyText(entry, MASK_JP_KWAN))); if ((tag & MASK_JP_OTHER) > 0) sb.append(formatReading("他", getCopyText(entry, MASK_JP_OTHER))); return sb.toString(); case MASK_ALL_READINGS: sb = new StringBuilder(); String hanzi = ((TextView) entry.findViewById(R.id.text_hz)).getText().toString(); String unicode = ((TextView) entry.findViewById(R.id.text_unicode)).getText().toString(); sb.append(hanzi + " " + unicode + "\n"); if ((tag & MASK_MC) > 0) sb.append(formatReading("中古", getCopyText(entry, MASK_MC))); if ((tag & MASK_PU) > 0) sb.append(formatReading("普", getCopyText(entry, MASK_PU))); if ((tag & MASK_CT) > 0) sb.append(formatReading("粵", getCopyText(entry, MASK_CT))); if ((tag & MASK_SH) > 0) sb.append(formatReading("吳", getCopyText(entry, MASK_SH))); if ((tag & MASK_MN) > 0) sb.append(formatReading("閩", getCopyText(entry, MASK_MN))); if ((tag & MASK_KR) > 0) sb.append(formatReading("朝", getCopyText(entry, MASK_KR))); if ((tag & MASK_VN) > 0) sb.append(formatReading("越", getCopyText(entry, MASK_VN))); if ((tag & MASK_JP_GO) > 0) sb.append(formatReading("日·吳", getCopyText(entry, MASK_JP_GO))); if ((tag & MASK_JP_KAN) > 0) sb.append(formatReading("日·漢", getCopyText(entry, MASK_JP_KAN))); if ((tag & MASK_JP_TOU) > 0) sb.append(formatReading("日·唐", getCopyText(entry, MASK_JP_TOU))); if ((tag & MASK_JP_KWAN) > 0) sb.append(formatReading("日·慣", getCopyText(entry, MASK_JP_KWAN))); if ((tag & MASK_JP_OTHER) > 0) sb.append(formatReading("日·他", getCopyText(entry, MASK_JP_OTHER))); return sb.toString(); } return null; } private String formatReading(String prefix, String reading) { String separator = reading.contains("\n") ? "\n" : " "; return "[" + prefix + "]" + separator + reading + "\n"; } public void setData(Cursor data) { if (adapter == null) return; adapter.changeCursor(data); } public void scrollToTop() { listView.setSelectionAfterHeaderView(); } }