package pipe.gui.widgets; import pipe.controllers.ArcController; import uk.ac.imperial.pipe.animation.AnimationUtils; import uk.ac.imperial.pipe.models.petrinet.PetriNet; import uk.ac.imperial.pipe.models.petrinet.Place; import uk.ac.imperial.pipe.parsers.FunctionalResults; import uk.ac.imperial.pipe.parsers.FunctionalWeightParser; import uk.ac.imperial.pipe.parsers.PetriNetWeightParser; import uk.ac.imperial.pipe.parsers.StateEvalVisitor; import uk.ac.imperial.state.State; import javax.swing.*; import java.awt.BorderLayout; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Collection; import java.util.LinkedList; import java.util.List; /** * Editor for modifying arc properties */ @SuppressWarnings("serial") public class ArcFunctionEditor extends JPanel { /** * Petri net arc belongs to */ private PetriNet petriNet; /** * dialog for messages */ private EscapableDialog rootPane; /** * Arc controller */ private ArcController<?, ?> arcController; /** * Token id */ private String token; /** * Editor panel */ private ArcWeightEditorPanel weightEditorPanel; /** * Constructor * @param weightEditorPanel panel * @param guiDialog dialog * @param petriNet Petr net * @param arcController controller * @param token currently selected token */ public ArcFunctionEditor(ArcWeightEditorPanel weightEditorPanel, EscapableDialog guiDialog, PetriNet petriNet, ArcController<?, ?> arcController, String token) { this.weightEditorPanel = weightEditorPanel; this.petriNet = petriNet; rootPane = guiDialog; this.arcController = arcController; this.token = token; init(); } /** * Initializes the editor */ private void init() { final JTextArea function = new JTextArea(); function.setText(arcController.getWeightForToken(token)); JScrollPane scrollPane = new JScrollPane(function); scrollPane.setBorder(javax.swing.BorderFactory.createTitledBorder("Weight expression input:")); JPanel north = new JPanel(); north.setBorder(javax.swing.BorderFactory.createTitledBorder("Places input:")); Collection<String> placeNames = new LinkedList<>(); for (Place place : petriNet.getPlaces()) { placeNames.add(place.getName()); } JComboBox places = new JComboBox(placeNames.toArray()); north.add(places); JPanel south = new JPanel(new FlowLayout()); JButton okbutton = new JButton("OK"); JButton helpbutton = new JButton("Help"); okbutton.addActionListener(new ArcOKAction(function)); helpbutton.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { String help = "Operators supported:\r\n" + "+\r\n" + "-\r\n" + "*\r\n" + "/\r\n" + "max()\r\n" + "min()\r\n" + "ceil()\r\n" + "floor()\r\n" + "cap(place_name)"; JOptionPane.showMessageDialog(null, help); } }); south.add(okbutton); south.add(helpbutton); places.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { JComboBox cb = (JComboBox) evt.getSource(); String placeName = (String) cb.getSelectedItem(); function.replaceSelection(placeName); } }); this.setLayout(new BorderLayout()); this.add(north, BorderLayout.NORTH); this.add(scrollPane, BorderLayout.CENTER); this.add(south, BorderLayout.SOUTH); this.setSize(100, 100); this.setVisible(true); } /** * Exits the editor */ private void exit() { rootPane.setVisible(false); } /** * Concatenates a list of errors into a single string * * @param errors to be concatenated * @return single string representation of the error, which is just the errors * appended together and separated via a comma. */ private String concatenateErrors(List<String> errors) { StringBuilder builder = new StringBuilder(); for (String error : errors) { builder.append(error).append(", "); } return builder.toString(); } /** * Action performed when OK is pressed on the arc editor. * * Saves the properties */ private final class ArcOKAction implements ActionListener { /** * functional expression */ private final JTextArea function; /** * Constructor * @param function arc functional expression */ private ArcOKAction(JTextArea function) { this.function = function; } /** * Tries to parse the functional expression to determine its validity * @param e event */ @Override public void actionPerformed(ActionEvent e) { String func = function.getText(); if (func == null || func.equals("")) { exit(); return; } State state = AnimationUtils.getState(petriNet); StateEvalVisitor evalVisitor = new StateEvalVisitor(petriNet, state); FunctionalWeightParser<Double> parser = new PetriNetWeightParser(evalVisitor, petriNet); FunctionalResults<Double> results = parser.evaluateExpression(func); if (!results.hasErrors()) { weightEditorPanel.setWeight(func, token); } else { List<String> errors = results.getErrors(); String concatenated = concatenateErrors(errors); JOptionPane.showMessageDialog(null, concatenated); return; } exit(); } } }