package net.osmand.plus; import android.content.Context; import android.support.annotation.Nullable; import net.osmand.data.LatLon; import net.osmand.data.LocationPoint; import net.osmand.data.PointDescription; import net.osmand.util.Algorithms; import java.util.ArrayList; import java.util.List; public class MapMarkersHelper { public static final int MAP_MARKERS_COLORS_COUNT = 7; private List<MapMarker> mapMarkers = new ArrayList<>(); private List<MapMarker> mapMarkersHistory = new ArrayList<>(); private OsmandSettings settings; private List<MapMarkerChangedListener> listeners = new ArrayList<>(); private OsmandApplication ctx; private boolean startFromMyLocation; public interface MapMarkerChangedListener { void onMapMarkerChanged(MapMarker mapMarker); void onMapMarkersChanged(); } public static class MapMarker implements LocationPoint { public LatLon point; private PointDescription pointDescription; public int colorIndex; public int index; public boolean history; public boolean selected; public int dist; public MapMarker(LatLon point, PointDescription name, int colorIndex, boolean selected, int index) { this.point = point; this.pointDescription = name; this.colorIndex = colorIndex; this.selected = selected; this.index = index; } public PointDescription getPointDescription(Context ctx) { return new PointDescription(PointDescription.POINT_TYPE_MAP_MARKER, ctx.getString(R.string.map_marker), getOnlyName()); } public String getName(Context ctx) { String name; PointDescription pd = getPointDescription(ctx); if (Algorithms.isEmpty(pd.getName())) { name = pd.getTypeName(); } else { name = pd.getName(); } return name; } public PointDescription getOriginalPointDescription() { return pointDescription; } public String getOnlyName() { return pointDescription == null ? "" : pointDescription.getName(); } public double getLatitude() { return point.getLatitude(); } public double getLongitude() { return point.getLongitude(); } @Override public int getColor() { return 0; } @Override public boolean isVisible() { return false; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; MapMarker mapMarker = (MapMarker) o; if (colorIndex != mapMarker.colorIndex) return false; return point.equals(mapMarker.point); } @Override public int hashCode() { int result = point.hashCode(); result = 31 * result + colorIndex; return result; } } public MapMarkersHelper(OsmandApplication ctx) { this.ctx = ctx; settings = ctx.getSettings(); startFromMyLocation = settings.ROUTE_MAP_MARKERS_START_MY_LOC.get(); readFromSettings(); } public boolean isStartFromMyLocation() { return startFromMyLocation; } public void setStartFromMyLocation(boolean startFromMyLocation) { this.startFromMyLocation = startFromMyLocation; settings.ROUTE_MAP_MARKERS_START_MY_LOC.set(startFromMyLocation); } public void lookupAddressAll() { for (MapMarker mapMarker : mapMarkers) { lookupAddress(mapMarker, false); } for (MapMarker mapMarker : mapMarkersHistory) { lookupAddress(mapMarker, true); } } private void readFromSettings() { mapMarkers.clear(); mapMarkersHistory.clear(); List<LatLon> ips = settings.getMapMarkersPoints(); List<String> desc = settings.getMapMarkersPointDescriptions(ips.size()); List<Integer> colors = settings.getMapMarkersColors(ips.size()); List<Boolean> selections = settings.getMapMarkersSelections(ips.size()); int colorIndex = 0; for (int i = 0; i < ips.size(); i++) { if (colors.size() > i) { colorIndex = colors.get(i); } MapMarker mapMarker = new MapMarker(ips.get(i), PointDescription.deserializeFromString(desc.get(i), ips.get(i)), colorIndex, selections.get(i), i); mapMarkers.add(mapMarker); } ips = settings.getMapMarkersHistoryPoints(); desc = settings.getMapMarkersHistoryPointDescriptions(ips.size()); for (int i = 0; i < ips.size(); i++) { MapMarker mapMarker = new MapMarker(ips.get(i), PointDescription.deserializeFromString(desc.get(i), ips.get(i)), 0, false, i); mapMarker.history = true; mapMarkersHistory.add(mapMarker); } if (!ctx.isApplicationInitializing()) { lookupAddressAll(); } } private void lookupAddress(final MapMarker mapMarker, final boolean history) { if (mapMarker != null && mapMarker.pointDescription.isSearchingAddress(ctx)) { cancelPointAddressRequests(mapMarker.point); GeocodingLookupService.AddressLookupRequest lookupRequest = new GeocodingLookupService.AddressLookupRequest(mapMarker.point, new GeocodingLookupService.OnAddressLookupResult() { @Override public void geocodingDone(String address) { if (Algorithms.isEmpty(address)) { mapMarker.pointDescription.setName(PointDescription.getAddressNotFoundStr(ctx)); } else { mapMarker.pointDescription.setName(address); } if (history) { settings.updateMapMarkerHistory(mapMarker.point.getLatitude(), mapMarker.point.getLongitude(), mapMarker.pointDescription, mapMarker.colorIndex); } else { settings.updateMapMarker(mapMarker.point.getLatitude(), mapMarker.point.getLongitude(), mapMarker.pointDescription, mapMarker.colorIndex, mapMarker.selected); } updateMarker(mapMarker); } }, null); ctx.getGeocodingLookupService().lookupAddress(lookupRequest); } } public void removeMapMarker(int index) { settings.deleteMapMarker(index); MapMarker mapMarker = mapMarkers.remove(index); cancelPointAddressRequests(mapMarker.point); int ind = 0; for (MapMarker marker : mapMarkers) { marker.index = ind++; } refresh(); } public List<MapMarker> getMapMarkers() { return mapMarkers; } public MapMarker getFirstMapMarker() { if (mapMarkers.size() > 0) { return mapMarkers.get(0); } else { return null; } } public List<MapMarker> getMapMarkersHistory() { return mapMarkersHistory; } public List<MapMarker> getSelectedMarkers() { List<MapMarker> list = new ArrayList<>(); for (MapMarker m : this.mapMarkers) { if (m.selected) { list.add(m); } } return list; } public List<LatLon> getActiveMarkersLatLon() { List<LatLon> list = new ArrayList<>(); for (MapMarker m : this.mapMarkers) { list.add(m.point); } return list; } public List<LatLon> getSelectedMarkersLatLon() { List<LatLon> list = new ArrayList<>(); for (MapMarker m : this.mapMarkers) { if (m.selected) { list.add(m.point); } } return list; } public List<LatLon> getMarkersHistoryLatLon() { List<LatLon> list = new ArrayList<>(); for (MapMarker m : this.mapMarkersHistory) { list.add(m.point); } return list; } public void reverseActiveMarkersOrder() { cancelAddressRequests(); List<MapMarker> markers = new ArrayList<>(mapMarkers.size()); for (int i = mapMarkers.size() - 1; i >= 0; i--) { MapMarker marker = mapMarkers.get(i); markers.add(marker); } mapMarkers = markers; saveMapMarkers(mapMarkers, null); } public void removeActiveMarkers() { cancelAddressRequests(); for (int i = mapMarkers.size() - 1; i>= 0; i--) { MapMarker marker = mapMarkers.get(i); addMapMarkerHistory(marker); } settings.clearActiveMapMarkers(); readFromSettings(); refresh(); } public void removeMarkersHistory() { cancelAddressRequests(); settings.clearMapMarkersHistory(); readFromSettings(); refresh(); } public void addMapMarker(LatLon point, PointDescription historyName) { List<LatLon> points = new ArrayList<>(1); List<PointDescription> historyNames = new ArrayList<>(1); points.add(point); historyNames.add(historyName); addMapMarkers(points, historyNames); } public void addMapMarkers(List<LatLon> points, List<PointDescription> historyNames) { if (points.size() > 0) { int colorIndex = -1; double[] latitudes = new double[points.size()]; double[] longitudes = new double[points.size()]; List<PointDescription> pointDescriptions = new ArrayList<>(); int[] colorIndexes = new int[points.size()]; int[] positions = new int[points.size()]; boolean[] selections = new boolean[points.size()]; int[] indexes = new int[points.size()]; for (int i = 0; i < points.size(); i++) { LatLon point = points.get(i); PointDescription historyName = historyNames.get(i); final PointDescription pointDescription; if (historyName == null) { pointDescription = new PointDescription(PointDescription.POINT_TYPE_LOCATION, ""); } else { pointDescription = historyName; } if (pointDescription.isLocation() && Algorithms.isEmpty(pointDescription.getName())) { pointDescription.setName(PointDescription.getSearchAddressStr(ctx)); } if (colorIndex == -1) { if (mapMarkers.size() > 0) { colorIndex = (mapMarkers.get(0).colorIndex + 1) % MAP_MARKERS_COLORS_COUNT; } else { colorIndex = 0; } } else { colorIndex = (colorIndex + 1) % MAP_MARKERS_COLORS_COUNT; } latitudes[i] = point.getLatitude(); longitudes[i] = point.getLongitude(); pointDescriptions.add(pointDescription); colorIndexes[i] = colorIndex; positions[i] = -1 - i; selections[i] = false; indexes[i] = 0; } /* adding map marker to second topbar's row if (sortedMapMarkers.size() > 0) { MapMarker firstMarker = sortedMapMarkers.get(0); settings.updateMapMarker(firstMarker.getLatitude(), firstMarker.getLongitude(), firstMarker.pointDescription, firstMarker.colorIndex, -points.size(), firstMarker.selected); } */ settings.insertMapMarkers(latitudes, longitudes, pointDescriptions, colorIndexes, positions, selections, indexes); readFromSettings(); } } public void updateMapMarker(MapMarker marker, boolean refresh) { if (marker != null) { settings.updateMapMarker(marker.getLatitude(), marker.getLongitude(), marker.pointDescription, marker.colorIndex, marker.selected); if (refresh) { readFromSettings(); refresh(); } } } public void moveMapMarker(@Nullable MapMarker marker, LatLon latLon) { if (marker != null) { settings.moveMapMarker(new LatLon(marker.getLatitude(), marker.getLongitude()), latLon, marker.pointDescription, marker.colorIndex, marker.selected); marker.point = new LatLon(latLon.getLatitude(), latLon.getLongitude()); readFromSettings(); refresh(); } } public void removeMapMarker(MapMarker marker) { if (marker != null) { settings.deleteMapMarker(marker.index); readFromSettings(); refresh(); } } public void addMapMarkerHistory(MapMarker marker) { if (marker != null) { settings.insertMapMarkerHistory(marker.getLatitude(), marker.getLongitude(), marker.pointDescription, marker.colorIndex, 0); readFromSettings(); refresh(); } } public void removeMapMarkerHistory(MapMarker marker) { if (marker != null) { settings.deleteMapMarkerHistory(marker.index); readFromSettings(); refresh(); } } public void saveMapMarkers(List<MapMarker> markers, List<MapMarker> markersHistory) { if (markers != null) { List<LatLon> ls = new ArrayList<>(markers.size()); List<String> names = new ArrayList<>(markers.size()); List<Integer> colors = new ArrayList<>(markers.size()); List<Boolean> selections = new ArrayList<>(markers.size()); for (MapMarker marker : markers) { ls.add(marker.point); names.add(PointDescription.serializeToString(marker.pointDescription)); colors.add(marker.colorIndex); selections.add(marker.selected); } settings.saveMapMarkers(ls, names, colors, selections); } if (markersHistory != null) { List<LatLon> ls = new ArrayList<>(markersHistory.size()); List<String> names = new ArrayList<>(markersHistory.size()); List<Integer> colors = new ArrayList<>(markersHistory.size()); for (MapMarker marker : markersHistory) { ls.add(marker.point); names.add(PointDescription.serializeToString(marker.pointDescription)); colors.add(marker.colorIndex); } settings.saveMapMarkersHistory(ls, names, colors); } if (markers != null || markersHistory != null) { readFromSettings(); refresh(); } } public void addListener(MapMarkerChangedListener l) { if (!listeners.contains(l)) { listeners.add(l); } } public void removeListener(MapMarkerChangedListener l) { listeners.remove(l); } private void updateMarker(MapMarker marker) { for (MapMarkerChangedListener l : listeners) { l.onMapMarkerChanged(marker); } } private void updateMarkers() { for (MapMarkerChangedListener l : listeners) { l.onMapMarkersChanged(); } } public void refresh() { updateMarkers(); } private void cancelAddressRequests() { List<LatLon> list = getActiveMarkersLatLon(); for (LatLon latLon : list) { cancelPointAddressRequests(latLon); } list = getMarkersHistoryLatLon(); for (LatLon latLon : list) { cancelPointAddressRequests(latLon); } } private void cancelPointAddressRequests(LatLon latLon) { if (latLon != null) { ctx.getGeocodingLookupService().cancel(latLon); } } }