package pipe.gui;
import pipe.controllers.PetriNetController;
import uk.ac.imperial.pipe.models.petrinet.RateParameter;
import uk.ac.imperial.pipe.parsers.FunctionalResults;
import javax.swing.*;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
/**
* This is a panel for modifying and creating rate parameters
*/
public class RateEditorPanel extends JPanel {
private final JTable table;
private final RateModel model;
public RateEditorPanel(PetriNetController petriNetController) {
model = new RateModel(petriNetController);
table = new JTable(model);
table.setPreferredScrollableViewportSize(new Dimension(500, 70));
table.setFillsViewportHeight(true);
JButton deleteButton = new JButton("Delete");
deleteButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int selected = table.getSelectedRow();
model.deleteRow(selected);
}
});
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane);
add(deleteButton);
}
public List<RateModel.Datum> getTableData() {
return model.getTableData();
}
public boolean isDataValid() {
return model.isValid();
}
public boolean isExistingRateParameter(RateModel.Datum datum) {
return model.isExistingDatum(datum);
}
public Iterable<RateModel.Datum> getDeletedData() {
return model.deletedData;
}
public class RateModel extends AbstractComponentTableModel<RateModel.Datum> {
private static final int ID_COL = 0;
private final PetriNetController petriNetController;
public RateModel(PetriNetController petriNetController) {
this.petriNetController = petriNetController;
columnNames = new String[]{"Name", "Value"};
for (RateParameter rateParameter : petriNetController.getRateParameters()) {
Datum initial = new Datum(rateParameter.getId(), rateParameter.getExpression());
modifiedData.add(new Datum(initial, rateParameter.getId(), rateParameter.getExpression()));
count++;
}
for (int index = modifiedData.size(); index < DATA_SIZE; index++) {
modifiedData.add(new Datum("", ""));
}
}
/**
* Updates the table the values added.
*
* @param value new value
* @param rowIndex index of row changed
* @param colIndex index of column changed
*/
@Override
public void updateTableAt(Object value, int rowIndex, int colIndex) {
String id = modifiedData.get(rowIndex).id;
String expression = modifiedData.get(rowIndex).expression;
if (colIndex == ID_COL) {
id = (String) value;
} else {
expression = (String) value;
}
modifiedData.get(rowIndex).id = id;
modifiedData.get(rowIndex).expression = expression;
}
/**
* Checks the following conditions:
* - Name is not empty
* - Rate value is not empty
*
* @return true if the values in the table are valid for each rate parameter
*/
public boolean isValid() {
for (int row = 0; row < getRowCount(); row++) {
Datum datum = modifiedData.get(row);
if (isExistingRateParameter(datum)) {
if (datum.id.isEmpty()) {
showWarning("The rate name cannot be empty");
return false;
}
if (!isValidRate(datum.id, datum.expression)) {
return false;
}
}
if (datum.id.isEmpty() && !datum.expression.isEmpty()) {
showWarning("The rate name cannot be empty");
return false;
}
if (!datum.id.isEmpty() && datum.expression.isEmpty()) {
showWarning("The rate value cannot be empty");
return false;
}
if (!datum.id.isEmpty() && !isValidRate(datum.id, datum.expression)) {
return false;
}
}
return true;
}
/**
* Shows a warning to the user as a dialog
*
* @param warningMessage message to show
*/
private void showWarning(String warningMessage) {
JOptionPane.showMessageDialog(new JPanel(), warningMessage, "Warning", JOptionPane.WARNING_MESSAGE);
}
/**
* Pops up an error if the rate is invalid
*
* @param rate
* @return if rate is valid or not
*/
private boolean isValidRate(String id, String rate) {
FunctionalResults<Double> results = petriNetController.parseFunctionalExpression(rate);
if (results.hasErrors()) {
showWarning("Error! Invalid rate for: " + id + "\n" + "Problem is: " + results.getErrorString(", "));
return false;
}
return true;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
if (columnIndex == ID_COL) {
return modifiedData.get(rowIndex).id;
}
return modifiedData.get(rowIndex).expression;
}
/**
* Holds rate parameter information in the table
*/
public final class Datum extends AbstractDatum {
public String expression;
private Datum(String id, String expression) {
super(id);
this.expression = expression;
}
private Datum(Datum initial, String id, String expression) {
super(initial, id);
this.expression = expression;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Datum datum = (Datum) o;
if (expression != null ? !expression.equals(datum.expression) : datum.expression != null) {
return false;
}
if (id != null ? !id.equals(datum.id) : datum.id != null) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (expression != null ? expression.hashCode() : 0);
return result;
}
}
}
}