// License: GPL. For details, see LICENSE file.
package public_transport;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.awt.event.ActionEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.text.DecimalFormat;
import java.text.Format;
import java.util.Iterator;
import java.util.Vector;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.DefaultListModel;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JTable;
import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.actions.JosmAction;
import org.openstreetmap.josm.data.coor.LatLon;
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.visitor.BoundingXYVisitor;
public class GTFSImporterAction extends JosmAction {
private static GTFSImporterDialog dialog = null;
private static DefaultListModel<?> tracksListModel = null;
private static Vector<String> data = null;
private static TrackReference currentTrack = null;
private static GTFSStopTableModel gtfsStopTM = null;
public boolean inEvent = false;
/**
* Constructs a new {@code GTFSImporterAction}.
*/
public GTFSImporterAction() {
super(tr("Create Stops from GTFS ..."), null, tr("Create Stops from a GTFS file"), null,
false);
putValue("toolbar", "publictransport/gtfsimporter");
Main.toolbar.register(this);
}
public GTFSStopTableModel getGTFSStopTableModel() {
return gtfsStopTM;
}
public GTFSImporterDialog getDialog() {
return dialog;
}
public DefaultListModel<?> getTracksListModel() {
if (tracksListModel == null)
tracksListModel = new DefaultListModel<>();
return tracksListModel;
}
public TrackReference getCurrentTrack() {
return currentTrack;
}
@Override
public void actionPerformed(ActionEvent event) {
if (dialog == null)
dialog = new GTFSImporterDialog(this);
dialog.setVisible(true);
if (tr("Create Stops from GTFS ...").equals(event.getActionCommand())) {
String curDir = Main.pref.get("lastDirectory");
if (curDir.isEmpty()) {
curDir = ".";
}
JFileChooser fc = new JFileChooser(new File(curDir));
fc.setDialogTitle(tr("Select GTFS file (stops.txt)"));
fc.setMultiSelectionEnabled(false);
int answer = fc.showOpenDialog(Main.parent);
if (answer != JFileChooser.APPROVE_OPTION)
return;
if (!fc.getCurrentDirectory().getAbsolutePath().equals(curDir))
Main.pref.put("lastDirectory", fc.getCurrentDirectory().getAbsolutePath());
importData(fc.getSelectedFile());
refreshData();
/* } else if ("stopImporter.settingsGPSTimeStart".equals(event.getActionCommand()))
{
if ((!inEvent) && (dialog.gpsTimeStartValid()) && (currentTrack != null))
Main.main.undoRedo.add(new TrackStoplistRelocateCommand(this));
}
else if ("stopImporter.settingsStopwatchStart".equals(event.getActionCommand()))
{
if ((!inEvent) && (dialog.stopwatchStartValid()) && (currentTrack != null))
Main.main.undoRedo.add(new TrackStoplistRelocateCommand(this));
}
else if ("stopImporter.settingsTimeWindow".equals(event.getActionCommand()))
{
if (currentTrack != null)
currentTrack.timeWindow = dialog.getTimeWindow();
}
else if ("stopImporter.settingsThreshold".equals(event.getActionCommand()))
{
if (currentTrack != null)
currentTrack.threshold = dialog.getThreshold();
}
else if ("stopImporter.settingsSuggestStops".equals(event.getActionCommand()))
Main.main.undoRedo.add(new TrackSuggestStopsCommand(this));
else if ("stopImporter.stoplistFind".equals(event.getActionCommand()))
findNodesInTable(dialog.getStoplistTable(), currentTrack.stoplistTM.getNodes());
else if ("stopImporter.stoplistShow".equals(event.getActionCommand()))
showNodesFromTable(dialog.getStoplistTable(), currentTrack.stoplistTM.getNodes());
else if ("stopImporter.stoplistMark".equals(event.getActionCommand()))
markNodesFromTable(dialog.getStoplistTable(), currentTrack.stoplistTM.getNodes());
else if ("stopImporter.stoplistDetach".equals(event.getActionCommand()))
{
Main.main.undoRedo.add(new TrackStoplistDetachCommand(this));
dialog.getStoplistTable().clearSelection();
*/
} else if ("gtfsImporter.gtfsStopsAdd".equals(event.getActionCommand()))
Main.main.undoRedo.add(new GTFSAddCommand(this));
else if ("gtfsImporter.gtfsStopsDelete".equals(event.getActionCommand()))
Main.main.undoRedo.add(new GTFSDeleteCommand(this));
else if ("gtfsImporter.gtfsStopsCatch".equals(event.getActionCommand()))
Main.main.undoRedo.add(new GTFSCatchCommand(this));
else if ("gtfsImporter.gtfsStopsJoin".equals(event.getActionCommand()))
Main.main.undoRedo.add(new GTFSJoinCommand(this));
else if ("gtfsImporter.gtfsStopsFind".equals(event.getActionCommand()))
findNodesInTable(dialog.getGTFSStopTable(), gtfsStopTM.nodes);
else if ("gtfsImporter.gtfsStopsShow".equals(event.getActionCommand()))
showNodesFromTable(dialog.getGTFSStopTable(), gtfsStopTM.nodes);
else if ("gtfsImporter.gtfsStopsMark".equals(event.getActionCommand()))
markNodesFromTable(dialog.getGTFSStopTable(), gtfsStopTM.nodes);
}
private void importData(final File file) {
try (BufferedReader r = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)) {
if (data == null)
data = new Vector<>();
else
data.clear();
while (r.ready()) {
data.add(r.readLine());
}
} catch (FileNotFoundException e) {
Main.error(e);
JOptionPane.showMessageDialog(null, tr("File \"{0}\" does not exist", file.getName()));
} catch (IOException e) {
Main.error(e);
JOptionPane.showMessageDialog(null, tr("IOException \"{0}\" occurred", e.toString()));
}
}
private void refreshData() {
if (data != null) {
Vector<Node> existingStops = new Vector<>();
DataSet ds = Main.getLayerManager().getEditDataSet();
if (ds == null) {
JOptionPane.showMessageDialog(null,
tr("There exists no dataset. Try to download data from the server or open an OSM file."),
tr("No data found"), JOptionPane.ERROR_MESSAGE);
return;
} else {
Iterator<Node> iter = ds.getNodes().iterator();
while (iter.hasNext()) {
Node node = iter.next();
if ("bus_stop".equals(node.get("highway")))
existingStops.add(node);
}
}
Iterator<String> iter = data.iterator();
if (iter.hasNext())
gtfsStopTM = new GTFSStopTableModel(this, iter.next());
else {
JOptionPane.showMessageDialog(null, tr("The GTFS file was empty."),
tr("No data found"), JOptionPane.ERROR_MESSAGE);
return;
}
while (iter.hasNext()) {
String s = iter.next();
gtfsStopTM.addRow(s, existingStops);
}
dialog.setGTFSStopTableModel(gtfsStopTM);
} else {
JOptionPane.showMessageDialog(null, tr("The GTFS file was empty."), tr("No data found"),
JOptionPane.ERROR_MESSAGE);
}
}
// public void tracksSelectionChanged(int selectedPos)
// {
// if (selectedPos >= 0)
// {
// currentTrack = ((TrackReference)tracksListModel.elementAt(selectedPos));
// dialog.setTrackValid(true);
//
// //Prepare Settings
// dialog.setSettings
// (currentTrack.gpsSyncTime, currentTrack.stopwatchStart,
// currentTrack.timeWindow, currentTrack.threshold);
//
// //Prepare Stoplist
// dialog.setStoplistTableModel
// (((TrackReference)tracksListModel.elementAt(selectedPos)).stoplistTM);
// }
// else
// {
// currentTrack = null;
// dialog.setTrackValid(false);
// }
// }
public static Node createNode(LatLon latLon, String id, String name) {
Node node = new Node(latLon);
node.put("highway", "bus_stop");
node.put("stop_id", id);
node.put("name", name);
DataSet ds = Main.getLayerManager().getEditDataSet();
if (ds == null) {
JOptionPane.showMessageDialog(null,
tr("There exists no dataset."
+ " Try to download data from the server or open an OSM file."),
tr("No data found"), JOptionPane.ERROR_MESSAGE);
return null;
}
ds.addPrimitive(node);
return node;
}
/**
* returns a collection of all selected lines or a collection of all lines otherwise
*/
public static Vector<Integer> getConsideredLines(JTable table) {
int[] selectedLines = table.getSelectedRows();
Vector<Integer> consideredLines = new Vector<>();
if (selectedLines.length > 0) {
for (int i = 0; i < selectedLines.length; ++i) {
consideredLines.add(selectedLines[i]);
}
} else {
for (int i = 0; i < table.getRowCount(); ++i) {
consideredLines.add(Integer.valueOf(i));
}
}
return consideredLines;
}
/** marks the table items whose nodes are marked on the map */
public static void findNodesInTable(JTable table, Vector<Node> nodes) {
DataSet ds = Main.getLayerManager().getEditDataSet();
if (ds == null)
return;
table.clearSelection();
for (int i = 0; i < table.getRowCount(); ++i) {
if ((nodes.elementAt(i) != null) && (ds.isSelected(nodes.elementAt(i))))
table.addRowSelectionInterval(i, i);
}
}
/**
* shows the nodes that correspond to the marked lines in the table.
* If no lines are marked in the table, show all nodes from the vector
*/
public static void showNodesFromTable(JTable table, Vector<Node> nodes) {
BoundingXYVisitor box = new BoundingXYVisitor();
Vector<Integer> consideredLines = getConsideredLines(table);
for (int i = 0; i < consideredLines.size(); ++i) {
int j = consideredLines.elementAt(i);
if (nodes.elementAt(j) != null)
nodes.elementAt(j).accept(box);
}
if (box.getBounds() == null)
return;
box.enlargeBoundingBox();
Main.map.mapView.zoomTo(box);
}
/**
* marks the nodes that correspond to the marked lines in the table.
* If no lines are marked in the table, mark all nodes from the vector
*/
public static void markNodesFromTable(JTable table, Vector<Node> nodes) {
OsmPrimitive[] osmp = {null};
DataSet ds = Main.getLayerManager().getEditDataSet();
ds.setSelected(osmp);
Vector<Integer> consideredLines = getConsideredLines(table);
for (int i = 0; i < consideredLines.size(); ++i) {
int j = consideredLines.elementAt(i);
if (nodes.elementAt(j) != null)
ds.addSelected(nodes.elementAt(j));
}
}
public static String timeOf(double t) {
t -= Math.floor(t / 24 / 60 / 60) * 24 * 60 * 60;
int hour = (int) Math.floor(t / 60 / 60);
t -= Math.floor(t / 60 / 60) * 60 * 60;
int minute = (int) Math.floor(t / 60);
t -= Math.floor(t / 60) * 60;
double second = t;
Format format = new DecimalFormat("00");
Format formatS = new DecimalFormat("00.###");
return format.format(hour) + ":" + format.format(minute) + ":" + formatS.format(second);
}
public Action getFocusAddAction() {
return new FocusAddAction();
}
private class FocusAddAction extends AbstractAction {
@Override
public void actionPerformed(ActionEvent e) {
Main.main.undoRedo.add(new GTFSAddCommand(GTFSImporterAction.this));
showNodesFromTable(dialog.getGTFSStopTable(), gtfsStopTM.nodes);
}
}
/* public Action getFocusWaypointShelterAction(String shelter)
{
return new FocusWaypointShelterAction(shelter);
}
public Action getFocusWaypointDeleteAction()
{
return new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
JTable table = dialog.getWaypointsTable();
int row = table.getEditingRow();
if (row < 0)
return;
table.clearSelection();
table.addRowSelectionInterval(row, row);
/* Main.main.undoRedo.add
(new WaypointsDisableCommand(GTFSImporterAction.this));*
}
};
}
public Action getFocusTrackStoplistNameAction()
{
return new FocusTrackStoplistNameAction();
}
public Action getFocusTrackStoplistShelterAction(String shelter)
{
return new FocusTrackStoplistShelterAction(shelter);
}
public Action getFocusStoplistDeleteAction()
{
return new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
JTable table = dialog.getStoplistTable();
int row = table.getEditingRow();
if (row < 0)
return;
table.clearSelection();
table.addRowSelectionInterval(row, row);
/* Main.main.undoRedo.add
(new TrackStoplistDeleteCommand(GTFSImporterAction.this));*
}
};
}
private class FocusWaypointNameAction extends AbstractAction
{
public void actionPerformed(ActionEvent e)
{
JTable table = dialog.getWaypointsTable();
showNodesFromTable(table, waypointTM.nodes);
markNodesFromTable(table, waypointTM.nodes);
int row = table.getEditingRow();
if (row < 0)
row = 0;
waypointTM.inEvent = true;
if (table.getCellEditor() != null)
{
if (!table.getCellEditor().stopCellEditing())
table.getCellEditor().cancelCellEditing();
}
table.editCellAt(row, 1);
table.getCellEditor().getTableCellEditorComponent
(table, "", true, row, 1);
waypointTM.inEvent = false;
}
};
private class FocusWaypointShelterAction extends AbstractAction
{
private String defaultShelter = null;
public FocusWaypointShelterAction(String defaultShelter)
{
this.defaultShelter = defaultShelter;
}
public void actionPerformed(ActionEvent e)
{
JTable table = dialog.getWaypointsTable();
showNodesFromTable(table, waypointTM.nodes);
markNodesFromTable(table, waypointTM.nodes);
int row = table.getEditingRow();
if (row < 0)
row = 0;
waypointTM.inEvent = true;
if (table.getCellEditor() != null)
{
if (!table.getCellEditor().stopCellEditing())
table.getCellEditor().cancelCellEditing();
}
table.editCellAt(row, 2);
waypointTM.inEvent = false;
table.getCellEditor().getTableCellEditorComponent
(table, defaultShelter, true, row, 2);
}
};
private class FocusTrackStoplistNameAction extends AbstractAction
{
public void actionPerformed(ActionEvent e)
{
JTable table = dialog.getStoplistTable();
showNodesFromTable(table, currentTrack.stoplistTM.getNodes());
markNodesFromTable(table, currentTrack.stoplistTM.getNodes());
int row = table.getEditingRow();
if (row < 0)
row = 0;
currentTrack.inEvent = true;
if (table.getCellEditor() != null)
{
if (!table.getCellEditor().stopCellEditing())
table.getCellEditor().cancelCellEditing();
}
table.editCellAt(row, 1);
table.getCellEditor().getTableCellEditorComponent
(table, "", true, row, 1);
currentTrack.inEvent = false;
}
};
private class FocusTrackStoplistShelterAction extends AbstractAction
{
private String defaultShelter = null;
public FocusTrackStoplistShelterAction(String defaultShelter)
{
this.defaultShelter = defaultShelter;
}
public void actionPerformed(ActionEvent e)
{
JTable table = dialog.getStoplistTable();
showNodesFromTable(table, currentTrack.stoplistTM.getNodes());
markNodesFromTable(table, currentTrack.stoplistTM.getNodes());
int row = table.getEditingRow();
if (row < 0)
row = 0;
currentTrack.inEvent = true;
if (table.getCellEditor() != null)
{
if (!table.getCellEditor().stopCellEditing())
table.getCellEditor().cancelCellEditing();
}
table.editCellAt(row, 2);
currentTrack.inEvent = false;
table.getCellEditor().getTableCellEditorComponent
(table, defaultShelter, true, row, 2);
}
};*/
}