package maps.gml.view; import java.awt.BorderLayout; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableModel; import maps.gml.GMLDirectedEdge; import maps.gml.GMLEdge; import maps.gml.GMLMap; import maps.gml.GMLNode; import maps.gml.GMLObject; import maps.gml.GMLShape; import maps.validate.ValidationError; /** A class for inspecting GML objects. */ public class GMLObjectInspector extends JPanel { private static final int NODE_ROW_ID = 0; private static final int NODE_ROW_X = 1; private static final int NODE_ROW_Y = 2; private static final int NODE_ROW_ATTACHED_EDGES = 3; private static final int NODE_ROWS = 4; private static final int EDGE_ROW_ID = 0; private static final int EDGE_ROW_START = 1; private static final int EDGE_ROW_END = 2; private static final int EDGE_ROW_PASSABLE = 3; private static final int EDGE_ROW_ATTACHED_SHAPES = 4; private static final int EDGE_ROWS = 5; private static final int SHAPE_ROW_ID = 0; private static final int SHAPE_ROW_EDGE_COUNT = 1; private static final int SHAPE_BASE_ROWS = 2; private static final TableModel EMPTY_MODEL = new AbstractTableModel() { @Override public int getRowCount() { return 0; } @Override public int getColumnCount() { return 0; } @Override public Object getValueAt(int row, int col) { return null; } }; private GMLMap map; private JTable table; private NodeTableModel nodeModel; private EdgeTableModel edgeModel; private ShapeTableModel shapeModel; private Map<Integer, List<ValidationError>> errors; /** Construct a new GMLObjectInspector. @param map The GMLMap to consult for geometry information. */ public GMLObjectInspector(GMLMap map) { super(new BorderLayout()); this.map = map; errors = new HashMap<Integer, List<ValidationError>>(); nodeModel = new NodeTableModel(); edgeModel = new EdgeTableModel(); shapeModel = new ShapeTableModel(); table = new JTable(); JScrollPane scroll = new JScrollPane(table); add(scroll, BorderLayout.CENTER); } /** Set the map this inspector should consult for geometry information. @param newMap The new map. */ public void setMap(GMLMap newMap) { map = newMap; } /** Inspect a GMLNode. @param node The node to inspect. */ public void inspect(GMLNode node) { table.setModel(nodeModel); List<ValidationError> e = (node == null) ? null : errors.get(node.getID()); nodeModel.show(node, e); } /** Inspect a GMLEdge. @param edge The edge to inspect. */ public void inspect(GMLEdge edge) { table.setModel(edgeModel); List<ValidationError> e = (edge == null) ? null : errors.get(edge.getID()); edgeModel.show(edge, e); } /** Inspect a GMLShape. @param shape The shape to inspect. */ public void inspect(GMLShape shape) { table.setModel(shapeModel); List<ValidationError> e = (shape == null) ? null : errors.get(shape.getID()); shapeModel.show(shape, e); } /** Inspect a GMLObject. @param object The object to inspect. */ public void inspect(GMLObject object) { if (object == null) { table.setModel(EMPTY_MODEL); } else if (object instanceof GMLNode) { inspect((GMLNode)object); } else if (object instanceof GMLEdge) { inspect((GMLEdge)object); } else if (object instanceof GMLShape) { inspect((GMLShape)object); } else { throw new IllegalArgumentException("Don't know how to inspect " + object); } } /** * Set the Collection of ValidationErrors for the Inspector to display in the table. * @param err The collection of errors. */ public void setErrors(Collection<ValidationError> err) { errors.clear(); for (ValidationError e : err) { if (!errors.containsKey(e.getId())) { errors.put(e.getId(), new ArrayList<ValidationError>()); } errors.get(e.getId()).add(e); } } private class NodeTableModel extends AbstractTableModel { private GMLNode node; private List<ValidationError> errors; void show(GMLNode n, List<ValidationError> err) { node = n; errors = err; fireTableDataChanged(); } @Override public int getRowCount() { int errorCount = (errors == null) ? 0 : errors.size(); return NODE_ROWS + errorCount; } @Override public int getColumnCount() { return 2; } @Override public Object getValueAt(int row, int col) { if (col == 0) { switch (row) { case NODE_ROW_ID: return "Node ID"; case NODE_ROW_X: return "X"; case NODE_ROW_Y: return "Y"; case NODE_ROW_ATTACHED_EDGES: return "Attached edges"; default: return "Error"; } } else if (col == 1) { if (node == null) { return null; } switch (row) { case NODE_ROW_ID: return node.getID(); case NODE_ROW_X: return node.getX(); case NODE_ROW_Y: return node.getY(); case NODE_ROW_ATTACHED_EDGES: if (map == null) { return ""; } Collection<GMLEdge> attached = map.getAttachedEdges(node); StringBuilder result = new StringBuilder(); for (GMLEdge next : attached) { result.append(next.toString()); result.append(" "); } return result.toString(); default: int errorCount = (errors == null) ? 0 : errors.size(); int index = row - NODE_ROWS; if (index < 0 || index >= errorCount) { throw new IllegalArgumentException("Invalid row: " + row); } return errors.get(index).getMessage(); } } else { throw new IllegalArgumentException("Unrecognised column: " + col); } } } private class EdgeTableModel extends AbstractTableModel { private GMLEdge edge; private List<ValidationError> errors; void show(GMLEdge e, List<ValidationError> err) { edge = e; errors = err; fireTableDataChanged(); } @Override public int getRowCount() { int errorCount = (errors == null) ? 0 : errors.size(); return EDGE_ROWS + errorCount; } @Override public int getColumnCount() { return 2; } @Override public Object getValueAt(int row, int col) { if (col == 0) { switch (row) { case EDGE_ROW_ID: return "Edge ID"; case EDGE_ROW_START: return "Start node"; case EDGE_ROW_END: return "End node"; case EDGE_ROW_PASSABLE: return "Passable"; case EDGE_ROW_ATTACHED_SHAPES: return "Attached shapes"; default: return "Error"; } } else if (col == 1) { if (edge == null) { return null; } switch (row) { case EDGE_ROW_ID: return edge.getID(); case EDGE_ROW_START: return edge.getStart().getID(); case EDGE_ROW_END: return edge.getEnd().getID(); case EDGE_ROW_PASSABLE: return edge.isPassable(); case EDGE_ROW_ATTACHED_SHAPES: if (map == null) { return ""; } Collection<GMLShape> attached = map.getAttachedShapes(edge); StringBuilder result = new StringBuilder(); for (GMLShape next : attached) { result.append(next.toString()); result.append(" "); } return result.toString(); default: int errorCount = (errors == null) ? 0 : errors.size(); int index = row - EDGE_ROWS; if (index < 0 || index >= errorCount) { throw new IllegalArgumentException("Invalid row: " + row); } return errors.get(index).getMessage(); } } else { throw new IllegalArgumentException("Unrecognised column: " + col); } } } private static class ShapeTableModel extends AbstractTableModel { private GMLShape shape; private List<ValidationError> errors; void show(GMLShape s, List<ValidationError> err) { shape = s; errors = err; fireTableDataChanged(); } @Override public int getRowCount() { int edgeCount = (shape == null) ? 0 : shape.getEdges().size(); int errorCount = (errors == null) ? 0 : errors.size(); return SHAPE_BASE_ROWS + edgeCount + errorCount; } @Override public int getColumnCount() { return 2; } @Override public Object getValueAt(int row, int col) { if (col == 0) { switch (row) { case SHAPE_ROW_ID: return "Shape ID"; case SHAPE_ROW_EDGE_COUNT: return "Number of edges"; default: int edgeCount = (shape == null) ? 0 : shape.getEdges().size(); if (row < SHAPE_BASE_ROWS + edgeCount) { return "Edge " + (row - SHAPE_BASE_ROWS + 1); } return "Error"; } } else if (col == 1) { if (shape == null) { return null; } switch (row) { case SHAPE_ROW_ID: return shape.getID(); case SHAPE_ROW_EDGE_COUNT: return shape.getEdges().size(); default: int edgeCount = shape.getEdges().size(); if (row < SHAPE_BASE_ROWS + edgeCount) { List<GMLDirectedEdge> edges = shape.getEdges(); int index = row - SHAPE_BASE_ROWS; if (index < 0 || index >= edges.size()) { throw new IllegalArgumentException("Invalid row: " + row); } return edges.get(index); } int errorCount = (errors == null) ? 0 : errors.size(); int index = row - SHAPE_BASE_ROWS - edgeCount; if (index < 0 || index >= errorCount) { throw new IllegalArgumentException("Invalid row: " + row); } return errors.get(index).getMessage(); } } else { throw new IllegalArgumentException("Unrecognised column: " + col); } } } }