diff --git a/OsmAnd-java/src/main/java/net/osmand/GPXUtilities.java b/OsmAnd-java/src/main/java/net/osmand/GPXUtilities.java index 11bba3c899..f9b71be11d 100644 --- a/OsmAnd-java/src/main/java/net/osmand/GPXUtilities.java +++ b/OsmAnd-java/src/main/java/net/osmand/GPXUtilities.java @@ -112,7 +112,7 @@ public class GPXUtilities { } public interface GPXExtensionsReader { - public boolean readExtensions(GPXFile res, XmlPullParser parser) throws Exception; + public boolean readExtensions(GPXFile res, XmlPullParser parser) throws IOException, XmlPullParserException; } public static class GPXExtensions { @@ -2085,7 +2085,7 @@ public class GPXUtilities { } } - private static String readText(XmlPullParser parser, String key) throws XmlPullParserException, IOException { + public static String readText(XmlPullParser parser, String key) throws XmlPullParserException, IOException { int tok; StringBuilder text = null; while ((tok = parser.next()) != XmlPullParser.END_DOCUMENT) { @@ -2146,18 +2146,19 @@ public class GPXUtilities { return time; } - public static GPXFile loadGPXFile(File f) { + public static GPXFile loadGPXFile(File file) { + return loadGPXFile(file, null); + } + + public static GPXFile loadGPXFile(File f, GPXExtensionsReader extensionsReader) { FileInputStream fis = null; try { fis = new FileInputStream(f); - GPXFile file = loadGPXFile(fis); + GPXFile file = loadGPXFile(fis, extensionsReader); file.path = f.getAbsolutePath(); file.modifiedTime = f.lastModified(); - try { - fis.close(); - } catch (IOException e) { - } + Algorithms.closeStream(fis); return file; } catch (IOException e) { GPXFile res = new GPXFile(null); @@ -2166,24 +2167,15 @@ public class GPXUtilities { res.error = e; return res; } finally { - try { - if (fis != null) - fis.close(); - } catch (IOException ignore) { - // ignore - } + Algorithms.closeStream(fis); } } - public static class ItineraryGroupItem { - public String name; - public String type; - public String path; - public String alias; - public String categories; + public static GPXFile loadGPXFile(InputStream stream) { + return loadGPXFile(stream, null); } - public static GPXFile loadGPXFile(InputStream f) { + public static GPXFile loadGPXFile(InputStream stream, GPXExtensionsReader extensionsReader) { GPXFile gpxFile = new GPXFile(null); SimpleDateFormat format = new SimpleDateFormat(GPX_TIME_FORMAT, Locale.US); format.setTimeZone(TimeZone.getTimeZone("UTC")); @@ -2191,7 +2183,7 @@ public class GPXUtilities { formatMillis.setTimeZone(TimeZone.getTimeZone("UTC")); try { XmlPullParser parser = PlatformUtil.newXMLPullParser(); - parser.setInput(getUTF8Reader(f)); + parser.setInput(getUTF8Reader(stream)); Track routeTrack = new Track(); TrkSegment routeTrackSegment = new TrkSegment(); routeTrack.segments.add(routeTrackSegment); @@ -2239,17 +2231,19 @@ public class GPXUtilities { break; default: - Map values = readTextMap(parser, tag); - if (values.size() > 0) { - for (Entry entry : values.entrySet()) { - String t = entry.getKey().toLowerCase(); - String value = entry.getValue(); - parse.getExtensionsToWrite().put(t, value); - if (tag.equals("speed") && parse instanceof WptPt) { - try { - ((WptPt) parse).speed = Float.parseFloat(value); - } catch (NumberFormatException e) { - log.debug(e.getMessage(), e); + if (extensionsReader == null || !extensionsReader.readExtensions(gpxFile, parser)) { + Map values = readTextMap(parser, tag); + if (values.size() > 0) { + for (Entry entry : values.entrySet()) { + String t = entry.getKey().toLowerCase(); + String value = entry.getValue(); + parse.getExtensionsToWrite().put(t, value); + if (tag.equals("speed") && parse instanceof WptPt) { + try { + ((WptPt) parse).speed = Float.parseFloat(value); + } catch (NumberFormatException e) { + log.debug(e.getMessage(), e); + } } } } diff --git a/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java b/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java index d3a280632e..f3c3d1904b 100644 --- a/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java +++ b/OsmAnd-java/src/main/java/net/osmand/util/Algorithms.java @@ -26,8 +26,8 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; import java.util.Map; @@ -305,7 +305,7 @@ public class Algorithms { if (isEmpty(s)) { return Collections.emptySet(); } - return new HashSet<>(Arrays.asList(s.split(split))); + return new LinkedHashSet<>(Arrays.asList(s.split(split))); } public static String encodeStringSet(Set set) { diff --git a/OsmAnd/src/net/osmand/data/FavouritePoint.java b/OsmAnd/src/net/osmand/data/FavouritePoint.java index 4414de8d87..bb52b9fd35 100644 --- a/OsmAnd/src/net/osmand/data/FavouritePoint.java +++ b/OsmAnd/src/net/osmand/data/FavouritePoint.java @@ -24,12 +24,11 @@ import net.osmand.util.Algorithms; import java.io.Serializable; -import static net.osmand.plus.itinerary.ItineraryHelper.PASSED_TIMESTAMP; - public class FavouritePoint implements Serializable, LocationPoint { private static final long serialVersionUID = 729654300829771466L; + private static final String PASSED_TIMESTAMP = "passed_timestamp"; private static final String HIDDEN = "hidden"; private static final String ADDRESS_EXTENSION = "address"; public static final BackgroundType DEFAULT_BACKGROUND_TYPE = BackgroundType.CIRCLE; @@ -348,8 +347,8 @@ public class FavouritePoint implements Serializable, LocationPoint { result = prime * result + (int) Math.floor(latitude * 10000); result = prime * result + (int) Math.floor(longitude * 10000); result = prime * result + (int) Math.floor(altitude * 10000); - result = prime * result + (int) Math.floor(timestamp * 10000); - result = prime * result + (int) Math.floor(passedTimestamp * 10000); + result = prime * result + (int) (timestamp ^ (timestamp >>> 32)); + result = prime * result + (int) (passedTimestamp ^ (passedTimestamp >>> 32)); result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((category == null) ? 0 : category.hashCode()); result = prime * result + ((description == null) ? 0 : description.hashCode()); @@ -487,7 +486,6 @@ public class FavouritePoint implements Serializable, LocationPoint { String time = pt.getExtensionsToWrite().get(PASSED_TIMESTAMP); fp.setPassedTimestamp(Algorithms.parseLongSilently(time, 0)); } - BackgroundType backgroundType = BackgroundType.getByTypeName(pt.getBackgroundType(), null); fp.setBackgroundType(backgroundType); return fp; diff --git a/OsmAnd/src/net/osmand/plus/AppInitializer.java b/OsmAnd/src/net/osmand/plus/AppInitializer.java index afb7dedfbe..aa9833cfc7 100644 --- a/OsmAnd/src/net/osmand/plus/AppInitializer.java +++ b/OsmAnd/src/net/osmand/plus/AppInitializer.java @@ -685,7 +685,7 @@ public class AppInitializer implements IProgress { // restore backuped favorites to normal file restoreBackupForFavoritesFiles(); notifyEvent(InitEvents.RESTORE_BACKUPS); - app.itineraryHelper.syncMarkersGroups(); + app.itineraryHelper.syncAllGroups(); app.searchUICore.initSearchUICore(); checkLiveUpdatesAlerts(); diff --git a/OsmAnd/src/net/osmand/plus/FavouritesDbHelper.java b/OsmAnd/src/net/osmand/plus/FavouritesDbHelper.java index 36321520ac..14e98dda9a 100644 --- a/OsmAnd/src/net/osmand/plus/FavouritesDbHelper.java +++ b/OsmAnd/src/net/osmand/plus/FavouritesDbHelper.java @@ -711,17 +711,6 @@ public class FavouritesDbHelper { return null; } - @Nullable - public FavouritePoint getFavByLatLon(@NonNull LatLon latLon, String name) { - for (FavouritePoint fav : cachedFavoritePoints) { - if (latLon.equals(new LatLon(fav.getLatitude(), fav.getLongitude())) - && Algorithms.stringsEqual(fav.getName(), name)) { - return fav; - } - } - return null; - } - public List getFavoriteGroups() { return favoriteGroups; } @@ -848,9 +837,7 @@ public class FavouritesDbHelper { } for (WptPt p : res.getPoints()) { FavouritePoint fp = FavouritePoint.fromWpt(p, context); - if (fp != null) { - points.put(getKey(fp), fp); - } + points.put(getKey(fp), fp); } return true; } diff --git a/OsmAnd/src/net/osmand/plus/itinerary/ItineraryGroup.java b/OsmAnd/src/net/osmand/plus/itinerary/ItineraryGroup.java new file mode 100644 index 0000000000..dc6a292992 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/itinerary/ItineraryGroup.java @@ -0,0 +1,69 @@ +package net.osmand.plus.itinerary; + +import net.osmand.plus.mapmarkers.MapMarkersGroup; +import net.osmand.util.Algorithms; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import static net.osmand.plus.itinerary.ItineraryHelper.CATEGORIES_SPLIT; + +public class ItineraryGroup { + + public String id; + public String name; + public ItineraryType type = ItineraryType.POINTS; + public Set wptCategories; + public List itineraryItems = new ArrayList<>(); + + public ItineraryGroup() { + + } + + public ItineraryGroup(ItineraryGroup group) { + this.id = group.id; + this.name = group.name; + this.type = group.type; + this.wptCategories = group.wptCategories; + this.itineraryItems.addAll(group.itineraryItems); + } + + public static ItineraryGroup createGroup(MapMarkersGroup markersGroup) { + ItineraryGroup group = new ItineraryGroup(); + group.id = markersGroup.getId(); + group.name = markersGroup.getName(); + group.type = markersGroup.getType(); + group.wptCategories = markersGroup.getWptCategories(); + return group; + } + + public static ItineraryGroup createGroup(ItineraryGroupInfo groupInfo) { + ItineraryGroup group = new ItineraryGroup(); + group.name = groupInfo.name; + group.type = ItineraryType.findTypeForName(groupInfo.type); + group.id = group.type == ItineraryType.TRACK ? groupInfo.path : groupInfo.name; + group.wptCategories = Algorithms.decodeStringSet(groupInfo.categories, CATEGORIES_SPLIT); + return group; + } + + public ItineraryGroupInfo convertToGroupInfo() { + ItineraryGroupInfo groupInfo = new ItineraryGroupInfo(); + groupInfo.name = name; + groupInfo.type = type.name().toLowerCase(); + groupInfo.path = type == ItineraryType.TRACK ? id : null; + groupInfo.alias = groupInfo.type + ":" + (name != null ? name : ""); + if (!Algorithms.isEmpty(wptCategories)) { + groupInfo.categories = Algorithms.encodeStringSet(wptCategories, CATEGORIES_SPLIT); + } + return groupInfo; + } + + public static class ItineraryGroupInfo { + public String name; + public String type; + public String path; + public String alias; + public String categories; + } +} diff --git a/OsmAnd/src/net/osmand/plus/itinerary/ItineraryHelper.java b/OsmAnd/src/net/osmand/plus/itinerary/ItineraryHelper.java index a1f1db0425..c7a602df1c 100644 --- a/OsmAnd/src/net/osmand/plus/itinerary/ItineraryHelper.java +++ b/OsmAnd/src/net/osmand/plus/itinerary/ItineraryHelper.java @@ -6,9 +6,9 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import net.osmand.GPXUtilities; +import net.osmand.GPXUtilities.GPXExtensionsReader; import net.osmand.GPXUtilities.GPXExtensionsWriter; import net.osmand.GPXUtilities.GPXFile; -import net.osmand.GPXUtilities.ItineraryGroupItem; import net.osmand.GPXUtilities.WptPt; import net.osmand.IndexConstants; import net.osmand.PlatformUtil; @@ -22,6 +22,8 @@ import net.osmand.plus.GpxSelectionHelper; import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile; import net.osmand.plus.OsmandApplication; import net.osmand.plus.R; +import net.osmand.plus.Version; +import net.osmand.plus.itinerary.ItineraryGroup.ItineraryGroupInfo; import net.osmand.plus.mapmarkers.CategoriesSubHeader; import net.osmand.plus.mapmarkers.GroupHeader; import net.osmand.plus.mapmarkers.MapMarker; @@ -35,6 +37,8 @@ import net.osmand.plus.wikivoyage.data.TravelHelper; import net.osmand.util.Algorithms; import org.apache.commons.logging.Log; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import java.io.File; @@ -51,18 +55,21 @@ import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import static net.osmand.GPXUtilities.readText; import static net.osmand.GPXUtilities.writeNotNullText; +import static net.osmand.plus.FavouritesDbHelper.backup; import static net.osmand.plus.mapmarkers.MapMarkersHelper.BY_DATE_ADDED_DESC; +import static net.osmand.util.Algorithms.getFileNameWithoutExtension; public class ItineraryHelper { private static final Log log = PlatformUtil.getLog(ItineraryHelper.class); - public static final String PASSED_TIMESTAMP = "passed_timestamp"; - - private static final String CATEGORIES_SPLIT = ","; + protected static final String CATEGORIES_SPLIT = ","; private static final String FILE_TO_SAVE = "itinerary.gpx"; private static final String FILE_TO_BACKUP = "itinerary_bak.gpx"; + private static final String ITINERARY_ID = "itinerary_id"; + private static final String ITINERARY_GROUP = "itinerary_group"; private OsmandApplication app; @@ -82,179 +89,124 @@ public class ItineraryHelper { loadMarkersGroups(); } - public static class ItineraryItem { - - public final String id; - public final Object object; - public final ItineraryType type; - public final ItineraryGroup group; - - public ItineraryItem(ItineraryGroup group, Object object, ItineraryType type) { - this.type = type; - this.group = group; - this.object = object; - this.id = acquireItemId(object); - } - - private String acquireItemId(Object object) { - if (object instanceof MapMarker) { - return (((MapMarker) object)).id; - } else if (object instanceof WptPt) { - return (((WptPt) object)).name; - } else if (object instanceof FavouritePoint) { - return (((FavouritePoint) object)).getName(); - } - return ""; - } + public List getItineraryGroups() { + return itineraryGroups; } - public static class ItineraryGroup { - - public String id; - public String name; - public ItineraryType type = ItineraryType.POINTS; - public Set wptCategories; - - private List itineraryItems = new ArrayList<>(); - + public List getMapMarkersGroups() { + return mapMarkersGroups; } - public void syncItineraryGroups() { - for (MapMarkersGroup markersGroup : mapMarkersGroups) { - ItineraryGroup itineraryGroup = new ItineraryGroup(); - itineraryGroup.id = markersGroup.getId(); - itineraryGroup.name = markersGroup.getName(); - itineraryGroup.type = markersGroup.getType(); - itineraryGroup.wptCategories = markersGroup.getWptCategories(); + public void syncAllGroups() { + itineraryGroups.clear(); + } - if (markersGroup.getType() == ItineraryType.FAVOURITES) { - syncFavoriteGroup(itineraryGroup, markersGroup); - } else if (markersGroup.getType() == ItineraryType.TRACK) { - syncTrackGroup(itineraryGroup, markersGroup); - } else { - syncMarkersGroup(itineraryGroup, markersGroup); + private boolean merge(Map source, Map destination) { + boolean changed = false; + for (Map.Entry entry : source.entrySet()) { + Object ks = entry.getKey(); + if (!destination.containsKey(ks)) { + changed = true; + destination.put(ks, entry.getValue()); } } - trimEmptyGroups(); + return changed; } - public void trimEmptyGroups() { - Iterator iterator = itineraryGroups.iterator(); - while (iterator.hasNext()) { - ItineraryGroup group = iterator.next(); - if (Algorithms.isEmpty(group.itineraryItems)) { - iterator.remove(); - } + private boolean loadGPXFile(File file, Map groups) { + if (!file.exists()) { + return false; } - } - - private void syncFavoriteGroup(ItineraryGroup itineraryGroup, MapMarkersGroup markersGroup) { - FavoriteGroup favoriteGroup = app.getFavorites().getGroup(markersGroup.getId()); - if (favoriteGroup != null) { - for (FavouritePoint favouritePoint : favoriteGroup.getPoints()) { - if (favouritePoint.getPassedTimestamp() == 0) { - ItineraryItem itineraryItem = new ItineraryItem(itineraryGroup, favouritePoint, ItineraryType.FAVOURITES); - itineraryGroup.itineraryItems.add(itineraryItem); - } - } - itineraryGroups.add(itineraryGroup); + List groupInfos = new ArrayList<>(); + GPXFile gpxFile = loadGPXFile(file, groupInfos); + if (gpxFile.error != null) { + return false; } + for (ItineraryGroupInfo groupInfo : groupInfos) { + ItineraryGroup group = ItineraryGroup.createGroup(groupInfo); + Object key = group.name != null ? group.name : group.type; + groups.put(key, group); + } + return true; } - private void syncTrackGroup(ItineraryGroup itineraryGroup, MapMarkersGroup markersGroup) { - File file = new File(markersGroup.getId()); - if (file.exists()) { - GPXFile gpxFile; - SelectedGpxFile selectedGpxFile = app.getSelectedGpxHelper().getSelectedFileByPath(markersGroup.getId()); - if (selectedGpxFile != null) { - gpxFile = selectedGpxFile.getGpxFile(); - } else { - gpxFile = GPXUtilities.loadGPXFile(file); - } - if (gpxFile != null && gpxFile.error == null) { - for (WptPt wptPt : gpxFile.getPoints()) { - if (shouldAddWpt(wptPt, itineraryGroup.wptCategories)) { - ItineraryItem itineraryItem = new ItineraryItem(itineraryGroup, wptPt, ItineraryType.TRACK); - itineraryGroup.itineraryItems.add(itineraryItem); + private GPXFile loadGPXFile(File file, final List groupInfos) { + return GPXUtilities.loadGPXFile(file, new GPXExtensionsReader() { + @Override + public boolean readExtensions(GPXFile res, XmlPullParser parser) throws IOException, XmlPullParserException { + if (ITINERARY_GROUP.equalsIgnoreCase(parser.getName())) { + ItineraryGroupInfo groupInfo = new ItineraryGroupInfo(); + + int tok; + while ((tok = parser.next()) != XmlPullParser.END_DOCUMENT) { + if (tok == XmlPullParser.START_TAG) { + String tagName = parser.getName().toLowerCase(); + if ("name".equalsIgnoreCase(tagName)) { + groupInfo.name = readText(parser, tagName); + } else if ("type".equalsIgnoreCase(tagName)) { + groupInfo.type = readText(parser, tagName); + } else if ("path".equalsIgnoreCase(tagName)) { + groupInfo.path = readText(parser, tagName); + } else if ("alias".equalsIgnoreCase(tagName)) { + groupInfo.alias = readText(parser, tagName); + } else if ("categories".equalsIgnoreCase(tagName)) { + groupInfo.categories = readText(parser, tagName); + } + } else if (tok == XmlPullParser.END_TAG) { + if (ITINERARY_GROUP.equalsIgnoreCase(parser.getName())) { + groupInfos.add(groupInfo); + return true; + } + } } } - itineraryGroups.add(itineraryGroup); + return false; } + }); + } + + public void saveGroupsIntoFile() { + try { + saveFile(getInternalFile()); + saveFile(getExternalFile()); + backup(getBackupFile(), getExternalFile()); + } catch (Exception e) { + log.error(e.getMessage(), e); } } - private void syncMarkersGroup(ItineraryGroup itineraryGroup, MapMarkersGroup markersGroup) { - for (MapMarker marker : markersGroup.getMarkers()) { - if (!marker.history) { - PointDescription pointDescription = marker.getOriginalPointDescription(); - if (pointDescription == null || !pointDescription.isWpt() && !pointDescription.isFavorite()) { - ItineraryItem itineraryItem = new ItineraryItem(itineraryGroup, marker, ItineraryType.MARKERS); - itineraryGroup.itineraryItems.add(itineraryItem); - } - } - } - itineraryGroups.add(itineraryGroup); + public Exception saveFile(File file) { + GPXFile gpxFile = asGpxFile(); + return GPXUtilities.writeGpxFile(file, gpxFile); } - private boolean shouldAddWpt(WptPt wptPt, Set wptCategories) { - boolean addAll = wptCategories == null || wptCategories.isEmpty(); - return addAll || wptCategories.contains(wptPt.category) - || wptPt.category == null && wptCategories.contains(""); + public GPXFile asGpxFile() { + GPXFile gpxFile = new GPXFile(Version.getFullVersion(app)); + List groups = new ArrayList<>(); + for (ItineraryGroup group : itineraryGroups) { + ItineraryGroupInfo groupInfo = group.convertToGroupInfo(); + + for (ItineraryItem item : group.itineraryItems) { + WptPt wptPt = new WptPt(); + wptPt.lat = item.latLon.getLatitude(); + wptPt.lon = item.latLon.getLongitude(); + wptPt.getExtensionsToWrite().put(ITINERARY_ID, groupInfo.alias + ":" + item.id); + gpxFile.addPoint(wptPt); + } + groups.add(groupInfo); + } + assignRouteExtensionWriter(gpxFile, groups); + return gpxFile; } - private void loadMarkersGroups() { - Map groupsMap = markersDbHelper.getAllGroupsMap(); - List allMarkers = new ArrayList<>(markersHelper.getMapMarkers()); - allMarkers.addAll(markersHelper.getMapMarkersHistory()); - - Iterator> iterator = groupsMap.entrySet().iterator(); - while (iterator.hasNext()) { - MapMarkersGroup group = iterator.next().getValue(); - if (group.getType() == ItineraryType.TRACK && !new File(group.getId()).exists()) { - markersDbHelper.removeMarkersGroup(group.getId()); - iterator.remove(); - } - } - - MapMarkersGroup noGroup = null; - - for (MapMarker marker : allMarkers) { - MapMarkersGroup group = groupsMap.get(marker.groupKey); - if (group == null) { - if (noGroup == null) { - noGroup = new MapMarkersGroup(); - noGroup.setCreationDate(Long.MAX_VALUE); - } - noGroup.getMarkers().add(marker); - } else { - if (marker.creationDate < group.getCreationDate()) { - group.setCreationDate(marker.creationDate); - } - group.getMarkers().add(marker); - } - } - - mapMarkersGroups = new ArrayList<>(groupsMap.values()); - if (noGroup != null) { - markersHelper.sortMarkers(noGroup.getMarkers(), false, BY_DATE_ADDED_DESC); - addToGroupsList(noGroup); - } - - sortGroups(); - - for (MapMarkersGroup group : mapMarkersGroups) { - updateGroup(group); - } - } - - private void assignRouteExtensionWriter(GPXFile gpx, final List groups) { - if (gpx.getExtensionsWriter() == null) { - gpx.setExtensionsWriter(new GPXExtensionsWriter() { + private void assignRouteExtensionWriter(GPXFile gpxFile, final List groups) { + if (gpxFile.getExtensionsWriter() == null) { + gpxFile.setExtensionsWriter(new GPXExtensionsWriter() { @Override public void writeExtensions(XmlSerializer serializer) { - for (ItineraryGroupItem group : groups) { + for (ItineraryGroupInfo group : groups) { try { - serializer.startTag(null, "itinerary_group"); + serializer.startTag(null, "osmand:itinerary_group"); writeNotNullText(serializer, "osmand:name", group.name); writeNotNullText(serializer, "osmand:type", group.type); @@ -262,7 +214,7 @@ public class ItineraryHelper { writeNotNullText(serializer, "osmand:alias", group.alias); writeNotNullText(serializer, "osmand:categories", group.categories); - serializer.endTag(null, "itinerary_group"); + serializer.endTag(null, "osmand:itinerary_group"); } catch (IOException e) { log.error(e); } @@ -272,6 +224,95 @@ public class ItineraryHelper { } } + public void syncMarkersGroups() { + for (MapMarkersGroup group : mapMarkersGroups) { + if (group.getId() != null && group.getName() != null) { + runGroupSynchronization(group); + } + } + } + + private List convertToItineraryGroups() { + List groups = new ArrayList<>(); + for (MapMarkersGroup markersGroup : mapMarkersGroups) { + groups.add(ItineraryGroup.createGroup(markersGroup)); + } + return groups; + } + + public void syncItineraryGroups() { + syncItineraryGroups(convertToItineraryGroups()); + } + + public void syncItineraryGroups(List itineraryGroups) { + for (ItineraryGroup group : itineraryGroups) { + if (group.type == ItineraryType.FAVOURITES) { + syncFavoriteGroup(group); + } else if (group.type == ItineraryType.TRACK) { + syncTrackGroup(group); + } else if (group.type == ItineraryType.MARKERS) { + syncMarkersGroup(group); + } + } + } + + private void syncFavoriteGroup(ItineraryGroup group) { + FavoriteGroup favoriteGroup = app.getFavorites().getGroup(group.id); + if (favoriteGroup != null && favoriteGroup.isVisible()) { + for (FavouritePoint point : favoriteGroup.getPoints()) { + if (point.getPassedTimestamp() == 0) { + ItineraryItem item = new ItineraryItem(group, point, ItineraryType.FAVOURITES); + group.itineraryItems.add(item); + } + } + itineraryGroups.add(group); + } + } + + private void syncTrackGroup(ItineraryGroup group) { + SelectedGpxFile selectedGpxFile = app.getSelectedGpxHelper().getSelectedFileByPath(group.id); + if (selectedGpxFile != null) { + for (WptPt wptPt : selectedGpxFile.getGpxFile().getPoints()) { + if (shouldAddWpt(wptPt, group.wptCategories)) { + ItineraryItem item = new ItineraryItem(group, wptPt, ItineraryType.TRACK); + group.itineraryItems.add(item); + } + } + itineraryGroups.add(group); + } + } + + private void syncMarkersGroup(ItineraryGroup group) { + ItineraryGroup pointsGroup = new ItineraryGroup(group); + ItineraryGroup markersGroup = new ItineraryGroup(group); + + pointsGroup.type = ItineraryType.POINTS; + markersGroup.type = ItineraryType.MARKERS; + + List allMarkers = new ArrayList<>(markersHelper.getMapMarkers()); + for (MapMarker marker : allMarkers) { + PointDescription description = marker.getOriginalPointDescription(); + if (description.isFavorite()) { + FavouritePoint point = app.getFavorites().getVisibleFavByLatLon(marker.point); + if (point != null && point.getPassedTimestamp() == 0) { + ItineraryItem item = new ItineraryItem(pointsGroup, point, ItineraryType.FAVOURITES); + pointsGroup.itineraryItems.add(item); + } + } else if (description.isWpt()) { + WptPt wptPt = app.getSelectedGpxHelper().getVisibleWayPointByLatLon(marker.point); + if (wptPt != null && shouldAddWpt(wptPt, null)) { + ItineraryItem item = new ItineraryItem(pointsGroup, wptPt, ItineraryType.TRACK); + pointsGroup.itineraryItems.add(item); + } + } else if (!marker.history) { + ItineraryItem item = new ItineraryItem(markersGroup, marker, ItineraryType.MARKERS); + markersGroup.itineraryItems.add(item); + } + } + itineraryGroups.add(pointsGroup); + itineraryGroups.add(markersGroup); + } + public File getExternalFile() { return new File(app.getAppPath(null), FILE_TO_SAVE); } @@ -284,18 +325,6 @@ public class ItineraryHelper { return FavouritesDbHelper.getBackupFile(app, "itinerary_bak_"); } - public List getMapMarkersGroups() { - return mapMarkersGroups; - } - - public void syncMarkersGroups() { - for (MapMarkersGroup group : mapMarkersGroups) { - if (group.getType() != ItineraryType.MARKERS) { - runGroupSynchronization(group); - } - } - } - public void updateGroupWptCategories(@NonNull MapMarkersGroup group, Set wptCategories) { String id = group.getId(); if (id != null) { @@ -345,10 +374,54 @@ public class ItineraryHelper { return mapMarkers; } - public void addGroupInternally(MapMarkersGroup gr) { - markersDbHelper.addGroup(gr); - markersHelper.addHistoryMarkersToGroup(gr); - addToGroupsList(gr); + private void loadMarkersGroups() { + Map groupsMap = markersDbHelper.getAllGroupsMap(); + List allMarkers = new ArrayList<>(markersHelper.getMapMarkers()); + allMarkers.addAll(markersHelper.getMapMarkersHistory()); + + Iterator> iterator = groupsMap.entrySet().iterator(); + while (iterator.hasNext()) { + MapMarkersGroup group = iterator.next().getValue(); + if (group.getType() == ItineraryType.TRACK && !new File(group.getId()).exists()) { + markersDbHelper.removeMarkersGroup(group.getId()); + iterator.remove(); + } + } + + MapMarkersGroup noGroup = null; + for (MapMarker marker : allMarkers) { + MapMarkersGroup group = groupsMap.get(marker.groupKey); + if (group == null) { + if (noGroup == null) { + noGroup = new MapMarkersGroup(); + noGroup.setCreationDate(Long.MAX_VALUE); + } + noGroup.getMarkers().add(marker); + } else { + if (marker.creationDate < group.getCreationDate()) { + group.setCreationDate(marker.creationDate); + } + group.getMarkers().add(marker); + } + } + + mapMarkersGroups = new ArrayList<>(groupsMap.values()); + if (noGroup != null) { + markersHelper.sortMarkers(noGroup.getMarkers(), false, BY_DATE_ADDED_DESC); + addToGroupsList(noGroup); + } + + sortGroups(); + + for (MapMarkersGroup group : mapMarkersGroups) { + updateGroup(group); + } + } + + public void addGroupInternally(MapMarkersGroup group) { + markersDbHelper.addGroup(group); + markersHelper.addHistoryMarkersToGroup(group); + addToGroupsList(group); } public void updateGpxShowAsMarkers(File file) { @@ -403,22 +476,20 @@ public class ItineraryHelper { } public void addMarkerToGroup(MapMarker marker) { - if (marker != null) { - MapMarkersGroup mapMarkersGroup = app.getItineraryHelper().getMapMarkerGroupById(marker.groupKey, marker.getType()); - if (mapMarkersGroup != null) { - mapMarkersGroup.getMarkers().add(marker); - updateGroup(mapMarkersGroup); - if (mapMarkersGroup.getName() == null) { - markersHelper.sortMarkers(mapMarkersGroup.getMarkers(), false, BY_DATE_ADDED_DESC); - } - } else { - mapMarkersGroup = new MapMarkersGroup(marker.groupKey, marker.groupName, ItineraryType.MARKERS); - mapMarkersGroup.setCreationDate(Long.MAX_VALUE); - mapMarkersGroup.getMarkers().add(marker); - addToGroupsList(mapMarkersGroup); - sortGroups(); - updateGroup(mapMarkersGroup); + MapMarkersGroup mapMarkersGroup = app.getItineraryHelper().getMapMarkerGroupById(marker.groupKey, marker.getType()); + if (mapMarkersGroup != null) { + mapMarkersGroup.getMarkers().add(marker); + updateGroup(mapMarkersGroup); + if (mapMarkersGroup.getName() == null) { + markersHelper.sortMarkers(mapMarkersGroup.getMarkers(), false, BY_DATE_ADDED_DESC); } + } else { + mapMarkersGroup = new MapMarkersGroup(marker.groupKey, marker.groupName, ItineraryType.MARKERS); + mapMarkersGroup.setCreationDate(Long.MAX_VALUE); + mapMarkersGroup.getMarkers().add(marker); + addToGroupsList(mapMarkersGroup); + sortGroups(); + updateGroup(mapMarkersGroup); } } @@ -500,9 +571,7 @@ public class ItineraryHelper { } private MapMarkersGroup createGPXMarkerGroup(File fl) { - return new MapMarkersGroup(getMarkerGroupId(fl), - Algorithms.getFileNameWithoutExtension(fl.getName()), - ItineraryType.TRACK); + return new MapMarkersGroup(getMarkerGroupId(fl), getFileNameWithoutExtension(fl), ItineraryType.TRACK); } private MapMarkersGroup createFavMarkerGroup(FavoriteGroup favGroup) { @@ -665,6 +734,12 @@ public class ItineraryHelper { markersHelper.removeOldMarkersIfPresent(groupMarkers); } + private boolean shouldAddWpt(WptPt wptPt, Set wptCategories) { + boolean addAll = wptCategories == null || wptCategories.isEmpty(); + return addAll || wptCategories.contains(wptPt.category) + || wptPt.category == null && wptCategories.contains(""); + } + private class SyncGroupTask extends AsyncTask { private MapMarkersGroup group; diff --git a/OsmAnd/src/net/osmand/plus/itinerary/ItineraryItem.java b/OsmAnd/src/net/osmand/plus/itinerary/ItineraryItem.java new file mode 100644 index 0000000000..bc004530a8 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/itinerary/ItineraryItem.java @@ -0,0 +1,46 @@ +package net.osmand.plus.itinerary; + +import net.osmand.GPXUtilities.WptPt; +import net.osmand.data.FavouritePoint; +import net.osmand.data.LatLon; +import net.osmand.plus.mapmarkers.MapMarker; + +public class ItineraryItem { + + public final String id; + public final Object object; + public final LatLon latLon; + public final ItineraryType type; + public final ItineraryGroup group; + + public ItineraryItem(ItineraryGroup group, Object object, ItineraryType type) { + this.type = type; + this.group = group; + this.object = object; + this.id = acquireItemId(object); + + if (object instanceof MapMarker) { + MapMarker marker = (MapMarker) object; + latLon = marker.point; + } else if (object instanceof WptPt) { + WptPt point = (WptPt) object; + latLon = new LatLon(point.lat, point.lon); + } else if (object instanceof FavouritePoint) { + FavouritePoint point = (FavouritePoint) object; + latLon = new LatLon(point.getLatitude(), point.getLongitude()); + } else { + latLon = null; + } + } + + private String acquireItemId(Object object) { + if (object instanceof MapMarker) { + return (((MapMarker) object)).id; + } else if (object instanceof WptPt) { + return (((WptPt) object)).name; + } else if (object instanceof FavouritePoint) { + return (((FavouritePoint) object)).getName(); + } + return ""; + } +} diff --git a/OsmAnd/src/net/osmand/plus/itinerary/ItineraryType.java b/OsmAnd/src/net/osmand/plus/itinerary/ItineraryType.java index 20cdb309f6..b03fdbd996 100644 --- a/OsmAnd/src/net/osmand/plus/itinerary/ItineraryType.java +++ b/OsmAnd/src/net/osmand/plus/itinerary/ItineraryType.java @@ -1,18 +1,14 @@ package net.osmand.plus.itinerary; -import androidx.annotation.NonNull; - public enum ItineraryType { - MARKERS("markers", -1), - FAVOURITES("favourites", 0), - TRACK("track", 1), - POINTS("points", 2); + MARKERS(-1), + FAVOURITES(0), + TRACK(1), + POINTS(2); private int typeId; - private String typeName; - ItineraryType(@NonNull String typeName, int typeId) { - this.typeName = typeName; + ItineraryType(int typeId) { this.typeId = typeId; } @@ -20,25 +16,21 @@ public enum ItineraryType { return typeId; } - public String getTypeName() { - return typeName; - } - public static ItineraryType findTypeForId(int typeId) { for (ItineraryType type : values()) { if (type.getTypeId() == typeId) { return type; } } - return ItineraryType.MARKERS; + return ItineraryType.POINTS; } public static ItineraryType findTypeForName(String typeName) { for (ItineraryType type : values()) { - if (type.getTypeName().equalsIgnoreCase(typeName)) { + if (type.name().equalsIgnoreCase(typeName)) { return type; } } - return ItineraryType.MARKERS; + return ItineraryType.POINTS; } } diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/controllers/MapMarkerMenuController.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/controllers/MapMarkerMenuController.java index 638cd076d3..b03e33a6b2 100644 --- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/controllers/MapMarkerMenuController.java +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/controllers/MapMarkerMenuController.java @@ -4,21 +4,20 @@ import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.shapes.OvalShape; -import android.os.Build; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; import net.osmand.data.PointDescription; -import net.osmand.plus.mapmarkers.MapMarkersHelper; -import net.osmand.plus.mapmarkers.MapMarker; -import net.osmand.plus.settings.backend.OsmandPreference; import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.helpers.MapMarkerDialogHelper; import net.osmand.plus.mapcontextmenu.MenuBuilder; import net.osmand.plus.mapcontextmenu.MenuController; +import net.osmand.plus.mapmarkers.MapMarker; +import net.osmand.plus.mapmarkers.MapMarkersHelper; +import net.osmand.plus.settings.backend.OsmandPreference; import net.osmand.util.Algorithms; public class MapMarkerMenuController extends MenuController { diff --git a/OsmAnd/src/net/osmand/plus/mapmarkers/MapMarker.java b/OsmAnd/src/net/osmand/plus/mapmarkers/MapMarker.java index acee264ae8..ace58dfba6 100644 --- a/OsmAnd/src/net/osmand/plus/mapmarkers/MapMarker.java +++ b/OsmAnd/src/net/osmand/plus/mapmarkers/MapMarker.java @@ -3,6 +3,7 @@ package net.osmand.plus.mapmarkers; import android.content.Context; import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; import androidx.core.content.ContextCompat; import net.osmand.GPXUtilities.WptPt; @@ -37,7 +38,7 @@ public class MapMarker implements LocationPoint { public FavouritePoint favouritePoint; public String mapObjectName; - public MapMarker(LatLon point, PointDescription name, int colorIndex, boolean selected, int index) { + public MapMarker(@NonNull LatLon point, @NonNull PointDescription name, int colorIndex, boolean selected, int index) { this.point = point; this.pointDescription = name; this.colorIndex = colorIndex; @@ -66,11 +67,12 @@ public class MapMarker implements LocationPoint { return name; } + @NonNull public PointDescription getOriginalPointDescription() { return pointDescription; } - public void setOriginalPointDescription(PointDescription pointDescription) { + public void setOriginalPointDescription(@NonNull PointDescription pointDescription) { this.pointDescription = pointDescription; }