package edu.hws.eck.mdb; import java.awt.*; import java.awt.event.*; import javax.swing.*; /** * This class represents a dialog box where the user can enter new values * for xmin, xmax, ymin, and ymax. These values specify the ranges of * x and y values that are shown in the Mandelbrot image. */ public class SetLimitsDialog extends JDialog { /** * This static convenience method shows a dialog of type SetLimitsDialog, * waits for the user to input a response or to dismiss the dialog, and * returns the user's response (or null if the user cancels). Note that * if you use this method, then you don't have to do anything else with * this class. * @param frame The parent of this dialog, which is blocked while the * dialog is on screen. * @param oldLimitStrings an array of 4 strings that are used as the * initial content of the input boxes for xmin, xmax, ymin, ymax (in * that order). (Note that I pass strings rather than doubles because * I had nicely formatted strings available in the class that calls this * method.) * @return null, if the user cancels, or an array of four doubles, representing * the inputs for xmin, xmax, ymin, and ymax. It is guaranteed that * xmin is strictly less than xmax and ymin is strictl less than ymax. * (Actually, the return value will also be null when the user clicks OK * without ever editing the initial values in the input boxes. Only * CHANGED values are returned.) */ static double[] showDialog(JFrame frame, String[] oldLimitStrings) { SetLimitsDialog dialog = new SetLimitsDialog(frame,oldLimitStrings); dialog.setVisible(true); return dialog.getInputsIfChanged(); } private double[] inputValues; // Will contain the user's input after user clicks OK. boolean changed; // Will be set to true if the user actually edited the input boxes. private JButton cancelButton; private JButton okButton; private JTextField[] inputBoxes; private String[] oldLimitStrings; private static final String[] names = { "limitsdialog.xmin", "limitsdialog.xmax", "limitsdialog.ymin", "limitsdialog.ymax" }; /** * Constructor builds the dialog box and adds listeners to the buttons. This * does not make the dialog visible on the screen. Note that the dialog is * disposed when it is closed, so it cannot be reused. (For a reusable dialog, * it should be "hidden" rather than disposed.) * @param frame The parent of the dialog box, which is blocked while the dialog * is on the screen. * @param oldLimitStrings Initial content of input boxes. Must be an array of length four. */ public SetLimitsDialog(JFrame frame, String[] oldLimitStrings) { super(frame,I18n.tr("limitsdialog.title"),true); // "true" for a modal dialog. this.oldLimitStrings = oldLimitStrings; JPanel content = new JPanel(); content.setLayout(new BorderLayout(10,10)); setContentPane(content); content.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); JPanel input = new JPanel(); input.setLayout(new GridLayout(4,2,5,5)); inputBoxes = new JTextField[4]; for (int i = 0; i < 4; i++) { inputBoxes[i] = new JTextField(oldLimitStrings[i]); input.add(new JLabel(I18n.tr(names[i])+":")); input.add(inputBoxes[i]); } cancelButton = new JButton(I18n.tr("button.cancel")); okButton = new JButton(I18n.tr("button.ok")); getRootPane().setDefaultButton(okButton); // This means that the OK button can be invoked by pressing return. JPanel buttons = new JPanel(); buttons.add(cancelButton); buttons.add(okButton); content.add( new JLabel(I18n.tr("limitsdialog.question")), BorderLayout.NORTH ); content.add( input, BorderLayout.CENTER ); content.add( buttons, BorderLayout.SOUTH ); setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); pack(); setLocation(frame.getX()+50, frame.getY()+75); // Position near top-left corner of parent frame. Dimension screensize = Toolkit.getDefaultToolkit().getScreenSize(); int x = getX(); // The next six lines ensure that the dialog is actually visible on the screen. int y = getY(); if (x + getWidth() > screensize.width) x = screensize.width - getWidth() - 30; if (y + getHeight() > screensize.height) y = screensize.height - getHeight() - 30; setLocation(x,y); cancelButton.addActionListener( new ActionListener() { // Closes the dialog when the user clicks the cancel button. public void actionPerformed(ActionEvent evt) { dispose(); } }); okButton.addActionListener( new ActionListener() { // When the user clicks OK, close the dialog only if the input is legal. public void actionPerformed(ActionEvent evt) { if (checkInput()) dispose(); } }); } /** * This is called when the user clicks the OK button, to get the user's responses * and make sure they are legal. If not, the user is informed of the error and * the dialog will stay on the screen. * @return true if the input is legal. */ private boolean checkInput() { changed = false; inputValues = null; String[] inputStrings = new String[4]; for (int i = 0; i < 4; i++) { inputStrings[i] = inputBoxes[i].getText(); if (!inputStrings[i].equals(oldLimitStrings[i])) changed = true; // At least one of the input strings has been modified. } double[] values = new double[4]; for (int i = 0; i < 4; i++) { try { values[i] = Double.parseDouble(inputStrings[i]); } catch (NumberFormatException e) { JOptionPane.showMessageDialog( this, I18n.tr( "limitsdialog.error.NAN", inputStrings[i], I18n.tr(names[i]) ) ); inputBoxes[i].selectAll(); inputBoxes[i].requestFocus(); return false; } } if (values[1] <= values[0]) { JOptionPane.showMessageDialog(this, I18n.tr("limitsdialog.error.xValuesOutOfOrder" )); inputBoxes[1].selectAll(); inputBoxes[1].requestFocus(); return false; } if (values[3] <= values[2]) { JOptionPane.showMessageDialog(this, I18n.tr("limitsdialog.error.yValuesOutOfOrder" )); inputBoxes[3].selectAll(); inputBoxes[3].requestFocus(); return false; } inputValues = values; return true; } /** * Can be called after the dialog box is closed to get the user's inputs. * @return an array containing the four values from the input box, if the * user dismissed the dialog box with the OK button, or null if the user * canceled. */ public double[] getInputs() { return inputValues; } /** * Can be called after the dialog box is closed to get the user's inputs. * (This is provided because the double values that are returned might be * exactly the same as the original double values, even if the user has * not edited the values at all. This is true because of round-off error * when doubles are converted to string form. So, you can't check whether * the user edited the inputs just by checking whether the new values are * the same as the original values. (This would probably be called a rather * minor point by most people.)) * @return an array containing the four values from the input box, if the * user dismissed the dialog box with the OK button AND the user changed * the initial values before clicking OK, or null if the user canceled OR * if the user clicked OK but did not change the values.. */ public double[] getInputsIfChanged() { if (changed) return inputValues; else return null; } }