Skip to content

Commit

Permalink
Merge pull request #42 from NLthijs48/customizable-tagging
Browse files Browse the repository at this point in the history
Add customizable tagging: none/preset/search/address
  • Loading branch information
r00tat authored Jul 3, 2021
2 parents bb37cd3 + 82920a9 commit 2a5991d
Show file tree
Hide file tree
Showing 5 changed files with 555 additions and 147 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,7 @@ lib/*-source.jar
lib/*-jar.jar
lib/*-maven-plugin.jar
lib/*-bundle.jar
javadoc
# Intellij project files
*.iml

250 changes: 198 additions & 52 deletions src/org/openstreetmap/josm/plugins/areaselector/AreaSelectorAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.openstreetmap.josm.actions.mapmode.MapMode;
import org.openstreetmap.josm.command.AddCommand;
import org.openstreetmap.josm.command.ChangeCommand;
import org.openstreetmap.josm.command.ChangePropertyCommand;
import org.openstreetmap.josm.command.Command;
import org.openstreetmap.josm.command.DeleteCommand;
import org.openstreetmap.josm.command.PseudoCommand;
Expand All @@ -43,6 +44,7 @@
import org.openstreetmap.josm.data.osm.Node;
import org.openstreetmap.josm.data.osm.OsmPrimitive;
import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
import org.openstreetmap.josm.data.osm.Tag;
import org.openstreetmap.josm.data.osm.Way;
import org.openstreetmap.josm.data.preferences.BooleanProperty;
import org.openstreetmap.josm.data.preferences.DoubleProperty;
Expand All @@ -52,6 +54,17 @@
import org.openstreetmap.josm.gui.MapView;
import org.openstreetmap.josm.gui.Notification;
import org.openstreetmap.josm.gui.layer.Layer;
import org.openstreetmap.josm.gui.tagging.presets.TaggingPreset;
import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetItem;
import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetSearchDialog;
import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetType;
import org.openstreetmap.josm.gui.tagging.presets.TaggingPresets;
import org.openstreetmap.josm.gui.tagging.presets.items.Check;
import org.openstreetmap.josm.gui.tagging.presets.items.CheckGroup;
import org.openstreetmap.josm.gui.tagging.presets.items.ComboMultiSelect;
import org.openstreetmap.josm.gui.tagging.presets.items.Key;
import org.openstreetmap.josm.gui.tagging.presets.items.KeyedItem;
import org.openstreetmap.josm.gui.tagging.presets.items.Text;
import org.openstreetmap.josm.plugins.austriaaddresshelper.AustriaAddressHelperAction;
import org.openstreetmap.josm.tools.ImageProvider;
import org.openstreetmap.josm.tools.Shortcut;
Expand All @@ -68,14 +81,19 @@ public class AreaSelectorAction extends MapMode implements MouseListener {
toleranceAngle = ImageAnalyzer.DEFAULT_TOLERANCEANGLE;

protected boolean showAddressDialog = true, mergeNodes = true, useAustriaAdressHelper = false,
replaceBuildings = true, addSourceTag = false;
replaceBuildings = true, addSourceTag = false, applyPresetDirectly = false;
protected String taggingStyle = "none";
protected String taggingPresetName = "";

public static final String PLUGIN_NAME = "areaselector";

public static final String KEY_SHOWADDRESSDIALOG = PLUGIN_NAME + ".showaddressdialog",
KEY_TAGGINGSTYLE = PLUGIN_NAME + ".taggingstyle",
KEY_TAGGINGPRESETNAME = PLUGIN_NAME + ".taggingpresetname",
KEY_MERGENODES = PLUGIN_NAME + ".mergenodes", KEY_AAH = PLUGIN_NAME + ".austriaadresshelper",
KEY_REPLACEBUILDINGS = PLUGIN_NAME + ".replacebuildings",
KEY_ADDSOURCETAG = PLUGIN_NAME + ".addsourcetag";
KEY_ADDSOURCETAG = PLUGIN_NAME + ".addsourcetag",
KEY_APPLYPRESETDIRECTLY = PLUGIN_NAME + ".applypresetdirectly";

protected Logger log = LogManager.getLogger(AreaSelectorAction.class.getCanonicalName());

Expand All @@ -94,9 +112,12 @@ public AreaSelectorAction(MapFrame mapFrame) {
protected void readPrefs() {
this.mergeNodes = new BooleanProperty(KEY_MERGENODES, true).get();
this.showAddressDialog = new BooleanProperty(KEY_SHOWADDRESSDIALOG, true).get();
this.taggingStyle = new StringProperty(KEY_TAGGINGSTYLE, "none").get();
this.taggingPresetName = new StringProperty(KEY_TAGGINGPRESETNAME, "").get();
useAustriaAdressHelper = new BooleanProperty(KEY_AAH, false).get();
replaceBuildings = new BooleanProperty(KEY_REPLACEBUILDINGS, true).get();
addSourceTag = new BooleanProperty(KEY_ADDSOURCETAG, false).get();
applyPresetDirectly = new BooleanProperty(KEY_APPLYPRESETDIRECTLY, false).get();
}

private static Cursor getCursor() {
Expand Down Expand Up @@ -179,7 +200,7 @@ public BufferedImage getLayeredImage() {
}

public void createArea() {

////////// Polygon generation
MapView mapView = MainApplication.getMap().mapView;

BufferedImage bufImage = getLayeredImage();
Expand All @@ -196,78 +217,207 @@ public void createArea() {
imgAnalyzer.setToleranceDist(toleranceInPixel);

Polygon polygon = imgAnalyzer.getArea();
if (polygon == null) {
JOptionPane.showMessageDialog(MainApplication.getMap(), tr("Unable to detect a polygon where you clicked."),
tr("Area Selector"), JOptionPane.WARNING_MESSAGE);
return;
}

Way way = createWayFromPolygon(mapView, polygon);
Way newWay = null;

DataSet ds = MainApplication.getLayerManager().getEditDataSet();
Collection<Command> cmds = new LinkedList<>();
List<Node> nodes = way.getNodes();
for (int i = 0; i < nodes.size() - 1; i++) {
cmds.add(new AddCommand(ds, nodes.get(i)));
}
cmds.add(new AddCommand(ds, way));
UndoRedoHandler.getInstance().add(new SequenceCommand(/* I18n: Name of the command that adds the generated way */ tr("create closed way"), cmds));

if (polygon != null) {
if (replaceBuildings) {
Way existingWay = MainApplication.getMap().mapView.getNearestWay(clickPoint, OsmPrimitive::isUsable);
if (existingWay != null && way.getBBox().bounds(existingWay.getBBox().getCenter())) {
log.info("existing way is inside of new building: " + existingWay.toString() + " is in " + way.toString());
UndoRedoHandler.getInstance().add(new SequenceCommand(tr("replace building"), replaceWay(existingWay, way)));
way = existingWay;
}
}

Way way = createWayFromPolygon(mapView, polygon), newWay = null;
ds.setSelected(way);

way.put(AddressDialog.TAG_BUILDING, new StringProperty(AddressDialog.PREF_BUILDING, "yes").get());
if (mergeNodes) {
mergeNodes(way);
}

if (!showAddressDialog && addSourceTag) {
ArrayList<String> sources = new ArrayList<>();
for (Layer layer : mapView.getLayerManager().getVisibleLayersInZOrder()) {
if (layer.isVisible() && layer.isBackgroundLayer()) {
sources.add(layer.getName());
}
if (useAustriaAdressHelper) {
Map<String, String> newAddress = fetchAddress(way);
if (newAddress != null) {
newWay = new Way(way);
newWay.setKeys(newAddress);
log.info("Found attributes: {}", newWay.getKeys());
if (!showAddressDialog) {
final List<Command> commands = new ArrayList<>();
commands.add(new ChangeCommand(way, newWay));
UndoRedoHandler.getInstance().add(
new SequenceCommand(trn("Add address", "Add addresses", commands.size()), commands));
}
Collections.reverse(sources);
String source = sources.stream().map(Object::toString).collect(Collectors.joining("; ")).toString();
if (!source.isEmpty()) {
way.put(AddressDialog.TAG_SOURCE, source);
}
}

if (!showAddressDialog && addSourceTag) {
ArrayList<String> sources = new ArrayList<>();
for (Layer layer : mapView.getLayerManager().getVisibleLayersInZOrder()) {
if (layer.isVisible() && layer.isBackgroundLayer()) {
sources.add(layer.getName());
}
}
Collections.reverse(sources);
String source = sources.stream().map(Object::toString).collect(Collectors.joining("; "));
if (!source.isEmpty()) {
way.put(AddressDialog.TAG_SOURCE, source);
}
}

DataSet ds = MainApplication.getLayerManager().getEditDataSet();
Collection<Command> cmds = new LinkedList<>();
List<Node> nodes = way.getNodes();
for (int i = 0; i < nodes.size() - 1; i++) {
cmds.add(new AddCommand(ds, nodes.get(i)));
////////// Tagging
if (taggingStyle.equals("none")) {
// Do nothing
} else if (taggingStyle.equals("presetSearchDialog")) {
if (getLayerManager().getActiveData() == null) {
JOptionPane.showMessageDialog(
MainApplication.getMap(),
tr("There is no active data layer, cannot show preset search dialog."),
tr("Area Selector"),
JOptionPane.WARNING_MESSAGE
);
return;
}
cmds.add(new AddCommand(ds, way));
UndoRedoHandler.getInstance().add(new SequenceCommand(/* I18n: Name of command */ tr("create building"), cmds));

if (replaceBuildings && existingWay != null) {
if (way.getBBox().bounds(existingWay.getBBox().getCenter())) {
log.info("existing way is inside of new building: "+existingWay.toString() + " is in " + way.toString());
UndoRedoHandler.getInstance().add(new SequenceCommand(tr("replace building"), replaceWay(existingWay, way)));
way = existingWay;
}
TaggingPresetSearchDialog.getInstance().showDialog();
} else if (taggingStyle.equals("specificPreset")) {
if (taggingPresetName.isEmpty()) {
JOptionPane.showMessageDialog(
MainApplication.getMap(),
tr("No preset name configured in the settings, enter one."),
tr("Area Selector"),
JOptionPane.WARNING_MESSAGE
);
return;
}

ds.setSelected(way);
// Find the configured preset
TaggingPreset taggingPresetToApply = null;
for (TaggingPreset taggingPreset : TaggingPresets.getTaggingPresets()) {
if (taggingPreset.getRawName().equals(taggingPresetName)) {
taggingPresetToApply = taggingPreset;
break;
}
}
if (taggingPresetToApply == null) {
JOptionPane.showMessageDialog(
MainApplication.getMap(),
tr("Could not find configured tagging preset: '{0}'.", taggingPresetName),
tr("Area Selector"),
JOptionPane.WARNING_MESSAGE
);
return;
}

if (mergeNodes) {
mergeNodes(way);
// Check that tagging preset can be applied to closed ways
if (!taggingPresetToApply.types.contains(TaggingPresetType.CLOSEDWAY)) {
JOptionPane.showMessageDialog(
MainApplication.getMap(),
tr("Selected preset is not suitable for a closed way, select another one: '{0}'.", taggingPresetName),
tr("Area Selector"),
JOptionPane.WARNING_MESSAGE
);
return;
}

if (useAustriaAdressHelper) {
Map<String, String> newAddress = fetchAddress(way);
if (newAddress != null) {
newWay = new Way(way);
newWay.setKeys(newAddress);
log.info("Found attributes: {}", newWay.getKeys());
if (!showAddressDialog) {
final List<Command> commands = new ArrayList<>();
commands.add(new ChangeCommand(way, newWay));
UndoRedoHandler.getInstance().add(
new SequenceCommand(trn("Add address", "Add addresses", commands.size()), commands));
}
if (applyPresetDirectly) {
// Directly apply the tags of the configured preset
Collection<Tag> tags = getTagsForPreset(taggingPresetToApply);
Collection<Command> commands = new ArrayList<>();
for (Tag tag : tags) {
commands.add(new ChangePropertyCommand(way, tag.getKey(), tag.getValue()));
}
}

if (commands.isEmpty()) {
JOptionPane.showMessageDialog(
MainApplication.getMap(),
tr("Tagging preset '{0}' does not have any tags to apply.", taggingPresetToApply.getRawName()),
tr("Area Selector"),
JOptionPane.WARNING_MESSAGE
);
return;
}

// Apply the command
Command cmd = SequenceCommand.wrapIfNeeded(tr("Apply tagging preset default values: {0}", taggingPresetToApply.getRawName()), commands);
UndoRedoHandler.getInstance().add(cmd);
} else {
// Show the dialog of the configured taggin preset
taggingPresetToApply.showAndApply(Collections.singleton(way));
}
} else if (taggingStyle.equals("address")) {
way.put(AddressDialog.TAG_BUILDING, new StringProperty(AddressDialog.PREF_BUILDING, "yes").get());
if (showAddressDialog) {
if (newWay == null) {
newWay = way;
}
new AddressDialog(newWay, way).showAndSave();
}
} else {
JOptionPane.showMessageDialog(MainApplication.getMap(), tr("Unable to detect a polygon where you clicked."),
tr("Area Selector"), JOptionPane.WARNING_MESSAGE);
JOptionPane.showMessageDialog(
MainApplication.getMap(),
tr("Unknown tagging style setting: '{0}'.", taggingStyle),
tr("Area Selector"),
JOptionPane.WARNING_MESSAGE
);
}
}

/**
* Get all tags that should be applied directly for a given TaggingPreset
*/
public Collection<Tag> getTagsForPreset(TaggingPreset taggingPreset) {
Collection<Tag> tags = new ArrayList<>();
for (TaggingPresetItem item : taggingPreset.data) {
// Determine key (used for most single-tag TaggingPresetItem's)
String key = null;
if (item instanceof KeyedItem) {
key = ((KeyedItem) item).key;
}

// Detect item type
if (item instanceof Text) {
addTag(tags, key, ((Text) item).default_);
} else if (item instanceof Key) {
addTag(tags, key, ((Key) item).value);
} else if (item instanceof Check) {
addTag(tags, key, ((Check) item).default_);
} else if (item instanceof CheckGroup) {
for (Check check : ((CheckGroup) item).checks) {
addTag(tags, check.key, check.default_);
}
} else if (item instanceof ComboMultiSelect) {
addTag(tags, key, ((ComboMultiSelect) item).default_);
}
// Ignore other TaggingPresetItem's: like spacing/links/etc.
}

return tags;
}

/**
* Add a Tag to a Collection only when the key/value have proper values
*/
private void addTag(Collection<Tag> tags, String key, String value) {
if (key == null || key.equals("") || value == null || value.equals("")) {
return;
}
tags.add(new Tag(key, value));
}

/**
* fetch Address using Austria Address Helper
*/
Expand Down Expand Up @@ -399,10 +549,6 @@ public Command mergeNode(Node node) {
return MergeNodesAction.mergeNodes(selectedNodes, targetNode, targetLocationNode);
}

/**
* @param prefs
* the prefs to set
*/
public void setPrefs() {
this.readPrefs();
}
Expand Down
Loading

0 comments on commit 2a5991d

Please sign in to comment.