Skip to content

Commit 468d79b

Browse files
committed
Automatically open routing helper when selecting a route relation, make forward/backward navigation work and show connectivity (very primitive check)
1 parent 610fbc3 commit 468d79b

8 files changed

Lines changed: 363 additions & 83 deletions

File tree

src/main/java/org/openstreetmap/josm/plugins/pt_assistant/PTAssistantPlugin.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.openstreetmap.josm.plugins.pt_assistant.actions.SortPTRouteMembersAction;
4040
import org.openstreetmap.josm.plugins.pt_assistant.actions.SortPTRouteMembersMenuBar;
4141
import org.openstreetmap.josm.plugins.pt_assistant.actions.SplitRoundaboutAction;
42+
import org.openstreetmap.josm.plugins.pt_assistant.actions.routinghelper.RoutingHelperAction;
4243
import org.openstreetmap.josm.plugins.pt_assistant.data.PTRouteSegment;
4344
import org.openstreetmap.josm.plugins.pt_assistant.gui.PTAssistantLayerManager;
4445
import org.openstreetmap.josm.plugins.pt_assistant.validation.BicycleFootRouteValidatorTest;
@@ -79,6 +80,7 @@ public PTAssistantPlugin(PluginInformation info) {
7980
.addMenu("File", trc("menu", "Public Transport"), KeyEvent.VK_P, 5, ht("/Menu/Public Transport"));
8081
addToMenu(PublicTransportMenu);
8182

83+
SelectionEventManager.getInstance().addSelectionListener(new RoutingHelperAction());
8284
SelectionEventManager.getInstance().addSelectionListener(PTAssistantLayerManager.PTLM);
8385
KeyboardFocusManager.getCurrentKeyboardFocusManager().addPropertyChangeListener(PTAssistantLayerManager.PTLM);
8486
initialiseWizard();
Lines changed: 131 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,174 @@
11
package org.openstreetmap.josm.plugins.pt_assistant.actions.routinghelper;
22

3-
import java.awt.event.ActionEvent;
43
import java.util.Collections;
5-
import java.util.Objects;
4+
import java.util.List;
65
import java.util.Optional;
76
import java.util.Set;
7+
import java.util.concurrent.CancellationException;
8+
import java.util.concurrent.ExecutionException;
9+
import java.util.concurrent.Future;
10+
import java.util.stream.Collectors;
811

912
import javax.swing.JOptionPane;
1013

1114
import com.drew.lang.annotations.NotNull;
12-
import com.drew.lang.annotations.Nullable;
15+
import org.openstreetmap.josm.data.osm.AbstractPrimitive;
16+
import org.openstreetmap.josm.data.osm.DataSelectionListener;
1317
import org.openstreetmap.josm.data.osm.Relation;
14-
import org.openstreetmap.josm.data.osm.Way;
18+
import org.openstreetmap.josm.data.osm.RelationMember;
1519
import org.openstreetmap.josm.gui.MainApplication;
1620
import org.openstreetmap.josm.gui.MapFrame;
17-
import org.openstreetmap.josm.gui.dialogs.relation.actions.AbstractRelationEditorAction;
18-
import org.openstreetmap.josm.gui.dialogs.relation.actions.IRelationEditorActionAccess;
19-
import org.openstreetmap.josm.gui.dialogs.relation.actions.IRelationEditorUpdateOn;
20-
import org.openstreetmap.josm.plugins.pt_assistant.utils.BoundsUtils;
21+
import org.openstreetmap.josm.gui.Notification;
22+
import org.openstreetmap.josm.gui.dialogs.relation.DownloadRelationMemberTask;
23+
import org.openstreetmap.josm.plugins.pt_assistant.utils.DialogUtils;
24+
import org.openstreetmap.josm.plugins.pt_assistant.utils.RouteUtils;
25+
import org.openstreetmap.josm.plugins.pt_assistant.utils.WayUtils;
2126
import org.openstreetmap.josm.tools.I18n;
22-
import org.openstreetmap.josm.tools.ImageProvider;
2327

24-
public class RoutingHelperAction extends AbstractRelationEditorAction {
28+
public class RoutingHelperAction implements DataSelectionListener {
2529
private static final Set<ITransportMode> TRANSPORT_MODES = Collections.singleton(new BusTransportMode());
2630

2731
private Optional<ITransportMode> activeTransportMode;
2832

2933
private final RoutingHelperPanel routingHelperPanel = new RoutingHelperPanel(this);
3034

31-
public RoutingHelperAction(IRelationEditorActionAccess editorAccess) {
32-
super(editorAccess, IRelationEditorUpdateOn.TAG_CHANGE);
33-
new ImageProvider("dialogs/relation", "routing_assistance.svg").getResource().attachImageIcon(this, true);
34-
putValue(SHORT_DESCRIPTION, I18n.tr("Routing helper"));
35-
}
35+
@NotNull
36+
private Optional<Relation> currentRelation = Optional.empty();
37+
38+
private Optional<RelationMember> currentMember = Optional.empty();
3639

3740
@Override
38-
protected void updateEnabledState() {
39-
final Relation currentRelation = getEditor().getRelation();
40-
final Optional<ITransportMode> newActiveTransportMode = TRANSPORT_MODES.stream()
41-
.filter(mode -> mode.canBeUsedForRelation(currentRelation))
42-
.findFirst();
43-
this.activeTransportMode = newActiveTransportMode;
44-
setEnabled(newActiveTransportMode.isPresent() && MainApplication.getMap().getTopPanel(RoutingHelperPanel.class) == null);
41+
public void selectionChanged(SelectionChangeEvent event) {
42+
final MapFrame mapframe = MainApplication.getMap();
43+
if (mapframe != null) {
44+
final Optional<Relation> singleRelationSelection = Optional.of(event.getSelection())
45+
.filter(selection -> selection.size() == 1)
46+
.map(selection -> selection.iterator().next())
47+
.map(selectedPrimitive -> selectedPrimitive instanceof Relation ? (Relation) selectedPrimitive : null)
48+
.filter(RouteUtils::isRoute);
49+
this.currentRelation = singleRelationSelection;
50+
if (singleRelationSelection.isPresent()) {
51+
routingHelperPanel.onRelationChange(singleRelationSelection.get());
52+
if (mapframe.getTopPanel(RoutingHelperPanel.class) == null) {
53+
mapframe.addTopPanel(routingHelperPanel);
54+
}
55+
} else {
56+
mapframe.removeTopPanel(RoutingHelperPanel.class);
57+
}
58+
}
4559
}
4660

47-
@Override
48-
public void actionPerformed(@NotNull final ActionEvent actionEvent) {
49-
final MapFrame mapFrame = MainApplication.getMap();
61+
public void goToFirstWay() {
62+
final Optional<Relation> currentRelation = this.currentRelation;
63+
final long missingMembersCount = currentRelation
64+
.map(it ->
65+
it.getMembers().stream()
66+
.filter(member -> member.getMember().isIncomplete())
67+
.count()
68+
)
69+
.orElse(0L);
70+
if (missingMembersCount > 0) {
71+
if (
72+
DialogUtils.showYesNoQuestion(
73+
routingHelperPanel,
74+
I18n.tr("Relation is incomplete"),
75+
I18n.trn(
76+
"The relations has {0} missing member. Would you like to download the missing member now?",
77+
"The relations has {0} missing members. Would you like to download the missing members now?",
78+
missingMembersCount,
79+
missingMembersCount
80+
)
81+
)
82+
) {
83+
final Future<?> f = MainApplication.worker.submit(new DownloadRelationMemberTask(
84+
currentRelation.get(),
85+
currentRelation.get().getMembers().stream()
86+
.map(RelationMember::getMember)
87+
.filter(AbstractPrimitive::isIncomplete)
88+
.collect(Collectors.toSet()),
89+
MainApplication.getLayerManager().getActiveDataLayer()
90+
));
91+
new Thread(() -> {
92+
try {
93+
f.get();
5094

51-
if (mapFrame.getTopPanel(RoutingHelperPanel.class) == null) {
52-
mapFrame.addTopPanel(routingHelperPanel);
53-
updateEnabledState();
54-
}
95+
// try again, now the missingMembersCount should be 0, so we should go to the else-branch this time
96+
goToFirstWay();
97+
} catch (CancellationException | InterruptedException | ExecutionException e) {
98+
JOptionPane.showMessageDialog(
99+
routingHelperPanel,
100+
I18n.tr("The download of missing members has failed!"),
101+
I18n.tr("Download failed"),
102+
JOptionPane.ERROR_MESSAGE
103+
);
104+
}
55105

56-
final Way currentWay = editorAccess.getEditor().getRelation().getMembers().stream().map(it -> it.isWay() ? it.getWay() : null).filter(Objects::nonNull).findFirst().orElse(null);
57-
if (currentWay != null) {
58-
MainApplication.getMap().mapView.zoomTo(BoundsUtils.fromBBox(currentWay.getBBox()));
106+
}).start();
107+
}
108+
} else {
109+
final List<RelationMember> wayMembers = currentRelation.map(relation -> relation.getMembers().stream().filter(RouteUtils::isRouteWayMember).collect(Collectors.toList())).orElse(Collections.emptyList());
110+
this.currentMember = wayMembers.stream().findFirst();
111+
if (wayMembers.isEmpty()) {
112+
JOptionPane.showMessageDialog(routingHelperPanel, "No way found to traverse", "Could not find a way to traverse", JOptionPane.ERROR_MESSAGE);
113+
} else {
114+
routingHelperPanel.onCurrentWayChange(
115+
currentRelation.get(),
116+
wayMembers.get(0),
117+
RoutingHelperPanel.ConnectionType.END,
118+
wayMembers.size() == 1
119+
? RoutingHelperPanel.ConnectionType.END
120+
: (
121+
WayUtils.isTouchingOtherWay(wayMembers.get(0).getWay(), wayMembers.get(1).getWay())
122+
? RoutingHelperPanel.ConnectionType.CONNECTED
123+
: RoutingHelperPanel.ConnectionType.NOT_CONNECTED
124+
)
125+
);
126+
}
59127
}
60-
routingHelperPanel.onCurrentWayChange(currentWay);
61128
}
62129

63130
public void goToPreviousGap() {
64131
JOptionPane.showMessageDialog(routingHelperPanel, "Not implemented yet", "Not implemented", JOptionPane.ERROR_MESSAGE);
65132
}
66133

67134
public void goToPreviousWay() {
68-
JOptionPane.showMessageDialog(routingHelperPanel, "Not implemented yet", "Not implemented", JOptionPane.ERROR_MESSAGE);
135+
goNWaysForward(-1);
69136
}
70137

71138
public void goToNextWay() {
72-
JOptionPane.showMessageDialog(routingHelperPanel, "Not implemented yet", "Not implemented", JOptionPane.ERROR_MESSAGE);
139+
goNWaysForward(1);
140+
}
141+
142+
private void goNWaysForward(final int n) {
143+
currentRelation.ifPresent(relation ->
144+
currentMember.ifPresent(member -> {
145+
final List<RelationMember> wayMembers = relation.getMembers().stream().filter(RouteUtils::isRouteWayMember).collect(Collectors.toList());
146+
final int targetIndex = wayMembers.indexOf(member) + n;
147+
if (targetIndex < 0 || targetIndex >= wayMembers.size() - 1) {
148+
new Notification(I18n.tr("You reached the end of the route")).setIcon(JOptionPane.INFORMATION_MESSAGE).setDuration(Notification.TIME_SHORT).show();
149+
} else {
150+
currentMember = Optional.of(wayMembers.get(targetIndex));
151+
routingHelperPanel.onCurrentWayChange(
152+
relation,
153+
wayMembers.get(targetIndex),
154+
targetIndex <= 0 ? RoutingHelperPanel.ConnectionType.END : (
155+
WayUtils.isTouchingOtherWay(wayMembers.get(targetIndex).getWay(), wayMembers.get(targetIndex - 1).getWay())
156+
? RoutingHelperPanel.ConnectionType.CONNECTED
157+
: RoutingHelperPanel.ConnectionType.NOT_CONNECTED
158+
),
159+
targetIndex >= wayMembers.size() - 1 ? RoutingHelperPanel.ConnectionType.END : (
160+
WayUtils.isTouchingOtherWay(wayMembers.get(targetIndex).getWay(), wayMembers.get(targetIndex + 1).getWay())
161+
? RoutingHelperPanel.ConnectionType.CONNECTED
162+
: RoutingHelperPanel.ConnectionType.NOT_CONNECTED
163+
)
164+
);
165+
}
166+
})
167+
);
73168
}
74169

75170
public void goToNextGap() {
76171
JOptionPane.showMessageDialog(routingHelperPanel, "Not implemented yet", "Not implemented", JOptionPane.ERROR_MESSAGE);
77172
}
173+
78174
}

0 commit comments

Comments
 (0)