5df9f8ec48689bd782c9522e3e4ddf318929e5d5
[jSite2.git] / src / net / pterodactylus / jsite / gui / ConfigurationDialog.java
1 /**
2  * © 2008 INA Service GmbH
3  */
4
5 package net.pterodactylus.jsite.gui;
6
7 import java.awt.BorderLayout;
8 import java.awt.FlowLayout;
9 import java.awt.Font;
10 import java.awt.GridBagConstraints;
11 import java.awt.GridBagLayout;
12 import java.awt.Insets;
13 import java.awt.event.ActionEvent;
14 import java.util.ArrayList;
15 import java.util.List;
16
17 import javax.swing.BorderFactory;
18 import javax.swing.JButton;
19 import javax.swing.JCheckBox;
20 import javax.swing.JComboBox;
21 import javax.swing.JComponent;
22 import javax.swing.JDialog;
23 import javax.swing.JOptionPane;
24 import javax.swing.JPanel;
25 import javax.swing.JSpinner;
26 import javax.swing.JTabbedPane;
27 import javax.swing.LookAndFeel;
28 import javax.swing.SpinnerNumberModel;
29 import javax.swing.SwingConstants;
30 import javax.swing.UIManager;
31 import javax.swing.UIManager.LookAndFeelInfo;
32
33 import net.pterodactylus.jsite.i18n.I18n;
34 import net.pterodactylus.jsite.i18n.I18nable;
35 import net.pterodactylus.jsite.i18n.gui.I18nAction;
36 import net.pterodactylus.jsite.i18n.gui.I18nLabel;
37 import net.pterodactylus.util.swing.SwingUtils;
38
39 /**
40  * The configuration dialog.
41  * 
42  * @author <a href="mailto:dr@ina-germany.de">David Roden</a>
43  * @version $Id$
44  */
45 public class ConfigurationDialog extends JDialog implements I18nable {
46
47         /** The “okay” action. */
48         private I18nAction okayAction;
49
50         /** The “cancel” action. */
51         private I18nAction cancelAction;
52
53         /** The “advanced mode” action. */
54         private I18nAction advancedModeAction;
55
56         /** The “advanced mode” checkbox. */
57         private JCheckBox advancedModeCheckBox;
58
59         /** The “beautify GUI” action. */
60         private I18nAction antialiasAction;
61
62         /** The “use custom control font” action. */
63         private I18nAction useCustomControlFontAction;
64
65         /** The “use custom user font” action. */
66         private I18nAction useCustomUserFontAction;
67
68         /** The “use custom L&F” action. */
69         private I18nAction useCustomLAFAction;
70
71         /** The “restart required” warning label. */
72         private I18nLabel restartRequiredLabel;
73
74         /** The “beautify” checkbox. */
75         private JCheckBox antialiasCheckBox;
76
77         /** The “use custom” fonts checkbox. */
78         private JCheckBox useCustomControlFontCheckBox;
79
80         /** The control font list. */
81         private FontComboBox controlFontList;
82
83         /** The control font size spinner. */
84         private JSpinner controlFontSizeSpinner;
85
86         /** The checkbox for “use same as control font”. */
87         private JCheckBox useCustomUserFontCheckBox;
88
89         /** The user font list. */
90         private FontComboBox userFontList;
91
92         /** The user font size spinner. */
93         private JSpinner userFontSizeSpinner;
94
95         /** The checkbox for custom L&F. */
96         private JCheckBox useCustomLAFCheckBox;
97
98         /** The combo box for the L&Fs. */
99         private JComboBox customLAFComboBox;
100
101         /** Whether the dialog was cancelled. */
102         private boolean cancelled;
103
104         /**
105          * Creates a new configuration dialog.
106          * 
107          * @param swingInterface
108          *            The Swing interface
109          */
110         public ConfigurationDialog(SwingInterface swingInterface) {
111                 super(swingInterface.getMainWindow(), I18n.get("configurationDialog.title"), true);
112                 initActions();
113                 initComponents();
114                 pack();
115                 SwingUtils.center(this);
116                 I18n.registerI18nable(this);
117         }
118
119         //
120         // ACCESSORS
121         //
122
123         /**
124          * Returns whether the dialog was cancelled or confirmed. If the dialog was
125          * cancelled, no further processing should be done.
126          * 
127          * @return <code>true</code> if the dialog was cancelled,
128          *         <code>false</code> otherwise
129          */
130         public boolean wasCancelled() {
131                 return cancelled;
132         }
133
134         /**
135          * Returns whether the advanced mode is selected.
136          * 
137          * @return <code>true</code> if the advanced mode is selected,
138          *         <code>false</code> otherwise
139          */
140         public boolean isAdvancedMode() {
141                 return advancedModeCheckBox.isSelected();
142         }
143
144         /**
145          * Sets whether the advanced mode is selected.
146          * 
147          * @param advancedMode
148          *            <code>true</code> if the advanced mode is selected,
149          *            <code>false</code> otherwise
150          */
151         public void setAdvancedMode(boolean advancedMode) {
152                 advancedModeCheckBox.setSelected(advancedMode);
153         }
154
155         /**
156          * Returns whether the “beautify” checkbox has been selected. The result of
157          * this method should not be used if {@link #wasCancelled()} returned
158          * <code>true</code>!
159          * 
160          * @return <code>true</code> if the checkbox was selected,
161          *         <code>false</code> otherwise
162          */
163         public boolean isAntialias() {
164                 return antialiasCheckBox.isSelected();
165         }
166
167         /**
168          * Sets the state of the “antialias” checkbox.
169          * 
170          * @param antialias
171          *            The state of the checkbox
172          */
173         public void setAntialias(boolean antialias) {
174                 antialiasCheckBox.setSelected(antialias);
175         }
176
177         /**
178          * Returns the font for the controls.
179          * 
180          * @return The control font, or <code>null</code> if no custom control
181          *         font is to be used
182          */
183         public String getControlFont() {
184                 return useCustomControlFontCheckBox.isSelected() ? controlFontList.getSelectedItem() + "-" + controlFontSizeSpinner.getValue() : null;
185         }
186
187         /**
188          * Sets the font for the controls.
189          * 
190          * @param controlFont
191          *            The control font, or <code>null</code> if no custom control
192          *            font is to be used
193          */
194         public void setControlFont(String controlFont) {
195                 boolean hasControlFont = controlFont != null;
196                 useCustomControlFontCheckBox.setSelected(hasControlFont);
197                 controlFontList.setEnabled(hasControlFont);
198                 controlFontSizeSpinner.setEnabled(hasControlFont);
199                 if (hasControlFont) {
200                         Font font = Font.decode(controlFont);
201                         controlFontSizeSpinner.setValue(font.getSize());
202                         controlFontList.setSelectedItem(font.getName());
203                 } else {
204                         controlFontSizeSpinner.setValue(12);
205                         controlFontList.setSelectedItem(null);
206                 }
207         }
208
209         /**
210          * Returns the font for user input.
211          * 
212          * @return The font for user input, or <code>null</code> if no custom user
213          *         input font is to be used
214          */
215         public String getUserFont() {
216                 return useCustomUserFontCheckBox.isSelected() ? userFontList.getSelectedItem() + "-" + userFontSizeSpinner.getValue() : null;
217         }
218
219         /**
220          * Sets the font for user input.
221          * 
222          * @param userFont
223          *            The font for user input, or <code>null</code> if no custom
224          *            user input font is to be used
225          */
226         public void setUserFont(String userFont) {
227                 boolean hasUserFont = userFont != null;
228                 useCustomUserFontCheckBox.setSelected(hasUserFont);
229                 userFontList.setEnabled(hasUserFont);
230                 userFontSizeSpinner.setEnabled(hasUserFont);
231                 if (hasUserFont) {
232                         Font font = Font.decode(userFont);
233                         userFontSizeSpinner.setValue(font.getSize());
234                         userFontList.setSelectedItem(font.getName());
235                 } else {
236                         userFontSizeSpinner.setValue(12);
237                         userFontList.setSelectedItem(null);
238                 }
239         }
240
241         /**
242          * Returns the class name of the selected look and feel, if a custom look
243          * and feel is selected.
244          * 
245          * @return The class name of the look and feel to load, or <code>null</code>
246          *         if no special look and feel should be used
247          */
248         public String getLookAndFeel() {
249                 if (!useCustomLAFCheckBox.isSelected()) {
250                         return null;
251                 }
252                 return ((LookAndFeelWrapper) customLAFComboBox.getSelectedItem()).getClassName();
253         }
254
255         /**
256          * Sets the given look and feel.
257          * 
258          * @param lookAndFeel
259          *            The class name of the look and feel, or <code>null</code> to
260          *            not select a custom look and feel
261          */
262         public void setLookAndFeel(String lookAndFeel) {
263                 useCustomLAFCheckBox.setSelected(false);
264                 customLAFComboBox.setEnabled(false);
265                 if (lookAndFeel == null) {
266                         return;
267                 }
268                 for (int lookAndFeelIndex = 0; lookAndFeelIndex < customLAFComboBox.getItemCount(); lookAndFeelIndex++) {
269                         LookAndFeelWrapper lookAndFeelWrapper = (LookAndFeelWrapper) customLAFComboBox.getItemAt(lookAndFeelIndex);
270                         if (lookAndFeelWrapper.getClassName().equals(lookAndFeel)) {
271                                 customLAFComboBox.setSelectedIndex(lookAndFeelIndex);
272                                 customLAFComboBox.setEnabled(true);
273                                 useCustomLAFCheckBox.setSelected(true);
274                                 break;
275                         }
276                 }
277         }
278
279         //
280         // PRIVATE METHODS
281         //
282
283         /**
284          * Creates all actions.
285          */
286         private void initActions() {
287                 okayAction = new I18nAction("general.button.okay") {
288
289                         /**
290                          * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
291                          */
292                         @SuppressWarnings("synthetic-access")
293                         public void actionPerformed(ActionEvent actionEvent) {
294                                 actionOkay();
295                         }
296                 };
297                 cancelAction = new I18nAction("general.button.cancel") {
298
299                         /**
300                          * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
301                          */
302                         @SuppressWarnings("synthetic-access")
303                         public void actionPerformed(ActionEvent actionEvent) {
304                                 actionCancel();
305                         }
306                 };
307                 advancedModeAction = new I18nAction("configurationDialog.page.interface.item.advancedMode") {
308
309                         /**
310                          * {@inheritDoc}
311                          */
312                         public void actionPerformed(ActionEvent e) {
313                                 /* do nothing. */
314                         }
315                 };
316                 antialiasAction = new I18nAction("configurationDialog.page.interfaceTweaks.item.antialias") {
317
318                         /**
319                          * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
320                          */
321                         public void actionPerformed(ActionEvent actionEvent) {
322                                 /* do nothing. */
323                         }
324                 };
325                 useCustomControlFontAction = new I18nAction("configurationDialog.page.interfaceTweaks.item.useCustomControlFont") {
326
327                         /**
328                          * {@inheritDoc}
329                          */
330                         @SuppressWarnings("synthetic-access")
331                         public void actionPerformed(ActionEvent e) {
332                                 boolean selected = useCustomControlFontCheckBox.isSelected();
333                                 controlFontList.setEnabled(selected);
334                                 controlFontSizeSpinner.setEnabled(selected);
335                         }
336                 };
337                 useCustomUserFontAction = new I18nAction("configurationDialog.page.interfaceTweaks.item.useCustomUserFont") {
338
339                         /**
340                          * {@inheritDoc}
341                          */
342                         @SuppressWarnings("synthetic-access")
343                         public void actionPerformed(ActionEvent e) {
344                                 boolean selected = useCustomUserFontCheckBox.isSelected();
345                                 userFontList.setEnabled(selected);
346                                 userFontSizeSpinner.setEnabled(selected);
347                         }
348                 };
349                 useCustomLAFAction = new I18nAction("configurationDialog.page.interfaceTweaks.item.useCustomLAF") {
350
351                         /**
352                          * {@inheritDoc}
353                          */
354                         @SuppressWarnings("synthetic-access")
355                         public void actionPerformed(ActionEvent e) {
356                                 customLAFComboBox.setEnabled(useCustomLAFCheckBox.isSelected());
357                         }
358                 };
359         }
360
361         /**
362          * Creates all internal components.
363          */
364         private void initComponents() {
365                 JPanel contentPane = new JPanel(new BorderLayout(12, 12));
366                 contentPane.setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12));
367
368                 JTabbedPane tabbedPane = new JTabbedPane(SwingConstants.TOP, JTabbedPane.SCROLL_TAB_LAYOUT);
369                 contentPane.add(tabbedPane, BorderLayout.CENTER);
370
371                 JComponent interfaceConfig = createInterfaceConfig();
372                 tabbedPane.add(I18n.get("configurationDialog.page.interface.name"), interfaceConfig);
373
374                 JComponent interfaceTweaksConfig = createInterfaceTweaksConfig();
375                 tabbedPane.add(I18n.get("configurationDialog.page.interfaceTweaks.name"), interfaceTweaksConfig);
376
377                 JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING, 12, 12));
378                 contentPane.add(buttonPanel, BorderLayout.PAGE_END);
379                 buttonPanel.setBorder(BorderFactory.createEmptyBorder(-12, -12, -12, -12));
380                 buttonPanel.add(new JButton(cancelAction));
381                 JButton okayButton = new JButton(okayAction);
382                 buttonPanel.add(okayButton);
383                 getRootPane().setDefaultButton(okayButton);
384
385                 getContentPane().add(contentPane, BorderLayout.CENTER);
386         }
387
388         /**
389          * Creates the interface configuration panel.
390          * 
391          * @return The interface configuration panel
392          */
393         private JComponent createInterfaceConfig() {
394                 JPanel interfaceConfigPanel = new JPanel(new GridBagLayout());
395                 interfaceConfigPanel.setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12));
396
397                 advancedModeCheckBox = new JCheckBox(advancedModeAction);
398                 interfaceConfigPanel.add(advancedModeCheckBox, new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
399
400                 interfaceConfigPanel.add(new JPanel(), new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
401                 return interfaceConfigPanel;
402         }
403
404         /**
405          * Creates the panel for the interface tweaks configuration.
406          * 
407          * @return The interface tweaks configuration panel
408          */
409         private JComponent createInterfaceTweaksConfig() {
410                 JPanel interfaceTweaksConfigPanel = new JPanel(new GridBagLayout());
411                 interfaceTweaksConfigPanel.setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12));
412
413                 restartRequiredLabel = new I18nLabel("configurationDialog.page.interfaceTweaks.item.restartRequired");
414                 interfaceTweaksConfigPanel.add(restartRequiredLabel, new GridBagConstraints(0, 0, 3, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
415
416                 antialiasCheckBox = new JCheckBox(antialiasAction);
417                 interfaceTweaksConfigPanel.add(antialiasCheckBox, new GridBagConstraints(0, 1, 3, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(18, 0, 0, 0), 0, 0));
418
419                 useCustomControlFontCheckBox = new JCheckBox(useCustomControlFontAction);
420                 interfaceTweaksConfigPanel.add(useCustomControlFontCheckBox, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(6, 0, 0, 0), 0, 0));
421
422                 controlFontList = new FontComboBox();
423                 interfaceTweaksConfigPanel.add(controlFontList, new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(6, 6, 0, 0), 0, 0));
424
425                 controlFontSizeSpinner = new JSpinner(new SpinnerNumberModel(12, 6, 80, 1));
426                 interfaceTweaksConfigPanel.add(controlFontSizeSpinner, new GridBagConstraints(2, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(6, 6, 0, 0), 0, 0));
427
428                 useCustomUserFontCheckBox = new JCheckBox(useCustomUserFontAction);
429                 interfaceTweaksConfigPanel.add(useCustomUserFontCheckBox, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 0, 0, 0), 0, 0));
430
431                 userFontList = new FontComboBox();
432                 interfaceTweaksConfigPanel.add(userFontList, new GridBagConstraints(1, 3, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(6, 6, 0, 0), 0, 0));
433
434                 userFontSizeSpinner = new JSpinner(new SpinnerNumberModel(12, 6, 80, 1));
435                 interfaceTweaksConfigPanel.add(userFontSizeSpinner, new GridBagConstraints(2, 3, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(6, 6, 0, 0), 0, 0));
436
437                 useCustomLAFCheckBox = new JCheckBox(useCustomLAFAction);
438                 interfaceTweaksConfigPanel.add(useCustomLAFCheckBox, new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(6, 0, 0, 0), 0, 0));
439
440                 LookAndFeelInfo[] lookAndFeelInfos = UIManager.getInstalledLookAndFeels();
441                 List<LookAndFeelWrapper> lookAndFeelWrappers = new ArrayList<LookAndFeelWrapper>();
442                 for (LookAndFeelInfo lookAndFeelInfo: lookAndFeelInfos) {
443                         lookAndFeelWrappers.add(new LookAndFeelWrapper(lookAndFeelInfo.getClassName(), lookAndFeelInfo.getName()));
444                 }
445                 customLAFComboBox = new JComboBox(lookAndFeelWrappers.toArray(new LookAndFeelWrapper[0]));
446                 interfaceTweaksConfigPanel.add(customLAFComboBox, new GridBagConstraints(1, 4, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(6, 6, 0, 0), 0, 0));
447
448                 interfaceTweaksConfigPanel.add(new JPanel(), new GridBagConstraints(0, 5, 3, 1, 1.0, 1.0, GridBagConstraints.LINE_START, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
449
450                 return interfaceTweaksConfigPanel;
451         }
452
453         //
454         // PRIVATE ACTIONS
455         //
456
457         /**
458          * Called when the “okay” button is clicked.
459          */
460         private void actionOkay() {
461                 if (useCustomControlFontCheckBox.isSelected()) {
462                         if (controlFontList.getSelectedItem() == null) {
463                                 JOptionPane.showMessageDialog(this, I18n.get("configurationDialog.error.noControlFontSelected.message"), I18n.get("configurationDialog.error.noControlFontSelected.title"), JOptionPane.ERROR_MESSAGE);
464                                 return;
465                         }
466                 }
467                 if (useCustomUserFontCheckBox.isSelected()) {
468                         if (userFontList.getSelectedItem() == null) {
469                                 JOptionPane.showMessageDialog(this, I18n.get("configurationDialog.error.noUserFontSelected.message"), I18n.get("configurationDialog.error.noUserFontSelected.title"), JOptionPane.ERROR_MESSAGE);
470                                 return;
471                         }
472                 }
473                 cancelled = false;
474                 setVisible(false);
475         }
476
477         /**
478          * Called when the “cancel” button is clicked.
479          */
480         private void actionCancel() {
481                 cancelled = true;
482                 setVisible(false);
483         }
484
485         //
486         // INTERFACE I18nable
487         //
488
489         /**
490          * @see net.pterodactylus.jsite.i18n.I18nable#updateI18n()
491          */
492         public void updateI18n() {
493                 okayAction.updateI18n();
494                 cancelAction.updateI18n();
495                 advancedModeAction.updateI18n();
496                 restartRequiredLabel.updateI18n();
497                 antialiasAction.updateI18n();
498                 useCustomControlFontAction.updateI18n();
499                 useCustomUserFontAction.updateI18n();
500                 useCustomLAFAction.updateI18n();
501                 SwingUtils.repackCentered(this);
502         }
503
504         /**
505          * Wrapper around class name and name of a {@link LookAndFeel}.
506          * 
507          * @author David ‘Bombe’ Roden &lt;bombe@freenetproject.org&gt;
508          * @version $Id$
509          */
510         private static class LookAndFeelWrapper {
511
512                 /** The class name of the look and feel. */
513                 private final String className;
514
515                 /** The name of a look and feel. */
516                 private final String lookAndFeelName;
517
518                 /**
519                  * Creates a new wrapper around the given class name and name of a look
520                  * and feel.
521                  * 
522                  * @param className
523                  *            The class name of the look and feel
524                  * @param lookAndFeelName
525                  *            The name of the look and feel
526                  */
527                 public LookAndFeelWrapper(String className, String lookAndFeelName) {
528                         this.className = className;
529                         this.lookAndFeelName = lookAndFeelName;
530                 }
531
532                 /**
533                  * Returns the class name of the look and feel.
534                  * 
535                  * @return The class name of the look and feel
536                  */
537                 public String getClassName() {
538                         return className;
539                 }
540
541                 /**
542                  * {@inheritDoc}
543                  */
544                 @Override
545                 public String toString() {
546                         return lookAndFeelName;
547                 }
548
549         }
550
551 }