package usr.erichschroeter.jpreferences; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.util.prefs.Preferences; import javax.swing.AbstractAction; import javax.swing.GroupLayout; import javax.swing.GroupLayout.Alignment; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.table.TableModel; /** * A <code>PreferenceTable</code> displays {@link Preferences} in a table. It * allows different features to be enabled/disabled which change the way the * user can interact with preferences. * * @author Erich Schroeter */ @SuppressWarnings("serial") public class PreferenceTable extends JTable { /** The action that handles deleting preferences. */ private AbstractAction deleteAction = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { deleteRows(getSelectedRows()); } }; /** The action that handles adding preferences. */ private AbstractAction addAction = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { newPreference(); } }; /** * Constructs a default <code>PreferenceTable</code>. * <p> * This is equivalent to <code></code>. */ public PreferenceTable() { super(); initialize(); } /** * Initialize the features to be allowed by default. Bind keys to actions. */ protected void initialize() { // bind the Ctrl + D and Del key strokes to delete preferences bindDeleteKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), KeyStroke .getKeyStroke(KeyEvent.VK_D, InputEvent.CTRL_DOWN_MASK)); // bind the Ctrl + N key stroke to add preferences bindAddKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_DOWN_MASK)); // adding a preference can be handled a couple different ways // 1. add a row and let the user modify the values // 2. show dialog asking user for key and value // we are choosing to implement option 2 here } /** * Returns the table model for this table as a * <code>PreferenceTableModel</code>. * * @return the table model * @throws ClassCastException * if the {@link #getModel()} does not return a * <code>PreferenceTableModel</code> */ public PreferenceTableModel getPreferenceTableModel() { return (PreferenceTableModel) getModel(); } /** * Handles adding a new preference. This displays a dialog for the user to * enter a key and value. */ public void newPreference() { JPanel form = createPreferenceForm(); int selectedValue = JOptionPane.showConfirmDialog(this, form, "New Preference", JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE); if (selectedValue == JOptionPane.YES_OPTION) { String key = null; String value = null; // get the entered values for (Component c : form.getComponents()) { String name = c.getName(); if (name != null && name.equals("key")) { key = ((JTextField) c).getText(); } if (name != null && name.equals("value")) { value = ((JTextField) c).getText(); } } if (value == null) { value = ""; } // the key cannot be empty, but the value can if (key != null && !key.equals("")) { addRow(key, value); System.out.println("added [" + key + ", " + value + "]"); } } } protected JPanel createPreferenceForm() { JPanel form = new JPanel(); GroupLayout layout = new GroupLayout(form); form.setLayout(layout); JLabel keyLabel = new JLabel("Key:"); keyLabel.setToolTipText("cannot be empty"); JTextField keyField = new JTextField(10); keyField.setName("key"); JLabel valueLabel = new JLabel("Value:"); JTextField valueField = new JTextField(10); valueField.setName("value"); layout.setAutoCreateContainerGaps(true); layout.setAutoCreateGaps(true); layout.setHorizontalGroup(layout .createSequentialGroup() .addGroup( layout.createParallelGroup(Alignment.LEADING) .addComponent(keyLabel) .addComponent(valueLabel)) .addGroup( layout.createParallelGroup(Alignment.LEADING) .addComponent(keyField) .addComponent(valueField))); layout.setVerticalGroup(layout .createSequentialGroup() .addGroup( layout.createParallelGroup(Alignment.BASELINE) .addComponent(keyLabel).addComponent(keyField)) .addGroup( layout.createParallelGroup(Alignment.LEADING) .addComponent(valueLabel) .addComponent(valueField))); return form; } /** * Binds the specified key strokes to delete preferences. * * @see #unbindKeyStroke(KeyStroke...) * @param keyStrokes * key strokes for deleting preferences */ public void bindDeleteKeyStroke(KeyStroke... keyStrokes) { for (KeyStroke k : keyStrokes) { getInputMap().put(k, k.toString()); getActionMap().put(k.toString(), deleteAction); } } /** * Binds the specified key strokes to add preferences. * * @see #unbindKeyStroke(KeyStroke...) * @param keyStrokes * key strokes for adding preferences */ public void bindAddKeyStroke(KeyStroke... keyStrokes) { for (KeyStroke k : keyStrokes) { getInputMap().put(k, k.toString()); getActionMap().put(k.toString(), addAction); } } /** * Unbinds the specified key strokes from its action. This can be used for * unbinding key strokes bound from {@link #bindAddKeyStroke(KeyStroke...)} * and {@link #bindDeleteKeyStroke(KeyStroke...)}. * * @see #bindAddKeyStroke(KeyStroke...) * @see #bindDeleteKeyStroke(KeyStroke...) * @param keyStrokes * key strokes for adding preferences */ public void unbindKeyStroke(KeyStroke... keyStrokes) { for (KeyStroke k : keyStrokes) { getInputMap().remove(k); getActionMap().remove(k.toString()); } } public void deleteRows(int... rows) { if (getPreferenceTableModel().isDeleteAllowed()) { TableModel model = getModel(); if (model instanceof PreferenceTableModel) { PreferenceTableModel prefModel = (PreferenceTableModel) model; for (int i = 0; i < rows.length; i++) { prefModel.removeRow(rows[i]); } } } } public void addRow(String key, Object value) { if (getPreferenceTableModel().isAddAllowed()) { TableModel model = getModel(); if (model instanceof PreferenceTableModel) { PreferenceTableModel prefModel = (PreferenceTableModel) model; prefModel.addPreference(key, value); } } } }