From 0877d6f5485d3531b9fde6c264e5848630c80baf Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Fri, 17 May 2019 18:47:13 +0200 Subject: [PATCH] ConfigItem: add all types except LOCALE (array still not working) --- src/be/nikiroo/utils/resources/Meta.java | 15 +- src/be/nikiroo/utils/resources/MetaInfo.java | 31 +- src/be/nikiroo/utils/ui/ConfigItem.java | 431 ++++++++++++++----- 3 files changed, 368 insertions(+), 109 deletions(-) diff --git a/src/be/nikiroo/utils/resources/Meta.java b/src/be/nikiroo/utils/resources/Meta.java index a83bcca..f316df4 100644 --- a/src/be/nikiroo/utils/resources/Meta.java +++ b/src/be/nikiroo/utils/resources/Meta.java @@ -47,16 +47,6 @@ public @interface Meta { * option to enter a not accounted for value). */ COMBO_LIST, - /** - * A list of {@link Format#STRING}s. - *

- * The list items are separated by a comma, each surrounded by - * double-quotes, with backslashes and double-quotes escaped by a - * backslash. - *

- * Example: "un", "deux" - */ - LIST_OF_STRINGS, } /** @@ -109,6 +99,11 @@ public @interface Meta { /** * This item is a comma-separated list of values instead of a single value. + *

+ * The list items are separated by a comma, each surrounded by + * double-quotes, with backslashes and double-quotes escaped by a backslash. + *

+ * Example: "un", "deux" * * @return TRUE if it is */ diff --git a/src/be/nikiroo/utils/resources/MetaInfo.java b/src/be/nikiroo/utils/resources/MetaInfo.java index 746fd4d..d95e98c 100644 --- a/src/be/nikiroo/utils/resources/MetaInfo.java +++ b/src/be/nikiroo/utils/resources/MetaInfo.java @@ -1,6 +1,7 @@ package be.nikiroo.utils.resources; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -17,11 +18,12 @@ import be.nikiroo.utils.resources.Meta.Format; * @param * the type of {@link Bundle} to edit */ -public class MetaInfo> { +public class MetaInfo> implements Iterable> { private final Bundle bundle; private final E id; private Meta meta; + private List> children = new ArrayList>(); private String value; private List reloadedListeners = new ArrayList(); @@ -53,8 +55,14 @@ public class MetaInfo> { if (description == null) { description = meta.description(); + if (description == null) { + description = ""; + } if (meta.info() != null && !meta.info().isEmpty()) { - description += " (" + meta.info() + ")"; + if (!description.isEmpty()) { + description += "\n\n"; + } + description += meta.info(); } } @@ -94,6 +102,16 @@ public class MetaInfo> { return meta.format(); } + // for ComboBox, this is mostly a suggestion + public String[] getAllowedValues() { + return meta.list(); + } + + // TODO: use it! + public boolean isArray() { + return meta.array(); + } + /** * The value stored by this item, as a {@link String}. * @@ -217,6 +235,15 @@ public class MetaInfo> { saveListeners.add(listener); } + @Override + public Iterator> iterator() { + return children.iterator(); + } + + public List> getChildren() { + return children; + } + /** * Create a list of {@link MetaInfo}, one for each of the item in the given * {@link Bundle}. diff --git a/src/be/nikiroo/utils/ui/ConfigItem.java b/src/be/nikiroo/utils/ui/ConfigItem.java index 6afbb94..95de836 100644 --- a/src/be/nikiroo/utils/ui/ConfigItem.java +++ b/src/be/nikiroo/utils/ui/ConfigItem.java @@ -7,18 +7,27 @@ import java.awt.Graphics2D; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; +import java.io.File; import javax.swing.Icon; import javax.swing.ImageIcon; +import javax.swing.InputVerifier; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JColorChooser; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JFileChooser; import javax.swing.JLabel; +import javax.swing.JOptionPane; import javax.swing.JPanel; +import javax.swing.JPasswordField; import javax.swing.JTextField; +import javax.swing.plaf.basic.BasicArrowButton; +import be.nikiroo.utils.StringUtils; +import be.nikiroo.utils.StringUtils.Alignment; import be.nikiroo.utils.resources.Bundle; -import be.nikiroo.utils.resources.Meta.Format; import be.nikiroo.utils.resources.MetaInfo; /** @@ -33,123 +42,324 @@ import be.nikiroo.utils.resources.MetaInfo; public class ConfigItem> extends JPanel { private static final long serialVersionUID = 1L; - public ConfigItem(final MetaInfo info) { + public ConfigItem(MetaInfo info) { this.setLayout(new BorderLayout()); - if (info.getFormat() == Format.BOOLEAN) { - final JCheckBox field = new JCheckBox(); - field.setToolTipText(info.getDescription()); - Boolean state = info.getBoolean(); - if (state == null) { - info.getDefaultBoolean(); - } + switch (info.getFormat()) { + case BOOLEAN: + addBooleanField(info); + break; + case COLOR: + addColorField(info); + break; + case FILE: + addBrowseField(info, false); + break; + case DIRECTORY: + addBrowseField(info, true); + break; + case COMBO_LIST: + addComboboxField(info, true); + break; + case FIXED_LIST: + addComboboxField(info, false); + break; + case INT: + addIntField(info); + break; + case PASSWORD: + addPasswordField(info); + break; + case STRING: + case LOCALE: // TODO? + default: + addStringField(info); + break; + } + } - // Should not happen! - if (state == null) { - System.err - .println("No default value given for BOOLEAN parameter \"" - + info.getName() - + "\", we consider it is FALSE"); - state = false; + private void addStringField(final MetaInfo info) { + final JTextField field = new JTextField(); + field.setToolTipText(info.getDescription()); + field.setText(info.getString()); + + info.addReloadedListener(new Runnable() { + @Override + public void run() { + field.setText(info.getString()); + } + }); + info.addSaveListener(new Runnable() { + @Override + public void run() { + info.setString(field.getText()); } + }); - field.setSelected(state); + this.add(label(info), BorderLayout.WEST); + this.add(field, BorderLayout.CENTER); + } - info.addReloadedListener(new Runnable() { - @Override - public void run() { - Boolean state = info.getBoolean(); - if (state == null) { - info.getDefaultBoolean(); - } - if (state == null) { - state = false; - } + private void addBooleanField(final MetaInfo info) { + final JCheckBox field = new JCheckBox(); + field.setToolTipText(info.getDescription()); + Boolean state = info.getBoolean(); + if (state == null) { + info.getDefaultBoolean(); + } - field.setSelected(state); + // Should not happen! + if (state == null) { + System.err + .println("No default value given for BOOLEAN parameter \"" + + info.getName() + "\", we consider it is FALSE"); + state = false; + } + + field.setSelected(state); + + info.addReloadedListener(new Runnable() { + @Override + public void run() { + Boolean state = info.getBoolean(); + if (state == null) { + info.getDefaultBoolean(); } - }); - info.addSaveListener(new Runnable() { - @Override - public void run() { - info.setBoolean(field.isSelected()); + if (state == null) { + state = false; } - }); - - field.setText(info.getName()); - this.add(field, BorderLayout.CENTER); - } else if (info.getFormat() == Format.COLOR) { - final JTextField field = new JTextField(); - field.setToolTipText(info.getDescription()); - field.setText(info.getString()); - - info.addReloadedListener(new Runnable() { - @Override - public void run() { + + field.setSelected(state); + } + }); + info.addSaveListener(new Runnable() { + @Override + public void run() { + info.setBoolean(field.isSelected()); + } + }); + + field.setText(info.getName()); + this.add(field, BorderLayout.CENTER); + } + + private void addColorField(final MetaInfo info) { + final JTextField field = new JTextField(); + field.setToolTipText(info.getDescription()); + field.setText(info.getString()); + + info.addReloadedListener(new Runnable() { + @Override + public void run() { + field.setText(info.getString()); + } + }); + info.addSaveListener(new Runnable() { + @Override + public void run() { + info.setString(field.getText()); + } + }); + + this.add(label(info), BorderLayout.WEST); + JPanel pane = new JPanel(new BorderLayout()); + + final JButton colorWheel = new JButton(); + colorWheel.setIcon(getIcon(17, info.getColor())); + colorWheel.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + Color initialColor = new Color(info.getColor(), true); + Color newColor = JColorChooser.showDialog(ConfigItem.this, + info.getName(), initialColor); + if (newColor != null) { + info.setColor(newColor.getRGB()); field.setText(info.getString()); + colorWheel.setIcon(getIcon(17, info.getColor())); } - }); - info.addSaveListener(new Runnable() { - @Override - public void run() { - info.setString(field.getText()); - } - }); - - this.add(label(info.getName()), BorderLayout.WEST); - JPanel pane = new JPanel(new BorderLayout()); - - final JButton colorWheel = new JButton(); - colorWheel.setIcon(getIcon(17, info.getColor())); - colorWheel.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - Color initialColor = new Color(info.getColor(), true); - Color newColor = JColorChooser.showDialog(ConfigItem.this, - info.getName(), initialColor); - if (newColor != null) { - info.setColor(newColor.getRGB()); + } + }); + pane.add(colorWheel, BorderLayout.WEST); + pane.add(field, BorderLayout.CENTER); + this.add(pane, BorderLayout.CENTER); + } + + private void addBrowseField(final MetaInfo info, final boolean dir) { + final JTextField field = new JTextField(); + field.setToolTipText(info.getDescription()); + field.setText(info.getString()); + + info.addReloadedListener(new Runnable() { + @Override + public void run() { + field.setText(info.getString()); + } + }); + info.addSaveListener(new Runnable() { + @Override + public void run() { + info.setString(field.getText()); + } + }); + + 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) { + info.setString(file.getAbsolutePath()); field.setText(info.getString()); - colorWheel.setIcon(getIcon(17, info.getColor())); } } - }); - pane.add(colorWheel, BorderLayout.WEST); - pane.add(field, BorderLayout.CENTER); - this.add(pane, BorderLayout.CENTER); - } else { - final JTextField field = new JTextField(); - field.setToolTipText(info.getDescription()); - field.setText(info.getString()); - - info.addReloadedListener(new Runnable() { - @Override - public void run() { - field.setText(info.getString()); + } + }); + + JPanel pane = new JPanel(new BorderLayout()); + this.add(label(info), BorderLayout.WEST); + pane.add(browseButton, BorderLayout.WEST); + pane.add(field, BorderLayout.CENTER); + this.add(pane, BorderLayout.CENTER); + } + + private void addComboboxField(final MetaInfo info, boolean editable) { + // rawtypes for Java 1.6 (and 1.7 ?) support + @SuppressWarnings({ "rawtypes", "unchecked" }) + final JComboBox field = new JComboBox(info.getAllowedValues()); + field.setEditable(editable); + field.setSelectedItem(info.getString()); + + info.addReloadedListener(new Runnable() { + @Override + public void run() { + field.setSelectedItem(info.getString()); + } + }); + info.addSaveListener(new Runnable() { + @Override + public void run() { + info.setString(field.getSelectedItem().toString()); + } + }); + + this.add(label(info), BorderLayout.WEST); + this.add(field, BorderLayout.CENTER); + } + + private void addPasswordField(final MetaInfo info) { + final JPasswordField field = new JPasswordField(); + field.setToolTipText(info.getDescription()); + field.setText(info.getString()); + + info.addReloadedListener(new Runnable() { + @Override + public void run() { + field.setText(info.getString()); + } + }); + info.addSaveListener(new Runnable() { + @Override + public void run() { + info.setString(new String(field.getPassword())); + } + }); + + this.add(label(info), BorderLayout.WEST); + this.add(field, BorderLayout.CENTER); + } + + private void addIntField(final MetaInfo info) { + final JTextField field = new JTextField(); + field.setToolTipText(info.getDescription()); + field.setText(info.getString()); + field.setInputVerifier(new InputVerifier() { + @Override + public boolean verify(JComponent input) { + String text = field.getText().trim(); + if (text.startsWith("-")) { + text = text.substring(1).trim(); } - }); - info.addSaveListener(new Runnable() { - @Override - public void run() { - info.setString(field.getText()); + + return text.replaceAll("[0-9]", "").isEmpty(); + } + }); + + info.addReloadedListener(new Runnable() { + @Override + public void run() { + field.setText(info.getString()); + } + }); + info.addSaveListener(new Runnable() { + @Override + public void run() { + info.setString(field.getText()); + Integer value = info.getInteger(); + if (value == null) { + info.setString(""); + } else { + info.setInteger(value); } - }); + field.setText(info.getString()); + } + }); - this.add(label(info.getName()), BorderLayout.WEST); - this.add(field, BorderLayout.CENTER); - } + JButton up = new BasicArrowButton(BasicArrowButton.NORTH); + JButton down = new BasicArrowButton(BasicArrowButton.SOUTH); + + up.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent ae) { + int value = 0; + try { + value = Integer.parseInt(field.getText()); + } catch (NumberFormatException e) { + } + + field.setText(Integer.toString(value + 1)); + } + }); + + down.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent ae) { + int value = 0; + try { + value = Integer.parseInt(field.getText()); + } catch (NumberFormatException e) { + } + + field.setText(Integer.toString(value - 1)); + } + }); + + JPanel upDown = new JPanel(new BorderLayout()); + upDown.add(up, BorderLayout.NORTH); + upDown.add(down, BorderLayout.SOUTH); + + JPanel pane = new JPanel(new BorderLayout()); + pane.add(upDown, BorderLayout.WEST); + pane.add(field, BorderLayout.CENTER); + + this.add(label(info), BorderLayout.WEST); + this.add(pane, BorderLayout.CENTER); } /** * Create a label which width is constrained in lock steps. * - * @param text - * the text of the label + * @param info + * the {@link MetaInfo} for which we want to add a label * * @return the label */ - private JLabel label(String text) { - final JLabel label = new JLabel(text); + private JComponent label(final MetaInfo info) { + final JLabel label = new JLabel(info.getName()); Dimension ps = label.getPreferredSize(); if (ps == null) { @@ -165,11 +375,38 @@ public class ConfigItem> extends JPanel { } } - ps.width = w; - label.setSize(ps); - label.setPreferredSize(ps); + // TODO: image + JButton help = new JButton("?"); + help.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + StringBuilder builder = new StringBuilder(); + String text = info.getDescription().replace("\\n", "\n"); + for (String line : StringUtils.justifyText(text, 80, + Alignment.LEFT)) { + if (builder.length() > 0) { + builder.append("\n"); + } + builder.append(line); + } + text = builder.toString(); + JOptionPane.showMessageDialog(ConfigItem.this, text); + } + }); + + JPanel pane2 = new JPanel(new BorderLayout()); + pane2.add(help, BorderLayout.WEST); + pane2.add(new JLabel(" "), BorderLayout.CENTER); + + JPanel pane = new JPanel(new BorderLayout()); + pane.add(label, BorderLayout.WEST); + pane.add(pane2, BorderLayout.CENTER); + + ps.width = w + 30; // 30 for the (?) sign + pane.setSize(ps); + pane.setPreferredSize(ps); - return label; + return pane; } /** -- 2.27.0