package net.osmand.plus.poi; import net.osmand.osm.AbstractPoiType; import net.osmand.osm.MapPoiTypes; import net.osmand.osm.PoiCategory; import net.osmand.osm.PoiFilter; import net.osmand.osm.PoiType; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; import net.osmand.plus.api.SQLiteAPI.SQLiteConnection; import net.osmand.plus.api.SQLiteAPI.SQLiteCursor; import net.osmand.plus.api.SQLiteAPI.SQLiteStatement; import net.osmand.util.Algorithms; import android.support.annotation.NonNull; import android.util.ArraySet; import java.lang.reflect.Array; import java.text.Collator; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; public class PoiFiltersHelper { private final OsmandApplication application; private NominatimPoiFilter nominatimPOIFilter; private NominatimPoiFilter nominatimAddressFilter; private PoiUIFilter searchByNamePOIFilter; private PoiUIFilter customPOIFilter; private PoiUIFilter showAllPOIFilter; private PoiUIFilter localWikiPoiFilter; private List<PoiUIFilter> cacheTopStandardFilters; private Set<PoiUIFilter> selectedPoiFilters = new TreeSet<>(); private static final String UDF_CAR_AID = "car_aid"; private static final String UDF_FOR_TOURISTS = "for_tourists"; private static final String UDF_FOOD_SHOP = "food_shop"; private static final String UDF_FUEL = "fuel"; private static final String UDF_SIGHTSEEING = "sightseeing"; private static final String UDF_EMERGENCY = "emergency"; private static final String UDF_PUBLIC_TRANSPORT = "public_transport"; private static final String UDF_ACCOMMODATION = "accommodation"; private static final String UDF_RESTAURANTS = "restaurants"; private static final String UDF_PARKING = "parking"; private static final String[] DEL = new String[] { UDF_CAR_AID, UDF_FOR_TOURISTS, UDF_FOOD_SHOP, UDF_FUEL, UDF_SIGHTSEEING, UDF_EMERGENCY, UDF_PUBLIC_TRANSPORT, UDF_ACCOMMODATION, UDF_RESTAURANTS, UDF_PARKING }; public PoiFiltersHelper(OsmandApplication application) { this.application = application; } public NominatimPoiFilter getNominatimPOIFilter() { if (nominatimPOIFilter == null) { nominatimPOIFilter = new NominatimPoiFilter(application, false); } return nominatimPOIFilter; } public NominatimPoiFilter getNominatimAddressFilter() { if (nominatimAddressFilter == null) { nominatimAddressFilter = new NominatimPoiFilter(application, true); } return nominatimAddressFilter; } public PoiUIFilter getSearchByNamePOIFilter() { if (searchByNamePOIFilter == null) { PoiUIFilter filter = new SearchByNameFilter(application); filter.setStandardFilter(true); searchByNamePOIFilter = filter; } return searchByNamePOIFilter; } public PoiUIFilter getCustomPOIFilter() { if (customPOIFilter == null) { PoiUIFilter filter = new PoiUIFilter(application.getString(R.string.poi_filter_custom_filter), PoiUIFilter.CUSTOM_FILTER_ID, new LinkedHashMap<PoiCategory, LinkedHashSet<String>>(), application); //$NON-NLS-1$ filter.setStandardFilter(true); customPOIFilter = filter; } return customPOIFilter; } public PoiUIFilter getLocalWikiPOIFilter() { if (localWikiPoiFilter == null) { PoiType place = application.getPoiTypes().getPoiTypeByKey("wiki_place"); if (place != null && !Algorithms.isEmpty(application.getLanguage())) { PoiUIFilter filter = new PoiUIFilter(place, application, " " + application.getLangTranslation(application.getLanguage())); //$NON-NLS-1$ filter.setSavedFilterByName("wiki:lang:" + application.getLanguage()); filter.setStandardFilter(true); localWikiPoiFilter = filter; } } return localWikiPoiFilter; } public PoiUIFilter getShowAllPOIFilter() { if (showAllPOIFilter == null) { PoiUIFilter filter = new PoiUIFilter(null, application, ""); //$NON-NLS-1$ filter.setStandardFilter(true); showAllPOIFilter = filter; } return showAllPOIFilter; } private PoiUIFilter getFilterById(String filterId, PoiUIFilter... filters) { for (PoiUIFilter pf : filters) { if (pf != null && pf.getFilterId() != null && filterId != null && pf.getFilterId().equals(filterId)) { return pf; } } return null; } public PoiUIFilter getFilterById(String filterId) { if (filterId == null) { return null; } for (PoiUIFilter f : getTopDefinedPoiFilters()) { if (f.getFilterId().equals(filterId)) { return f; } } PoiUIFilter ff = getFilterById(filterId, getCustomPOIFilter(), getSearchByNamePOIFilter(), getLocalWikiPOIFilter(), getShowAllPOIFilter(), getNominatimPOIFilter(), getNominatimAddressFilter()); if (ff != null) { return ff; } if (filterId.startsWith(PoiUIFilter.STD_PREFIX)) { String typeId = filterId.substring(PoiUIFilter.STD_PREFIX.length()); AbstractPoiType tp = application.getPoiTypes().getAnyPoiTypeByKey(typeId); if (tp != null) { PoiUIFilter lf = new PoiUIFilter(tp, application, ""); ArrayList<PoiUIFilter> copy = new ArrayList<PoiUIFilter>(cacheTopStandardFilters); copy.add(lf); Collections.sort(copy); cacheTopStandardFilters = copy; return lf; } AbstractPoiType lt = application.getPoiTypes().getAnyPoiAdditionalTypeByKey(typeId); if (lt != null) { PoiUIFilter lf = new PoiUIFilter(lt, application, ""); ArrayList<PoiUIFilter> copy = new ArrayList<PoiUIFilter>(cacheTopStandardFilters); copy.add(lf); Collections.sort(copy); cacheTopStandardFilters = copy; return lf; } } return null; } public void reloadAllPoiFilters() { showAllPOIFilter = null; getShowAllPOIFilter(); cacheTopStandardFilters = null; getTopDefinedPoiFilters(); } public List<PoiUIFilter> getUserDefinedPoiFilters() { ArrayList<PoiUIFilter> userDefinedFilters = new ArrayList<PoiUIFilter>(); PoiFilterDbHelper helper = openDbHelper(); if (helper != null) { List<PoiUIFilter> userDefined = helper.getFilters(helper.getReadableDatabase()); userDefinedFilters.addAll(userDefined); helper.close(); } return userDefinedFilters; } public List<PoiUIFilter> getSearchPoiFilters() { List<PoiUIFilter> result = new ArrayList<>(); List<PoiUIFilter> filters = Arrays.asList(getCustomPOIFilter(), // getShowAllPOIFilter(), getSearchByNamePOIFilter(), getNominatimPOIFilter(), getNominatimAddressFilter()); for (PoiUIFilter f : filters) { if (f != null && !f.isEmpty()) { result.add(f); } } return result; } public List<PoiUIFilter> getTopDefinedPoiFilters() { if (cacheTopStandardFilters == null) { List<PoiUIFilter> top = new ArrayList<PoiUIFilter>(); // user defined top.addAll(getUserDefinedPoiFilters()); if (getLocalWikiPOIFilter() != null) { top.add(getLocalWikiPOIFilter()); } // default MapPoiTypes poiTypes = application.getPoiTypes(); for (PoiFilter t : poiTypes.getTopVisibleFilters()) { PoiUIFilter f = new PoiUIFilter(t, application, ""); top.add(f); } Collections.sort(top); cacheTopStandardFilters = top; } List<PoiUIFilter> result = new ArrayList<PoiUIFilter>(); result.addAll(cacheTopStandardFilters); result.add(getShowAllPOIFilter()); return result; } private PoiFilterDbHelper openDbHelper() { if (!application.getPoiTypes().isInit()) { return null; } return new PoiFilterDbHelper(application.getPoiTypes(), application); } public boolean removePoiFilter(PoiUIFilter filter) { if (filter.getFilterId().equals(PoiUIFilter.CUSTOM_FILTER_ID) || filter.getFilterId().equals(PoiUIFilter.BY_NAME_FILTER_ID) || filter.getFilterId().startsWith(PoiUIFilter.STD_PREFIX)) { return false; } PoiFilterDbHelper helper = openDbHelper(); if (helper == null) { return false; } boolean res = helper.deleteFilter(helper.getWritableDatabase(), filter); if (res) { ArrayList<PoiUIFilter> copy = new ArrayList<>(cacheTopStandardFilters); copy.remove(filter); cacheTopStandardFilters = copy; } helper.close(); return res; } public boolean createPoiFilter(PoiUIFilter filter) { PoiFilterDbHelper helper = openDbHelper(); if (helper == null) { return false; } boolean res = helper.deleteFilter(helper.getWritableDatabase(), filter); Iterator<PoiUIFilter> it = cacheTopStandardFilters.iterator(); while (it.hasNext()) { if (it.next().getFilterId().equals(filter.getFilterId())) { it.remove(); } } res = helper.addFilter(filter, helper.getWritableDatabase(), false); if (res) { ArrayList<PoiUIFilter> copy = new ArrayList<>(cacheTopStandardFilters); copy.add(filter); Collections.sort(copy); cacheTopStandardFilters = copy; } helper.close(); return res; } public boolean editPoiFilter(PoiUIFilter filter) { if (filter.getFilterId().equals(PoiUIFilter.CUSTOM_FILTER_ID) || filter.getFilterId().equals(PoiUIFilter.BY_NAME_FILTER_ID) || filter.getFilterId().startsWith(PoiUIFilter.STD_PREFIX)) { return false; } PoiFilterDbHelper helper = openDbHelper(); if (helper != null) { boolean res = helper.editFilter(helper.getWritableDatabase(), filter); helper.close(); return res; } return false; } @NonNull public Set<PoiUIFilter> getSelectedPoiFilters() { return selectedPoiFilters; } public void addSelectedPoiFilter(PoiUIFilter filter) { selectedPoiFilters.add(filter); saveSelectedPoiFilters(); } public void removeSelectedPoiFilter(PoiUIFilter filter) { selectedPoiFilters.remove(filter); saveSelectedPoiFilters(); } public boolean isShowingAnyPoi() { return !selectedPoiFilters.isEmpty(); } public void clearSelectedPoiFilters() { selectedPoiFilters.clear(); saveSelectedPoiFilters(); } public void hidePoiFilters() { selectedPoiFilters.clear(); } public String getFiltersName(Set<PoiUIFilter> filters) { if (filters.isEmpty()) { return application.getResources().getString(R.string.shared_string_none); } else { List<String> names = new ArrayList<>(); for (PoiUIFilter filter : filters) { names.add(filter.getName()); } return android.text.TextUtils.join(", ", names); } } public String getSelectedPoiFiltersName() { return getFiltersName(selectedPoiFilters); } public boolean isPoiFilterSelected(PoiUIFilter filter) { return selectedPoiFilters.contains(filter); } public boolean isPoiFilterSelected(String filterId) { for (PoiUIFilter filter : selectedPoiFilters) { if (filter.filterId.equals(filterId)) { return true; } } return false; } public void loadSelectedPoiFilters() { Set<String> filters = application.getSettings().getSelectedPoiFilters(); for (String f : filters) { PoiUIFilter filter = getFilterById(f); if (filter != null) { selectedPoiFilters.add(filter); } } } public void saveSelectedPoiFilters() { Set<String> filters = new HashSet<>(); for (PoiUIFilter f : selectedPoiFilters) { filters.add(f.filterId); } application.getSettings().setSelectedPoiFilters(filters); } public class PoiFilterDbHelper { public static final String DATABASE_NAME = "poi_filters"; //$NON-NLS-1$ private static final int DATABASE_VERSION = 5; private static final String FILTER_NAME = "poi_filters"; //$NON-NLS-1$ private static final String FILTER_COL_NAME = "name"; //$NON-NLS-1$ private static final String FILTER_COL_ID = "id"; //$NON-NLS-1$ private static final String FILTER_COL_FILTERBYNAME = "filterbyname"; //$NON-NLS-1$ private static final String FILTER_TABLE_CREATE = "CREATE TABLE " + FILTER_NAME + " (" + //$NON-NLS-1$ //$NON-NLS-2$ FILTER_COL_NAME + ", " + FILTER_COL_ID + ", " + FILTER_COL_FILTERBYNAME + ");"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ private static final String CATEGORIES_NAME = "categories"; //$NON-NLS-1$ private static final String CATEGORIES_FILTER_ID = "filter_id"; //$NON-NLS-1$ private static final String CATEGORIES_COL_CATEGORY = "category"; //$NON-NLS-1$ private static final String CATEGORIES_COL_SUBCATEGORY = "subcategory"; //$NON-NLS-1$ private static final String CATEGORIES_TABLE_CREATE = "CREATE TABLE " + CATEGORIES_NAME + " (" + //$NON-NLS-1$ //$NON-NLS-2$ CATEGORIES_FILTER_ID + ", " + CATEGORIES_COL_CATEGORY + ", " + CATEGORIES_COL_SUBCATEGORY + ");"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ private OsmandApplication context; private SQLiteConnection conn; private MapPoiTypes mapPoiTypes; PoiFilterDbHelper(MapPoiTypes mapPoiTypes, OsmandApplication context) { this.mapPoiTypes = mapPoiTypes; this.context = context; } public SQLiteConnection getWritableDatabase() { return openConnection(false); } public void close() { if (conn != null) { conn.close(); conn = null; } } public SQLiteConnection getReadableDatabase() { return openConnection(true); } private SQLiteConnection openConnection(boolean readonly) { conn = context.getSQLiteAPI().getOrCreateDatabase(DATABASE_NAME, readonly); if (conn.getVersion() == 0 || DATABASE_VERSION != conn.getVersion()) { if (readonly) { conn.close(); conn = context.getSQLiteAPI().getOrCreateDatabase(DATABASE_NAME, readonly); } if (conn.getVersion() == 0) { conn.setVersion(DATABASE_VERSION); onCreate(conn); } else { onUpgrade(conn, conn.getVersion(), DATABASE_VERSION); } } return conn; } public void onCreate(SQLiteConnection conn) { conn.execSQL(FILTER_TABLE_CREATE); conn.execSQL(CATEGORIES_TABLE_CREATE); } public void onUpgrade(SQLiteConnection conn, int oldVersion, int newVersion) { if (newVersion <= 5) { deleteOldFilters(conn); } conn.setVersion(newVersion); } private void deleteOldFilters(SQLiteConnection conn) { for (String toDel : DEL) { deleteFilter(conn, "user_" + toDel); } } protected boolean addFilter(PoiUIFilter p, SQLiteConnection db, boolean addOnlyCategories) { if (db != null) { if (!addOnlyCategories) { db.execSQL("INSERT INTO " + FILTER_NAME + " VALUES (?, ?, ?)", new Object[]{p.getName(), p.getFilterId(), p.getFilterByName()}); //$NON-NLS-1$ //$NON-NLS-2$ } Map<PoiCategory, LinkedHashSet<String>> types = p.getAcceptedTypes(); SQLiteStatement insertCategories = db.compileStatement("INSERT INTO " + CATEGORIES_NAME + " VALUES (?, ?, ?)"); //$NON-NLS-1$ //$NON-NLS-2$ for (PoiCategory a : types.keySet()) { if (types.get(a) == null) { insertCategories.bindString(1, p.getFilterId()); insertCategories.bindString(2, a.getKeyName()); insertCategories.bindNull(3); insertCategories.execute(); } else { for (String s : types.get(a)) { insertCategories.bindString(1, p.getFilterId()); insertCategories.bindString(2, a.getKeyName()); insertCategories.bindString(3, s); insertCategories.execute(); } } } insertCategories.close(); return true; } return false; } protected List<PoiUIFilter> getFilters(SQLiteConnection conn) { ArrayList<PoiUIFilter> list = new ArrayList<PoiUIFilter>(); if (conn != null) { SQLiteCursor query = conn.rawQuery("SELECT " + CATEGORIES_FILTER_ID + ", " + CATEGORIES_COL_CATEGORY + "," + CATEGORIES_COL_SUBCATEGORY + " FROM " + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ CATEGORIES_NAME, null); Map<String, Map<PoiCategory, LinkedHashSet<String>>> map = new LinkedHashMap<String, Map<PoiCategory, LinkedHashSet<String>>>(); if (query.moveToFirst()) { do { String filterId = query.getString(0); if (!map.containsKey(filterId)) { map.put(filterId, new LinkedHashMap<PoiCategory, LinkedHashSet<String>>()); } Map<PoiCategory, LinkedHashSet<String>> m = map.get(filterId); PoiCategory a = mapPoiTypes.getPoiCategoryByName(query.getString(1).toLowerCase(), false); String subCategory = query.getString(2); if (subCategory == null) { m.put(a, null); } else { if (m.get(a) == null) { m.put(a, new LinkedHashSet<String>()); } m.get(a).add(subCategory); } } while (query.moveToNext()); } query.close(); query = conn.rawQuery("SELECT " + FILTER_COL_ID + ", " + FILTER_COL_NAME + "," + FILTER_COL_FILTERBYNAME + " FROM " + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ FILTER_NAME, null); if (query.moveToFirst()) { do { String filterId = query.getString(0); if (map.containsKey(filterId)) { PoiUIFilter filter = new PoiUIFilter(query.getString(1), filterId, map.get(filterId), application); filter.setSavedFilterByName(query.getString(2)); list.add(filter); } } while (query.moveToNext()); } query.close(); } return list; } protected boolean editFilter(SQLiteConnection conn, PoiUIFilter filter) { if (conn != null) { conn.execSQL("DELETE FROM " + CATEGORIES_NAME + " WHERE " + CATEGORIES_FILTER_ID + " = ?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ new Object[]{filter.getFilterId()}); addFilter(filter, conn, true); updateName(conn, filter); return true; } return false; } private void updateName(SQLiteConnection db, PoiUIFilter filter) { db.execSQL("UPDATE " + FILTER_NAME + " SET " + FILTER_COL_FILTERBYNAME + " = ?, " + FILTER_COL_NAME + " = ? " + " WHERE " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + FILTER_COL_ID + "= ?", new Object[]{filter.getFilterByName(), filter.getName(), filter.getFilterId()}); //$NON-NLS-1$ } protected boolean deleteFilter(SQLiteConnection db, PoiUIFilter p) { String key = p.getFilterId(); return deleteFilter(db, key); } private boolean deleteFilter(SQLiteConnection db, String key) { if (db != null) { db.execSQL("DELETE FROM " + FILTER_NAME + " WHERE " + FILTER_COL_ID + " = ?", new Object[]{key}); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ db.execSQL( "DELETE FROM " + CATEGORIES_NAME + " WHERE " + CATEGORIES_FILTER_ID + " = ?", new Object[]{key}); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ return true; } return false; } } }