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
.MetaInfo
;
34 * A graphical item that reflect a configuration option from the given
40 * the type of {@link Bundle} to edit
42 public class ConfigItem
<E
extends Enum
<E
>> extends JPanel
{
43 private static final long serialVersionUID
= 1L;
45 public ConfigItem(MetaInfo
<E
> info
) {
46 this.setLayout(new BorderLayout());
48 switch (info
.getFormat()) {
50 addBooleanField(info
);
56 addBrowseField(info
, false);
59 addBrowseField(info
, true);
62 addComboboxField(info
, true);
65 addComboboxField(info
, false);
71 addPasswordField(info
);
81 private void addStringField(final MetaInfo
<E
> info
) {
82 final JTextField field
= new JTextField();
83 field
.setToolTipText(info
.getDescription());
84 field
.setText(info
.getString());
86 info
.addReloadedListener(new Runnable() {
89 field
.setText(info
.getString());
92 info
.addSaveListener(new Runnable() {
95 info
.setString(field
.getText());
99 this.add(label(info
), BorderLayout
.WEST
);
100 this.add(field
, BorderLayout
.CENTER
);
103 private void addBooleanField(final MetaInfo
<E
> info
) {
104 final JCheckBox field
= new JCheckBox();
105 field
.setToolTipText(info
.getDescription());
106 Boolean state
= info
.getBoolean();
108 info
.getDefaultBoolean();
111 // Should not happen!
114 .println("No default value given for BOOLEAN parameter \""
115 + info
.getName() + "\", we consider it is FALSE");
119 field
.setSelected(state
);
121 info
.addReloadedListener(new Runnable() {
124 Boolean state
= info
.getBoolean();
126 info
.getDefaultBoolean();
132 field
.setSelected(state
);
135 info
.addSaveListener(new Runnable() {
138 info
.setBoolean(field
.isSelected());
142 field
.setText(info
.getName());
143 this.add(field
, BorderLayout
.CENTER
);
146 private void addColorField(final MetaInfo
<E
> info
) {
147 final JTextField field
= new JTextField();
148 field
.setToolTipText(info
.getDescription());
149 field
.setText(info
.getString());
151 info
.addReloadedListener(new Runnable() {
154 field
.setText(info
.getString());
157 info
.addSaveListener(new Runnable() {
160 info
.setString(field
.getText());
164 this.add(label(info
), BorderLayout
.WEST
);
165 JPanel pane
= new JPanel(new BorderLayout());
167 final JButton colorWheel
= new JButton();
168 colorWheel
.setIcon(getIcon(17, info
.getColor()));
169 colorWheel
.addActionListener(new ActionListener() {
171 public void actionPerformed(ActionEvent e
) {
172 Color initialColor
= new Color(info
.getColor(), true);
173 Color newColor
= JColorChooser
.showDialog(ConfigItem
.this,
174 info
.getName(), initialColor
);
175 if (newColor
!= null) {
176 info
.setColor(newColor
.getRGB());
177 field
.setText(info
.getString());
178 colorWheel
.setIcon(getIcon(17, info
.getColor()));
182 pane
.add(colorWheel
, BorderLayout
.WEST
);
183 pane
.add(field
, BorderLayout
.CENTER
);
184 this.add(pane
, BorderLayout
.CENTER
);
187 private void addBrowseField(final MetaInfo
<E
> info
, final boolean dir
) {
188 final JTextField field
= new JTextField();
189 field
.setToolTipText(info
.getDescription());
190 field
.setText(info
.getString());
192 info
.addReloadedListener(new Runnable() {
195 field
.setText(info
.getString());
198 info
.addSaveListener(new Runnable() {
201 info
.setString(field
.getText());
205 JButton browseButton
= new JButton("...");
206 browseButton
.addActionListener(new ActionListener() {
208 public void actionPerformed(ActionEvent e
) {
209 JFileChooser chooser
= new JFileChooser();
210 chooser
.setCurrentDirectory(null);
211 chooser
.setFileSelectionMode(dir ? JFileChooser
.DIRECTORIES_ONLY
212 : JFileChooser
.FILES_ONLY
);
213 if (chooser
.showOpenDialog(ConfigItem
.this) == JFileChooser
.APPROVE_OPTION
) {
214 File file
= chooser
.getSelectedFile();
216 info
.setString(file
.getAbsolutePath());
217 field
.setText(info
.getString());
223 JPanel pane
= new JPanel(new BorderLayout());
224 this.add(label(info
), BorderLayout
.WEST
);
225 pane
.add(browseButton
, BorderLayout
.WEST
);
226 pane
.add(field
, BorderLayout
.CENTER
);
227 this.add(pane
, BorderLayout
.CENTER
);
230 private void addComboboxField(final MetaInfo
<E
> info
, boolean editable
) {
231 // rawtypes for Java 1.6 (and 1.7 ?) support
232 @SuppressWarnings({ "rawtypes", "unchecked" })
233 final JComboBox field
= new JComboBox(info
.getAllowedValues());
234 field
.setEditable(editable
);
235 field
.setSelectedItem(info
.getString());
237 info
.addReloadedListener(new Runnable() {
240 field
.setSelectedItem(info
.getString());
243 info
.addSaveListener(new Runnable() {
246 info
.setString(field
.getSelectedItem().toString());
250 this.add(label(info
), BorderLayout
.WEST
);
251 this.add(field
, BorderLayout
.CENTER
);
254 private void addPasswordField(final MetaInfo
<E
> info
) {
255 final JPasswordField field
= new JPasswordField();
256 field
.setToolTipText(info
.getDescription());
257 field
.setText(info
.getString());
259 info
.addReloadedListener(new Runnable() {
262 field
.setText(info
.getString());
265 info
.addSaveListener(new Runnable() {
268 info
.setString(new String(field
.getPassword()));
272 this.add(label(info
), BorderLayout
.WEST
);
273 this.add(field
, BorderLayout
.CENTER
);
276 private void addIntField(final MetaInfo
<E
> info
) {
277 final JTextField field
= new JTextField();
278 field
.setToolTipText(info
.getDescription());
279 field
.setText(info
.getString());
280 field
.setInputVerifier(new InputVerifier() {
282 public boolean verify(JComponent input
) {
283 String text
= field
.getText().trim();
284 if (text
.startsWith("-")) {
285 text
= text
.substring(1).trim();
288 return text
.replaceAll("[0-9]", "").isEmpty();
292 info
.addReloadedListener(new Runnable() {
295 field
.setText(info
.getString());
298 info
.addSaveListener(new Runnable() {
301 info
.setString(field
.getText());
302 Integer value
= info
.getInteger();
306 info
.setInteger(value
);
308 field
.setText(info
.getString());
312 JButton up
= new BasicArrowButton(BasicArrowButton
.NORTH
);
313 JButton down
= new BasicArrowButton(BasicArrowButton
.SOUTH
);
315 up
.addActionListener(new ActionListener() {
317 public void actionPerformed(ActionEvent ae
) {
320 value
= Integer
.parseInt(field
.getText());
321 } catch (NumberFormatException e
) {
324 field
.setText(Integer
.toString(value
+ 1));
328 down
.addActionListener(new ActionListener() {
330 public void actionPerformed(ActionEvent ae
) {
333 value
= Integer
.parseInt(field
.getText());
334 } catch (NumberFormatException e
) {
337 field
.setText(Integer
.toString(value
- 1));
341 JPanel upDown
= new JPanel(new BorderLayout());
342 upDown
.add(up
, BorderLayout
.NORTH
);
343 upDown
.add(down
, BorderLayout
.SOUTH
);
345 JPanel pane
= new JPanel(new BorderLayout());
346 pane
.add(upDown
, BorderLayout
.WEST
);
347 pane
.add(field
, BorderLayout
.CENTER
);
349 this.add(label(info
), BorderLayout
.WEST
);
350 this.add(pane
, BorderLayout
.CENTER
);
354 * Create a label which width is constrained in lock steps.
357 * the {@link MetaInfo} for which we want to add a label
361 private JComponent
label(final MetaInfo
<E
> info
) {
362 final JLabel label
= new JLabel(info
.getName());
364 Dimension ps
= label
.getPreferredSize();
366 ps
= label
.getSize();
371 for (int i
= 2 * step
; i
< 10 * step
; i
+= step
) {
379 JButton help
= new JButton("?");
380 help
.addActionListener(new ActionListener() {
382 public void actionPerformed(ActionEvent e
) {
383 StringBuilder builder
= new StringBuilder();
384 String text
= info
.getDescription().replace("\\n", "\n");
385 for (String line
: StringUtils
.justifyText(text
, 80,
387 if (builder
.length() > 0) {
388 builder
.append("\n");
390 builder
.append(line
);
392 text
= builder
.toString();
393 JOptionPane
.showMessageDialog(ConfigItem
.this, text
);
397 JPanel pane2
= new JPanel(new BorderLayout());
398 pane2
.add(help
, BorderLayout
.WEST
);
399 pane2
.add(new JLabel(" "), BorderLayout
.CENTER
);
401 JPanel pane
= new JPanel(new BorderLayout());
402 pane
.add(label
, BorderLayout
.WEST
);
403 pane
.add(pane2
, BorderLayout
.CENTER
);
405 ps
.width
= w
+ 30; // 30 for the (?) sign
407 pane
.setPreferredSize(ps
);
413 * Return an {@link Icon} to use as a colour badge for the colour field
417 * the size of the badge
419 * the colour of the badge
423 private Icon
getIcon(int size
, int color
) {
424 Color c
= new Color(color
, true);
425 int avg
= (c
.getRed() + c
.getGreen() + c
.getBlue()) / 3;
426 Color border
= (avg
>= 128 ? Color
.BLACK
: Color
.WHITE
);
428 BufferedImage img
= new BufferedImage(size
, size
,
429 BufferedImage
.TYPE_4BYTE_ABGR
);
431 Graphics2D g
= img
.createGraphics();
434 g
.fillRect(0, 0, img
.getWidth(), img
.getHeight());
436 g
.drawRect(0, 0, img
.getWidth() - 1, img
.getHeight() - 1);
441 return new ImageIcon(img
);