package pipe.gui; import pipe.controllers.PetriNetController; import uk.ac.imperial.pipe.models.petrinet.Token; import javax.swing.*; import java.awt.Color; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Collection; import java.util.List; import java.util.Random; /** * @author Alex Charalambous, June 2010: ColorDrawer, ColorPicker, * TokenPanel and TokenDialog are four classes used to display * the Token Classes dialog (accessible through the button toolbar). */ public class TokenEditorPanel extends JPanel { private final TableModel model; public TokenEditorPanel(final PetriNetController petriNetController) { model = new TableModel(petriNetController); final JTable table = new JTable(model); table.setPreferredScrollableViewportSize(new Dimension(500, 70)); table.setFillsViewportHeight(true); table.setDefaultRenderer(Color.class, new ColorDrawer(true)); table.setDefaultEditor(Color.class, new ColorPicker()); JButton deleteButton = new JButton("Delete"); deleteButton.addActionListener(new ActionListener() { /** * Only delete data if it is not the last token left! * @param e */ //TODO: This does not take into account adding new tokens before pressing ok // make sure it does.... @Override public void actionPerformed(ActionEvent e) { int selected = table.getSelectedRow(); if (model.count > 1) { model.deleteRow(selected); } } }); JScrollPane scrollPane = new JScrollPane(table); add(scrollPane); add(deleteButton); } public boolean isDataValid() { return model.isValid(); } public List<Datum> getTableData() { return model.getTableData(); } public Collection<Datum> getDeletedData() { return model.getDeletedData(); } public boolean isExistingDatum(Datum datum) { return model.isExistingDatum(datum); } /** * Private class to hold the data in the table. */ public static class Datum extends AbstractDatum { /** * Color of the token */ public Color color; public Datum(String name, Color color) { super(name); this.color = color; } public Datum(Datum initial, String name, Color color) { super(initial, name); this.color = color; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof Datum)) { return false; } if (!super.equals(o)) { return false; } Datum datum = (Datum) o; if (!color.equals(datum.color)) { return false; } return true; } @Override public int hashCode() { int result = super.hashCode(); result = 31 * result + color.hashCode(); return result; } } /** * TableModel for editing the Tokens */ public static class TableModel extends AbstractComponentTableModel<Datum> { private static final int NAME_COL = 0; public TableModel(PetriNetController petriNetController) { columnNames = new String[]{"Token Name Details", "Token Colour"}; for (Token token : petriNetController.getNetTokens()) { Datum initial = new Datum(token.getId(), token.getColor()); modifiedData.add(new Datum(initial, token.getId(), token.getColor())); count++; } initialiseEmptyRowColours(modifiedData.size()); } /** * Sets the first 6 rows as basic different colors. The rest of the rows are assigned * to a random color */ private void initialiseEmptyRowColours(int startIndex) { Random randomNumberGenerator = new Random(); for (int i = startIndex; i < DATA_SIZE; i++) { Color color; switch (i) { case 0: color = Color.black; break; case 1: color = Color.RED; break; case 2: color = Color.BLUE; break; case 3: color = Color.YELLOW; break; case 4: color = Color.GREEN; break; case 5: color = Color.ORANGE; break; case 6: color = Color.PINK; break; default: color = new Color(randomNumberGenerator.nextInt(256), randomNumberGenerator.nextInt(256), randomNumberGenerator.nextInt(256)); } modifiedData.add(new Datum("", color)); } } @Override public Class<?> getColumnClass(int c) { return getValueAt(0, c).getClass(); } @Override public Object getValueAt(int row, int col) { if (col == NAME_COL) { return modifiedData.get(row).id; } return modifiedData.get(row).color; } /** * Sets modifiedData with the new value * Also performs checks on the new value and displays * warnings if it is likely to be invalid * * @param value new value of the changed cell * @param row row that has changed * @param col column that has changed */ @Override public void updateTableAt(Object value, int row, int col) { String id = modifiedData.get(row).id; Color color = modifiedData.get(row).color; if (col == NAME_COL) { id = (String) value; for (int i = 0; i < modifiedData.size(); i++) { if (i != row && modifiedData.get(i).id.equals(value)) { JOptionPane.showMessageDialog(new JPanel(), "Another token exists with that name", "Warning", JOptionPane.WARNING_MESSAGE); return; } } } else { color = (Color) value; } // //TODO: DO THIS IN A BETTER WAY // if (row < initialData.length) { // Datum initial = initialData[row]; // String originalTokenName = initial.name; // for (Place place : petriNetController.getPetriNet().getPlaces()) { // for (Map.Entry<Token, Integer> entry : place.getTokenCounts().entrySet()) { // if (entry.getKey().getId().equals(originalTokenName)) { // if (entry.getValue() > 0) { // JOptionPane.showMessageDialog(new JPanel(), "Places exist that use this token. " // + "Such markings must be removed before this class can be edited", "Warning", // JOptionPane.WARNING_MESSAGE); // return; // } // } // } // } // } modifiedData.get(row).id = id; modifiedData.get(row).color = color; } /** * Checks to see if all the tokens in the table are valid. * If they are not it will print the relevant error message for the first * invalid token it comes across. * * @return true if all the tokens in the table are valid, false if not */ public boolean isValid() { return true; } } }