Fix file saving

This commit is contained in:
Vitaliy 2021-04-19 07:27:30 +03:00
parent f5e68691eb
commit de9fde3df6
11 changed files with 425 additions and 263 deletions

View file

@ -112,7 +112,7 @@ public class GPXUtilities {
} }
public interface GPXExtensionsReader { 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 { 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; int tok;
StringBuilder text = null; StringBuilder text = null;
while ((tok = parser.next()) != XmlPullParser.END_DOCUMENT) { while ((tok = parser.next()) != XmlPullParser.END_DOCUMENT) {
@ -2146,18 +2146,19 @@ public class GPXUtilities {
return time; 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; FileInputStream fis = null;
try { try {
fis = new FileInputStream(f); fis = new FileInputStream(f);
GPXFile file = loadGPXFile(fis); GPXFile file = loadGPXFile(fis, extensionsReader);
file.path = f.getAbsolutePath(); file.path = f.getAbsolutePath();
file.modifiedTime = f.lastModified(); file.modifiedTime = f.lastModified();
try { Algorithms.closeStream(fis);
fis.close();
} catch (IOException e) {
}
return file; return file;
} catch (IOException e) { } catch (IOException e) {
GPXFile res = new GPXFile(null); GPXFile res = new GPXFile(null);
@ -2166,24 +2167,15 @@ public class GPXUtilities {
res.error = e; res.error = e;
return res; return res;
} finally { } finally {
try { Algorithms.closeStream(fis);
if (fis != null)
fis.close();
} catch (IOException ignore) {
// ignore
}
} }
} }
public static class ItineraryGroupItem { public static GPXFile loadGPXFile(InputStream stream) {
public String name; return loadGPXFile(stream, null);
public String type;
public String path;
public String alias;
public String categories;
} }
public static GPXFile loadGPXFile(InputStream f) { public static GPXFile loadGPXFile(InputStream stream, GPXExtensionsReader extensionsReader) {
GPXFile gpxFile = new GPXFile(null); GPXFile gpxFile = new GPXFile(null);
SimpleDateFormat format = new SimpleDateFormat(GPX_TIME_FORMAT, Locale.US); SimpleDateFormat format = new SimpleDateFormat(GPX_TIME_FORMAT, Locale.US);
format.setTimeZone(TimeZone.getTimeZone("UTC")); format.setTimeZone(TimeZone.getTimeZone("UTC"));
@ -2191,7 +2183,7 @@ public class GPXUtilities {
formatMillis.setTimeZone(TimeZone.getTimeZone("UTC")); formatMillis.setTimeZone(TimeZone.getTimeZone("UTC"));
try { try {
XmlPullParser parser = PlatformUtil.newXMLPullParser(); XmlPullParser parser = PlatformUtil.newXMLPullParser();
parser.setInput(getUTF8Reader(f)); parser.setInput(getUTF8Reader(stream));
Track routeTrack = new Track(); Track routeTrack = new Track();
TrkSegment routeTrackSegment = new TrkSegment(); TrkSegment routeTrackSegment = new TrkSegment();
routeTrack.segments.add(routeTrackSegment); routeTrack.segments.add(routeTrackSegment);
@ -2239,17 +2231,19 @@ public class GPXUtilities {
break; break;
default: default:
Map<String, String> values = readTextMap(parser, tag); if (extensionsReader == null || !extensionsReader.readExtensions(gpxFile, parser)) {
if (values.size() > 0) { Map<String, String> values = readTextMap(parser, tag);
for (Entry<String, String> entry : values.entrySet()) { if (values.size() > 0) {
String t = entry.getKey().toLowerCase(); for (Entry<String, String> entry : values.entrySet()) {
String value = entry.getValue(); String t = entry.getKey().toLowerCase();
parse.getExtensionsToWrite().put(t, value); String value = entry.getValue();
if (tag.equals("speed") && parse instanceof WptPt) { parse.getExtensionsToWrite().put(t, value);
try { if (tag.equals("speed") && parse instanceof WptPt) {
((WptPt) parse).speed = Float.parseFloat(value); try {
} catch (NumberFormatException e) { ((WptPt) parse).speed = Float.parseFloat(value);
log.debug(e.getMessage(), e); } catch (NumberFormatException e) {
log.debug(e.getMessage(), e);
}
} }
} }
} }

View file

@ -26,8 +26,8 @@ import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
@ -305,7 +305,7 @@ public class Algorithms {
if (isEmpty(s)) { if (isEmpty(s)) {
return Collections.emptySet(); return Collections.emptySet();
} }
return new HashSet<>(Arrays.asList(s.split(split))); return new LinkedHashSet<>(Arrays.asList(s.split(split)));
} }
public static String encodeStringSet(Set<String> set) { public static String encodeStringSet(Set<String> set) {

View file

@ -24,12 +24,11 @@ import net.osmand.util.Algorithms;
import java.io.Serializable; import java.io.Serializable;
import static net.osmand.plus.itinerary.ItineraryHelper.PASSED_TIMESTAMP;
public class FavouritePoint implements Serializable, LocationPoint { public class FavouritePoint implements Serializable, LocationPoint {
private static final long serialVersionUID = 729654300829771466L; private static final long serialVersionUID = 729654300829771466L;
private static final String PASSED_TIMESTAMP = "passed_timestamp";
private static final String HIDDEN = "hidden"; private static final String HIDDEN = "hidden";
private static final String ADDRESS_EXTENSION = "address"; private static final String ADDRESS_EXTENSION = "address";
public static final BackgroundType DEFAULT_BACKGROUND_TYPE = BackgroundType.CIRCLE; 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(latitude * 10000);
result = prime * result + (int) Math.floor(longitude * 10000); result = prime * result + (int) Math.floor(longitude * 10000);
result = prime * result + (int) Math.floor(altitude * 10000); result = prime * result + (int) Math.floor(altitude * 10000);
result = prime * result + (int) Math.floor(timestamp * 10000); result = prime * result + (int) (timestamp ^ (timestamp >>> 32));
result = prime * result + (int) Math.floor(passedTimestamp * 10000); result = prime * result + (int) (passedTimestamp ^ (passedTimestamp >>> 32));
result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((category == null) ? 0 : category.hashCode()); result = prime * result + ((category == null) ? 0 : category.hashCode());
result = prime * result + ((description == null) ? 0 : description.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); String time = pt.getExtensionsToWrite().get(PASSED_TIMESTAMP);
fp.setPassedTimestamp(Algorithms.parseLongSilently(time, 0)); fp.setPassedTimestamp(Algorithms.parseLongSilently(time, 0));
} }
BackgroundType backgroundType = BackgroundType.getByTypeName(pt.getBackgroundType(), null); BackgroundType backgroundType = BackgroundType.getByTypeName(pt.getBackgroundType(), null);
fp.setBackgroundType(backgroundType); fp.setBackgroundType(backgroundType);
return fp; return fp;

View file

@ -685,7 +685,7 @@ public class AppInitializer implements IProgress {
// restore backuped favorites to normal file // restore backuped favorites to normal file
restoreBackupForFavoritesFiles(); restoreBackupForFavoritesFiles();
notifyEvent(InitEvents.RESTORE_BACKUPS); notifyEvent(InitEvents.RESTORE_BACKUPS);
app.itineraryHelper.syncMarkersGroups(); app.itineraryHelper.syncAllGroups();
app.searchUICore.initSearchUICore(); app.searchUICore.initSearchUICore();
checkLiveUpdatesAlerts(); checkLiveUpdatesAlerts();

View file

@ -711,17 +711,6 @@ public class FavouritesDbHelper {
return null; 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<FavoriteGroup> getFavoriteGroups() { public List<FavoriteGroup> getFavoriteGroups() {
return favoriteGroups; return favoriteGroups;
} }
@ -848,9 +837,7 @@ public class FavouritesDbHelper {
} }
for (WptPt p : res.getPoints()) { for (WptPt p : res.getPoints()) {
FavouritePoint fp = FavouritePoint.fromWpt(p, context); FavouritePoint fp = FavouritePoint.fromWpt(p, context);
if (fp != null) { points.put(getKey(fp), fp);
points.put(getKey(fp), fp);
}
} }
return true; return true;
} }

View file

@ -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<String> wptCategories;
public List<ItineraryItem> 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;
}
}

View file

@ -6,9 +6,9 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import net.osmand.GPXUtilities; import net.osmand.GPXUtilities;
import net.osmand.GPXUtilities.GPXExtensionsReader;
import net.osmand.GPXUtilities.GPXExtensionsWriter; import net.osmand.GPXUtilities.GPXExtensionsWriter;
import net.osmand.GPXUtilities.GPXFile; import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.ItineraryGroupItem;
import net.osmand.GPXUtilities.WptPt; import net.osmand.GPXUtilities.WptPt;
import net.osmand.IndexConstants; import net.osmand.IndexConstants;
import net.osmand.PlatformUtil; import net.osmand.PlatformUtil;
@ -22,6 +22,8 @@ import net.osmand.plus.GpxSelectionHelper;
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile; import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R; 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.CategoriesSubHeader;
import net.osmand.plus.mapmarkers.GroupHeader; import net.osmand.plus.mapmarkers.GroupHeader;
import net.osmand.plus.mapmarkers.MapMarker; import net.osmand.plus.mapmarkers.MapMarker;
@ -35,6 +37,8 @@ import net.osmand.plus.wikivoyage.data.TravelHelper;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer; import org.xmlpull.v1.XmlSerializer;
import java.io.File; import java.io.File;
@ -51,18 +55,21 @@ import java.util.Set;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import static net.osmand.GPXUtilities.readText;
import static net.osmand.GPXUtilities.writeNotNullText; 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.plus.mapmarkers.MapMarkersHelper.BY_DATE_ADDED_DESC;
import static net.osmand.util.Algorithms.getFileNameWithoutExtension;
public class ItineraryHelper { public class ItineraryHelper {
private static final Log log = PlatformUtil.getLog(ItineraryHelper.class); private static final Log log = PlatformUtil.getLog(ItineraryHelper.class);
public static final String PASSED_TIMESTAMP = "passed_timestamp"; protected static final String CATEGORIES_SPLIT = ",";
private static final String CATEGORIES_SPLIT = ",";
private static final String FILE_TO_SAVE = "itinerary.gpx"; private static final String FILE_TO_SAVE = "itinerary.gpx";
private static final String FILE_TO_BACKUP = "itinerary_bak.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; private OsmandApplication app;
@ -82,179 +89,124 @@ public class ItineraryHelper {
loadMarkersGroups(); loadMarkersGroups();
} }
public static class ItineraryItem { public List<ItineraryGroup> getItineraryGroups() {
return itineraryGroups;
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 static class ItineraryGroup { public List<MapMarkersGroup> getMapMarkersGroups() {
return mapMarkersGroups;
public String id;
public String name;
public ItineraryType type = ItineraryType.POINTS;
public Set<String> wptCategories;
private List<ItineraryItem> itineraryItems = new ArrayList<>();
} }
public void syncItineraryGroups() { public void syncAllGroups() {
for (MapMarkersGroup markersGroup : mapMarkersGroups) { itineraryGroups.clear();
ItineraryGroup itineraryGroup = new ItineraryGroup(); }
itineraryGroup.id = markersGroup.getId();
itineraryGroup.name = markersGroup.getName();
itineraryGroup.type = markersGroup.getType();
itineraryGroup.wptCategories = markersGroup.getWptCategories();
if (markersGroup.getType() == ItineraryType.FAVOURITES) { private boolean merge(Map<Object, ItineraryGroup> source, Map<Object, ItineraryGroup> destination) {
syncFavoriteGroup(itineraryGroup, markersGroup); boolean changed = false;
} else if (markersGroup.getType() == ItineraryType.TRACK) { for (Map.Entry<Object, ItineraryGroup> entry : source.entrySet()) {
syncTrackGroup(itineraryGroup, markersGroup); Object ks = entry.getKey();
} else { if (!destination.containsKey(ks)) {
syncMarkersGroup(itineraryGroup, markersGroup); changed = true;
destination.put(ks, entry.getValue());
} }
} }
trimEmptyGroups(); return changed;
} }
public void trimEmptyGroups() { private boolean loadGPXFile(File file, Map<Object, ItineraryGroup> groups) {
Iterator<ItineraryGroup> iterator = itineraryGroups.iterator(); if (!file.exists()) {
while (iterator.hasNext()) { return false;
ItineraryGroup group = iterator.next();
if (Algorithms.isEmpty(group.itineraryItems)) {
iterator.remove();
}
} }
} List<ItineraryGroupInfo> groupInfos = new ArrayList<>();
GPXFile gpxFile = loadGPXFile(file, groupInfos);
private void syncFavoriteGroup(ItineraryGroup itineraryGroup, MapMarkersGroup markersGroup) { if (gpxFile.error != null) {
FavoriteGroup favoriteGroup = app.getFavorites().getGroup(markersGroup.getId()); return false;
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);
} }
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) { private GPXFile loadGPXFile(File file, final List<ItineraryGroupInfo> groupInfos) {
File file = new File(markersGroup.getId()); return GPXUtilities.loadGPXFile(file, new GPXExtensionsReader() {
if (file.exists()) { @Override
GPXFile gpxFile; public boolean readExtensions(GPXFile res, XmlPullParser parser) throws IOException, XmlPullParserException {
SelectedGpxFile selectedGpxFile = app.getSelectedGpxHelper().getSelectedFileByPath(markersGroup.getId()); if (ITINERARY_GROUP.equalsIgnoreCase(parser.getName())) {
if (selectedGpxFile != null) { ItineraryGroupInfo groupInfo = new ItineraryGroupInfo();
gpxFile = selectedGpxFile.getGpxFile();
} else { int tok;
gpxFile = GPXUtilities.loadGPXFile(file); while ((tok = parser.next()) != XmlPullParser.END_DOCUMENT) {
} if (tok == XmlPullParser.START_TAG) {
if (gpxFile != null && gpxFile.error == null) { String tagName = parser.getName().toLowerCase();
for (WptPt wptPt : gpxFile.getPoints()) { if ("name".equalsIgnoreCase(tagName)) {
if (shouldAddWpt(wptPt, itineraryGroup.wptCategories)) { groupInfo.name = readText(parser, tagName);
ItineraryItem itineraryItem = new ItineraryItem(itineraryGroup, wptPt, ItineraryType.TRACK); } else if ("type".equalsIgnoreCase(tagName)) {
itineraryGroup.itineraryItems.add(itineraryItem); 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) { public Exception saveFile(File file) {
for (MapMarker marker : markersGroup.getMarkers()) { GPXFile gpxFile = asGpxFile();
if (!marker.history) { return GPXUtilities.writeGpxFile(file, gpxFile);
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);
} }
private boolean shouldAddWpt(WptPt wptPt, Set<String> wptCategories) { public GPXFile asGpxFile() {
boolean addAll = wptCategories == null || wptCategories.isEmpty(); GPXFile gpxFile = new GPXFile(Version.getFullVersion(app));
return addAll || wptCategories.contains(wptPt.category) List<ItineraryGroupInfo> groups = new ArrayList<>();
|| wptPt.category == null && wptCategories.contains(""); 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() { private void assignRouteExtensionWriter(GPXFile gpxFile, final List<ItineraryGroupInfo> groups) {
Map<String, MapMarkersGroup> groupsMap = markersDbHelper.getAllGroupsMap(); if (gpxFile.getExtensionsWriter() == null) {
List<MapMarker> allMarkers = new ArrayList<>(markersHelper.getMapMarkers()); gpxFile.setExtensionsWriter(new GPXExtensionsWriter() {
allMarkers.addAll(markersHelper.getMapMarkersHistory());
Iterator<Entry<String, MapMarkersGroup>> 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<ItineraryGroupItem> groups) {
if (gpx.getExtensionsWriter() == null) {
gpx.setExtensionsWriter(new GPXExtensionsWriter() {
@Override @Override
public void writeExtensions(XmlSerializer serializer) { public void writeExtensions(XmlSerializer serializer) {
for (ItineraryGroupItem group : groups) { for (ItineraryGroupInfo group : groups) {
try { try {
serializer.startTag(null, "itinerary_group"); serializer.startTag(null, "osmand:itinerary_group");
writeNotNullText(serializer, "osmand:name", group.name); writeNotNullText(serializer, "osmand:name", group.name);
writeNotNullText(serializer, "osmand:type", group.type); writeNotNullText(serializer, "osmand:type", group.type);
@ -262,7 +214,7 @@ public class ItineraryHelper {
writeNotNullText(serializer, "osmand:alias", group.alias); writeNotNullText(serializer, "osmand:alias", group.alias);
writeNotNullText(serializer, "osmand:categories", group.categories); writeNotNullText(serializer, "osmand:categories", group.categories);
serializer.endTag(null, "itinerary_group"); serializer.endTag(null, "osmand:itinerary_group");
} catch (IOException e) { } catch (IOException e) {
log.error(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<ItineraryGroup> convertToItineraryGroups() {
List<ItineraryGroup> groups = new ArrayList<>();
for (MapMarkersGroup markersGroup : mapMarkersGroups) {
groups.add(ItineraryGroup.createGroup(markersGroup));
}
return groups;
}
public void syncItineraryGroups() {
syncItineraryGroups(convertToItineraryGroups());
}
public void syncItineraryGroups(List<ItineraryGroup> 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<MapMarker> 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() { public File getExternalFile() {
return new File(app.getAppPath(null), FILE_TO_SAVE); return new File(app.getAppPath(null), FILE_TO_SAVE);
} }
@ -284,18 +325,6 @@ public class ItineraryHelper {
return FavouritesDbHelper.getBackupFile(app, "itinerary_bak_"); return FavouritesDbHelper.getBackupFile(app, "itinerary_bak_");
} }
public List<MapMarkersGroup> getMapMarkersGroups() {
return mapMarkersGroups;
}
public void syncMarkersGroups() {
for (MapMarkersGroup group : mapMarkersGroups) {
if (group.getType() != ItineraryType.MARKERS) {
runGroupSynchronization(group);
}
}
}
public void updateGroupWptCategories(@NonNull MapMarkersGroup group, Set<String> wptCategories) { public void updateGroupWptCategories(@NonNull MapMarkersGroup group, Set<String> wptCategories) {
String id = group.getId(); String id = group.getId();
if (id != null) { if (id != null) {
@ -345,10 +374,54 @@ public class ItineraryHelper {
return mapMarkers; return mapMarkers;
} }
public void addGroupInternally(MapMarkersGroup gr) { private void loadMarkersGroups() {
markersDbHelper.addGroup(gr); Map<String, MapMarkersGroup> groupsMap = markersDbHelper.getAllGroupsMap();
markersHelper.addHistoryMarkersToGroup(gr); List<MapMarker> allMarkers = new ArrayList<>(markersHelper.getMapMarkers());
addToGroupsList(gr); allMarkers.addAll(markersHelper.getMapMarkersHistory());
Iterator<Entry<String, MapMarkersGroup>> 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) { public void updateGpxShowAsMarkers(File file) {
@ -403,22 +476,20 @@ public class ItineraryHelper {
} }
public void addMarkerToGroup(MapMarker marker) { public void addMarkerToGroup(MapMarker marker) {
if (marker != null) { MapMarkersGroup mapMarkersGroup = app.getItineraryHelper().getMapMarkerGroupById(marker.groupKey, marker.getType());
MapMarkersGroup mapMarkersGroup = app.getItineraryHelper().getMapMarkerGroupById(marker.groupKey, marker.getType()); if (mapMarkersGroup != null) {
if (mapMarkersGroup != null) { mapMarkersGroup.getMarkers().add(marker);
mapMarkersGroup.getMarkers().add(marker); updateGroup(mapMarkersGroup);
updateGroup(mapMarkersGroup); if (mapMarkersGroup.getName() == null) {
if (mapMarkersGroup.getName() == null) { markersHelper.sortMarkers(mapMarkersGroup.getMarkers(), false, BY_DATE_ADDED_DESC);
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);
} }
} 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) { private MapMarkersGroup createGPXMarkerGroup(File fl) {
return new MapMarkersGroup(getMarkerGroupId(fl), return new MapMarkersGroup(getMarkerGroupId(fl), getFileNameWithoutExtension(fl), ItineraryType.TRACK);
Algorithms.getFileNameWithoutExtension(fl.getName()),
ItineraryType.TRACK);
} }
private MapMarkersGroup createFavMarkerGroup(FavoriteGroup favGroup) { private MapMarkersGroup createFavMarkerGroup(FavoriteGroup favGroup) {
@ -665,6 +734,12 @@ public class ItineraryHelper {
markersHelper.removeOldMarkersIfPresent(groupMarkers); markersHelper.removeOldMarkersIfPresent(groupMarkers);
} }
private boolean shouldAddWpt(WptPt wptPt, Set<String> wptCategories) {
boolean addAll = wptCategories == null || wptCategories.isEmpty();
return addAll || wptCategories.contains(wptPt.category)
|| wptPt.category == null && wptCategories.contains("");
}
private class SyncGroupTask extends AsyncTask<Void, Void, Void> { private class SyncGroupTask extends AsyncTask<Void, Void, Void> {
private MapMarkersGroup group; private MapMarkersGroup group;

View file

@ -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 "";
}
}

View file

@ -1,18 +1,14 @@
package net.osmand.plus.itinerary; package net.osmand.plus.itinerary;
import androidx.annotation.NonNull;
public enum ItineraryType { public enum ItineraryType {
MARKERS("markers", -1), MARKERS(-1),
FAVOURITES("favourites", 0), FAVOURITES(0),
TRACK("track", 1), TRACK(1),
POINTS("points", 2); POINTS(2);
private int typeId; private int typeId;
private String typeName;
ItineraryType(@NonNull String typeName, int typeId) { ItineraryType(int typeId) {
this.typeName = typeName;
this.typeId = typeId; this.typeId = typeId;
} }
@ -20,25 +16,21 @@ public enum ItineraryType {
return typeId; return typeId;
} }
public String getTypeName() {
return typeName;
}
public static ItineraryType findTypeForId(int typeId) { public static ItineraryType findTypeForId(int typeId) {
for (ItineraryType type : values()) { for (ItineraryType type : values()) {
if (type.getTypeId() == typeId) { if (type.getTypeId() == typeId) {
return type; return type;
} }
} }
return ItineraryType.MARKERS; return ItineraryType.POINTS;
} }
public static ItineraryType findTypeForName(String typeName) { public static ItineraryType findTypeForName(String typeName) {
for (ItineraryType type : values()) { for (ItineraryType type : values()) {
if (type.getTypeName().equalsIgnoreCase(typeName)) { if (type.name().equalsIgnoreCase(typeName)) {
return type; return type;
} }
} }
return ItineraryType.MARKERS; return ItineraryType.POINTS;
} }
} }

View file

@ -4,21 +4,20 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable; import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape; import android.graphics.drawable.shapes.OvalShape;
import android.os.Build;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import net.osmand.data.PointDescription; 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.R;
import net.osmand.plus.activities.MapActivity; import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.helpers.MapMarkerDialogHelper; import net.osmand.plus.helpers.MapMarkerDialogHelper;
import net.osmand.plus.mapcontextmenu.MenuBuilder; import net.osmand.plus.mapcontextmenu.MenuBuilder;
import net.osmand.plus.mapcontextmenu.MenuController; 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; import net.osmand.util.Algorithms;
public class MapMarkerMenuController extends MenuController { public class MapMarkerMenuController extends MenuController {

View file

@ -3,6 +3,7 @@ package net.osmand.plus.mapmarkers;
import android.content.Context; import android.content.Context;
import androidx.annotation.ColorInt; import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import net.osmand.GPXUtilities.WptPt; import net.osmand.GPXUtilities.WptPt;
@ -37,7 +38,7 @@ public class MapMarker implements LocationPoint {
public FavouritePoint favouritePoint; public FavouritePoint favouritePoint;
public String mapObjectName; 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.point = point;
this.pointDescription = name; this.pointDescription = name;
this.colorIndex = colorIndex; this.colorIndex = colorIndex;
@ -66,11 +67,12 @@ public class MapMarker implements LocationPoint {
return name; return name;
} }
@NonNull
public PointDescription getOriginalPointDescription() { public PointDescription getOriginalPointDescription() {
return pointDescription; return pointDescription;
} }
public void setOriginalPointDescription(PointDescription pointDescription) { public void setOriginalPointDescription(@NonNull PointDescription pointDescription) {
this.pointDescription = pointDescription; this.pointDescription = pointDescription;
} }