package org.openstreetmap.josm.plugins.pt_assistant.actions;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.awt.Cursor;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.actions.JoinNodeWayAction;
import org.openstreetmap.josm.actions.SplitWayAction;
import org.openstreetmap.josm.actions.mapmode.MapMode;
import org.openstreetmap.josm.command.AddCommand;
import org.openstreetmap.josm.command.ChangeCommand;
import org.openstreetmap.josm.data.osm.DataSet;
import org.openstreetmap.josm.data.osm.Node;
import org.openstreetmap.josm.data.osm.OsmPrimitive;
import org.openstreetmap.josm.data.osm.WaySegment;
import org.openstreetmap.josm.gui.MapFrame;
import org.openstreetmap.josm.tools.ImageProvider;
import org.openstreetmap.josm.tools.Shortcut;
/*
* The AddStopPositionAction is a mapmode that allows users to add
* new stop_positions or to convert already existing nodes.
*/
@SuppressWarnings("serial")
public class AddStopPositionAction extends MapMode {
private transient Set<OsmPrimitive> newHighlights = new HashSet<>();
private transient Set<OsmPrimitive> oldHighlights = new HashSet<>();
private final Cursor cursorJoinNode;
private final Cursor cursorJoinWay;
public AddStopPositionAction(MapFrame mapFrame) {
super(tr("Add stop position"),
"bus",
tr("Add stop position"),
Shortcut.registerShortcut("mapmode:stop_position",
tr("Mode: {0}", tr("Add stop position")),
KeyEvent.VK_T, Shortcut.DIRECT),
mapFrame,
getCursor());
cursorJoinNode = ImageProvider.getCursor("crosshair", "joinnode");
cursorJoinWay = ImageProvider.getCursor("crosshair", "joinway");
}
private static Cursor getCursor() {
try {
return ImageProvider.getCursor("crosshair", "bus");
} catch (Exception e) {
Main.error(e);
}
return Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
}
@Override
public void enterMode() {
super.enterMode();
Main.map.mapView.addMouseListener(this);
Main.map.mapView.addMouseMotionListener(this);
}
@Override
public void exitMode() {
super.exitMode();
Main.map.mapView.removeMouseListener(this);
Main.map.mapView.removeMouseMotionListener(this);
}
@Override
public void mouseMoved (MouseEvent e) {
//while the mouse is moving, surroundings are checked
//if anything is found, it will be highlighted.
//priority is given to nodes
Cursor newCurs = getCursor();
Node n = Main.map.mapView.getNearestNode(e.getPoint(), OsmPrimitive::isUsable);
if(n != null) {
newHighlights.add(n);
newCurs = cursorJoinNode;
} else {
List<WaySegment> wss =
Main.map.mapView.getNearestWaySegments(e.getPoint(), OsmPrimitive::isSelectable);
if(wss.size() > 0) {
for(WaySegment ws : wss) {
newHighlights.add(ws.way);
}
newCurs = cursorJoinWay;
}
}
Main.map.mapView.setCursor(newCurs);
updateHighlights();
}
@Override
public void mouseClicked (MouseEvent e) {
Boolean newNode = false;
Node newStopPos;
//check if the user as selected an existing node, or a new one
Node n = Main.map.mapView.getNearestNode(e.getPoint(), OsmPrimitive::isUsable);
if (n == null) {
newNode = true;
newStopPos = new Node(Main.map.mapView.getLatLon(e.getX(), e.getY()));
} else {
newStopPos = new Node(n);
clearNodeTags(newStopPos);
}
//add the tags of the stop position
newStopPos.put("bus", "yes");
newStopPos.put("public_transport", "stop_position");
if(newNode) {
Main.main.undoRedo.add(new AddCommand(newStopPos));
} else {
Main.main.undoRedo.add(new ChangeCommand(n, newStopPos));
}
DataSet ds = Main.getLayerManager().getEditLayer().data;
ds.setSelected(newStopPos);
//join the node to the way only if the node is new
if(newNode) {
JoinNodeWayAction joinNodeWayAction = JoinNodeWayAction.createJoinNodeToWayAction();
joinNodeWayAction.actionPerformed(null);
}
// split the way in any case
SplitWayAction splitWayAction = new SplitWayAction();
splitWayAction.actionPerformed(null);
}
private void clearNodeTags(Node newStopPos) {
for(String key : newStopPos.keySet()) {
newStopPos.put(key, null);
}
}
//turn off what has been highlighted on last mouse move and highlight what has to be highlighted now
private void updateHighlights()
{
if(oldHighlights.size() > 0 || newHighlights.size() > 0) {
for(OsmPrimitive osm : oldHighlights) {
osm.setHighlighted(false);
}
for(OsmPrimitive osm : newHighlights) {
osm.setHighlighted(true);
}
Main.getLayerManager().getEditLayer().invalidate();
oldHighlights.clear();
oldHighlights.addAll(newHighlights);
newHighlights.clear();
}
}
}