// License: GPL. For details, see LICENSE file.
package indoor_sweepline;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import java.util.Vector;
import javax.swing.AbstractAction;
import javax.swing.DefaultCellEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
import org.openstreetmap.josm.Main;
public class IndoorSweeplineWizardDialog extends JDialog {
public IndoorSweeplineWizardDialog(IndoorSweeplineController controller) {
super(JOptionPane.getFrameForComponent(Main.parent), "Indoor Sweepline Wizard", false);
this.controller = controller;
beamIndex = 0;
prev = new PrevAction();
next = new NextAction();
GridbagPanel panel = new GridbagPanel();
panel.add(new JLabel(tr("Vertical layer:")), 0, 0, 3, 1);
panel.add(makeLevelField(), 3, 0, 1, 1);
panel.add(new JLabel(tr("Structure type:")), 0, 1, 3, 1);
panel.add(typeBox(), 3, 1, 1, 1);
panel.add(new JButton(prev), 0, 2, 1, 1);
panel.add(structureBox(), 1, 2, 1, 1);
panel.add(new JButton(next), 2, 2, 2, 1);
panel.add(makeWidthLabel(), 0, 3, 3, 1);
panel.add(makeWidthField(), 3, 3, 1, 1);
panel.add(makeStructureTable(), 0, 4, 4, 1);
add(panel);
pack();
refresh();
}
@Override
public void setVisible(boolean visible) {
if (visible)
setLocationRelativeTo(JOptionPane.getFrameForComponent(Main.parent));
super.setVisible(visible);
}
private void refresh() {
inRefresh = true;
leftRightCount = controller.leftRightCount();
prev.setEnabled(beamIndex > 0);
DefaultComboBoxModel<String> structureBoxModel = controller.structures();
structureBoxModel.setSelectedItem(structureBoxModel.getElementAt(beamIndex));
try {
if (beamIndex % 2 == 0) {
widthOffsetLabel.setText("Offset into background:");
stripWidth.setText(Double.toString(controller.getBeamOffset(beamIndex)));
} else {
widthOffsetLabel.setText("Strip width:");
stripWidth.setText(Double.toString(controller.getStripWidth(beamIndex)));
}
} catch (IllegalStateException ex) {
Main.trace(ex);
}
try {
level.setText(controller.getLevel());
} catch (IllegalStateException ex) {
Main.trace(ex);
}
typeBoxModel.setSelectedItem(structureTypeToString(controller.getType()));
structureTableModel.setRowCount(0);
if (beamIndex % 2 == 0) {
Vector<Object> row = new Vector<>();
row.addElement("");
row.addElement("");
row.addElement("");
structureTableModel.addRow(row);
List<CorridorPart> parts = controller.getBeamParts(beamIndex);
for (CorridorPart part : parts) {
row = new Vector<>();
row.addElement(Double.toString(part.width));
row.addElement(corridorPartTypeToString(part.getType()));
row.addElement(corridorPartSideToString(part.getSide()));
structureTableModel.addRow(row);
}
row = new Vector<>();
row.addElement("");
row.addElement("");
row.addElement("");
structureTableModel.addRow(row);
structureTableModel.isBeam = true;
} else {
Strip strip = controller.getStrip(beamIndex);
for (int i = 0; i < strip.lhs.size() || i < strip.rhs.size(); ++i) {
Vector<Object> row = new Vector<>();
String position = i < strip.lhs.size() ? strip.lhs.elementAt(i).toString() : "X";
position += " - " + (i < strip.rhs.size() ? strip.rhs.elementAt(i).toString() : "X");
row.addElement(position);
row.addElement(i < strip.parts.size() ?
corridorPartTypeToString(strip.parts.elementAt(i).getType()) : "wall");
row.addElement(i < strip.parts.size() ?
corridorPartSideToString(strip.parts.elementAt(i).getSide()) : "all");
structureTableModel.addRow(row);
}
structureTableModel.isBeam = false;
}
inRefresh = false;
}
private String corridorPartTypeToString(CorridorPart.Type type) {
if (type == CorridorPart.Type.VOID)
return "void";
else if (type == CorridorPart.Type.PASSAGE)
return "passage";
else if (type == CorridorPart.Type.WALL)
return "wall";
else if (type == CorridorPart.Type.STAIRS_UP)
return "stairs to upper level";
else if (type == CorridorPart.Type.STAIRS_DOWN)
return "stairs to lower level";
else if (type == CorridorPart.Type.ESCALATOR_UP_LEAVING)
return "escalator leaving to upper level";
else if (type == CorridorPart.Type.ESCALATOR_UP_ARRIVING)
return "escalator arriving from upper level";
else if (type == CorridorPart.Type.ESCALATOR_UP_BIDIRECTIONAL)
return "escalator (reversible) to upper level";
else if (type == CorridorPart.Type.ESCALATOR_DOWN_LEAVING)
return "escalator leaving to lower level";
else if (type == CorridorPart.Type.ESCALATOR_DOWN_ARRIVING)
return "escalator arriving from lower level";
else if (type == CorridorPart.Type.ESCALATOR_DOWN_BIDIRECTIONAL)
return "escalator (reversible) to lower level";
else if (type == CorridorPart.Type.ELEVATOR)
return "elevator";
return "";
}
private CorridorPart.Type parseCorridorPartType(String val) {
if (val == "void")
return CorridorPart.Type.VOID;
else if (val == "passage")
return CorridorPart.Type.PASSAGE;
else if (val == "wall")
return CorridorPart.Type.WALL;
else if (val == "stairs to upper level")
return CorridorPart.Type.STAIRS_UP;
else if (val == "stairs to lower level")
return CorridorPart.Type.STAIRS_DOWN;
else if (val == "escalator leaving to upper level")
return CorridorPart.Type.ESCALATOR_UP_LEAVING;
else if (val == "escalator arriving from upper level")
return CorridorPart.Type.ESCALATOR_UP_ARRIVING;
else if (val == "escalator (reversible) to upper level")
return CorridorPart.Type.ESCALATOR_UP_BIDIRECTIONAL;
else if (val == "escalator leaving to lower level")
return CorridorPart.Type.ESCALATOR_DOWN_LEAVING;
else if (val == "escalator arriving from lower level")
return CorridorPart.Type.ESCALATOR_DOWN_ARRIVING;
else if (val == "escalator (reversible) to lower level")
return CorridorPart.Type.ESCALATOR_DOWN_BIDIRECTIONAL;
else if (val == "elevator")
return CorridorPart.Type.ELEVATOR;
return CorridorPart.Type.VOID;
}
private String corridorPartSideToString(CorridorPart.ReachableSide side) {
if (side == CorridorPart.ReachableSide.ALL)
return "all";
else if (side == CorridorPart.ReachableSide.FRONT)
return "front";
else if (side == CorridorPart.ReachableSide.BACK)
return "back";
else if (side == CorridorPart.ReachableSide.LEFT)
return "left";
else if (side == CorridorPart.ReachableSide.RIGHT)
return "right";
return "";
}
private CorridorPart.ReachableSide parseCorridorPartSide(String val) {
if (val == "all")
return CorridorPart.ReachableSide.ALL;
else if (val == "front")
return CorridorPart.ReachableSide.FRONT;
else if (val == "back")
return CorridorPart.ReachableSide.BACK;
else if (val == "left")
return CorridorPart.ReachableSide.LEFT;
else if (val == "right")
return CorridorPart.ReachableSide.RIGHT;
return CorridorPart.ReachableSide.ALL;
}
private String structureTypeToString(IndoorSweeplineModel.Type type) {
if (type == IndoorSweeplineModel.Type.CORRIDOR)
return "corridor";
else if (type == IndoorSweeplineModel.Type.PLATFORM)
return "platform";
return "";
}
private JComboBox<String> structureBox() {
JComboBox<String> structureBox = new JComboBox<>(controller.structures());
structureBox.addActionListener(new StructureBoxListener());
return structureBox;
}
private IndoorSweeplineController controller;
private int beamIndex;
private int leftRightCount;
private PrevAction prev;
private NextAction next;
boolean inRefresh;
private JComboBox<String> typeBox() {
if (typeBoxModel == null) {
typeBoxModel = new DefaultComboBoxModel<>();
typeBoxModel.addElement("corridor");
typeBoxModel.addElement("platform");
}
JComboBox<String> typeBox = new JComboBox<>(typeBoxModel);
typeBox.addActionListener(new TypeBoxListener());
return typeBox;
}
private DefaultComboBoxModel<String> typeBoxModel;
private class TypeBoxListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
if (inRefresh)
return;
@SuppressWarnings("unchecked")
String entry = (String) ((JComboBox<String>) e.getSource()).getSelectedItem();
if (entry == "corridor")
controller.setType(IndoorSweeplineModel.Type.CORRIDOR);
else
controller.setType(IndoorSweeplineModel.Type.PLATFORM);
refresh();
}
}
private class PrevAction extends AbstractAction {
PrevAction() {
super("Prev");
}
@Override
public void actionPerformed(ActionEvent e) {
if (inRefresh)
return;
if (beamIndex > 0)
--beamIndex;
refresh();
}
}
private class NextAction extends AbstractAction {
NextAction() {
super("Next");
}
@Override
public void actionPerformed(ActionEvent e) {
if (inRefresh)
return;
++beamIndex;
if (beamIndex >= leftRightCount)
controller.addRightStructure();
refresh();
}
}
private class StructureBoxListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
if (inRefresh)
return;
@SuppressWarnings("unchecked")
String entry = (String) ((JComboBox<String>) e.getSource()).getSelectedItem();
DefaultComboBoxModel<String> structureBoxModel = controller.structures();
for (int i = 0; i < structureBoxModel.getSize(); ++i) {
if (structureBoxModel.getElementAt(i).equals(entry))
beamIndex = i;
}
refresh();
}
}
private JLabel widthOffsetLabel;
private JLabel makeWidthLabel() {
widthOffsetLabel = new JLabel(tr("Offset into background:"));
return widthOffsetLabel;
}
private JTextField stripWidth;
private JTextField makeWidthField() {
stripWidth = new JTextField(5);
stripWidth.getDocument().addDocumentListener(new StripWidthListener());
return stripWidth;
}
private class StripWidthListener implements DocumentListener {
@Override
public void changedUpdate(DocumentEvent e) {
update(e);
}
@Override
public void insertUpdate(DocumentEvent e) {
update(e);
}
@Override
public void removeUpdate(DocumentEvent e) {
update(e);
}
private void update(DocumentEvent e) {
if (inRefresh)
return;
try {
if (beamIndex % 2 == 0)
controller.setBeamOffset(beamIndex, Double.parseDouble(stripWidth.getText()));
else
controller.setStripWidth(beamIndex, Double.parseDouble(stripWidth.getText()));
} catch (NumberFormatException ex) {
Main.trace(ex);
}
refresh();
}
}
private JTextField level;
private JTextField makeLevelField() {
level = new JTextField(5);
level.getDocument().addDocumentListener(new LevelFieldListener());
return level;
}
private class LevelFieldListener implements DocumentListener {
@Override
public void changedUpdate(DocumentEvent e) {
update(e);
}
@Override
public void insertUpdate(DocumentEvent e) {
update(e);
}
@Override
public void removeUpdate(DocumentEvent e) {
update(e);
}
private void update(DocumentEvent e) {
if (inRefresh)
return;
controller.setLevel(level.getText());
refresh();
}
}
private class StructureTableModel extends DefaultTableModel {
@Override
public boolean isCellEditable(int row, int column) {
return isBeam || column == 1;
}
public boolean isBeam;
}
private StructureTableModel structureTableModel;
private JScrollPane makeStructureTable() {
structureTableModel = new StructureTableModel();
structureTableModel.addColumn("Width");
structureTableModel.addColumn("Type");
structureTableModel.addColumn("Reachable Side");
structureTableModel.addTableModelListener(new StructureTableListener());
JTable table = new JTable(structureTableModel);
TableColumn column = table.getColumnModel().getColumn(1);
JComboBox<String> comboBox = new JComboBox<>();
comboBox.addItem("void");
comboBox.addItem("passage");
comboBox.addItem("wall");
comboBox.addItem("stairs to upper level");
comboBox.addItem("stairs to lower level");
comboBox.addItem("escalator leaving to upper level");
comboBox.addItem("escalator arriving from upper level");
comboBox.addItem("escalator (reversible) to upper level");
comboBox.addItem("escalator leaving to lower level");
comboBox.addItem("escalator arriving from lower level");
comboBox.addItem("escalator (reversible) to lower level");
comboBox.addItem("elevator");
column.setCellEditor(new DefaultCellEditor(comboBox));
column = table.getColumnModel().getColumn(2);
comboBox = new JComboBox<>();
comboBox.addItem("all");
comboBox.addItem("left");
comboBox.addItem("right");
column.setCellEditor(new DefaultCellEditor(comboBox));
return new JScrollPane(table);
}
private class StructureTableListener implements TableModelListener {
@Override
public void tableChanged(TableModelEvent e) {
if (inRefresh)
return;
int column = e.getColumn();
int row = e.getFirstRow();
if (column == 0 && beamIndex % 2 == 0) {
try {
if (row == 0 || row == structureTableModel.getRowCount() - 1)
controller.addCorridorPart(beamIndex, row != 0,
Double.parseDouble(((TableModel) e.getSource()).getValueAt(row, column).toString()));
else
controller.setCorridorPartWidth(beamIndex, row - 1,
Double.parseDouble(((TableModel) e.getSource()).getValueAt(row, column).toString()));
} catch (NumberFormatException ex) {
Main.trace(ex);
}
} else if (column == 1 && beamIndex % 2 == 0) {
if (row > 0 && row < structureTableModel.getRowCount() - 1)
controller.setCorridorPartType(beamIndex, row - 1,
parseCorridorPartType(((TableModel) e.getSource()).getValueAt(row, column).toString()));
} else if (column == 1 && beamIndex % 2 == 1) {
controller.setCorridorPartType(beamIndex, row,
parseCorridorPartType(((TableModel) e.getSource()).getValueAt(row, column).toString()));
} else if (column == 2 && beamIndex % 2 == 0) {
if (row > 0 && row < structureTableModel.getRowCount() - 1)
controller.setCorridorPartSide(beamIndex, row - 1,
parseCorridorPartSide(((TableModel) e.getSource()).getValueAt(row, column).toString()));
}
refresh();
}
}
private class GridbagPanel extends JPanel {
GridbagPanel() {
gridbag = new GridBagLayout();
layoutCons = new GridBagConstraints();
setLayout(gridbag);
}
public void add(Component comp, int gridx, int gridy, int gridwidth, int gridheight) {
layoutCons.gridx = gridx;
layoutCons.gridy = gridy;
layoutCons.gridwidth = gridwidth;
layoutCons.gridheight = gridheight;
layoutCons.weightx = 0.0;
layoutCons.weighty = 0.0;
layoutCons.fill = GridBagConstraints.BOTH;
gridbag.setConstraints(comp, layoutCons);
add(comp);
}
private GridBagLayout gridbag;
private GridBagConstraints layoutCons;
}
}