package ui;
import java.awt.Dimension;
import java.awt.Font;
import model.CriterionEditor;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import model.Criterion;
/**
*
* @author mark
*/
public class CriterionPanel extends JPanel implements CriterionEditor {
private RadioGroup radioGroup = null;
private final JTextArea txtComment;
private final Criterion criterion;
private final JButton clearBtn;
private JTextField txtSpecial = null;
private static Dimension selectedSize;
@SuppressWarnings("Convert2Lambda")
public CriterionPanel(Criterion criterion) {
this.criterion = criterion;
this.setLayout(new GridBagLayout());
// label is left aligned and full width
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridwidth = 3;
gbc.weightx = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(0, 0, 5, 0);
this.add(new JLabel(criterion.getDescription()), gbc);
// clear mark buttonleft aligned, but doesn't grow
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 1;
clearBtn = new JButton("X");
this.add(clearBtn, gbc);
// mark component is left aligned, but doesn't grow
gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 1;
if (!criterion.isIsSpecial()) {
radioGroup = new RadioGroup(criterion.getMin(), criterion.getMax());
this.add(radioGroup, gbc);
} else {
gbc.insets.left = 20;
gbc.insets.right = 20;
gbc.fill = GridBagConstraints.HORIZONTAL;
txtSpecial = new JTextField();
this.add(txtSpecial, gbc);
}
// text area is right aligned, but grows in both directions
gbc = new GridBagConstraints();
gbc.gridx = 2;
gbc.gridy = 1;
gbc.weightx = 1;
gbc.weighty = 1;
gbc.fill = GridBagConstraints.BOTH;
txtComment = new JTextArea();
txtComment.setWrapStyleWord(true);
txtComment.setLineWrap(true);
JScrollPane scrollPane = new JScrollPane();
scrollPane.setViewportView(txtComment);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
// Dimensions are necessary to prevent the semi-famous "text area grows infinitely" bug.
// Unfortunately this also means we can't let the layout manager figure out the correct
// size dynamically...
txtComment.setMinimumSize(new Dimension(10, 20));
txtComment.setPreferredSize(new Dimension(10, 100)); // need to hardcode height which is annoying...
scrollPane.setPreferredSize(new Dimension(10, 20));
txtComment.addFocusListener(new FocusAdapter() {
@Override
public void focusGained(FocusEvent fe) {
super.focusGained(fe);
CriterionPanel selectedPanel = CriterionPanel.this;
MarkingFrame frame = (MarkingFrame) SwingUtilities.getWindowAncestor(selectedPanel);
if (frame.getExpandable()) {
selectedPanel.setPreferredSize(new Dimension(10, 150));
selectedPanel.invalidate();
SwingUtilities.getWindowAncestor(selectedPanel).pack();
}
}
@Override
public void focusLost(FocusEvent fe) {
super.focusLost(fe);
CriterionPanel selectedPanel = CriterionPanel.this;
MarkingFrame frame = (MarkingFrame) SwingUtilities.getWindowAncestor(selectedPanel);
if (frame.getExpandable()) {
selectedPanel.setPreferredSize(selectedSize);
selectedPanel.invalidate();
SwingUtilities.getWindowAncestor(selectedPanel).pack();
}
}
});
clearBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
if (!criterion.isIsSpecial()) {
radioGroup.clearSelection();
} else {
txtSpecial.setText("");
}
}
});
Font font = txtComment.getFont();
Font biggerFont = font.deriveFont(14f);
txtComment.setFont(biggerFont);
this.add(scrollPane, gbc);
}
@Override
public String getComment() {
return txtComment.getText().trim();
}
@Override
public Double getResult() {
if (!criterion.isIsSpecial()) {
Integer result = radioGroup.getSelected();
return result != null ? Double.valueOf(result) : null;
} else {
try {
String val = txtSpecial.getText();
if (val.isBlank()) {
// mark not entered, so return null
return null;
}
Double result = Double.valueOf(val);
if (result < criterion.getMin() || result > criterion.getMax()) {
JOptionPane.showMessageDialog(null, txtSpecial.getText() + " is not within the exected range.\n\nMinimum: " + criterion.getMin() + "\nMaximum: " + criterion.getMax(), "Invalid Number", JOptionPane.ERROR_MESSAGE);
throw new RuntimeException("Number is not within expected range");
}
return Double.valueOf(txtSpecial.getText());
} catch (NumberFormatException ex) {
JOptionPane.showMessageDialog(null, txtSpecial.getText() + " is not a valid number", "Invalid Number", JOptionPane.ERROR_MESSAGE);
throw new RuntimeException(ex.getLocalizedMessage());
}
}
}
@Override
public boolean isComplete() {
return getResult() != null;
}
@Override
public void setComment(String comment) {
txtComment.setText(comment);
}
@Override
public void setResult(Double result) {
if (!criterion.isIsSpecial()) {
radioGroup.setSelected(result.intValue());
} else {
txtSpecial.setText(String.valueOf(result));
}
}
public void setZero() {
setResult(0.0);
}
public void setMax() {
setResult(Double.valueOf(criterion.getMax()));
}
public Criterion getCriterion() {
return criterion;
}
}