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