Merge pull request #2541 from osmandapp/cities-search
Fix #2471 and #2540
This commit is contained in:
commit
5f01735c07
3 changed files with 93 additions and 66 deletions
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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$
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue