/******************************************************************************* * This file is part of the RozkladPKP project. * * RozkladPKP is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * RozkladPKP is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with RozkladPKP. If not, see <http://www.gnu.org/licenses/>. ******************************************************************************/ package org.tyszecki.rozkladpkp.widgets; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Map; import org.tyszecki.rozkladpkp.DatabaseHelper; import org.tyszecki.rozkladpkp.R; import org.tyszecki.rozkladpkp.RozkladPKPApplication; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.util.AttributeSet; import android.widget.ArrayAdapter; import android.widget.AutoCompleteTextView; import android.widget.Filter; public class StationEdit extends AutoCompleteTextView { static TernaryTree tree; private boolean enableAC = true; static class Node { private char m_char; private Node m_left, m_center, m_right; private String v = null; public Node(char ch) { m_char = ch; } }; static class TernaryTree { private Node m_root = null; private final Map<Character,Character> chmap = new HashMap<Character,Character>(){ private static final long serialVersionUID = 1L; { put('ą','a'); put('ć','c'); put('ę','e'); put('ł','l'); put('ń','n'); put('ó','o'); put('ś','s'); put('ż','z'); put('ź','z'); } }; private char strip(char in) { in = Character.toLowerCase(in); if(chmap.containsKey(in)) in = chmap.get(in); return in; } private Node Add(String s, int pos, Node node) { char p = strip(s.charAt(pos)); if (node == null) { node = new Node(p); } if (p < node.m_char) { node.m_left = Add(s, pos, node.m_left); } else if (p > node.m_char) { node.m_right = Add(s, pos, node.m_right); } else { //TODO: teraz zakładamy, że nie ma dwóch stacji różniących się jedynie znakami diakrytycznymi, //tj. że nie istnieją np. "Baby" i "Bąby". Jeśli taka sytuacja zdarzy się, tylko jedna stacja będzie //dostępna w autouzupełnianiu. if (pos + 1 == s.length()) {node.v = s;} else { node.m_center = Add(s, pos + 1, node.m_center); } } return node; } public void Add(String s) { if (s == null || s == "") return; m_root = Add(s, 0, m_root); } private void Matching(Node n, ArrayList<String> list) { if(n.v != null) list.add(n.v); if(n.m_center != null) Matching(n.m_center, list); if(n.m_left != null) Matching(n.m_left, list); if(n.m_right != null) Matching(n.m_right, list); } public ArrayList<String> Autocomplete(String s) { if (s == null || s == "") return new ArrayList<String>(); int pos = 0; Node node = m_root; while (node != null) { char p = strip(s.charAt(pos)); if (p < node.m_char) { node = node.m_left; } else if (p > node.m_char) { node = node.m_right; } else { if (++pos == s.length()) { ArrayList<String> results = new ArrayList<String>(); if(node.m_center != null) Matching(node.m_center,results); return results; } node = node.m_center; } } return new ArrayList<String>(); } } class StationAdapter extends ArrayAdapter<String>{ private StationFilter mFilter; public StationAdapter(Context context, int textViewResourceId) { super(context, textViewResourceId, new ArrayList<String>()); } private class StationFilter extends Filter{ @Override protected FilterResults performFiltering(CharSequence constraint) { FilterResults results = new FilterResults(); if ((constraint == null) || (constraint.length() == 0)) { ArrayList<String> list = new ArrayList<String>(); results.values = list; results.count = list.size(); } else { ArrayList<String> al = tree.Autocomplete(constraint.toString()); //Wywal przystanki ZTM na koniec listy, resztę zostaw tak jak były Collections.sort(al, new Comparator<String>() { @Override public int compare(String lhs, String rhs) { boolean rc = rhs.contains("ZTM"); if(lhs.contains("ZTM")) { if(rc) return 0; else return 1; } else{ if(rc) return -1; else return 0; } } }); results.values = al; results.count = al.size(); } return results; } @SuppressWarnings("unchecked") @Override protected void publishResults(CharSequence arg0, FilterResults results) { if (results.count > 0) { clear(); notifyDataSetChanged(); for(String t:(ArrayList<String>)results.values) add(t); } else notifyDataSetInvalidated(); } } public Filter getFilter() { if (mFilter == null) mFilter = new StationFilter(); return mFilter; } } public StationEdit(Context context, AttributeSet attrs) { super(context, attrs); setSingleLine(); setDropDownHeight(-2); StationAdapter a = new StationAdapter(getContext(), R.layout.station_edit_item); setAdapter(a); }; public static void initTree() { new Thread(new Runnable() { @Override public void run() { SQLiteDatabase db = DatabaseHelper.getDb(RozkladPKPApplication.getAppContext()); Cursor cur = db.query("stations", new String[]{"name"}, null, null, null, null, null); tree = new TernaryTree(); while(cur.moveToNext()) tree.Add(cur.getString(0)); db.close(); } }).run(); } public String getCurrentSID() { String cstation = getText().toString(); SQLiteDatabase db = DatabaseHelper.getDb(getContext()); Cursor cur = db.query("stations", new String[]{"_id","x","y"}, "name LIKE ?", new String[]{cstation}, null, null, null,"1"); if(cur.moveToNext()) { db.close(); return "A=1@O="+cstation+"@X="+cur.getInt(1)+"@Y="+cur.getInt(2)+"@L="+Integer.toString(cur.getInt(0))+"@"; } db.close(); return ""; } public void setAutoComplete(boolean en) { enableAC = en; } public boolean autoComplete() { return enableAC; } public boolean inputValid() { return getText().toString().trim().length() > 0; } }