package gui.groupsPanel; import gui.bsvComponents.BSVComboBox; import gui.settings.Settings; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import java.text.NumberFormat; import java.text.ParseException; import java.util.ResourceBundle; import javax.imageio.ImageIO; import javax.swing.AbstractAction; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.PlainDocument; import util.Operator; import controller.Constraint; import controller.DynamicConstraint; import controller.Feature; import controller.Group; import controller.SubspaceController; import db.DatabaseAccessException; /** * Implements a single static constraint panel. Gives the user the ability to * change, enable, disable or delete the constraint. */ public class SingleConstraintPanel extends JPanel { private static final long serialVersionUID = 860191389614348893L; /* * Swing components used in this class. */ private JTextField value; private JComboBox featureChoice; private JComboBox operatorChoice; private JCheckBox status; private JButton deleteButton; /** * The dynamic constraint. */ private DynamicConstraint constraint; /** * Reference to the SubspaceController. */ private final SubspaceController subspaceController; /** * Reference to the group. */ private final Group group; /* * Actions */ private DeleteConstraintAction deleteConstraintAction; private ChangeConstraintStatus changeConstraintStatus; private FeatureActionListener featureChanged; private OperatorActionListener operatorChanged; private ValueActionListener valueChanged; /** * Reference to the SingleGroup */ private final SingleGroup singleGroup; /** * Dimension constants. */ private static final Dimension MAXDIM = new Dimension(1200, 40); private static final Dimension MINDIM = new Dimension(190, 40); /** * ResourceBundle for the Strings. */ private final ResourceBundle rb; /** * Formatter for parsing float values */ private final NumberFormat formatter; /** * Constructor * * @param subspaceController * reference to the SubspaceController. * @param group * the Group. * @param dc * reference to the DynamicConstraint. * * @param sg * reference to the SingleGroup. */ public SingleConstraintPanel(SubspaceController subspaceController, Group group, Constraint dc, SingleGroup sg) { if (subspaceController == null || group == null || sg == null) { throw new IllegalArgumentException("Controller cannot be null"); } this.group = group; this.singleGroup = sg; this.constraint = (DynamicConstraint) dc; this.subspaceController = subspaceController; this.rb = Settings.getInstance().getResourceBundle(); this.setLayout(new FlowLayout(FlowLayout.LEADING)); this.setMinimumSize(MINDIM); this.setMaximumSize(MAXDIM); this.formatter = NumberFormat.getNumberInstance(Settings.getInstance() .getLanguage()); initConstraint(); synchronize(); } /** * If constraint was not null, initializes the values of the corresponding * fields. */ private void synchronize() { if (this.constraint != null) { this.featureChoice.setSelectedItem(this.constraint.getFeature()); this.operatorChoice.setSelectedItem(this .operatorToString(this.constraint.getOperator())); this.status.setSelected(this.constraint.isActive()); this.value .setText(this.formatter.format(this.constraint.getValue())); } } /** * Provides the Strings for the operator list. * * @param op * the operator. * @return the corresponding String. */ private String operatorToString(Operator op) { String s; switch (op) { case EQUAL: s = "="; break; case NOT_EQUAL: s = "!="; break; case LESS: s = "<"; break; case LESS_OR_EQUAL: s = "<="; break; case GREATER: s = ">"; break; case GREATER_OR_EQUAL: s = ">="; break; default: s = "invalid"; break; } return s; } private void initButtons() { Dimension deleteButtonDim = new Dimension(20, 20); this.deleteButton = new JButton(deleteConstraintAction); try { this.deleteButton.setIcon(new ImageIcon(ImageIO.read(this .getClass().getResourceAsStream("/delete_small.png")))); } catch (IOException e) { this.deleteButton.setText("x"); } this.deleteButton.setSize(deleteButtonDim); this.deleteButton.setMinimumSize(deleteButtonDim); this.deleteButton.setMaximumSize(deleteButtonDim); this.deleteButton.setPreferredSize(deleteButtonDim); this.deleteButton.validate(); } private void initConstraint() { try { initListeners(); initActions(); initButtons(); Feature[] features = this.subspaceController.getSubspaces()[0].getFeatures(); int countNotVirtual = 0; for(int i = 0; i < features.length; i++) { if (!features[i].isVirtual()) { countNotVirtual++; } } Feature[] featuresWithoutVirtuals = new Feature[countNotVirtual]; for(int i = 0, counter = 0; i < features.length; i++) { if (!features[i].isVirtual()) { featuresWithoutVirtuals[counter++] = features[i]; } } this.featureChoice = new BSVComboBox(featuresWithoutVirtuals); this.featureChoice.addActionListener(this.featureChanged); String[] s = new String[Operator.values().length]; int i = 0; for (Operator current : Operator.values()) { s[i++] = this.operatorToString(current); } this.operatorChoice = new BSVComboBox(s); this.operatorChoice.addActionListener(this.operatorChanged); this.value = new JTextField(); this.value.setText(""); value.setDocument(new TextDoc(10)); this.value.setMinimumSize(new Dimension(85, 25)); this.value.setPreferredSize(new Dimension(85, 25)); this.value.addActionListener(this.valueChanged); this.status = new JCheckBox(this.changeConstraintStatus); if (this.constraint != null) { this.status.setSelected(this.constraint.isActive()); } else { this.status.setSelected(false); this.status.setEnabled(false); } addTooltips(); addComponents(); } catch (DatabaseAccessException e) { JOptionPane.showMessageDialog(null, rb.getString("databaseExceptionRead"), rb.getString("databaseSubspaceReadFailed"), JOptionPane.ERROR_MESSAGE); e.printStackTrace(); } } private void addTooltips() { this.status .setToolTipText(this.rb.getString("ToolTipConstraintStatus")); this.deleteButton.setToolTipText(this.rb .getString("ToolTipDeleteConstraint")); } private void initActions() { this.deleteConstraintAction = new DeleteConstraintAction(); this.changeConstraintStatus = new ChangeConstraintStatus(); } private void addComponents() { this.add(this.featureChoice); this.add(this.operatorChoice); this.add(this.value); this.add(this.status); this.add(this.deleteButton); this.validate(); } /** * Updates the properties of a constraint. * * @param action * indicates what is being updated. */ private void updateConstraint(char action) { float val = this.getSelectedValue(); this.value.setText(this.formatter.format(val)); if (this.constraint == null) { try { this.constraint = this.group.createDynamicConstraint( this.getSelectedFeature(), this.getSelectedOperator(), val); this.status.setEnabled(true); this.status.setSelected(this.constraint.isActive()); } catch (DatabaseAccessException e) { JOptionPane.showMessageDialog(null, rb.getString("DatabaseWriteError"), rb.getString("error"), JOptionPane.ERROR_MESSAGE); e.printStackTrace(); } } else { try { if (action == 'f') { this.constraint.setFeature(this.getSelectedFeature()); } if (action == 'o') { this.constraint.setOperator(this.getSelectedOperator()); } if (action == 'v') { this.constraint.setValue(val); } this.value.setFocusable(false); this.value.setFocusable(true); } catch (DatabaseAccessException e) { JOptionPane.showMessageDialog(null, rb.getString("DatabaseWriteError"), rb.getString("error"), JOptionPane.ERROR_MESSAGE); e.printStackTrace(); } } } private void initListeners() { this.featureChanged = new FeatureActionListener(); this.operatorChanged = new OperatorActionListener(); this.valueChanged = new ValueActionListener(); } private void deleteThis() { try { if (this.constraint != null) { this.group.removeConstraint(this.constraint); } this.singleGroup.deleteConstraint(this); } catch (DatabaseAccessException e) { JOptionPane.showMessageDialog(null, rb.getString("DatabaseWriteError"), rb.getString("error"), JOptionPane.ERROR_MESSAGE); e.printStackTrace(); } } /** * Returns the selected feature. * * @return a feature. */ private Feature getSelectedFeature() { return (Feature) featureChoice.getSelectedItem(); } /** * Returns the selected Operator. * * @return an operator. */ private Operator getSelectedOperator() { for (Operator current : Operator.values()) { if (this.operatorToString(current).equals( operatorChoice.getSelectedItem())) { return current; } } return null; } /** * Returns the selected Value. * * @return a float representing the value. */ private float getSelectedValue() { try { return this.formatter.parse(value.getText()).floatValue(); } catch (ParseException e) { return (float) 0.0; } } private void changeStatus() { try { if (this.constraint != null) { this.constraint.setActive(this.status.isSelected()); } } catch (DatabaseAccessException e) { JOptionPane.showMessageDialog(null, rb.getString("DatabaseWriteError"), rb.getString("error"), JOptionPane.ERROR_MESSAGE); e.printStackTrace(); } } /** * Feature changed. * */ class FeatureActionListener implements ActionListener { /** * Action triggered. * * @param evt * the event */ @Override public void actionPerformed(ActionEvent evt) { if (value.getText().length() > 0) { updateConstraint('f'); } } } /** * Operator changed. * */ class OperatorActionListener implements ActionListener { /** * Action triggered. * * @param evt * the event */ @Override public void actionPerformed(ActionEvent evt) { if (value.getText().length() > 0) { updateConstraint('o'); } } } /** * Value changed. * */ class ValueActionListener implements ActionListener { /** * Action triggered. * * @param evt * the event */ @Override public void actionPerformed(ActionEvent evt) { if (value.getText().length() > 0) { updateConstraint('v'); } } } /** * Defines the delete constraint action. */ class DeleteConstraintAction extends AbstractAction { private static final long serialVersionUID = 8295888203795540876L; /** * Defines what happens when this action is triggered. * * @param e * - action event. */ @Override public void actionPerformed(ActionEvent e) { deleteThis(); } } /** * Used to restrain the number of symbols in a text field. * */ class TextDoc extends PlainDocument { private static final long serialVersionUID = 3532684139324670212L; private final int maxLength; /** * Constructor * * @param maxLength * the max string length for the text */ public TextDoc(int maxLength) { this.maxLength = maxLength; } @Override public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { if (str.length() == 0) { return; } if (getLength() + str.length() < maxLength) { super.insertString(offs, str, a); } } } /** * Defines the change status action. */ class ChangeConstraintStatus extends AbstractAction { private static final long serialVersionUID = -2651079710854433407L; /** * Defines what happens when this action is triggered. * * @param e * - action event. */ @Override public void actionPerformed(ActionEvent e) { changeStatus(); } } }