+ private void addBrowseField(final MetaInfo<E> info, int nhgap,
+ final boolean dir) {
+ final JTextField field = new JTextField();
+ field.setToolTipText(info.getDescription());
+ String value = info.getString(false);
+ reload(value);
+ field.setText(value);
+
+ info.addReloadedListener(new Runnable() {
+ @Override
+ public void run() {
+ String value = info.getString(false);
+ reload(value);
+ field.setText(value);
+ }
+ });
+ info.addSaveListener(new Runnable() {
+ @Override
+ public void run() {
+ String value = field.getText();
+ if (isChanged(value)) {
+ info.setString(value);
+ }
+ }
+ });
+
+ JButton browseButton = new JButton("...");
+ browseButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ JFileChooser chooser = new JFileChooser();
+ chooser.setCurrentDirectory(null);
+ chooser.setFileSelectionMode(dir ? JFileChooser.DIRECTORIES_ONLY
+ : JFileChooser.FILES_ONLY);
+ if (chooser.showOpenDialog(ConfigItem.this) == JFileChooser.APPROVE_OPTION) {
+ File file = chooser.getSelectedFile();
+ if (file != null) {
+ String value = file.getAbsolutePath();
+ if (isChanged(value)) {
+ info.setString(value);
+ }
+ field.setText(value);
+ }
+ }
+ }
+ });
+
+ JPanel pane = new JPanel(new BorderLayout());
+ this.add(label(info, nhgap), BorderLayout.WEST);
+ pane.add(browseButton, BorderLayout.WEST);
+ pane.add(field, BorderLayout.CENTER);
+ this.add(pane, BorderLayout.CENTER);
+
+ setPreferredSize(pane);
+ }
+
+ private void addComboboxField(final MetaInfo<E> info, int nhgap,
+ boolean editable) {
+ // rawtypes for Java 1.6 (and 1.7 ?) support
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ final JComboBox field = new JComboBox(info.getAllowedValues());
+ field.setEditable(editable);
+ String value = info.getString(false);
+ reload(value);
+ field.setSelectedItem(value);
+
+ info.addReloadedListener(new Runnable() {
+ @Override
+ public void run() {
+ String value = info.getString(false);
+ reload(value);
+ field.setSelectedItem(value);
+ }
+ });
+ info.addSaveListener(new Runnable() {
+ @Override
+ public void run() {
+ Object item = field.getSelectedItem();
+ String value = item == null ? null : item.toString();
+ if (isChanged(value)) {
+ info.setString(value);
+ }
+ }
+ });
+
+ this.add(label(info, nhgap), BorderLayout.WEST);
+ this.add(field, BorderLayout.CENTER);
+
+ setPreferredSize(field);
+ }
+
+ private void addPasswordField(final MetaInfo<E> info, int nhgap) {
+ final JPasswordField field = new JPasswordField();
+ field.setToolTipText(info.getDescription());
+ String value = info.getString(false);
+ reload(value);
+ field.setText(value);
+
+ info.addReloadedListener(new Runnable() {
+ @Override
+ public void run() {
+ String value = info.getString(false);
+ reload(value);
+ field.setText(value);
+ }
+ });
+ info.addSaveListener(new Runnable() {
+ @Override
+ public void run() {
+ String value = new String(field.getPassword());
+ if (isChanged(value)) {
+ info.setString(value);
+ }
+ }
+ });
+
+ this.add(label(info, nhgap), BorderLayout.WEST);
+ this.add(field, BorderLayout.CENTER);
+
+ setPreferredSize(field);
+ }
+
+ private void addIntField(final MetaInfo<E> info, int nhgap) {
+ final JSpinner field = new JSpinner();
+ field.setToolTipText(info.getDescription());
+ int value = info.getInteger(true) == null ? 0 : info.getInteger(true);
+ reload(value);
+ field.setValue(value);
+
+ info.addReloadedListener(new Runnable() {
+ @Override
+ public void run() {
+ int value = info.getInteger(true) == null ? 0 : info
+ .getInteger(true);
+ reload(value);
+ field.setValue(value);
+ }
+ });
+ info.addSaveListener(new Runnable() {
+ @Override
+ public void run() {
+ int value = field.getValue() == null ? 0 : (Integer) field
+ .getValue();
+ if (isChanged(value)) {
+ info.setInteger(value);
+ }
+ }
+ });
+
+ this.add(label(info, nhgap), BorderLayout.WEST);
+ this.add(field, BorderLayout.CENTER);
+
+ setPreferredSize(field);
+ }
+
+ /**
+ * Create a label which width is constrained in lock steps.
+ *
+ * @param info
+ * the {@link MetaInfo} for which we want to add a label
+ * @param nhgap
+ * negative horisontal gap in pixel to use for the label, i.e.,
+ * the step lock sized labels will start smaller by that amount
+ * (the use case would be to align controls that start at a
+ * different horisontal position)
+ *
+ * @return the label
+ */
+ private JComponent label(final MetaInfo<E> info, int nhgap) {
+ final JLabel label = new JLabel(info.getName());
+
+ Dimension ps = label.getPreferredSize();
+ if (ps == null) {
+ ps = label.getSize();
+ }
+
+ ps.height = Math.max(ps.height, getMinimumHeight());
+
+ int w = ps.width;
+ int step = 150;
+ for (int i = 2 * step - nhgap; i < 10 * step; i += step) {
+ if (w < i) {
+ w = i;
+ break;
+ }