Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
4ff225af89
12 changed files with 288 additions and 312 deletions
|
@ -3,7 +3,12 @@ package net.osmand.osm;
|
|||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.text.Collator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
@ -61,6 +66,33 @@ public class MapPoiTypes {
|
|||
return otherCategory;
|
||||
}
|
||||
|
||||
public List<PoiFilter> getTopVisibleFilters() {
|
||||
List<PoiFilter> lf = new ArrayList<PoiFilter>();
|
||||
for(PoiCategory pc : categories) {
|
||||
if(pc.isTopVisible()) {
|
||||
lf.add(pc);
|
||||
}
|
||||
for(PoiFilter p : pc.getPoiFilters()) {
|
||||
if(p.isTopVisible()) {
|
||||
lf.add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
sortList(lf);
|
||||
return lf;
|
||||
}
|
||||
|
||||
|
||||
private void sortList(List<? extends PoiFilter> lf) {
|
||||
final Collator instance = Collator.getInstance();
|
||||
Collections.sort(lf, new Comparator<PoiFilter>() {
|
||||
@Override
|
||||
public int compare(PoiFilter object1, PoiFilter object2) {
|
||||
return instance.compare(object1.getTranslation(), object2.getTranslation());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public PoiCategory getUserDefinedCategory() {
|
||||
return otherCategory;
|
||||
}
|
||||
|
@ -70,21 +102,23 @@ public class MapPoiTypes {
|
|||
return getPoiCategoryByName(name, false);
|
||||
}
|
||||
|
||||
|
||||
public PoiCategory getPoiCategoryBySubtypeName(String name) {
|
||||
public PoiType getPoiTypeByKey(String name) {
|
||||
for(PoiCategory pc : categories) {
|
||||
PoiType pt = pc.getPoiTypeByKeyName(name);
|
||||
if(pt != null) {
|
||||
return pc;
|
||||
if(pt != null && !pt.isReference()) {
|
||||
return pt;
|
||||
}
|
||||
}
|
||||
return otherCategory;
|
||||
return null;
|
||||
}
|
||||
|
||||
public Map<String, PoiType> getAllTranslatedNames() {
|
||||
Map<String, PoiType> translation = new TreeMap<String, PoiType>();
|
||||
for(PoiCategory pc : categories) {
|
||||
for(PoiType pt : pc.getPoiTypes()) {
|
||||
if(pt.isReference()) {
|
||||
continue;
|
||||
}
|
||||
translation.put(pt.getTranslation(), pt);
|
||||
}
|
||||
}
|
||||
|
@ -126,11 +160,14 @@ public class MapPoiTypes {
|
|||
|
||||
public void setPoiTranslator(PoiTranslator poiTranslator) {
|
||||
this.poiTranslator = poiTranslator;
|
||||
sortList(categories);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void init(){
|
||||
InputStream is;
|
||||
List<PoiType> referenceTypes = new ArrayList<PoiType>();
|
||||
try {
|
||||
if(resourceName == null){
|
||||
is = MapRenderingTypes.class.getResourceAsStream("poi_types.xml"); //$NON-NLS-1$
|
||||
|
@ -148,16 +185,19 @@ public class MapPoiTypes {
|
|||
String name = parser.getName();
|
||||
if (name.equals("poi_category")) {
|
||||
lastCategory = new PoiCategory(this, parser.getAttributeValue("","name"), categories.size());
|
||||
lastCategory.setTopVisible(Boolean.parseBoolean(parser.getAttributeValue("","top")));
|
||||
categories.add(lastCategory);
|
||||
} else if (name.equals("poi_filter")) {
|
||||
PoiFilter tp = new PoiFilter(this, lastCategory,
|
||||
parser.getAttributeValue("", "name"));
|
||||
tp.setTopVisible(Boolean.parseBoolean(parser.getAttributeValue("","top")));
|
||||
lastFilter = tp;
|
||||
lastCategory.addPoiType(tp);
|
||||
} else if(name.equals("poi_reference")){
|
||||
PoiType tp = new PoiType(this,
|
||||
lastCategory, parser.getAttributeValue("","name"));
|
||||
tp.setReference(true);
|
||||
referenceTypes.add(tp);
|
||||
tp.setReferenceType(tp);
|
||||
if(lastFilter != null) {
|
||||
lastFilter.addPoiType(tp);
|
||||
}
|
||||
|
@ -197,6 +237,14 @@ public class MapPoiTypes {
|
|||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
for (PoiType gt : referenceTypes) {
|
||||
PoiType pt = getPoiTypeByKey(gt.keyName);
|
||||
if (pt == null || pt.getOsmTag() == null) {
|
||||
throw new IllegalStateException("Can't find poi type for poi reference '" + gt.keyName + "'");
|
||||
} else {
|
||||
gt.setReferenceType(pt);
|
||||
}
|
||||
}
|
||||
findDefaultOtherCategory();
|
||||
init = true;
|
||||
}
|
||||
|
@ -229,14 +277,25 @@ public class MapPoiTypes {
|
|||
|
||||
private static void print(String indent, PoiFilter f) {
|
||||
for(PoiType pt : f.getPoiTypes()) {
|
||||
System.out.println(indent + " Type " + pt.getName());
|
||||
System.out.println(indent + " Type " + pt.getName() +
|
||||
(pt.isReference() ? (" -> " + pt.getReferenceType().getCategory().getKey() ): ""));
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
DEFAULT_INSTANCE = new MapPoiTypes("/Users/victorshcherb/osmand/repos/resources/poi/poi_types.xml");
|
||||
DEFAULT_INSTANCE.init();
|
||||
print(DEFAULT_INSTANCE) ;
|
||||
// print(DEFAULT_INSTANCE) ;
|
||||
// System.out.println("-----------------");
|
||||
List<PoiFilter> lf = DEFAULT_INSTANCE.getTopVisibleFilters();
|
||||
for(PoiFilter l : lf) {
|
||||
System.out.println("----------------- " + l.getKeyName());
|
||||
print("", l);
|
||||
Map<PoiCategory, LinkedHashSet<String>> m =
|
||||
l.putTypes(new LinkedHashMap<PoiCategory, LinkedHashSet<String>>());
|
||||
System.out.println(m);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public String getTranslation(AbstractPoiType abstractPoiType) {
|
||||
|
@ -254,8 +313,4 @@ public class MapPoiTypes {
|
|||
return getPoiCategoryByName(t.getKeyName()) != otherCategory;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package net.osmand.osm;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class PoiCategory extends PoiFilter {
|
||||
|
@ -34,6 +36,13 @@ public class PoiCategory extends PoiFilter {
|
|||
this.defaultTag = defaultTag;
|
||||
}
|
||||
|
||||
public Map<PoiCategory, LinkedHashSet<String>> putTypes(
|
||||
Map<PoiCategory, LinkedHashSet<String>> acceptedTypes) {
|
||||
acceptedTypes.put(this, null);
|
||||
addReferenceTypes(acceptedTypes);
|
||||
return acceptedTypes;
|
||||
}
|
||||
|
||||
|
||||
public boolean isWiki() {
|
||||
return keyName.equals(MapPoiTypes.OSM_WIKI_CATEGORY);
|
||||
|
@ -47,4 +56,6 @@ public class PoiCategory extends PoiFilter {
|
|||
return regId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -2,12 +2,14 @@ package net.osmand.osm;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class PoiFilter extends AbstractPoiType {
|
||||
|
||||
private PoiCategory pc;
|
||||
private boolean topVisible;
|
||||
private List<PoiType> poiTypes = new ArrayList<PoiType>();
|
||||
private Map<String, PoiType> map = new LinkedHashMap<String, PoiType>();
|
||||
|
||||
|
@ -28,6 +30,40 @@ public class PoiFilter extends AbstractPoiType {
|
|||
if(!map.containsKey(type.getName())) {
|
||||
poiTypes.add(type);
|
||||
map.put(type.getName(), type);
|
||||
} else {
|
||||
PoiType prev = map.get(type.getName());
|
||||
if(prev.isReference()) {
|
||||
poiTypes.remove(prev);
|
||||
poiTypes.add(type);
|
||||
map.put(type.getName(), type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Map<PoiCategory, LinkedHashSet<String>> putTypes(Map<PoiCategory, LinkedHashSet<String>> acceptedTypes) {
|
||||
if (!acceptedTypes.containsKey(pc)) {
|
||||
acceptedTypes.put(pc, new LinkedHashSet<String>());
|
||||
}
|
||||
LinkedHashSet<String> set = acceptedTypes.get(pc);
|
||||
for (PoiType pt : poiTypes) {
|
||||
set.add(pt.getKeyName());
|
||||
}
|
||||
addReferenceTypes(acceptedTypes);
|
||||
return acceptedTypes;
|
||||
}
|
||||
|
||||
protected void addReferenceTypes(Map<PoiCategory, LinkedHashSet<String>> acceptedTypes) {
|
||||
for (PoiType pt : getPoiTypes()) {
|
||||
if (pt.isReference()) {
|
||||
PoiCategory refCat = pt.getReferenceType().getCategory();
|
||||
if (!acceptedTypes.containsKey(refCat)) {
|
||||
acceptedTypes.put(refCat, new LinkedHashSet<String>());
|
||||
}
|
||||
LinkedHashSet<String> ls = acceptedTypes.get(refCat);
|
||||
if (ls != null) {
|
||||
ls.add(pt.getKeyName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,5 +75,12 @@ public class PoiFilter extends AbstractPoiType {
|
|||
return keyName;
|
||||
}
|
||||
|
||||
public void setTopVisible(boolean topVisible) {
|
||||
this.topVisible = topVisible;
|
||||
}
|
||||
|
||||
public boolean isTopVisible() {
|
||||
return topVisible;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,14 +2,34 @@ package net.osmand.osm;
|
|||
|
||||
public class PoiType extends AbstractPoiType {
|
||||
|
||||
private PoiCategory category;
|
||||
private PoiType referenceType;
|
||||
private String osmTag;
|
||||
private String osmTag2;
|
||||
private String osmValue;
|
||||
private String osmValue2;
|
||||
|
||||
public PoiType(MapPoiTypes poiTypes, PoiCategory category, String name){
|
||||
public PoiType(MapPoiTypes poiTypes, PoiCategory category, String name) {
|
||||
super(name, poiTypes);
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
public PoiType getReferenceType() {
|
||||
return referenceType;
|
||||
}
|
||||
|
||||
public void setReferenceType(PoiType referenceType) {
|
||||
this.referenceType = referenceType;
|
||||
}
|
||||
|
||||
public boolean isReference() {
|
||||
return referenceType != null;
|
||||
}
|
||||
|
||||
public String getOsmTag() {
|
||||
if(isReference()) {
|
||||
return referenceType.getOsmTag();
|
||||
}
|
||||
return osmTag;
|
||||
}
|
||||
|
||||
|
@ -18,6 +38,9 @@ public class PoiType extends AbstractPoiType {
|
|||
}
|
||||
|
||||
public String getOsmTag2() {
|
||||
if(isReference()) {
|
||||
return referenceType.getOsmTag2();
|
||||
}
|
||||
return osmTag2;
|
||||
}
|
||||
|
||||
|
@ -26,6 +49,9 @@ public class PoiType extends AbstractPoiType {
|
|||
}
|
||||
|
||||
public String getOsmValue() {
|
||||
if(isReference()) {
|
||||
return referenceType.getOsmValue();
|
||||
}
|
||||
return osmValue;
|
||||
}
|
||||
|
||||
|
@ -34,6 +60,9 @@ public class PoiType extends AbstractPoiType {
|
|||
}
|
||||
|
||||
public String getOsmValue2() {
|
||||
if(isReference()) {
|
||||
return referenceType.getOsmValue2();
|
||||
}
|
||||
return osmValue2;
|
||||
}
|
||||
|
||||
|
@ -41,21 +70,9 @@ public class PoiType extends AbstractPoiType {
|
|||
this.osmValue2 = osmValue2;
|
||||
}
|
||||
|
||||
private PoiCategory category;
|
||||
private String osmTag;
|
||||
private String osmTag2;
|
||||
private String osmValue;
|
||||
private String osmValue2;
|
||||
|
||||
|
||||
public PoiCategory getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
|
||||
public void setReference(boolean b) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -380,10 +380,6 @@ public class MapActivity extends AccessibleActivity {
|
|||
|
||||
String filterId = settings.getPoiFilterForMap();
|
||||
PoiLegacyFilter poiFilter = app.getPoiFilters().getFilterById(filterId);
|
||||
if (poiFilter == null) {
|
||||
poiFilter = new PoiLegacyFilter(null, app);
|
||||
}
|
||||
|
||||
mapLayers.getPoiMapLayer().setFilter(poiFilter);
|
||||
|
||||
// if destination point was changed try to recalculate route
|
||||
|
|
|
@ -259,16 +259,13 @@ public class MapActivityLayers {
|
|||
OsmandApplication app = (OsmandApplication)getApplication();
|
||||
final PoiFiltersHelper poiFilters = app.getPoiFilters();
|
||||
final ContextMenuAdapter adapter = new ContextMenuAdapter(activity);
|
||||
|
||||
Item is = adapter.item(getString(R.string.any_poi));
|
||||
if(RenderingIcons.containsBigIcon("null")) {
|
||||
is.icon(RenderingIcons.getBigIconResourceId("null"));
|
||||
}
|
||||
is.reg();
|
||||
// 2nd custom
|
||||
adapter.item(getString(R.string.poi_filter_custom_filter)).icon(RenderingIcons.getBigIconResourceId("user_defined")).reg();
|
||||
|
||||
for (PoiLegacyFilter f : poiFilters.getUserDefinedPoiFilters()) {
|
||||
final List<PoiLegacyFilter> list = new ArrayList<PoiLegacyFilter>();
|
||||
for (PoiLegacyFilter f : poiFilters.getTopDefinedPoiFilters()) {
|
||||
if(PoiLegacyFilter.BY_NAME_FILTER_ID.equals(f.getFilterId()) ||
|
||||
PoiLegacyFilter.NAME_FINDER_FILTER_ID.equals(f.getFilterId())) {
|
||||
continue;
|
||||
}
|
||||
list.add(f);
|
||||
Item it = adapter.item(f.getName());
|
||||
if (RenderingIcons.containsBigIcon(f.getSimplifiedId())) {
|
||||
it.icon(RenderingIcons.getBigIconResourceId(f.getSimplifiedId()));
|
||||
|
@ -278,22 +275,15 @@ public class MapActivityLayers {
|
|||
it.reg();
|
||||
userDefined.add(f);
|
||||
}
|
||||
final List<PoiCategory> categories = getApplication().getPoiTypes().getCategories();
|
||||
for(PoiCategory t : categories){
|
||||
Item it = adapter.item(t.getTranslation());
|
||||
if(RenderingIcons.containsBigIcon(t.getKeyName())) {
|
||||
it.icon(RenderingIcons.getBigIconResourceId(t.getKeyName()));
|
||||
}
|
||||
it.reg();
|
||||
}
|
||||
Builder builder = new AlertDialog.Builder(activity);
|
||||
ListAdapter listAdapter =adapter.createListAdapter(activity, app.getSettings().isLightContent());
|
||||
ListAdapter listAdapter = adapter.createListAdapter(activity, app.getSettings().isLightContent());
|
||||
builder.setAdapter(listAdapter, new DialogInterface.OnClickListener(){
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if(which == 1){
|
||||
String filterId = PoiLegacyFilter.CUSTOM_FILTER_ID;
|
||||
PoiLegacyFilter pf = list.get(which);
|
||||
String filterId = pf.getFilterId();
|
||||
if(filterId.equals(PoiLegacyFilter.CUSTOM_FILTER_ID)){
|
||||
getApplication().getSettings().setPoiFilterForMap(filterId);
|
||||
Intent newIntent = new Intent(activity, EditPOIFilterActivity.class);
|
||||
newIntent.putExtra(EditPOIFilterActivity.AMENITY_FILTER, filterId);
|
||||
|
@ -301,23 +291,15 @@ public class MapActivityLayers {
|
|||
newIntent.putExtra(EditPOIFilterActivity.SEARCH_LON, mapView.getLongitude());
|
||||
activity.startActivity(newIntent);
|
||||
} else {
|
||||
String filterId;
|
||||
if (which == 0) {
|
||||
filterId = PoiFiltersHelper.getOsmDefinedFilterId(null);
|
||||
} else if (which <= userDefined.size() + 1) {
|
||||
filterId = userDefined.get(which - 2).getFilterId();
|
||||
} else {
|
||||
filterId = PoiFiltersHelper.getOsmDefinedFilterId(categories.get(which - userDefined.size() - 2));
|
||||
}
|
||||
getApplication().getSettings().setPoiFilterForMap(filterId);
|
||||
PoiLegacyFilter f = poiFilters.getFilterById(filterId);
|
||||
if (f != null) {
|
||||
f.clearNameFilter();
|
||||
pf = poiFilters.getFilterById(filterId);
|
||||
if (pf != null && pf.isStandardFilter()) {
|
||||
pf.clearNameFilter();
|
||||
}
|
||||
poiMapLayer.setFilter(f);
|
||||
poiMapLayer.setFilter(pf);
|
||||
mapView.refreshMap();
|
||||
if(selected != null && selected.length > 0) {
|
||||
selected[0] = f;
|
||||
selected[0] = pf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,10 +71,7 @@ public class SearchPoiFilterFragment extends ListFragment implements SearchActiv
|
|||
public void refreshPoiListAdapter() {
|
||||
PoiFiltersHelper poiFilters = getApp().getPoiFilters();
|
||||
List<PoiLegacyFilter> filters = new ArrayList<PoiLegacyFilter>() ;
|
||||
filters.addAll(poiFilters.getTopStandardFilters());
|
||||
filters.addAll(poiFilters.getUserDefinedPoiFilters());
|
||||
filters.addAll(poiFilters.getOsmDefinedPoiFilters());
|
||||
filters.add(poiFilters.getNameFinderPOIFilter());
|
||||
filters.addAll(poiFilters.getTopDefinedPoiFilters());
|
||||
setListAdapter(new AmenityAdapter(filters));
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ import org.xmlpull.v1.XmlPullParserException;
|
|||
|
||||
public class NameFinderPoiFilter extends PoiLegacyFilter {
|
||||
|
||||
public static final String FILTER_ID = "name_finder"; //$NON-NLS-1$
|
||||
public static final String FILTER_ID = NAME_FINDER_FILTER_ID; //$NON-NLS-1$
|
||||
private static final Log log = PlatformUtil.getLog(NameFinderPoiFilter.class);
|
||||
private static final int LIMIT = 300;
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import java.util.Map;
|
|||
|
||||
import net.osmand.osm.MapPoiTypes;
|
||||
import net.osmand.osm.PoiCategory;
|
||||
import net.osmand.osm.PoiFilter;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.api.SQLiteAPI.SQLiteConnection;
|
||||
|
@ -23,8 +24,6 @@ public class PoiFiltersHelper {
|
|||
|
||||
private NameFinderPoiFilter nameFinderPOIFilter;
|
||||
private List<PoiLegacyFilter> cacheTopStandardFilters;
|
||||
private List<PoiLegacyFilter> cacheUserDefinedFilters;
|
||||
private List<PoiLegacyFilter> cacheOsmDefinedFilters;
|
||||
|
||||
private static final String UDF_CAR_AID = "car_aid";
|
||||
private static final String UDF_FOR_TOURISTS = "for_tourists";
|
||||
|
@ -37,7 +36,10 @@ public class PoiFiltersHelper {
|
|||
private static final String UDF_RESTAURANTS = "restaurants";
|
||||
private static final String UDF_PARKING = "parking";
|
||||
|
||||
private static final String[] DEL = new String[] {};
|
||||
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;
|
||||
|
@ -50,202 +52,96 @@ public class PoiFiltersHelper {
|
|||
}
|
||||
|
||||
|
||||
private PoiLegacyFilter findPoiFilter(String filterId, List<PoiLegacyFilter>... collections) {
|
||||
for(List<PoiLegacyFilter> c : collections) {
|
||||
for(PoiLegacyFilter f : c) {
|
||||
if(f.getFilterId().equals(filterId)){
|
||||
return f;
|
||||
}
|
||||
|
||||
public PoiLegacyFilter getFilterById(String filterId){
|
||||
if(filterId == null){
|
||||
return null;
|
||||
}
|
||||
for(PoiLegacyFilter f : getTopDefinedPoiFilters()) {
|
||||
if(f.getFilterId().equals(filterId)){
|
||||
return f;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public PoiLegacyFilter getFilterById(String filterId){
|
||||
if(filterId == null){
|
||||
return null;
|
||||
}
|
||||
if(filterId.equals(NameFinderPoiFilter.FILTER_ID)){
|
||||
return getNameFinderPOIFilter();
|
||||
}
|
||||
return findPoiFilter(filterId, getUserDefinedPoiFilters(), getTopStandardFilters(), getOsmDefinedPoiFilters());
|
||||
}
|
||||
|
||||
|
||||
private void putAll(MapPoiTypes poiTypes, Map<PoiCategory, LinkedHashSet<String>> types, String tp) {
|
||||
types.put(poiTypes.getPoiCategoryByName(tp), null);
|
||||
}
|
||||
|
||||
private void putValues(MapPoiTypes poiTypes, Map<PoiCategory, LinkedHashSet<String>> types, String p, String... vls) {
|
||||
LinkedHashSet<String> list = new LinkedHashSet<String>();
|
||||
Collections.addAll(list, vls);
|
||||
PoiCategory pc = poiTypes.getPoiCategoryByName(p);
|
||||
if(pc == null) {
|
||||
throw new NullPointerException("Category " + p + " was not found");
|
||||
}
|
||||
types.put(poiTypes.getPoiCategoryByName(p), list);
|
||||
}
|
||||
|
||||
private List<PoiLegacyFilter> getUserDefinedDefaultFilters(MapPoiTypes poiTypes) {
|
||||
List<PoiLegacyFilter> filters = new ArrayList<PoiLegacyFilter>();
|
||||
filters.add(new PoiLegacyFilter(application.getString(R.string.poi_filter_accomodation), PoiLegacyFilter.USER_PREFIX + UDF_ACCOMMODATION,
|
||||
configureDefaultUserDefinedFilter(poiTypes, UDF_ACCOMMODATION), application));
|
||||
filters.add(new PoiLegacyFilter(application.getString(R.string.poi_filter_car_aid), PoiLegacyFilter.USER_PREFIX + UDF_CAR_AID,
|
||||
configureDefaultUserDefinedFilter(poiTypes, UDF_CAR_AID), application));
|
||||
filters.add(new PoiLegacyFilter(application.getString(R.string.poi_filter_food_shop), PoiLegacyFilter.USER_PREFIX + UDF_FOOD_SHOP,
|
||||
configureDefaultUserDefinedFilter(poiTypes, UDF_FOOD_SHOP), application));
|
||||
filters.add(new PoiLegacyFilter(application.getString(R.string.poi_filter_for_tourists), PoiLegacyFilter.USER_PREFIX + UDF_FOR_TOURISTS,
|
||||
configureDefaultUserDefinedFilter(poiTypes, UDF_FOR_TOURISTS), application));
|
||||
filters.add(new PoiLegacyFilter(application.getString(R.string.poi_filter_fuel), PoiLegacyFilter.USER_PREFIX + UDF_FUEL,
|
||||
configureDefaultUserDefinedFilter(poiTypes, UDF_FUEL), application));
|
||||
filters.add(new PoiLegacyFilter(application.getString(R.string.poi_filter_parking), PoiLegacyFilter.USER_PREFIX + UDF_PARKING,
|
||||
configureDefaultUserDefinedFilter(poiTypes, UDF_PARKING), application));
|
||||
filters.add(new PoiLegacyFilter(application.getString(R.string.poi_filter_public_transport),
|
||||
PoiLegacyFilter.USER_PREFIX + UDF_PUBLIC_TRANSPORT, configureDefaultUserDefinedFilter(poiTypes, UDF_PUBLIC_TRANSPORT), application));
|
||||
filters.add(new PoiLegacyFilter(application.getString(R.string.poi_filter_restaurants), PoiLegacyFilter.USER_PREFIX + UDF_RESTAURANTS,
|
||||
configureDefaultUserDefinedFilter(poiTypes, UDF_RESTAURANTS), application));
|
||||
filters.add(new PoiLegacyFilter(application.getString(R.string.poi_filter_sightseeing), PoiLegacyFilter.USER_PREFIX + UDF_SIGHTSEEING,
|
||||
configureDefaultUserDefinedFilter(poiTypes, UDF_SIGHTSEEING), application));
|
||||
// UDF_EMERGENCY = "emergency";
|
||||
// UDF_ENTERTAINMENT = "entertainment";
|
||||
return filters;
|
||||
}
|
||||
|
||||
private Map<PoiCategory, LinkedHashSet<String>> configureDefaultUserDefinedFilter(MapPoiTypes poiTypes, String key) {
|
||||
Map<PoiCategory, LinkedHashSet<String>> types = new LinkedHashMap<PoiCategory, LinkedHashSet<String>>();
|
||||
if(UDF_ACCOMMODATION.equals(key)){
|
||||
putValues(poiTypes, types, "tourism", "camp_site",
|
||||
"caravan_site","picnic_site","alpine_hut", "chalet","guest_house",
|
||||
"hostel", "hotel","motel");
|
||||
} else if (UDF_CAR_AID.equals(key)) {
|
||||
putValues(poiTypes, types, "transportation", "fuel", "car_wash", "car_repair","car", "car_sharing");
|
||||
putValues(poiTypes, types, "shop", "fuel", "car_wash", "car_repair","car", "car_parts");
|
||||
} else if (UDF_FOOD_SHOP.equals(key)) {
|
||||
putValues(poiTypes, types, "shop", "alcohol", "bakery", "beverages", "butcher", "convenience", "department_store",
|
||||
"convenience", "farm", "general", "ice_cream", "kiosk", "seafood", "supermarket", "variety_store");
|
||||
} else if(UDF_FOR_TOURISTS.equals(key)){
|
||||
putAll(poiTypes, types, "tourism");
|
||||
putAll(poiTypes, types, "finance");
|
||||
putAll(poiTypes, types, "osmwiki");
|
||||
} else if(UDF_FUEL.equals(key)){
|
||||
putValues(poiTypes, types, "transportation", "fuel");
|
||||
} else if (UDF_PARKING.equals(key)) {
|
||||
putValues(poiTypes, types, "transportation", "parking",
|
||||
"bicycle_parking");
|
||||
} else if (UDF_PUBLIC_TRANSPORT.equals(key)) {
|
||||
putValues(poiTypes, types, "transportation", "public_transport_stop_position", "public_transport_platform",
|
||||
"public_transport_station",
|
||||
// railway
|
||||
"railway_platform", "railway_station", "halt", "tram_stop", "subway_entrance", "railway_buffer_stop",
|
||||
// bus, cars, bicycle
|
||||
"bus_stop", "platform", "ferry_terminal", "taxi", "bicycle_rental", "bus_station", "car_rental", "car_sharing",
|
||||
// aero
|
||||
"airport", "aerodrome", "terminal", "gate",
|
||||
// aerial ways ( hide ways)
|
||||
// "aerialway_cable_car", "aerialway_gondola", "aerialway_chair_lift", "aerialway_mixed_lift", "aerialway_drag_lift", "aerialway_goods",
|
||||
"aerialway_station"
|
||||
// ways (hide ways)
|
||||
// "rail", "tram", "light_rail", "subway", "railway_narrow_gauge", "railway_monorail", "railway_funicular"
|
||||
);
|
||||
} else if (UDF_RESTAURANTS.equals(key)) {
|
||||
putValues(poiTypes, types, "sustenance", "restaurant_not_found",
|
||||
"cafe", "food_court", "pub", "bar", "biergarten");
|
||||
} else if (UDF_SIGHTSEEING.equals(key)) {
|
||||
// TODO filter only sightseeing from tourimsm
|
||||
// putValues(types, "tourism", "...","...");
|
||||
putAll(poiTypes, types, "tourism");
|
||||
putAll(poiTypes, types, "osmwiki");
|
||||
} else if (UDF_EMERGENCY.equals(key)) {
|
||||
putAll(poiTypes, types, "healthcare");
|
||||
putAll(poiTypes, types, "emergency");
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
public void reloadAllPoiFilters() {
|
||||
cacheOsmDefinedFilters = null;
|
||||
cacheTopStandardFilters = null;
|
||||
cacheUserDefinedFilters = null;
|
||||
getUserDefinedPoiFilters();
|
||||
getTopStandardFilters();
|
||||
getOsmDefinedPoiFilters();
|
||||
|
||||
getTopDefinedPoiFilters();
|
||||
}
|
||||
|
||||
|
||||
public List<PoiLegacyFilter> getUserDefinedPoiFilters(){
|
||||
if(cacheUserDefinedFilters == null){
|
||||
cacheUserDefinedFilters = new ArrayList<PoiLegacyFilter>();
|
||||
PoiFilterDbHelper helper = openDbHelper();
|
||||
if (helper != null) {
|
||||
List<PoiLegacyFilter> userDefined = helper.getFilters(helper.getReadableDatabase());
|
||||
sortListOfFiltersByName(userDefined);
|
||||
cacheUserDefinedFilters.addAll(userDefined);
|
||||
helper.close();
|
||||
}
|
||||
private List<PoiLegacyFilter> getUserDefinedPoiFilters() {
|
||||
ArrayList<PoiLegacyFilter> userDefinedFilters = new ArrayList<PoiLegacyFilter>();
|
||||
PoiFilterDbHelper helper = openDbHelper();
|
||||
if (helper != null) {
|
||||
List<PoiLegacyFilter> userDefined = helper.getFilters(helper.getReadableDatabase());
|
||||
userDefinedFilters.addAll(userDefined);
|
||||
helper.close();
|
||||
}
|
||||
return Collections.unmodifiableList(cacheUserDefinedFilters);
|
||||
return userDefinedFilters;
|
||||
}
|
||||
private void sortListOfFiltersByName(List<PoiLegacyFilter> userDefined) {
|
||||
|
||||
public void sortListOfFilters(List<PoiLegacyFilter> list) {
|
||||
final Collator instance = Collator.getInstance();
|
||||
Collections.sort(userDefined, new Comparator<PoiLegacyFilter>() {
|
||||
Collections.sort(list, new Comparator<PoiLegacyFilter>() {
|
||||
private int getRank(PoiLegacyFilter lf) {
|
||||
if(PoiLegacyFilter.BY_NAME_FILTER_ID.equals(lf.getFilterId())) {
|
||||
return 0;
|
||||
} else if(lf.areAllTypesAccepted()) {
|
||||
return 3;
|
||||
} else if(PoiLegacyFilter.CUSTOM_FILTER_ID.equals(lf.getFilterId())) {
|
||||
return 4;
|
||||
} else if(PoiLegacyFilter.NAME_FINDER_FILTER_ID.equals(lf.getFilterId())) {
|
||||
return 5;
|
||||
} else if(lf.isStandardFilter()) {
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(PoiLegacyFilter object1, PoiLegacyFilter object2) {
|
||||
return instance.compare(object1.getName(), object2.getName());
|
||||
public int compare(PoiLegacyFilter lhs, PoiLegacyFilter rhs) {
|
||||
int lr = getRank(lhs);
|
||||
int rr = getRank(rhs);
|
||||
if(lr != rr) {
|
||||
return lr < rr ? -1 : 1;
|
||||
}
|
||||
return instance.compare(lhs.getName(), rhs.getName());
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public List<PoiLegacyFilter> getTopStandardFilters() {
|
||||
public List<PoiLegacyFilter> getTopDefinedPoiFilters() {
|
||||
if (cacheTopStandardFilters == null) {
|
||||
cacheTopStandardFilters = new ArrayList<PoiLegacyFilter>();
|
||||
|
||||
// by name
|
||||
PoiLegacyFilter filter = new SearchByNameFilter(application);
|
||||
filter.setStandardFilter(true);
|
||||
cacheTopStandardFilters.add(filter);
|
||||
|
||||
// custom
|
||||
filter = new PoiLegacyFilter(application.getString(R.string.poi_filter_custom_filter),
|
||||
PoiLegacyFilter.CUSTOM_FILTER_ID, new LinkedHashMap<PoiCategory, LinkedHashSet<String>>(), application); //$NON-NLS-1$
|
||||
filter.setStandardFilter(true);
|
||||
cacheTopStandardFilters.add(filter);
|
||||
|
||||
// all
|
||||
cacheTopStandardFilters.add(new PoiLegacyFilter(null, application));
|
||||
// name finder
|
||||
cacheTopStandardFilters.add(getNameFinderPOIFilter());
|
||||
// user defined
|
||||
cacheTopStandardFilters.addAll(getUserDefinedPoiFilters());
|
||||
// default
|
||||
MapPoiTypes poiTypes = application.getPoiTypes();
|
||||
for (PoiFilter t : poiTypes.getTopVisibleFilters()) {
|
||||
cacheTopStandardFilters.add(new PoiLegacyFilter(t, application));
|
||||
}
|
||||
sortListOfFilters(cacheTopStandardFilters);
|
||||
}
|
||||
return Collections.unmodifiableList(cacheTopStandardFilters);
|
||||
}
|
||||
|
||||
public static String getOsmDefinedFilterId(PoiCategory t){
|
||||
return PoiLegacyFilter.STD_PREFIX + (t == null ? null : t.getKeyName());
|
||||
}
|
||||
|
||||
public void updateFilters(boolean onlyAddFilters){
|
||||
PoiFilterDbHelper helper = openDbHelper();
|
||||
if(helper != null ) {
|
||||
helper.upgradeFilters(helper.getWritableDatabase(), onlyAddFilters);
|
||||
helper.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<PoiLegacyFilter> getOsmDefinedPoiFilters(){
|
||||
if(cacheOsmDefinedFilters == null){
|
||||
cacheOsmDefinedFilters = new ArrayList<PoiLegacyFilter>();
|
||||
MapPoiTypes poiTypes = application.getPoiTypes();
|
||||
for(PoiCategory t : poiTypes.getCategories()){
|
||||
cacheOsmDefinedFilters.add(new PoiLegacyFilter(t, application));
|
||||
}
|
||||
final Collator instance = Collator.getInstance();
|
||||
Collections.sort(cacheOsmDefinedFilters, new Comparator<PoiLegacyFilter>() {
|
||||
@Override
|
||||
public int compare(PoiLegacyFilter object1, PoiLegacyFilter object2) {
|
||||
return instance.compare(object1.getName(), object2.getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
return Collections.unmodifiableList(cacheOsmDefinedFilters);
|
||||
}
|
||||
|
||||
private PoiFilterDbHelper openDbHelper(){
|
||||
if(!application.getPoiTypes().isInit()) {
|
||||
return null;
|
||||
|
@ -265,7 +161,7 @@ public class PoiFiltersHelper {
|
|||
}
|
||||
boolean res = helper.deleteFilter(helper.getWritableDatabase(), filter);
|
||||
if(res){
|
||||
cacheUserDefinedFilters.remove(filter);
|
||||
cacheTopStandardFilters.remove(filter);
|
||||
}
|
||||
helper.close();
|
||||
return res;
|
||||
|
@ -278,8 +174,8 @@ public class PoiFiltersHelper {
|
|||
}
|
||||
boolean res = helper.addFilter(filter, helper.getWritableDatabase(), false);
|
||||
if(res){
|
||||
cacheUserDefinedFilters.add(filter);
|
||||
sortListOfFiltersByName(cacheUserDefinedFilters);
|
||||
cacheTopStandardFilters.add(filter);
|
||||
sortListOfFilters(cacheTopStandardFilters);
|
||||
}
|
||||
helper.close();
|
||||
return res;
|
||||
|
@ -305,7 +201,7 @@ public class PoiFiltersHelper {
|
|||
public class PoiFilterDbHelper {
|
||||
|
||||
public static final String DATABASE_NAME = "poi_filters"; //$NON-NLS-1$
|
||||
private static final int DATABASE_VERSION = 4;
|
||||
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$
|
||||
|
@ -365,45 +261,23 @@ public class PoiFiltersHelper {
|
|||
public void onCreate(SQLiteConnection conn) {
|
||||
conn.execSQL(FILTER_TABLE_CREATE);
|
||||
conn.execSQL(CATEGORIES_TABLE_CREATE);
|
||||
upgradeFilters(conn, true);
|
||||
}
|
||||
|
||||
public void upgradeFilters(SQLiteConnection conn, boolean onlyAdd) {
|
||||
List<PoiLegacyFilter> filters = PoiFilterDbHelper.this.getFilters( conn);
|
||||
List<PoiLegacyFilter> def = getUserDefinedDefaultFilters(mapPoiTypes);
|
||||
for(PoiLegacyFilter f : filters){
|
||||
PoiLegacyFilter std = null;
|
||||
for(PoiLegacyFilter d : def){
|
||||
if(f.getFilterId().equals(d.getFilterId())){
|
||||
std = d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for(String toDel : DEL) {
|
||||
if(f.getFilterId().equals(toDel)) {
|
||||
deleteFilter(conn, f);
|
||||
}
|
||||
}
|
||||
if(std != null){
|
||||
if(!onlyAdd){
|
||||
editFilter(conn, std);
|
||||
} else {
|
||||
updateName(conn, std);
|
||||
}
|
||||
def.remove(std);
|
||||
}
|
||||
}
|
||||
for(PoiLegacyFilter d : def){
|
||||
addFilter(d, conn, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void onUpgrade(SQLiteConnection conn, int oldVersion, int newVersion) {
|
||||
upgradeFilters(conn, false);
|
||||
if(newVersion <= 5) {
|
||||
deleteOldFilters(conn);
|
||||
}
|
||||
conn.setVersion(newVersion);
|
||||
}
|
||||
|
||||
protected boolean addFilter(PoiLegacyFilter p, SQLiteConnection db, boolean addOnlyCategories){
|
||||
private void deleteOldFilters(SQLiteConnection conn) {
|
||||
for (String toDel : DEL) {
|
||||
deleteFilter(conn, "user_" + toDel);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean addFilter(PoiLegacyFilter 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$
|
||||
|
@ -493,14 +367,20 @@ public class PoiFiltersHelper {
|
|||
}
|
||||
|
||||
protected boolean deleteFilter(SQLiteConnection db, PoiLegacyFilter p){
|
||||
if(db != null){
|
||||
db.execSQL("DELETE FROM " + FILTER_NAME + " WHERE " +FILTER_COL_ID + " = ?",new Object[]{p.getFilterId()}); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
db.execSQL("DELETE FROM " + CATEGORIES_NAME + " WHERE " +CATEGORIES_FILTER_ID + " = ?", new Object[]{p.getFilterId()}); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import net.osmand.ResultMatcher;
|
|||
import net.osmand.data.Amenity;
|
||||
import net.osmand.osm.MapPoiTypes;
|
||||
import net.osmand.osm.PoiCategory;
|
||||
import net.osmand.osm.PoiFilter;
|
||||
import net.osmand.plus.OsmAndFormatter;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
|
@ -26,6 +27,7 @@ public class PoiLegacyFilter {
|
|||
public final static String USER_PREFIX = "user_"; //$NON-NLS-1$
|
||||
public final static String CUSTOM_FILTER_ID = USER_PREFIX + "custom_id"; //$NON-NLS-1$
|
||||
public final static String BY_NAME_FILTER_ID = USER_PREFIX + "by_name"; //$NON-NLS-1$
|
||||
public static final String NAME_FINDER_FILTER_ID = "name_finder";
|
||||
|
||||
private Map<PoiCategory, LinkedHashSet<String>> acceptedTypes = new LinkedHashMap<PoiCategory,
|
||||
LinkedHashSet<String>>();
|
||||
|
@ -45,19 +47,21 @@ public class PoiLegacyFilter {
|
|||
|
||||
|
||||
// constructor for standard filters
|
||||
public PoiLegacyFilter(PoiCategory type, OsmandApplication application){
|
||||
public PoiLegacyFilter(PoiFilter type, OsmandApplication application) {
|
||||
this.app = application;
|
||||
isStandardFilter = true;
|
||||
filterId = STD_PREFIX + (type == null? null: type.getName());
|
||||
filterId = STD_PREFIX + (type == null ? null : type.getName());
|
||||
poiTypes = application.getPoiTypes();
|
||||
name = type == null ? application.getString(R.string.poi_filter_closest_poi) : type.getTranslation(); //$NON-NLS-1$
|
||||
if (type == null) {
|
||||
initSearchAll();
|
||||
} else {
|
||||
acceptedTypes.put(type, null);
|
||||
type.putTypes(acceptedTypes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// constructor for user defined filters
|
||||
public PoiLegacyFilter(String name, String filterId, Map<PoiCategory, LinkedHashSet<String>> acceptedTypes, OsmandApplication app){
|
||||
this.app = app;
|
||||
|
|
|
@ -466,7 +466,6 @@ public class ResourceManager {
|
|||
boolean isFirstInstall = context.getSettings().PREVIOUS_INSTALLED_VERSION.get().equals("");
|
||||
unpackBundledAssets(assetManager, applicationDataDir, progress, isFirstInstall);
|
||||
context.getSettings().PREVIOUS_INSTALLED_VERSION.set(Version.getFullVersion(context));
|
||||
context.getPoiFilters().updateFilters(false);
|
||||
copyRegionsBoundaries();
|
||||
} catch (SQLiteException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
|
|
|
@ -81,39 +81,31 @@ public class POIMapLayer extends OsmandMapLayer implements ContextMenuLayer.ICon
|
|||
@Override
|
||||
protected List<Amenity> calculateResult(RotatedTileBox tileBox) {
|
||||
QuadRect latLonBounds = tileBox.getLatLonBounds();
|
||||
// if(path) {
|
||||
// RouteCalculationResult result = routingHelper.getRoute();
|
||||
// return resourceManager.searchAmenitiesOnThePath(result.getImmutableAllLocations(), radius, filter, null);
|
||||
// } else {
|
||||
return resourceManager.searchAmenities(filter, latLonBounds.top, latLonBounds.left,
|
||||
latLonBounds.bottom, latLonBounds.right, tileBox.getZoom(), new ResultMatcher<Amenity>() {
|
||||
if (filter == null) {
|
||||
return new ArrayList<Amenity>();
|
||||
}
|
||||
return resourceManager.searchAmenities(filter, latLonBounds.top, latLonBounds.left,
|
||||
latLonBounds.bottom, latLonBounds.right, tileBox.getZoom(), new ResultMatcher<Amenity>() {
|
||||
|
||||
@Override
|
||||
public boolean publish(Amenity object) {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean publish(Amenity object) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return isInterrupted();
|
||||
}
|
||||
});
|
||||
// }
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return isInterrupted();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public PoiLegacyFilter getFilter() {
|
||||
return filter;
|
||||
}
|
||||
|
||||
public void setFilter(PoiLegacyFilter filter) {
|
||||
this.filter = filter;
|
||||
data.clearCache();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void getAmenityFromPoint(RotatedTileBox tb, PointF point, List<? super Amenity> am) {
|
||||
List<Amenity> objects = data.getResults();
|
||||
if (objects != null) {
|
||||
|
|
Loading…
Reference in a new issue