| 1 | package be.nikiroo.utils.ui; |
| 2 | |
| 3 | import java.awt.BorderLayout; |
| 4 | import java.awt.Color; |
| 5 | import java.awt.event.ActionEvent; |
| 6 | import java.awt.event.ActionListener; |
| 7 | import java.io.IOException; |
| 8 | import java.util.ArrayList; |
| 9 | import java.util.List; |
| 10 | |
| 11 | import javax.swing.BoxLayout; |
| 12 | import javax.swing.JButton; |
| 13 | import javax.swing.JComponent; |
| 14 | import javax.swing.JLabel; |
| 15 | import javax.swing.JPanel; |
| 16 | import javax.swing.JScrollPane; |
| 17 | import javax.swing.JTextArea; |
| 18 | import javax.swing.border.EmptyBorder; |
| 19 | import javax.swing.border.TitledBorder; |
| 20 | |
| 21 | import be.nikiroo.utils.StringUtils; |
| 22 | import be.nikiroo.utils.resources.Bundle; |
| 23 | import be.nikiroo.utils.resources.MetaInfo; |
| 24 | |
| 25 | /** |
| 26 | * A configuration panel for a {@link Bundle}. |
| 27 | * <p> |
| 28 | * All the items in the given {@link Bundle} will be displayed in editable |
| 29 | * controls, with options to Save, Reset and/or Reset to the application default |
| 30 | * values. |
| 31 | * |
| 32 | * @author niki |
| 33 | * |
| 34 | * @param <E> |
| 35 | * the type of {@link Bundle} to edit |
| 36 | */ |
| 37 | public class ConfigEditor<E extends Enum<E>> extends JPanel { |
| 38 | private static final long serialVersionUID = 1L; |
| 39 | private List<MetaInfo<E>> items; |
| 40 | |
| 41 | /** |
| 42 | * Create a new {@link ConfigEditor} for this {@link Bundle}. |
| 43 | * |
| 44 | * @param type |
| 45 | * a class instance of the item type to work on |
| 46 | * @param bundle |
| 47 | * the {@link Bundle} to sort through |
| 48 | * @param title |
| 49 | * the title to display before the options |
| 50 | */ |
| 51 | public ConfigEditor(Class<E> type, final Bundle<E> bundle, String title) { |
| 52 | this.setLayout(new BorderLayout()); |
| 53 | |
| 54 | JPanel main = new JPanel(); |
| 55 | main.setLayout(new BoxLayout(main, BoxLayout.PAGE_AXIS)); |
| 56 | main.setBorder(new EmptyBorder(5, 5, 5, 5)); |
| 57 | |
| 58 | main.add(new JLabel(title)); |
| 59 | |
| 60 | items = new ArrayList<MetaInfo<E>>(); |
| 61 | List<MetaInfo<E>> groupedItems = MetaInfo.getItems(type, bundle); |
| 62 | for (MetaInfo<E> item : groupedItems) { |
| 63 | // will init this.items |
| 64 | addItem(main, item, 0); |
| 65 | } |
| 66 | |
| 67 | JPanel buttons = new JPanel(); |
| 68 | buttons.setLayout(new BoxLayout(buttons, BoxLayout.PAGE_AXIS)); |
| 69 | buttons.setBorder(new EmptyBorder(5, 5, 5, 5)); |
| 70 | |
| 71 | buttons.add(createButton("Reset", new ActionListener() { |
| 72 | @Override |
| 73 | public void actionPerformed(ActionEvent e) { |
| 74 | for (MetaInfo<E> item : items) { |
| 75 | item.reload(); |
| 76 | } |
| 77 | } |
| 78 | })); |
| 79 | |
| 80 | buttons.add(createButton("Default", new ActionListener() { |
| 81 | @Override |
| 82 | public void actionPerformed(ActionEvent e) { |
| 83 | Object snap = bundle.takeSnapshot(); |
| 84 | bundle.reload(true); |
| 85 | for (MetaInfo<E> item : items) { |
| 86 | item.reload(); |
| 87 | } |
| 88 | bundle.reload(false); |
| 89 | bundle.restoreSnapshot(snap); |
| 90 | } |
| 91 | })); |
| 92 | |
| 93 | buttons.add(createButton("Save", new ActionListener() { |
| 94 | @Override |
| 95 | public void actionPerformed(ActionEvent e) { |
| 96 | for (MetaInfo<E> item : items) { |
| 97 | item.save(true); |
| 98 | } |
| 99 | |
| 100 | try { |
| 101 | bundle.updateFile(); |
| 102 | } catch (IOException e1) { |
| 103 | e1.printStackTrace(); |
| 104 | } |
| 105 | } |
| 106 | })); |
| 107 | |
| 108 | JScrollPane scroll = new JScrollPane(main); |
| 109 | scroll.getVerticalScrollBar().setUnitIncrement(16); |
| 110 | |
| 111 | this.add(scroll, BorderLayout.CENTER); |
| 112 | this.add(buttons, BorderLayout.SOUTH); |
| 113 | } |
| 114 | |
| 115 | private void addItem(JPanel main, MetaInfo<E> item, int nhgap) { |
| 116 | if (item.isGroup()) { |
| 117 | JPanel bpane = new JPanel(new BorderLayout()); |
| 118 | bpane.setBorder(new TitledBorder(item.getName())); |
| 119 | JPanel pane = new JPanel(); |
| 120 | pane.setBorder(new EmptyBorder(5, 5, 5, 5)); |
| 121 | pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS)); |
| 122 | |
| 123 | String info = item.getDescription(); |
| 124 | info = StringUtils.justifyTexts(info, 100); |
| 125 | if (!info.isEmpty()) { |
| 126 | info = info + "\n"; |
| 127 | JTextArea text = new JTextArea(info); |
| 128 | text.setWrapStyleWord(true); |
| 129 | text.setOpaque(false); |
| 130 | text.setForeground(new Color(100, 100, 180)); |
| 131 | text.setEditable(false); |
| 132 | pane.add(text); |
| 133 | } |
| 134 | |
| 135 | for (MetaInfo<E> subitem : item) { |
| 136 | addItem(pane, subitem, nhgap + 11); |
| 137 | } |
| 138 | bpane.add(pane, BorderLayout.CENTER); |
| 139 | main.add(bpane); |
| 140 | } else { |
| 141 | items.add(item); |
| 142 | main.add(ConfigItem.createItem(item, nhgap)); |
| 143 | } |
| 144 | } |
| 145 | |
| 146 | /** |
| 147 | * Add an action button for this action. |
| 148 | * |
| 149 | * @param title |
| 150 | * the action title |
| 151 | * @param listener |
| 152 | * the action |
| 153 | */ |
| 154 | private JComponent createButton(String title, ActionListener listener) { |
| 155 | JButton button = new JButton(title); |
| 156 | button.addActionListener(listener); |
| 157 | |
| 158 | JPanel panel = new JPanel(); |
| 159 | panel.setLayout(new BorderLayout()); |
| 160 | panel.setBorder(new EmptyBorder(2, 10, 2, 10)); |
| 161 | panel.add(button, BorderLayout.CENTER); |
| 162 | |
| 163 | return panel; |
| 164 | } |
| 165 | } |