package org.oddjob.swing; import java.awt.Component; import java.awt.Container; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicReference; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JPasswordField; import javax.swing.JTextField; import org.oddjob.arooa.design.screem.FileSelectionOptions; import org.oddjob.arooa.design.view.DialogueHelper; import org.oddjob.arooa.design.view.FileSelectionWidget; import org.oddjob.arooa.design.view.Looks; import org.oddjob.input.InputHandler; import org.oddjob.input.InputMedium; import org.oddjob.input.InputRequest; /** * Implementation of an {@link InputHandler} in Swing. * * @author rob * */ public class SwingInputHandler implements InputHandler { /** The parent component. Probably the OddjobExplorer window. */ private Component parent; /** * Constructor. * * @param owner The parent component. */ public SwingInputHandler(Component owner) { this.parent = owner; } @Override public Properties handleInput(InputRequest[] requests) { InputDialogue form = new InputDialogue(); List<AtomicReference<String>> refs = new ArrayList<AtomicReference<String>>(); final List<Callable<Boolean>> validations = new ArrayList<Callable<Boolean>>(); Properties properties = new Properties(); for (InputRequest request : requests) { AtomicReference<String> ref = new AtomicReference<String>(); refs.add(ref); FieldBuilder medium = new FieldBuilder(ref); request.render(medium); FormWriter formWriter = medium.getFormWriter(); form.accept(formWriter); validations.add(medium.getValidator()); } DialogManager dialogManager = new DialogManager(); dialogManager.showDialog(form.getForm(), new Callable<Boolean>() { @Override public Boolean call() throws Exception { for (Callable<Boolean> validator : validations) { if (validator == null) { continue; } if (!validator.call()) { return Boolean.FALSE; } } return Boolean.TRUE; } }); if (dialogManager.isChosen()) { int i = 0; for (AtomicReference<String> ref : refs) { String property = requests[i++].getProperty(); if (property == null) { continue; } if (ref.get() == null) { continue; } properties.setProperty(property, ref.get()); } return properties; } else { return null; } } /** * Builds the input form. */ class InputDialogue { private final JPanel form = new JPanel(); private int row; public InputDialogue() { form.setLayout(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); c.weightx = 1.0; c.weighty = 0.0; c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.NORTHWEST; c.insets = new Insets(Looks.DETAIL_FORM_BORDER, Looks.DETAIL_FORM_BORDER, Looks.DETAIL_FORM_BORDER, Looks.DETAIL_FORM_BORDER); c.gridx = 0; c.gridy = 0; } public void accept(FormWriter formWriter) { row = formWriter.writeTo(form, row); } public JPanel getForm() { return form; } } /** * Something that can add a line to the {@link InputDialogue}. * */ interface FormWriter { public int writeTo(Container container, int row); } /** * Create a {@link FormWriter} for the different {@link InputMedium} * input types. */ class FieldBuilder implements InputMedium { /** Holds the value of the input that will be set on pressing OK. */ private final AtomicReference<String> reference; /** Will be created for each input. */ private FormWriter formWriter; /** Validates each input. */ private Callable<Boolean> validator; /** Constructor. * * @param reference To set the input value with. */ public FieldBuilder(AtomicReference<String> reference) { this.reference = reference; } @Override public void confirm(String message, Boolean defaultValue) { final JLabel label = new JLabel(formatLabelText(message)); final JCheckBox toggle = new JCheckBox(); if (defaultValue != null) { toggle.setSelected(defaultValue.booleanValue()); } formWriter = new FormWriter() { @Override public int writeTo(Container container, int row) { GridBagConstraints c = new GridBagConstraints(); c.weightx = 0.3; c.weighty = 0.0; c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.NORTHWEST; c.gridx = 0; c.gridy = row; c.insets = new Insets(3, 3, 3, 20); container.add(label, c); c.weightx = 1.0; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.WEST; c.gridx = 1; c.gridwidth = GridBagConstraints.REMAINDER; c.insets = new Insets(3, 3, 3, 3); container.add(toggle, c); return row + 1; } }; validator = new Callable<Boolean>() { @Override public Boolean call() throws Exception { reference.set(new Boolean( toggle.isSelected()).toString()); return true; } }; } @Override public void password(String prompt) { final JLabel label = new JLabel(formatLabelText(prompt)); final JPasswordField text = new JPasswordField(Looks.TEXT_FIELD_SIZE); formWriter = new FormWriter() { @Override public int writeTo(Container container, int row) { GridBagConstraints c = new GridBagConstraints(); c.weightx = 0.3; c.weighty = 0.0; c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.NORTHWEST; c.gridx = 0; c.gridy = row; c.insets = new Insets(3, 3, 3, 20); container.add(label, c); c.weightx = 1.0; c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.WEST; c.gridx = 1; c.gridwidth = GridBagConstraints.REMAINDER; c.insets = new Insets(3, 3, 3, 3); container.add(text, c); return row + 1; } }; validator = new Callable<Boolean>() { @Override public Boolean call() throws Exception { reference.set(new String(text.getPassword())); return true; } }; } @Override public void prompt(String prompt, String defaultValue) { final JLabel label = new JLabel(formatLabelText(prompt)); final JTextField text = new JTextField(Looks.TEXT_FIELD_SIZE); text.setText(defaultValue); reference.set(defaultValue); formWriter = new FormWriter() { @Override public int writeTo(Container container, int row) { GridBagConstraints c = new GridBagConstraints(); c.weightx = 0.3; c.weighty = 0.0; c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.NORTHWEST; c.gridx = 0; c.gridy = row; c.insets = new Insets(3, 3, 3, 20); container.add(label, c); c.weightx = 1.0; c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.WEST; c.gridx = 1; c.gridwidth = GridBagConstraints.REMAINDER; c.insets = new Insets(3, 3, 3, 3); container.add(text, c); return row + 1; } }; validator = new Callable<Boolean>() { @Override public Boolean call() throws Exception { reference.set(new String(text.getText())); return true; } }; } public void message(String message) { final JLabel label = new JLabel(formatLabelText(message)); label.setAlignmentY(0.5f); formWriter = new FormWriter() { @Override public int writeTo(Container container, int row) { GridBagConstraints c = new GridBagConstraints(); c.weightx = 0.0; c.weighty = 0.0; c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.NORTH; c.gridx = 0; c.gridy = row; c.gridwidth = GridBagConstraints.REMAINDER; c.insets = new Insets(3, 3, 3, 3); container.add(label, c); return row + 1; } }; } @Override public void file(final String prompt, String defaultValue, final FileSelectionOptions options) { final JLabel label = new JLabel(formatLabelText(prompt)); final FileSelectionWidget chooser = new FileSelectionWidget(); if (defaultValue != null) { chooser.setSelectedFile(defaultValue); } chooser.setOptions(options); formWriter = new FormWriter() { @Override public int writeTo(Container container, int row) { GridBagConstraints c = new GridBagConstraints(); c.weightx = 0.3; c.weighty = 0.0; c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.NORTHWEST; c.gridx = 0; c.gridy = row; c.insets = new Insets(3, 3, 3, 20); container.add(label, c); c.weightx = 1.0; c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.WEST; c.gridx = 1; c.gridwidth = GridBagConstraints.REMAINDER; c.insets = new Insets(3, 3, 3, 3); container.add(chooser, c); return row + 1; } }; validator = new Callable<Boolean>() { @Override public Boolean call() throws Exception { String chosen = chooser.getSelectedFile(); if (chosen == null) { reference.set(null); } else { reference.set(new File(chosen).getCanonicalPath()); } return Boolean.TRUE; } }; } public FormWriter getFormWriter() { return formWriter; } public Callable<Boolean> getValidator() { return validator; } } /** * Responsible for displaying the dialogue. */ class DialogManager { /** True when OK pressed. */ private boolean chosen; public boolean isChosen() { return chosen; } /** * Show the form on an OK/CANCEL dialogue. * * @param form The form component. */ public void showDialog(Component form, Callable<Boolean> okAction) { chosen = DialogueHelper.showOKCancelDialogue( parent, form, okAction); } } static String formatLabelText(String labelText) { if (labelText.contains("\n")) { return "<html>" + labelText.replaceAll("\\n", "<br/>") + "</html>"; } else { return labelText; } } @Override public String toString() { return getClass().getSimpleName(); } }