9769ab164eb7e1377b34d744bb10873ac3ce8d51
1 package be
.nikiroo
.utils
.ui
;
3 import java
.awt
.BorderLayout
;
5 import java
.awt
.Dimension
;
6 import java
.awt
.Graphics2D
;
7 import java
.awt
.event
.ActionEvent
;
8 import java
.awt
.event
.ActionListener
;
9 import java
.awt
.image
.BufferedImage
;
12 import javax
.swing
.Icon
;
13 import javax
.swing
.ImageIcon
;
14 import javax
.swing
.InputVerifier
;
15 import javax
.swing
.JButton
;
16 import javax
.swing
.JCheckBox
;
17 import javax
.swing
.JColorChooser
;
18 import javax
.swing
.JComboBox
;
19 import javax
.swing
.JComponent
;
20 import javax
.swing
.JFileChooser
;
21 import javax
.swing
.JLabel
;
22 import javax
.swing
.JOptionPane
;
23 import javax
.swing
.JPanel
;
24 import javax
.swing
.JPasswordField
;
25 import javax
.swing
.JTextField
;
26 import javax
.swing
.plaf
.basic
.BasicArrowButton
;
28 import be
.nikiroo
.utils
.StringUtils
;
29 import be
.nikiroo
.utils
.StringUtils
.Alignment
;
30 import be
.nikiroo
.utils
.resources
.Bundle
;
31 import be
.nikiroo
.utils
.resources
.Meta
.Format
;
32 import be
.nikiroo
.utils
.resources
.MetaInfo
;
35 * A graphical item that reflect a configuration option from the given
38 * This graphical item can be edited, and the result will be saved back into the
39 * linked {@link MetaInfo}; you still have to save the {@link MetaInfo} should
40 * you wish to, of course.
45 * the type of {@link Bundle} to edit
47 public class ConfigItem
<E
extends Enum
<E
>> extends JPanel
{
48 private static final long serialVersionUID
= 1L;
51 * Create a new {@link ConfigItem} for the given {@link MetaInfo}.
54 * the {@link MetaInfo}
56 public ConfigItem(MetaInfo
<E
> info
) {
57 this.setLayout(new BorderLayout());
59 // TODO: support arrays
60 Format fmt
= info
.getFormat();
67 addBooleanField(info
);
73 addBrowseField(info
, false);
76 addBrowseField(info
, true);
79 addComboboxField(info
, true);
82 addComboboxField(info
, false);
88 addPasswordField(info
);
98 private void addStringField(final MetaInfo
<E
> info
) {
99 final JTextField field
= new JTextField();
100 field
.setToolTipText(info
.getDescription());
101 field
.setText(info
.getString());
103 info
.addReloadedListener(new Runnable() {
106 field
.setText(info
.getString());
109 info
.addSaveListener(new Runnable() {
112 info
.setString(field
.getText());
116 this.add(label(info
), BorderLayout
.WEST
);
117 this.add(field
, BorderLayout
.CENTER
);
120 private void addBooleanField(final MetaInfo
<E
> info
) {
121 final JCheckBox field
= new JCheckBox();
122 field
.setToolTipText(info
.getDescription());
123 Boolean state
= info
.getBoolean();
125 info
.getDefaultBoolean();
128 // Should not happen!
131 .println("No default value given for BOOLEAN parameter \""
132 + info
.getName() + "\", we consider it is FALSE");
136 field
.setSelected(state
);
138 info
.addReloadedListener(new Runnable() {
141 Boolean state
= info
.getBoolean();
143 info
.getDefaultBoolean();
149 field
.setSelected(state
);
152 info
.addSaveListener(new Runnable() {
155 info
.setBoolean(field
.isSelected());
159 field
.setText(info
.getName());
160 this.add(field
, BorderLayout
.CENTER
);
163 private void addColorField(final MetaInfo
<E
> info
) {
164 final JTextField field
= new JTextField();
165 field
.setToolTipText(info
.getDescription());
166 field
.setText(info
.getString());
168 info
.addReloadedListener(new Runnable() {
171 field
.setText(info
.getString());
174 info
.addSaveListener(new Runnable() {
177 info
.setString(field
.getText());
181 this.add(label(info
), BorderLayout
.WEST
);
182 JPanel pane
= new JPanel(new BorderLayout());
184 final JButton colorWheel
= new JButton();
185 colorWheel
.setIcon(getIcon(17, info
.getColor()));
186 colorWheel
.addActionListener(new ActionListener() {
188 public void actionPerformed(ActionEvent e
) {
189 Color initialColor
= new Color(info
.getColor(), true);
190 Color newColor
= JColorChooser
.showDialog(ConfigItem
.this,
191 info
.getName(), initialColor
);
192 if (newColor
!= null) {
193 info
.setColor(newColor
.getRGB());
194 field
.setText(info
.getString());
195 colorWheel
.setIcon(getIcon(17, info
.getColor()));
199 pane
.add(colorWheel
, BorderLayout
.WEST
);
200 pane
.add(field
, BorderLayout
.CENTER
);
201 this.add(pane
, BorderLayout
.CENTER
);
204 private void addBrowseField(final MetaInfo
<E
> info
, final boolean dir
) {
205 final JTextField field
= new JTextField();
206 field
.setToolTipText(info
.getDescription());
207 field
.setText(info
.getString());
209 info
.addReloadedListener(new Runnable() {
212 field
.setText(info
.getString());
215 info
.addSaveListener(new Runnable() {
218 info
.setString(field
.getText());
222 JButton browseButton
= new JButton("...");
223 browseButton
.addActionListener(new ActionListener() {
225 public void actionPerformed(ActionEvent e
) {
226 JFileChooser chooser
= new JFileChooser();
227 chooser
.setCurrentDirectory(null);
228 chooser
.setFileSelectionMode(dir ? JFileChooser
.DIRECTORIES_ONLY
229 : JFileChooser
.FILES_ONLY
);
230 if (chooser
.showOpenDialog(ConfigItem
.this) == JFileChooser
.APPROVE_OPTION
) {
231 File file
= chooser
.getSelectedFile();
233 info
.setString(file
.getAbsolutePath());
234 field
.setText(info
.getString());
240 JPanel pane
= new JPanel(new BorderLayout());
241 this.add(label(info
), BorderLayout
.WEST
);
242 pane
.add(browseButton
, BorderLayout
.WEST
);
243 pane
.add(field
, BorderLayout
.CENTER
);
244 this.add(pane
, BorderLayout
.CENTER
);
247 private void addComboboxField(final MetaInfo
<E
> info
, boolean editable
) {
248 // rawtypes for Java 1.6 (and 1.7 ?) support
249 @SuppressWarnings({ "rawtypes", "unchecked" })
250 final JComboBox field
= new JComboBox(info
.getAllowedValues());
251 field
.setEditable(editable
);
252 field
.setSelectedItem(info
.getString());
254 info
.addReloadedListener(new Runnable() {
257 field
.setSelectedItem(info
.getString());
260 info
.addSaveListener(new Runnable() {
263 info
.setString(field
.getSelectedItem().toString());
267 this.add(label(info
), BorderLayout
.WEST
);
268 this.add(field
, BorderLayout
.CENTER
);
271 private void addPasswordField(final MetaInfo
<E
> info
) {
272 final JPasswordField field
= new JPasswordField();
273 field
.setToolTipText(info
.getDescription());
274 field
.setText(info
.getString());
276 info
.addReloadedListener(new Runnable() {
279 field
.setText(info
.getString());
282 info
.addSaveListener(new Runnable() {
285 info
.setString(new String(field
.getPassword()));
289 this.add(label(info
), BorderLayout
.WEST
);
290 this.add(field
, BorderLayout
.CENTER
);
293 private void addIntField(final MetaInfo
<E
> info
) {
294 final JTextField field
= new JTextField();
295 field
.setToolTipText(info
.getDescription());
296 field
.setText(info
.getString());
297 field
.setInputVerifier(new InputVerifier() {
299 public boolean verify(JComponent input
) {
300 String text
= field
.getText().trim();
301 if (text
.startsWith("-")) {
302 text
= text
.substring(1).trim();
305 return text
.replaceAll("[0-9]", "").isEmpty();
309 info
.addReloadedListener(new Runnable() {
312 field
.setText(info
.getString());
315 info
.addSaveListener(new Runnable() {
318 info
.setString(field
.getText());
319 Integer value
= info
.getInteger();
323 info
.setInteger(value
);
325 field
.setText(info
.getString());
329 JButton up
= new BasicArrowButton(BasicArrowButton
.NORTH
);
330 JButton down
= new BasicArrowButton(BasicArrowButton
.SOUTH
);
332 up
.addActionListener(new ActionListener() {
334 public void actionPerformed(ActionEvent ae
) {
337 value
= Integer
.parseInt(field
.getText());
338 } catch (NumberFormatException e
) {
341 field
.setText(Integer
.toString(value
+ 1));
345 down
.addActionListener(new ActionListener() {
347 public void actionPerformed(ActionEvent ae
) {
350 value
= Integer
.parseInt(field
.getText());
351 } catch (NumberFormatException e
) {
354 field
.setText(Integer
.toString(value
- 1));
358 JPanel upDown
= new JPanel(new BorderLayout());
359 upDown
.add(up
, BorderLayout
.NORTH
);
360 upDown
.add(down
, BorderLayout
.SOUTH
);
362 JPanel pane
= new JPanel(new BorderLayout());
363 pane
.add(upDown
, BorderLayout
.WEST
);
364 pane
.add(field
, BorderLayout
.CENTER
);
366 this.add(label(info
), BorderLayout
.WEST
);
367 this.add(pane
, BorderLayout
.CENTER
);
371 * Create a label which width is constrained in lock steps.
374 * the {@link MetaInfo} for which we want to add a label
378 private JComponent
label(final MetaInfo
<E
> info
) {
379 final JLabel label
= new JLabel(info
.getName());
381 Dimension ps
= label
.getPreferredSize();
383 ps
= label
.getSize();
388 for (int i
= 2 * step
; i
< 10 * step
; i
+= step
) {
396 JButton help
= new JButton("?");
397 help
.addActionListener(new ActionListener() {
399 public void actionPerformed(ActionEvent e
) {
400 StringBuilder builder
= new StringBuilder();
401 String text
= info
.getDescription().replace("\\n", "\n");
402 for (String line
: StringUtils
.justifyText(text
, 80,
404 if (builder
.length() > 0) {
405 builder
.append("\n");
407 builder
.append(line
);
409 text
= builder
.toString();
410 JOptionPane
.showMessageDialog(ConfigItem
.this, text
);
414 JPanel pane2
= new JPanel(new BorderLayout());
415 pane2
.add(help
, BorderLayout
.WEST
);
416 pane2
.add(new JLabel(" "), BorderLayout
.CENTER
);
418 JPanel pane
= new JPanel(new BorderLayout());
419 pane
.add(label
, BorderLayout
.WEST
);
420 pane
.add(pane2
, BorderLayout
.CENTER
);
422 ps
.width
= w
+ 30; // 30 for the (?) sign
424 pane
.setPreferredSize(ps
);
430 * Return an {@link Icon} to use as a colour badge for the colour field
434 * the size of the badge
436 * the colour of the badge
440 private Icon
getIcon(int size
, int color
) {
441 Color c
= new Color(color
, true);
442 int avg
= (c
.getRed() + c
.getGreen() + c
.getBlue()) / 3;
443 Color border
= (avg
>= 128 ? Color
.BLACK
: Color
.WHITE
);
445 BufferedImage img
= new BufferedImage(size
, size
,
446 BufferedImage
.TYPE_4BYTE_ABGR
);
448 Graphics2D g
= img
.createGraphics();
451 g
.fillRect(0, 0, img
.getWidth(), img
.getHeight());
453 g
.drawRect(0, 0, img
.getWidth() - 1, img
.getHeight() - 1);
458 return new ImageIcon(img
);