diff --git a/src/main/java/de/blau/android/Logic.java b/src/main/java/de/blau/android/Logic.java index 0192fea839..6affec140d 100644 --- a/src/main/java/de/blau/android/Logic.java +++ b/src/main/java/de/blau/android/Logic.java @@ -99,6 +99,7 @@ import de.blau.android.osm.RelationMemberDescription; import de.blau.android.osm.RelationMemberPosition; import de.blau.android.osm.RelationUtils; +import de.blau.android.osm.ReplaceIssue; import de.blau.android.osm.Result; import de.blau.android.osm.Server; import de.blau.android.osm.Storage; @@ -2115,7 +2116,7 @@ private void handleDelegatorException(@Nullable final FragmentActivity activity, * @param way the way to split * @param node the node at which the way should be split * @param fromEnd create new Way from Nodes after node - * @return a Result object containing the new Way or null if failed + * @return a List of Result objects containing the new Way and any issues * @throws OsmIllegalOperationException if the operation failed * @throws StorageException if we ran out of memory */ @@ -2740,8 +2741,10 @@ public synchronized void performAppendAppend(@Nullable final Activity activity, * @param activity optional Activity * @param target way that will get the new geometry * @param geometry list of GeoPoint with the new geometry + * @return a List of Result elements */ - public synchronized void performReplaceGeometry(@Nullable final FragmentActivity activity, @NonNull Way target, + @NonNull + public synchronized List performReplaceGeometry(@Nullable final FragmentActivity activity, @NonNull Way target, @NonNull List geometry) { StorageDelegator delegator = getDelegator(); createCheckpoint(activity, R.string.undo_action_replace_geometry); @@ -2773,11 +2776,17 @@ public synchronized void performReplaceGeometry(@Nullable f } delegator.replaceWayNodes(newNodes, target); // final act: delete all unused untagged nodes left + List result = new ArrayList<>(); for (Node n : targetNodes) { if (!n.isTagged() && !n.hasParentRelations() && getWaysForNode(n).isEmpty()) { performEraseNode(activity, n, false); + } else { + Result r = new Result(n); + r.addIssue(ReplaceIssue.EXTRACTED_NODE); + result.add(r); } } + return result; } catch (OsmIllegalOperationException | StorageException ex) { handleDelegatorException(activity, ex); throw ex; // rethrow @@ -2799,7 +2808,7 @@ private Node findTargetNode(@NonNull List targetNodes, double newLon, doub for (Node target : targetNodes) { double distance = GeoMath.haversineDistance(target.getLon() / 1E7D, target.getLat() / 1E7D, newLon, newLat); if (distance < bestDistance) { - if (target.hasTags() && distance > 1) { // only use tagged nodes if they are really close to new + if (target.hasTags() && prefs != null && distance > prefs.getReplaceTolerance()) { // only use tagged nodes if they are really close to new // position continue; } diff --git a/src/main/java/de/blau/android/dialogs/TagConflictDialog.java b/src/main/java/de/blau/android/dialogs/ElementIssueDialog.java similarity index 67% rename from src/main/java/de/blau/android/dialogs/TagConflictDialog.java rename to src/main/java/de/blau/android/dialogs/ElementIssueDialog.java index d80087a1f4..a01c962580 100644 --- a/src/main/java/de/blau/android/dialogs/TagConflictDialog.java +++ b/src/main/java/de/blau/android/dialogs/ElementIssueDialog.java @@ -1,5 +1,7 @@ package de.blau.android.dialogs; +import static de.blau.android.contract.Constants.LOG_TAG_LEN; + import java.io.Serializable; import java.util.ArrayList; import java.util.List; @@ -34,30 +36,64 @@ import de.blau.android.util.ThemeUtils; import de.blau.android.util.Util; -public class TagConflictDialog extends ImmersiveDialogFragment { - private static final String DEBUG_TAG = TagConflictDialog.class.getSimpleName().substring(0, Math.min(23, TagConflictDialog.class.getSimpleName().length())); +public class ElementIssueDialog extends ImmersiveDialogFragment { + private static final int TAG_LEN = Math.min(LOG_TAG_LEN, ElementIssueDialog.class.getSimpleName().length()); + private static final String DEBUG_TAG = ElementIssueDialog.class.getSimpleName().substring(0, TAG_LEN); - private static final String TAG = "fragment_tag_conflict"; + private static final String TAG = "fragment_element_issue"; + private static final String TITLE_KEY = "title_key"; + private static final String MESSAGE_KEY = "message_key"; + private static final String TIP_KEY_KEY = "tip_key_key"; + private static final String TIP_KEY = "tip_key"; private static final String RESULTS_KEY = "results"; + private int titleRes; + private int messageRes; + private int tipKeyRes; + private int tipRes; private List result; + /** + * Show a dialog with a list of tag conflict issues + * + * @param activity the calling FragmentActivity + * @param result the List of Result elements + */ + public static void showTagConflictDialog(@NonNull AppCompatActivity activity, @NonNull List result) { + showDialog(activity, R.string.tag_conflict_title, R.string.tag_conflict_message, R.string.tip_tag_conflict_key, R.string.tip_tag_conflict, result); + } + + /** + * Show a dialog with a list of issues caused by replacing geometry + * + * @param activity the calling FragmentActivity + * @param result the List of Result elements + */ + public static void showReplaceGeometryIssuetDialog(@NonNull AppCompatActivity activity, @NonNull List result) { + showDialog(activity, R.string.replace_geometry_issue_title, R.string.replace_geometry_issue_message, R.string.tip_replace_geometry_key, + R.string.tip_replace_geometry, result); + } + /** * Show a dialog with a list of issues * * @param activity the calling FragmentActivity + * @param titleRes resource id for the title + * @param messageRes resource if for the message + * @param tipKeyRes tip key resource + * @param tipRes tip message resource * @param result the List of Result elements */ - public static void showDialog(@NonNull AppCompatActivity activity, @NonNull List result) { + private static void showDialog(@NonNull AppCompatActivity activity, int titleRes, int messageRes, int tipKeyRes, int tipRes, @NonNull List result) { dismissDialog(activity); try { FragmentManager fm = activity.getSupportFragmentManager(); if (activity instanceof Main) { ((Main) activity).descheduleAutoLock(); } - TagConflictDialog tagConflictFragment = newInstance(result); - tagConflictFragment.show(fm, TAG); + ElementIssueDialog elementIssueFragment = newInstance(titleRes, messageRes, tipKeyRes, tipRes, result); + elementIssueFragment.show(fm, TAG); } catch (IllegalStateException isex) { Log.e(DEBUG_TAG, "showDialog", isex); } @@ -75,12 +111,20 @@ private static void dismissDialog(@NonNull AppCompatActivity activity) { /** * Create new instance of this object * + * @param titleRes resource id for the title + * @param messageRes resource if for the message + * @param tipKeyRes tip key resource + * @param tipRes tip message resource * @param result the List of Result elements * @return a TagConflictDialog instance */ - private static TagConflictDialog newInstance(@NonNull List result) { - TagConflictDialog f = new TagConflictDialog(); + private static ElementIssueDialog newInstance(int titleRes, int messageRes, int tipKeyRes, int tipRes, @NonNull List result) { + ElementIssueDialog f = new ElementIssueDialog(); Bundle args = new Bundle(); + args.putInt(TITLE_KEY, titleRes); + args.putInt(MESSAGE_KEY, messageRes); + args.putInt(TIP_KEY_KEY, tipKeyRes); + args.putInt(TIP_KEY, tipRes); args.putSerializable(RESULTS_KEY, (Serializable) result); f.setArguments(args); @@ -95,19 +139,28 @@ private static TagConflictDialog newInstance(@NonNull List result) { public AppCompatDialog onCreateDialog(Bundle savedInstanceState) { if (savedInstanceState != null) { Log.d(DEBUG_TAG, "Recreating from saved state"); + titleRes = savedInstanceState.getInt(TITLE_KEY); + messageRes = savedInstanceState.getInt(MESSAGE_KEY); + tipKeyRes = savedInstanceState.getInt(TIP_KEY_KEY); + tipRes = savedInstanceState.getInt(TIP_KEY); result = Util.getSerializeableArrayList(savedInstanceState, RESULTS_KEY, Result.class); // restore the elements for (Result r : result) { r.restoreElement(App.getDelegator()); } } else { + Bundle args = getArguments(); + titleRes = args.getInt(TITLE_KEY); + messageRes = args.getInt(MESSAGE_KEY); + tipKeyRes = args.getInt(TIP_KEY_KEY); + tipRes = args.getInt(TIP_KEY); result = Util.getSerializeableArrayList(getArguments(), RESULTS_KEY, Result.class); } final LayoutInflater inflater = ThemeUtils.getLayoutInflater(getActivity()); View layout = inflater.inflate(R.layout.tag_conflict, null); AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); - builder.setTitle(R.string.tag_conflict_title); - builder.setMessage(R.string.tag_conflict_message); + builder.setTitle(titleRes); + builder.setMessage(messageRes); ListView list = layout.findViewById(R.id.elements); list.setAdapter(new ResultArrayAdapter(getContext(), R.layout.tag_conflict_item, R.id.text1, result)); @@ -129,7 +182,7 @@ public AppCompatDialog onCreateDialog(Bundle savedInstanceState) { public void onStart() { super.onStart(); getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); - Tip.showDialog(getActivity(), R.string.tip_tag_conflict_key, R.string.tip_tag_conflict); + Tip.showDialog(getActivity(), tipKeyRes, tipRes); } @Override @@ -144,6 +197,10 @@ public void onDismiss(DialogInterface dialog) { public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); Log.d(DEBUG_TAG, "onSaveInstanceState"); + outState.putInt(TITLE_KEY, titleRes); + outState.putInt(MESSAGE_KEY, messageRes); + outState.putInt(TIP_KEY_KEY, tipKeyRes); + outState.putInt(TIP_KEY, tipRes); List toSave = new ArrayList<>(); // directly saving OsmElements is a bad idea // we need to copy everything as otherwise we diff --git a/src/main/java/de/blau/android/dialogs/UploadConflict.java b/src/main/java/de/blau/android/dialogs/UploadConflict.java index 5def07645b..babfde816e 100644 --- a/src/main/java/de/blau/android/dialogs/UploadConflict.java +++ b/src/main/java/de/blau/android/dialogs/UploadConflict.java @@ -430,7 +430,7 @@ private void setMergedTags(@NonNull final FragmentActivity activity, @NonNull fi if (mergeResult.hasIssue()) { ((Main) activity).edit(into); // NOTE Arrays.asList doesn't work here - TagConflictDialog.showDialog(((Main) activity), de.blau.android.util.Util.wrapInList(mergeResult)); + ElementIssueDialog.showTagConflictDialog(((Main) activity), de.blau.android.util.Util.wrapInList(mergeResult)); } else { restartHandler.onSuccess(); } diff --git a/src/main/java/de/blau/android/easyedit/EasyEditActionModeCallback.java b/src/main/java/de/blau/android/easyedit/EasyEditActionModeCallback.java index 9b14822b96..e40b6aa1e3 100644 --- a/src/main/java/de/blau/android/easyedit/EasyEditActionModeCallback.java +++ b/src/main/java/de/blau/android/easyedit/EasyEditActionModeCallback.java @@ -32,8 +32,8 @@ import de.blau.android.Main; import de.blau.android.PostAsyncActionHandler; import de.blau.android.R; +import de.blau.android.dialogs.ElementIssueDialog; import de.blau.android.dialogs.ErrorAlert; -import de.blau.android.dialogs.TagConflictDialog; import de.blau.android.osm.Node; import de.blau.android.osm.OsmElement; import de.blau.android.osm.RelationUtils; @@ -473,7 +473,7 @@ public void saveState(@NonNull SerializableState state) { protected void checkSplitResult(@NonNull Way originalWay, @Nullable List resultList) { saveSplitResult(originalWay, resultList); if (!savedResults.isEmpty()) { - TagConflictDialog.showDialog(main, new ArrayList<>(savedResults.values())); + ElementIssueDialog.showTagConflictDialog(main, new ArrayList<>(savedResults.values())); } } diff --git a/src/main/java/de/blau/android/easyedit/MultiSelectWithGeometryActionModeCallback.java b/src/main/java/de/blau/android/easyedit/MultiSelectWithGeometryActionModeCallback.java index cb053bd749..f96ec9aaf3 100644 --- a/src/main/java/de/blau/android/easyedit/MultiSelectWithGeometryActionModeCallback.java +++ b/src/main/java/de/blau/android/easyedit/MultiSelectWithGeometryActionModeCallback.java @@ -16,7 +16,7 @@ import de.blau.android.App; import de.blau.android.Map; import de.blau.android.R; -import de.blau.android.dialogs.TagConflictDialog; +import de.blau.android.dialogs.ElementIssueDialog; import de.blau.android.exception.OsmIllegalOperationException; import de.blau.android.osm.Node; import de.blau.android.osm.OsmElement; @@ -36,7 +36,7 @@ public class MultiSelectWithGeometryActionModeCallback extends MultiSelectActionModeCallback { - private static final int TAG_LEN = Math.min(LOG_TAG_LEN, EasyEditActionModeCallback.class.getSimpleName().length()); + private static final int TAG_LEN = Math.min(LOG_TAG_LEN, MultiSelectWithGeometryActionModeCallback.class.getSimpleName().length()); private static final String DEBUG_TAG = MultiSelectWithGeometryActionModeCallback.class.getSimpleName().substring(0, TAG_LEN); private static final int MENUITEM_MERGE = ElementSelectionActionModeCallback.LAST_REGULAR_MENUITEM + 1; @@ -308,7 +308,7 @@ void mergeWays() { final Result r = result.get(0); main.startSupportActionMode(new WaySelectionActionModeCallback(manager, (Way) r.getElement())); if (result.size() > 1 || r.hasIssue()) { - TagConflictDialog.showDialog(main, result); + ElementIssueDialog.showTagConflictDialog(main, result); } } catch (OsmIllegalOperationException | IllegalStateException e) { ScreenMessage.barError(main, e.getLocalizedMessage()); @@ -331,7 +331,7 @@ private void mergePolygons() { main.startSupportActionMode(new RelationSelectionActionModeCallback(manager, (Relation) e)); } if (result.size() > 1 || r.hasIssue()) { - TagConflictDialog.showDialog(main, result); + ElementIssueDialog.showTagConflictDialog(main, result); } } catch (OsmIllegalOperationException | IllegalStateException e) { ScreenMessage.barError(main, e.getLocalizedMessage()); diff --git a/src/main/java/de/blau/android/easyedit/NodeSelectionActionModeCallback.java b/src/main/java/de/blau/android/easyedit/NodeSelectionActionModeCallback.java index 8ab31bb342..f6f89926db 100644 --- a/src/main/java/de/blau/android/easyedit/NodeSelectionActionModeCallback.java +++ b/src/main/java/de/blau/android/easyedit/NodeSelectionActionModeCallback.java @@ -26,7 +26,7 @@ import androidx.appcompat.view.ActionMode; import de.blau.android.DisambiguationMenu; import de.blau.android.R; -import de.blau.android.dialogs.TagConflictDialog; +import de.blau.android.dialogs.ElementIssueDialog; import de.blau.android.easyedit.turnrestriction.FromElementWithViaNodeActionModeCallback; import de.blau.android.exception.OsmIllegalOperationException; import de.blau.android.exception.StorageException; @@ -236,7 +236,7 @@ private void mergeNodeWith(@NonNull List target) { manager.editElement(newElement); } if (result.size() > 1 || result.get(0).hasIssue()) { - TagConflictDialog.showDialog(main, result); + ElementIssueDialog.showTagConflictDialog(main, result); } else { ScreenMessage.toastTopInfo(main, R.string.toast_merged); } diff --git a/src/main/java/de/blau/android/easyedit/ReplaceGeometryActionModeCallback.java b/src/main/java/de/blau/android/easyedit/ReplaceGeometryActionModeCallback.java index e3231bf037..d1e45dbd60 100644 --- a/src/main/java/de/blau/android/easyedit/ReplaceGeometryActionModeCallback.java +++ b/src/main/java/de/blau/android/easyedit/ReplaceGeometryActionModeCallback.java @@ -19,7 +19,7 @@ import de.blau.android.App; import de.blau.android.Logic; import de.blau.android.R; -import de.blau.android.dialogs.TagConflictDialog; +import de.blau.android.dialogs.ElementIssueDialog; import de.blau.android.exception.OsmIllegalOperationException; import de.blau.android.exception.StorageException; import de.blau.android.osm.GeoPoint; @@ -103,16 +103,22 @@ public boolean handleElementClick(OsmElement element) { // NOSONAR Logic logic = App.getLogic(); try { if (target instanceof Way) { - logic.performReplaceGeometry(main, (Way) target, ((Way) element).getNodes()); + final List result = logic.performReplaceGeometry(main, (Way) target, ((Way) element).getNodes()); AlertDialog.Builder builder = new AlertDialog.Builder(main); builder.setTitle(R.string.remove_geometry_source); builder.setPositiveButton(R.string.Yes, (dialog, id) -> logic.performEraseWay(main, ((Way) element), true, false)); builder.setNegativeButton(R.string.No, null); AlertDialog d = builder.create(); - d.setOnDismissListener((DialogInterface dialog) -> main.startSupportActionMode(new WaySelectionActionModeCallback(manager, (Way) target))); + d.setOnDismissListener((DialogInterface dialog) -> { + main.startSupportActionMode(new WaySelectionActionModeCallback(manager, (Way) target)); + if (!result.isEmpty()) { + ElementIssueDialog.showReplaceGeometryIssuetDialog(main, result); + } + }); d.show(); } if (target instanceof Node) { + // arguably this section should really be in Logic logic.createCheckpoint(main, R.string.undo_action_replace_geometry); Node toReplace = findYoungestUntaggedNode((Way) element); logic.setTags(main, Node.NAME, target.getOsmId(), null, false); @@ -124,7 +130,7 @@ public boolean handleElementClick(OsmElement element) { // NOSONAR MergeAction.checkForMergedTags(targetTags, element.getTags(), mergedTags, r); logic.setTags(main, Way.NAME, element.getOsmId(), mergedTags, false); if (mergeResult.size() > 1 || r.hasIssue()) { - TagConflictDialog.showDialog(main, mergeResult); + ElementIssueDialog.showTagConflictDialog(main, mergeResult); } logic.deselectAll(); logic.addSelectedWay((Way) element); diff --git a/src/main/java/de/blau/android/easyedit/WayMergingActionModeCallback.java b/src/main/java/de/blau/android/easyedit/WayMergingActionModeCallback.java index 00bb5d097c..ab175b180a 100644 --- a/src/main/java/de/blau/android/easyedit/WayMergingActionModeCallback.java +++ b/src/main/java/de/blau/android/easyedit/WayMergingActionModeCallback.java @@ -1,5 +1,7 @@ package de.blau.android.easyedit; +import static de.blau.android.contract.Constants.LOG_TAG_LEN; + import java.util.List; import java.util.Set; @@ -9,7 +11,7 @@ import androidx.annotation.NonNull; import androidx.appcompat.view.ActionMode; import de.blau.android.R; -import de.blau.android.dialogs.TagConflictDialog; +import de.blau.android.dialogs.ElementIssueDialog; import de.blau.android.exception.OsmIllegalOperationException; import de.blau.android.osm.OsmElement; import de.blau.android.osm.Result; @@ -17,7 +19,10 @@ import de.blau.android.util.ScreenMessage; public class WayMergingActionModeCallback extends NonSimpleActionModeCallback { - private static final String DEBUG_TAG = "WayMerging..."; + + private static final int TAG_LEN = Math.min(LOG_TAG_LEN, WayMergingActionModeCallback.class.getSimpleName().length()); + private static final String DEBUG_TAG = WayMergingActionModeCallback.class.getSimpleName().substring(0, TAG_LEN); + private final Way way; private final Set ways; @@ -61,7 +66,7 @@ public boolean handleElementClick(OsmElement element) { // due to clickableEleme Result r = result.get(0); main.startSupportActionMode(new WaySelectionActionModeCallback(manager, (Way) r.getElement())); if (result.size() > 1 || r.hasIssue()) { - TagConflictDialog.showDialog(main, result); + ElementIssueDialog.showTagConflictDialog(main, result); } } catch (OsmIllegalOperationException e) { ScreenMessage.barError(main, e.getLocalizedMessage()); diff --git a/src/main/java/de/blau/android/easyedit/WaySelectionActionModeCallback.java b/src/main/java/de/blau/android/easyedit/WaySelectionActionModeCallback.java index 6bbe5a7b02..3dfa1aa96a 100644 --- a/src/main/java/de/blau/android/easyedit/WaySelectionActionModeCallback.java +++ b/src/main/java/de/blau/android/easyedit/WaySelectionActionModeCallback.java @@ -16,7 +16,7 @@ import androidx.appcompat.view.ActionMode; import de.blau.android.App; import de.blau.android.R; -import de.blau.android.dialogs.TagConflictDialog; +import de.blau.android.dialogs.ElementIssueDialog; import de.blau.android.easyedit.route.RouteSegmentActionModeCallback; import de.blau.android.easyedit.turnrestriction.FromElementActionModeCallback; import de.blau.android.exception.OsmIllegalOperationException; @@ -217,7 +217,7 @@ private void reverseWay(@NonNull final Way way) { try { List result = logic.performReverse(main, way); if (!result.isEmpty()) { - TagConflictDialog.showDialog(main, result); + ElementIssueDialog.showTagConflictDialog(main, result); } } catch (OsmIllegalOperationException | StorageException ex) { // toast has already been displayed diff --git a/src/main/java/de/blau/android/easyedit/route/RouteSegmentActionModeCallback.java b/src/main/java/de/blau/android/easyedit/route/RouteSegmentActionModeCallback.java index ec929008ac..925e2f50a4 100644 --- a/src/main/java/de/blau/android/easyedit/route/RouteSegmentActionModeCallback.java +++ b/src/main/java/de/blau/android/easyedit/route/RouteSegmentActionModeCallback.java @@ -1,5 +1,7 @@ package de.blau.android.easyedit.route; +import static de.blau.android.contract.Constants.LOG_TAG_LEN; + import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -15,7 +17,7 @@ import androidx.appcompat.view.ActionMode; import de.blau.android.App; import de.blau.android.R; -import de.blau.android.dialogs.TagConflictDialog; +import de.blau.android.dialogs.ElementIssueDialog; import de.blau.android.easyedit.BuilderActionModeCallback; import de.blau.android.easyedit.EasyEditManager; import de.blau.android.easyedit.ElementSelectionActionModeCallback; @@ -37,7 +39,8 @@ public class RouteSegmentActionModeCallback extends BuilderActionModeCallback { - private static final String DEBUG_TAG = RouteSegmentActionModeCallback.class.getSimpleName().substring(0, Math.min(23, RouteSegmentActionModeCallback.class.getSimpleName().length())); + private static final int TAG_LEN = Math.min(LOG_TAG_LEN, RouteSegmentActionModeCallback.class.getSimpleName().length()); + private static final String DEBUG_TAG = RouteSegmentActionModeCallback.class.getSimpleName().substring(0, TAG_LEN); static final String SEGMENT_IDS_KEY = "segment ids"; static final String ROUTE_ID_KEY = "route id"; @@ -337,7 +340,7 @@ public void finishBuilding() { main.performTagEdit(route, Tags.VALUE_ROUTE, false, false); main.startSupportActionMode(new RelationSelectionActionModeCallback(manager, route)); if (!savedResults.isEmpty()) { - TagConflictDialog.showDialog(main, new ArrayList<>(savedResults.values())); + ElementIssueDialog.showTagConflictDialog(main, new ArrayList<>(savedResults.values())); } } catch (OsmIllegalOperationException | StorageException ex) { // toast has already been displayed diff --git a/src/main/java/de/blau/android/easyedit/turnrestriction/ToElementActionModeCallback.java b/src/main/java/de/blau/android/easyedit/turnrestriction/ToElementActionModeCallback.java index dbd61a7871..3deefd1d05 100644 --- a/src/main/java/de/blau/android/easyedit/turnrestriction/ToElementActionModeCallback.java +++ b/src/main/java/de/blau/android/easyedit/turnrestriction/ToElementActionModeCallback.java @@ -1,5 +1,7 @@ package de.blau.android.easyedit.turnrestriction; +import static de.blau.android.contract.Constants.LOG_TAG_LEN; + import java.util.ArrayList; import java.util.Map; @@ -9,7 +11,7 @@ import androidx.annotation.Nullable; import androidx.appcompat.view.ActionMode; import de.blau.android.R; -import de.blau.android.dialogs.TagConflictDialog; +import de.blau.android.dialogs.ElementIssueDialog; import de.blau.android.easyedit.EasyEditManager; import de.blau.android.easyedit.NonSimpleActionModeCallback; import de.blau.android.easyedit.RelationSelectionActionModeCallback; @@ -22,7 +24,9 @@ import de.blau.android.osm.Way; public class ToElementActionModeCallback extends NonSimpleActionModeCallback { - private static final String DEBUG9_TAG = "RestrictionToElement..."; + + private static final int TAG_LEN = Math.min(LOG_TAG_LEN, ToElementActionModeCallback.class.getSimpleName().length()); + private static final String DEBUG_TAG = ToElementActionModeCallback.class.getSimpleName().substring(0, TAG_LEN); private final Way fromWay; private final OsmElement viaElement; @@ -57,11 +61,11 @@ public boolean onCreateActionMode(ActionMode mode, Menu menu) { boolean uTurn = fromWay == toWay; try { Relation restriction = logic.createRestriction(main, fromWay, viaElement, toWay, uTurn ? Tags.VALUE_NO_U_TURN : null); - Log.i(DEBUG9_TAG, "Created restriction"); + Log.i(DEBUG_TAG, "Created restriction"); main.performTagEdit(restriction, !uTurn ? Tags.VALUE_RESTRICTION : null, false, false); main.startSupportActionMode(new RelationSelectionActionModeCallback(manager, restriction)); if (!savedResults.isEmpty()) { - TagConflictDialog.showDialog(main, new ArrayList<>(savedResults.values())); + ElementIssueDialog.showTagConflictDialog(main, new ArrayList<>(savedResults.values())); } } catch (OsmIllegalOperationException | StorageException ex) { // logic will have already toasted diff --git a/src/main/java/de/blau/android/osm/ReplaceIssue.java b/src/main/java/de/blau/android/osm/ReplaceIssue.java new file mode 100644 index 0000000000..ae50644ff9 --- /dev/null +++ b/src/main/java/de/blau/android/osm/ReplaceIssue.java @@ -0,0 +1,28 @@ +package de.blau.android.osm; + +import android.content.Context; +import de.blau.android.R; + +/** + * Potential issues when replacing existing geometry + * + * @author Simon + * + */ +public enum ReplaceIssue implements Issue { + EXTRACTED_NODE; + + @Override + public String toTranslatedString(Context context) { + if (EXTRACTED_NODE.equals(this)) { + return context.getString(R.string.issue_replace_extracted_node); + } else { + return ""; + } + } + + @Override + public boolean isError() { + return false; + } +} diff --git a/src/main/java/de/blau/android/prefs/Preferences.java b/src/main/java/de/blau/android/prefs/Preferences.java index 96ef303117..b5f22fa722 100755 --- a/src/main/java/de/blau/android/prefs/Preferences.java +++ b/src/main/java/de/blau/android/prefs/Preferences.java @@ -151,6 +151,7 @@ public class Preferences { private final double maxCircleSegment; private final double minCircleSegment; private final Set poiKeys; + private final double replaceTolerance; public static final String DEFAULT_MAP_STYLE = "Color Round Nodes"; public static final String DEFAULT_PEN_MAP_STYLE = "Pen Round Nodes"; @@ -343,6 +344,8 @@ public Preferences(@NonNull Context ctx) { minCircleSegment = getFloatFromStringPref(R.string.config_minCircleSegment_key, 0.5f); poiKeys = prefs.getStringSet(r.getString(R.string.config_poi_keys_key), new HashSet<>(Arrays.asList(r.getStringArray(R.array.poi_keys_defaults)))); + + replaceTolerance = getFloatFromStringPref(R.string.config_replaceTolerance_key, 1.0f); } /** @@ -1959,7 +1962,7 @@ public double getMaxCircleSegment() { } /** - * Get the max distance two nodes on a circle should have after circulize or create circle operations + * Get the min distance two nodes on a circle should have after circulize or create circle operations * * @return the min. distance between two circle nodes */ @@ -1976,6 +1979,15 @@ public double getMinCircleSegment() { public Set poiKeys() { return poiKeys; } + + /** + * Get the max distance a tagged node can be moved when replacing a way geometry + * + * @return the max allowed distance a tagged node can be moved + */ + public double getReplaceTolerance() { + return replaceTolerance; + } /** * Get the preset path for item diff --git a/src/main/res/values/prefkeys.xml b/src/main/res/values/prefkeys.xml index dca6c8f5d3..f4a7bb76c4 100644 --- a/src/main/res/values/prefkeys.xml +++ b/src/main/res/values/prefkeys.xml @@ -145,6 +145,7 @@ minCircleNodes maxCircleSegment minCircleSegment + replaceTolerance gpxPreferredDir osmPreferredDir diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index b7b6eaf631..3ab3da15ed 100755 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -529,9 +529,11 @@ Last included date Attribution MapSplit read only source - + Properties changed The operation required changing properties of the elements involved. + Element changed + The operation required changing an elements position or membership. No suitable relations in downloaded data Select route @@ -576,6 +578,7 @@ In simple mode a long press will not do anything. Turn simple mode off in the main menu if you want to use long clicks to create objects. Starting with version 15, GPX tracks no longer contain elevation information by default.<p>To enable elevation recording, install a Geoid model with <i>Install EGM</i> from the Tools menu, or switch to NMEA input. Merging and reversing OSM elements sometimes requires changing attributes on the elements, if there is a potential error or conflict you are alerted to this and are offered an opportunity to review the objects in question. + Replacing the geometry of a way often requires moving the position of existing nodes, if these are tagged, that is they represent objects themselves, this might be undesireable.<p>To avoid this problem we extract nodes that are not within a small tolerance radius from the parent way and display a warning. You can adjust the tolerance (default 1m) in the advanced preferences. When you start GPX recording Vespucci collects location data to enable the GPX recording even when the app is not visible.<p>Explicitly closing the application or turning GPX recording off will stop the use of location data in such situations. When you start auto-downloading OSM data or tasks Vespucci utilizes location data to determine the current position even when the app is not visible.<p>Explicitly closing the application or turning auto-downloading off will stop the use of location data in such situations. You just touched a tristate checkbox, these work just as normal checkboxes, toggling between two values, for example yes/no or true/false.<p>However they have an additional third <b>not set</b> state, indicated by a greyed out checkbox which will stop the corresponding tag from being added. You can set the checkbox to this state with a long press. @@ -1397,10 +1400,13 @@ %1$d nodes Maximum circle segment length Maximum distance between two circle nodes. - %1$d meter(s) + %1$d meter(s) Minimum circle segment length Minimum distance between two circle nodes. - %1$d meter(s) + %1$d meter(s) + Maximum distance to move tagged node + Maximum distance to move a tagged node when replacing way geometry. + %1$d meter(s) Auto-download settings @@ -1665,6 +1671,7 @@ Length dependent value was split Route may need manual reordering Relation member count exceeded + Tagged node extracted from way 1 day diff --git a/src/main/res/values/tipkeys.xml b/src/main/res/values/tipkeys.xml index d1d83f0853..92877f60ad 100644 --- a/src/main/res/values/tipkeys.xml +++ b/src/main/res/values/tipkeys.xml @@ -11,6 +11,7 @@ longPressSimpleModeTip gpxNoElevationTip tagConflictTip + replaceGeometryTip gpxRecordingTip autoDownloadTip tristateCheckbox diff --git a/src/main/res/xml-v24/advancedpreferences.xml b/src/main/res/xml-v24/advancedpreferences.xml index 1d2f1bac06..54dcebc293 100644 --- a/src/main/res/xml-v24/advancedpreferences.xml +++ b/src/main/res/xml-v24/advancedpreferences.xml @@ -386,6 +386,12 @@ android:key="@string/config_minCircleSegment_key" android:summary="@string/config_minCircleSegment_summary" android:title="@string/config_minCircleSegment_title" /> + + +