Merge pull request #2541 from osmandapp/cities-search

Fix #2471 and #2540
This commit is contained in:
Roman Inflianskas 2016-05-13 19:37:14 +03:00
commit 5f01735c07
3 changed files with 93 additions and 66 deletions

View file

@ -296,7 +296,7 @@ public abstract class SearchByNameAbstractActivity<T> extends OsmandListActivity
protected void finishInitializing(List<T> list){ protected void finishInitializing(List<T> list){
Comparator<? super T> cmp = createComparator(); Comparator<? super T> cmp = createComparator();
getListAdapter().sort(cmp); getListAdapter().sort(cmp);
if(list != null){ if (list != null) {
Collections.sort(list,cmp); Collections.sort(list,cmp);
initialListToFilter = list; initialListToFilter = list;
} }
@ -393,11 +393,11 @@ public abstract class SearchByNameAbstractActivity<T> extends OsmandListActivity
@Override @Override
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
String currentFilter = SearchByNameAbstractActivity.this.currentFilter; String currentFilter = SearchByNameAbstractActivity.this.currentFilter;
if(msg.what == MESSAGE_CLEAR_LIST){ if (msg.what == MESSAGE_CLEAR_LIST){
minimalIndex = Integer.MAX_VALUE; minimalIndex = Integer.MAX_VALUE;
minimalText = null; minimalText = null;
getListAdapter().clear(); getListAdapter().clear();
if(currentFilter.length() == 0) { if (currentFilter.length() == 0) {
endingMap.clear(); endingMap.clear();
} }
updateTextBox(currentFilter, "", null, true); updateTextBox(currentFilter, "", null, true);

View file

@ -34,6 +34,16 @@ public class SearchCityByNameActivity extends SearchByNameAbstractActivity<City>
private Button searchVillages; private Button searchVillages;
private OsmandSettings osmandSettings; private OsmandSettings osmandSettings;
@Override
protected void finishInitializing(List<City> list) {
// Show villages if cities are not present in this region
if (list != null && list.isEmpty()) {
searchVillagesMode = 0;
searchVillages.setVisibility(View.GONE);
}
super.finishInitializing(list);
}
@Override @Override
protected void reset() { protected void reset() {
//This is really only a "clear input text field", hence do not reset settings here //This is really only a "clear input text field", hence do not reset settings here
@ -61,8 +71,8 @@ public class SearchCityByNameActivity extends SearchByNameAbstractActivity<City>
}); });
getListView().addFooterView(ll); getListView().addFooterView(ll);
} }
@Override @Override
protected Comparator<? super City> createComparator() { protected Comparator<? super City> createComparator() {
final StringMatcherMode startsWith = CollatorStringMatcher.StringMatcherMode.CHECK_ONLY_STARTS_WITH; final StringMatcherMode startsWith = CollatorStringMatcher.StringMatcherMode.CHECK_ONLY_STARTS_WITH;
@ -71,34 +81,34 @@ public class SearchCityByNameActivity extends SearchByNameAbstractActivity<City>
@Override @Override
public AsyncTask<Object, ?, ?> getInitializeTask() { public AsyncTask<Object, ?, ?> getInitializeTask() {
return new AsyncTask<Object, City, List<City>>(){ return new AsyncTask<Object, City, List<City>>() {
@Override @Override
protected void onPostExecute(List<City> result) { protected void onPostExecute(List<City> result) {
setLabelText(R.string.incremental_search_city); setLabelText(R.string.incremental_search_city);
progress.setVisibility(View.INVISIBLE); progress.setVisibility(View.INVISIBLE);
finishInitializing(result); finishInitializing(result);
} }
@Override @Override
protected void onPreExecute() { protected void onPreExecute() {
setLabelText(R.string.loading_cities); setLabelText(R.string.loading_cities);
progress.setVisibility(View.VISIBLE); progress.setVisibility(View.VISIBLE);
} }
@Override @Override
protected List<City> doInBackground(Object... params) { protected List<City> doInBackground(Object... params) {
region = ((OsmandApplication)getApplication()).getResourceManager().getRegionRepository(settings.getLastSearchedRegion()); region = ((OsmandApplication) getApplication()).getResourceManager().getRegionRepository(settings.getLastSearchedRegion());
if(region != null){ if (region != null) {
// preload cities // preload cities
region.preloadCities(new ResultMatcher<City>() { region.preloadCities(new ResultMatcher<City>() {
@Override @Override
public boolean publish(City object) { public boolean publish(City object) {
addObjectToInitialList(object); addObjectToInitialList(object);
return true; return true;
} }
@Override @Override
public boolean isCancelled() { public boolean isCancelled() {
return false; return false;
@ -110,11 +120,11 @@ public class SearchCityByNameActivity extends SearchByNameAbstractActivity<City>
} }
}; };
} }
@Override @Override
protected void filterLoop(String query, Collection<City> list) { protected void filterLoop(String query, Collection<City> list) {
redefineSearchVillagesMode(query.length()); redefineSearchVillagesMode(query.length());
if(!initializeTaskIsFinished() || (query.length() <= 3 && !searchVillages())){ if (!initializeTaskIsFinished() || (query.length() <= 3 && !searchVillages())) {
super.filterLoop(query, list); super.filterLoop(query, list);
} else { } else {
region.fillWithSuggestedCities(query, new ResultMatcher<City>() { region.fillWithSuggestedCities(query, new ResultMatcher<City>() {
@ -139,9 +149,9 @@ public class SearchCityByNameActivity extends SearchByNameAbstractActivity<City>
} }
private void redefineSearchVillagesMode(int queryLen) { private void redefineSearchVillagesMode(int queryLen) {
if(searchVillagesMode == 1) { if (searchVillagesMode == 1) {
searchVillagesMode = 0; searchVillagesMode = 0;
} else if(searchVillagesMode == 0 && queryLen <= 3) { } else if (searchVillagesMode == 0 && queryLen <= 3 && !initialListToFilter.isEmpty()) {
searchVillagesMode = -1; searchVillagesMode = -1;
uiHandler.post(new Runnable() { uiHandler.post(new Runnable() {
@Override @Override
@ -152,17 +162,17 @@ public class SearchCityByNameActivity extends SearchByNameAbstractActivity<City>
} }
} }
@Override @Override
public String getText(City obj) { public String getText(City obj) {
LatLon l = obj.getLocation(); LatLon l = obj.getLocation();
if (getCurrentFilter().length() > 2 ) { if (getCurrentFilter().length() > 2) {
String name = getShortText(obj); String name = getShortText(obj);
if(obj.getClosestCity() != null) { if (obj.getClosestCity() != null) {
name += " - " + obj.getClosestCity().getName(region.getLang()) ; name += " - " + obj.getClosestCity().getName(region.getLang());
LatLon loc = obj.getClosestCity().getLocation(); LatLon loc = obj.getClosestCity().getLocation();
if(loc != null && l != null) { if (loc != null && l != null) {
name += " " + OsmAndFormatter.getFormattedDistance((int) MapUtils.getDistance(l, loc), getMyApplication()); name += " " + OsmAndFormatter.getFormattedDistance((int) MapUtils.getDistance(l, loc), getMyApplication());
} }
return name; return name;
} else { } else {
@ -175,17 +185,17 @@ public class SearchCityByNameActivity extends SearchByNameAbstractActivity<City>
return getShortText(obj); return getShortText(obj);
} }
} }
@Override @Override
public String getShortText(City obj) { public String getShortText(City obj) {
String lName = obj.getName(region.getLang()); String lName = obj.getName(region.getLang());
String name = obj.getName(); String name = obj.getName();
if(!lName.equals(name)) { if (!lName.equals(name)) {
return lName + " / " + name; return lName + " / " + name;
} }
return lName; return lName;
} }
@Override @Override
public void itemSelected(City obj) { public void itemSelected(City obj) {
settings.setLastSearchedCity(obj.getId(), obj.getName(region.getLang()), obj.getLocation()); settings.setLastSearchedCity(obj.getId(), obj.getName(region.getLang()), obj.getLocation());
@ -203,10 +213,9 @@ public class SearchCityByNameActivity extends SearchByNameAbstractActivity<City>
private final class CityComparator implements Comparator<City> { private final class CityComparator implements Comparator<City> {
private final StringMatcherMode startsWith; private final StringMatcherMode startsWith;
private final net.osmand.Collator cs; private final net.osmand.Collator cs;
private final String lang ; private final String lang;
private CityComparator(StringMatcherMode startsWith, private CityComparator(StringMatcherMode startsWith, String lang) {
String lang ) {
this.startsWith = startsWith; this.startsWith = startsWith;
this.cs = OsmAndCollator.primaryCollator(); this.cs = OsmAndCollator.primaryCollator();
this.lang = lang; this.lang = lang;
@ -215,16 +224,16 @@ public class SearchCityByNameActivity extends SearchByNameAbstractActivity<City>
@Override @Override
public int compare(City lhs, City rhs) { public int compare(City lhs, City rhs) {
final String part = getFilter().toString(); final String part = getFilter().toString();
int compare = compareCityType(lhs, rhs); int compare = compareCityType(lhs, rhs);
if (compare != 0) { if (compare != 0) {
return compare; return compare;
} }
boolean st1 = CollatorStringMatcher.cmatches(cs, lhs.getName(lang), part, startsWith); boolean st1 = CollatorStringMatcher.cmatches(cs, lhs.getName(lang), part, startsWith);
boolean st2 = CollatorStringMatcher.cmatches(cs, rhs.getName(lang), part, startsWith); boolean st2 = CollatorStringMatcher.cmatches(cs, rhs.getName(lang), part, startsWith);
if(st1 != st2) { if (st1 != st2) {
return st1 ? 1 : -1; return st1 ? 1 : -1;
} }
compare = cs.compare(getText(lhs), getText(rhs)); compare = cs.compare(getText(lhs), getText(rhs));
if (compare != 0) { if (compare != 0) {
return compare; return compare;
@ -240,12 +249,12 @@ public class SearchCityByNameActivity extends SearchByNameAbstractActivity<City>
private int compareCityType(City lhs, City rhs) { private int compareCityType(City lhs, City rhs) {
boolean c1 = lhs.getType() == CityType.CITY || lhs.getType() == CityType.TOWN; boolean c1 = lhs.getType() == CityType.CITY || lhs.getType() == CityType.TOWN;
boolean c2 = rhs.getType() == CityType.CITY || rhs.getType() == CityType.TOWN; boolean c2 = rhs.getType() == CityType.CITY || rhs.getType() == CityType.TOWN;
if(c1 == c2){ if (c1 == c2) {
return 0; return 0;
} }
return c1? 1 : -1; return c1 ? 1 : -1;
} }
} }
} }

View file

@ -184,6 +184,34 @@ public class RegionAddressRepositoryBinary implements RegionAddressRepository {
return req.getSearchResults(); return req.getSearchResults();
} }
private List<City> fillWithVillages(String name, String lang, final ResultMatcher<City> resultMatcher) throws IOException {
List<City> result = new ArrayList<City>();
List<City> foundCities = file.getCities(BinaryMapIndexReader.buildAddressRequest(new ResultMatcher<City>() {
List<City> cache = new ArrayList<City>();
@Override
public boolean publish(City c) {
if(c.getLocation() != null) {
City ct = getClosestCity(c.getLocation(), cache);
c.setClosestCity(ct);
}
return resultMatcher.publish(c);
}
@Override
public boolean isCancelled() {
return resultMatcher.isCancelled();
}
}), new CollatorStringMatcher(name, StringMatcherMode.CHECK_STARTS_FROM_SPACE), lang,
BinaryMapAddressReaderAdapter.VILLAGES_TYPE);
for (City c : foundCities) {
result.add(c);
if (resultMatcher.isCancelled()) {
return result;
}
}
return result;
}
@Override @Override
public synchronized List<City> fillWithSuggestedCities(String name, final ResultMatcher<City> resultMatcher, boolean searchVillages, LatLon currentLocation) { public synchronized List<City> fillWithSuggestedCities(String name, final ResultMatcher<City> resultMatcher, boolean searchVillages, LatLon currentLocation) {
@ -191,16 +219,30 @@ public class RegionAddressRepositoryBinary implements RegionAddressRepository {
if (cities.isEmpty()) { if (cities.isEmpty()) {
preloadCities(resultMatcher); preloadCities(resultMatcher);
citiesToFill.addAll(cities.values()); citiesToFill.addAll(cities.values());
return citiesToFill; if (!citiesToFill.isEmpty()) {
return citiesToFill;
}
} }
String lang = getLang();
preloadCities(null); preloadCities(null);
if (name.length() == 0) { if (name.length() == 0) {
citiesToFill.addAll(cities.values()); citiesToFill.addAll(cities.values());
return citiesToFill; if (searchVillages) {
for (City c : citiesToFill) {
resultMatcher.publish(c);
}
try {
citiesToFill.addAll(fillWithVillages(name, lang, resultMatcher));
} catch (IOException e) {
log.error("Disk operation failed", e); //$NON-NLS-1$
}
}
if (!citiesToFill.isEmpty()) {
return citiesToFill;
}
} }
try { try {
String lang = getLang();
// essentially index is created that cities towns are first in cities map // essentially index is created that cities towns are first in cities map
if (/*name.length() >= 2 && Algorithms.containsDigit(name) && */searchVillages) { if (/*name.length() >= 2 && Algorithms.containsDigit(name) && */searchVillages) {
// also try to identify postcodes // also try to identify postcodes
@ -229,35 +271,11 @@ public class RegionAddressRepositoryBinary implements RegionAddressRepository {
} }
} }
int initialsize = citiesToFill.size(); int initialize = citiesToFill.size();
if (/*name.length() >= 3 && */searchVillages) { if (/*name.length() >= 3 && */searchVillages) {
citiesToFill.addAll(fillWithVillages(name, lang, resultMatcher));
List<City> foundCities = file.getCities(BinaryMapIndexReader.buildAddressRequest(new ResultMatcher<City>() {
List<City> cache = new ArrayList<City>();
@Override
public boolean publish(City c) {
if(c.getLocation() != null) {
City ct = getClosestCity(c.getLocation(), cache);
c.setClosestCity(ct);
}
return resultMatcher.publish(c);
}
@Override
public boolean isCancelled() {
return resultMatcher.isCancelled();
}
}), new CollatorStringMatcher(name,StringMatcherMode.CHECK_STARTS_FROM_SPACE), lang,
BinaryMapAddressReaderAdapter.VILLAGES_TYPE);
for (City c : foundCities) {
citiesToFill.add(c);
if (resultMatcher.isCancelled()) {
return citiesToFill;
}
}
} }
log.debug("Loaded citites " + (citiesToFill.size() - initialsize)); //$NON-NLS-1$ log.debug("Loaded citites " + (citiesToFill.size() - initialize)); //$NON-NLS-1$
} catch (IOException e) { } catch (IOException e) {
log.error("Disk operation failed", e); //$NON-NLS-1$ log.error("Disk operation failed", e); //$NON-NLS-1$
} }