package pipe.actions.gui; import pipe.controllers.PetriNetController; import pipe.controllers.application.PipeApplicationController; import pipe.gui.AbstractDatum; import pipe.gui.TokenEditorPanel; import pipe.historyActions.MultipleEdit; import pipe.historyActions.component.AddPetriNetObject; import pipe.historyActions.component.ChangePetriNetComponentName; import pipe.historyActions.component.DeletePetriNetObject; import pipe.historyActions.token.ChangeTokenColor; import pipe.utilities.gui.GuiUtils; import pipe.views.PipeApplicationView; import uk.ac.imperial.pipe.exceptions.PetriNetComponentException; import uk.ac.imperial.pipe.exceptions.PetriNetComponentNotFoundException; import uk.ac.imperial.pipe.models.petrinet.PetriNet; import uk.ac.imperial.pipe.models.petrinet.PetriNetComponent; import uk.ac.imperial.pipe.models.petrinet.Token; import javax.swing.*; import javax.swing.undo.UndoableEdit; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.util.LinkedList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; /** * Action used to create, delete and edit tokens in the Petri net */ @SuppressWarnings("serial") public class SpecifyTokenAction extends GuiAction { /** * Main PIPE application controller */ private final PipeApplicationController pipeApplicationController; /** * Main PIPE application view */ private final PipeApplicationView applicationView; /** * Pop up editor panel for the tokens */ private TokenEditorPanel tokenEditorPanel; /** * Pop up dialog */ private JDialog guiDialog; /** * Legacy action, I'm not sure what this is */ private ActionEvent forcedAction; public SpecifyTokenAction(PipeApplicationController pipeApplicationController, PipeApplicationView applicationView) { super("SpecifyTokenClasses", "Specify tokens (ctrl-shift-T)", KeyEvent.VK_T, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() | InputEvent.SHIFT_DOWN_MASK); this.pipeApplicationController = pipeApplicationController; this.applicationView = applicationView; } /** * Pops up to change the petri net tokens if there is an active petri net * * @param e event */ @Override public void actionPerformed(ActionEvent e) { if (pipeApplicationController.getActivePetriNetController() != null) { buildTokenGuiClasses(); finishBuildingGui(); } } /** * Creates a new token editor with the tokens from the Petri net */ public void buildTokenGuiClasses() { tokenEditorPanel = new TokenEditorPanel(pipeApplicationController.getActivePetriNetController()); guiDialog = new TokenDialog("Tokens", true, tokenEditorPanel); } /** * Provides the set up for what the token editor panel will look like */ public void finishBuildingGui() { guiDialog.setSize(600, 200); guiDialog.setLocationRelativeTo(null); tokenEditorPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); tokenEditorPanel.setOpaque(true); JPanel buttonPane = new JPanel(); buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS)); buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10)); buttonPane.add(Box.createHorizontalGlue()); JButton ok = new JButton("OK"); ok.addActionListener((ActionListener) guiDialog); buttonPane.add(ok); buttonPane.add(Box.createRigidArea(new Dimension(10, 0))); JButton cancel = new JButton("Cancel"); cancel.addActionListener((ActionListener) guiDialog); buttonPane.add(cancel); guiDialog.add(tokenEditorPanel, BorderLayout.CENTER); guiDialog.add(buttonPane, BorderLayout.PAGE_END); tokenEditorPanel.setVisible(true); if (forcedAction != null) { forceContinue(); } else { guiDialog.setVisible(true); } } /** * Legacy code */ private void forceContinue() { ((TokenDialog) guiDialog).actionPerformed(forcedAction); forcedAction = null; } /** * @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 TokenDialog<T extends PetriNetComponent> extends JDialog implements ActionListener { /** * Class logger */ private final Logger logger = Logger.getLogger(TokenDialog.class.getName()); /** * Editor panel */ private TokenEditorPanel tokenEditorPanel; /** * * @param title token dialog title * @param modal dialog * @param tokenEditorPanel panel */ public TokenDialog(String title, boolean modal, TokenEditorPanel tokenEditorPanel) { super(applicationView, title, modal); this.tokenEditorPanel = tokenEditorPanel; } /** * Processes the changing of Petri net tokens * @param e event */ @Override public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("OK")) { if (tokenEditorPanel.isDataValid()) { updateFromTable(tokenEditorPanel.getTableData()); removeDeletedData(tokenEditorPanel.getDeletedData()); setVisible(false); } } else if (e.getActionCommand().equals("Cancel")) { setVisible(false); } } //TODO: ONCE PETRINET CAN GET COMPONENT BY ID YOU CAN MAKE THIS WHOLE CLASS ABSTRACT // AND SHARE IT WITH RATE EDITOR /** * Removes tokens from the Petri net. * <p> * Creates error message if a token cannot be removed for some reason, for * example if places still contain tokens of its type. It will apply all other * changes. * </p> * @param deletedData contains Datum items that were deleted from the table */ private void removeDeletedData(Iterable<TokenEditorPanel.Datum> deletedData) { PetriNetController petriNetController = pipeApplicationController.getActivePetriNetController(); PetriNet petriNet = petriNetController.getPetriNet(); List<UndoableEdit> undoableEdits = new LinkedList<>(); for (TokenEditorPanel.Datum datum : deletedData) { if (tokenEditorPanel.isExistingDatum(datum)) { try { Token token = petriNet.getComponent(datum.id, Token.class); petriNet.removeToken(token); UndoableEdit historyItem = new DeletePetriNetObject(token, petriNet); undoableEdits.add(historyItem); } catch (PetriNetComponentNotFoundException e) { logger.log(Level.SEVERE, e.getMessage()); } catch (PetriNetComponentException e) { StringBuilder messageBuilder = new StringBuilder(); messageBuilder.append(e.getMessage()); messageBuilder.append("\n"); messageBuilder.append("All other changes will be applied but this token will not be deleted!"); GuiUtils.displayErrorMessage(null, messageBuilder.toString()); } } } if (undoableEdits.size() > 0) { registerUndoEvent(new MultipleEdit(undoableEdits)); } } /** * Update the Petri net component from the table data item * @param data for update */ private void updateFromTable(Iterable<TokenEditorPanel.Datum> data) { PetriNetController petriNetController = pipeApplicationController.getActivePetriNetController(); List<UndoableEdit> undoableEdits = new LinkedList<>(); for (TokenEditorPanel.Datum modified : data) { if (tokenEditorPanel.isExistingDatum(modified)) { AbstractDatum initial = modified.initial; if (!modified.equals(initial) && modified.hasBeenSet()) { try { Token token = petriNetController.getToken(initial.id); undoableEdits.add(new ChangePetriNetComponentName(token, initial.id, modified.id)); undoableEdits.add(new ChangeTokenColor(token, token.getColor(), modified.color)); petriNetController.updateToken(initial.id, modified.id, modified.color); } catch (PetriNetComponentNotFoundException petriNetComponentNotFoundException) { GuiUtils.displayErrorMessage(null, petriNetComponentNotFoundException.getMessage()); } } } else if (modified.hasBeenSet()) { petriNetController.createNewToken(modified.id, modified.color); try { Token token = petriNetController.getToken(modified.id); undoableEdits.add(new AddPetriNetObject(token, petriNetController.getPetriNet())); } catch (PetriNetComponentNotFoundException e) { logger.log(Level.SEVERE, e.getMessage()); } } } if (undoableEdits.size() > 0) { registerUndoEvent(new MultipleEdit(undoableEdits)); } } } }