Skip to content

Commit

Permalink
Add support for "duplicate" function
Browse files Browse the repository at this point in the history
This adds support for duplication, that is creating a copy in the same
location for nodes, ways and multipolygon relations, shallow duplication
for ways and all relations and copying of multipolygon relations.

Resolves: #1832
  • Loading branch information
simonpoole committed Jan 7, 2025
1 parent 6fad30b commit 1a52934
Show file tree
Hide file tree
Showing 11 changed files with 471 additions and 115 deletions.
27 changes: 26 additions & 1 deletion src/main/java/de/blau/android/Logic.java
Original file line number Diff line number Diff line change
Expand Up @@ -5915,7 +5915,7 @@ private int[] calcCentroid(@NonNull List<OsmElement> elements) {
* @param activity the activity we were called from
* @param x screen x to position the object at
* @param y screen y to position the object at
* @return the pasted object or null if the clipboard was empty
* @return the pasted objects or null if the clipboard was empty
*/
@Nullable
public List<OsmElement> pasteFromClipboard(@Nullable Activity activity, float x, float y) {
Expand All @@ -5925,6 +5925,31 @@ public List<OsmElement> pasteFromClipboard(@Nullable Activity activity, float x,
return getDelegator().pasteFromClipboard(lat, lon);
}

/**
* Duplicate a list of elements
*
* If the the duplicated objects have a name tag, a compositie name will be generated
*
* @param activity the activity we were called from
* @param elements the List of OsmElement
* @param deep duplicate child elements if true
* @return the duplicated objects
*/
@Nullable
public List<OsmElement> duplicate(@Nullable Activity activity, @NonNull List<OsmElement> elements, boolean deep) {
createCheckpoint(activity, R.string.undo_action_duplicate);
List<OsmElement> duplicated = getDelegator().duplicate(elements, deep);
for (OsmElement d : duplicated) {
String nameTag = d.getTagWithKey(Tags.KEY_NAME);
if (nameTag != null && activity != null) {
SortedMap<String, String> tags = new TreeMap<>(d.getTags());
tags.put(Tags.KEY_NAME, activity.getString(R.string.duplicated_name_template, nameTag));
setTags(activity, d, tags, false);
}
}
return duplicated;
}

/**
* Check if the clipboard is empty
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,24 +95,26 @@ public abstract class ElementSelectionActionModeCallback extends EasyEditActionM
private static final int MENUITEM_HISTORY_WEB = 4;
private static final int MENUITEM_HISTORY = 5;
static final int MENUITEM_COPY = 6;
static final int MENUITEM_CUT = 7;
private static final int MENUITEM_PASTE_TAGS = 8;
private static final int MENUITEM_CREATE_RELATION = 9;
private static final int MENUITEM_ADD_RELATION_MEMBERS = 10;
private static final int MENUITEM_EXTEND_SELECTION = 11;
private static final int MENUITEM_ELEMENT_INFO = 12;
static final int MENUITEM_DUPLICATE = 7;
static final int MENUITEM_SHALLOW_DUPLICATE = 8;
static final int MENUITEM_CUT = 9;
private static final int MENUITEM_PASTE_TAGS = 10;
private static final int MENUITEM_CREATE_RELATION = 11;
private static final int MENUITEM_ADD_RELATION_MEMBERS = 12;
private static final int MENUITEM_EXTEND_SELECTION = 13;
private static final int MENUITEM_ELEMENT_INFO = 14;
protected static final int LAST_REGULAR_MENUITEM = MENUITEM_ELEMENT_INFO;

static final int MENUITEM_UPLOAD = 31;
protected static final int MENUITEM_SHARE_POSITION = 32;
private static final int MENUITEM_TAG_LAST = 33;
static final int MENUITEM_ZOOM_TO_SELECTION = 34;
static final int MENUITEM_SEARCH_OBJECTS = 35;
private static final int MENUITEM_REPLACE_GEOMETRY = 36;
private static final int MENUITEM_CALIBRATE_BAROMETER = 37;
static final int MENUITEM_PREFERENCES = 38;
static final int MENUITEM_JS_CONSOLE = 39;
static final int MENUITEM_ADD_TO_TODO = 40;
static final int MENUITEM_UPLOAD = 40;
protected static final int MENUITEM_SHARE_POSITION = 41;
private static final int MENUITEM_TAG_LAST = 42;
static final int MENUITEM_ZOOM_TO_SELECTION = 43;
static final int MENUITEM_SEARCH_OBJECTS = 44;
private static final int MENUITEM_REPLACE_GEOMETRY = 45;
private static final int MENUITEM_CALIBRATE_BAROMETER = 46;
static final int MENUITEM_PREFERENCES = 47;
static final int MENUITEM_JS_CONSOLE = 48;
static final int MENUITEM_ADD_TO_TODO = 49;

private static final int MENUITEM_TODO_CLOSE_AND_NEXT = 70;
private static final int MENUITEM_TODO_SKIP_AND_NEXT = 71;
Expand Down Expand Up @@ -178,10 +180,17 @@ public boolean onCreateActionMode(ActionMode mode, Menu menu) {

menu.add(Menu.NONE, MENUITEM_DELETE, Menu.CATEGORY_SYSTEM, R.string.delete).setIcon(ThemeUtils.getResIdFromAttribute(main, R.attr.menu_delete));
final boolean isRelation = element instanceof Relation;
if (!isRelation) {
if (!isRelation || element.hasTag(Tags.KEY_TYPE, Tags.VALUE_MULTIPOLYGON)) {
menu.add(Menu.NONE, MENUITEM_COPY, Menu.CATEGORY_SECONDARY, R.string.menu_copy).setIcon(ThemeUtils.getResIdFromAttribute(main, R.attr.menu_copy));
menu.add(Menu.NONE, MENUITEM_DUPLICATE, Menu.CATEGORY_SECONDARY, R.string.menu_duplicate)
.setIcon(ThemeUtils.getResIdFromAttribute(main, R.attr.menu_duplicate));
}
if (!isRelation) {
menu.add(Menu.NONE, MENUITEM_CUT, Menu.CATEGORY_SECONDARY, R.string.menu_cut).setIcon(ThemeUtils.getResIdFromAttribute(main, R.attr.menu_cut));
}
if (!(element instanceof Node)) {
menu.add(Menu.NONE, MENUITEM_SHALLOW_DUPLICATE, Menu.CATEGORY_SECONDARY, R.string.menu_shallow_duplicate);
}
pasteItem = menu.add(Menu.NONE, MENUITEM_PASTE_TAGS, Menu.CATEGORY_SECONDARY, R.string.menu_paste_tags);

menu.add(GROUP_BASE, MENUITEM_EXTEND_SELECTION, Menu.CATEGORY_SYSTEM, R.string.menu_extend_selection)
Expand Down Expand Up @@ -312,7 +321,8 @@ public static boolean setItemVisibility(boolean condition, @NonNull MenuItem ite
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
super.onActionItemClicked(mode, item);
final TaskStorage taskStorage = App.getTaskStorage();
switch (item.getItemId()) {
final int itemId = item.getItemId();
switch (itemId) {
case MENUITEM_TAG:
main.performTagEdit(element, null, false, false);
break;
Expand All @@ -339,6 +349,13 @@ public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
logic.cutToClipboard(main, element);
mode.finish();
break;
case MENUITEM_DUPLICATE:
case MENUITEM_SHALLOW_DUPLICATE:
List<OsmElement> result = logic.duplicate(main, Util.wrapInList(element), itemId == MENUITEM_DUPLICATE);
mode.finish();
App.getLogic().setSelection(result);
manager.editElements();
break;
case MENUITEM_PASTE_TAGS:
main.performTagEdit(element, null, new HashMap<>(App.getTagClipboard(main).paste()), false);
break;
Expand Down Expand Up @@ -412,7 +429,7 @@ public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
case MENUITEM_TODO_CLOSE_AND_NEXT:
case MENUITEM_TODO_SKIP_AND_NEXT:
final List<Todo> todos = taskStorage.getTodosForElement(element);
State newState = item.getItemId() == MENUITEM_TODO_CLOSE_AND_NEXT ? State.CLOSED : State.SKIPPED;
State newState = itemId == MENUITEM_TODO_CLOSE_AND_NEXT ? State.CLOSED : State.SKIPPED;
Set<StringWithDescription> listNames = new HashSet<>();
for (int i = 0; i < todos.size(); i++) {
listNames.add(todos.get(i).getListName(main));
Expand Down
13 changes: 11 additions & 2 deletions src/main/java/de/blau/android/osm/ClipboardStorage.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package de.blau.android.osm;

import static de.blau.android.contract.Constants.LOG_TAG_LEN;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
Expand All @@ -9,7 +11,9 @@
import de.blau.android.exception.StorageException;

public class ClipboardStorage implements Serializable {
static final String DEBUG_TAG = ClipboardStorage.class.getSimpleName().substring(0, Math.min(23, ClipboardStorage.class.getSimpleName().length()));

private static final int TAG_LEN = Math.min(LOG_TAG_LEN, ClipboardStorage.class.getSimpleName().length());
private static final String DEBUG_TAG = ClipboardStorage.class.getSimpleName().substring(0, TAG_LEN);

/**
*
Expand Down Expand Up @@ -58,7 +62,6 @@ public void copyTo(@NonNull List<OsmElement> elements, int latE7, int lonE7) {
selectionLat = latE7;
selectionLon = lonE7;
mode = Mode.COPY;

try {
for (OsmElement e : elements) {
storage.insertElementUnsafe(e);
Expand Down Expand Up @@ -99,6 +102,7 @@ public boolean isEmpty() {
public List<OsmElement> pasteFrom() {
List<Way> ways = storage.getWays();
List<Node> nodes = storage.getNodes();
List<Relation> relations = storage.getRelations();
List<OsmElement> result = new ArrayList<>();
if (mode == Mode.CUT) {
reset(); // can only paste a cut way once
Expand All @@ -113,6 +117,11 @@ public List<OsmElement> pasteFrom() {
result.add(w);
}
}
if (relations != null) {
for (Relation r : relations) {
result.add(r);
}
}
return result;
}

Expand Down
Loading

0 comments on commit 1a52934

Please sign in to comment.