a8d212c9c5522645969840ae1a598491997c5abd
[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  */
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                                 customLAFComboBox.setEnabled(true);
272                                 useCustomLAFCheckBox.setSelected(true);
273                                 break;
274                         }
275                 }
276         }
277
278         //
279         // PRIVATE METHODS
280         //
281
282         /**
283          * Creates all actions.
284          */
285         private void initActions() {
286                 okayAction = new I18nAction("general.button.okay") {
287
288                         /**
289                          * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
290                          */
291                         @SuppressWarnings("synthetic-access")
292                         public void actionPerformed(ActionEvent actionEvent) {
293                                 actionOkay();
294                         }
295                 };
296                 cancelAction = new I18nAction("general.button.cancel") {
297
298                         /**
299                          * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
300                          */
301                         @SuppressWarnings("synthetic-access")
302                         public void actionPerformed(ActionEvent actionEvent) {
303                                 actionCancel();
304                         }
305                 };
306                 advancedModeAction = new I18nAction("configurationDialog.page.interface.item.advancedMode") {
307
308                         /**
309                          * {@inheritDoc}
310                          */
311                         public void actionPerformed(ActionEvent e) {
312                                 /* do nothing. */
313                         }
314                 };
315                 antialiasAction = new I18nAction("configurationDialog.page.interfaceTweaks.item.antialias") {
316
317                         /**
318                          * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
319                          */
320                         public void actionPerformed(ActionEvent actionEvent) {
321                                 /* do nothing. */
322                         }
323                 };
324                 useCustomControlFontAction = new I18nAction("configurationDialog.page.interfaceTweaks.item.useCustomControlFont") {
325
326                         /**
327                          * {@inheritDoc}
328                          */
329                         @SuppressWarnings("synthetic-access")
330                         public void actionPerformed(ActionEvent e) {
331                                 boolean selected = useCustomControlFontCheckBox.isSelected();
332                                 controlFontList.setEnabled(selected);
333                                 controlFontSizeSpinner.setEnabled(selected);
334                         }
335                 };
336                 useCustomUserFontAction = new I18nAction("configurationDialog.page.interfaceTweaks.item.useCustomUserFont") {
337
338                         /**
339                          * {@inheritDoc}
340                          */
341                         @SuppressWarnings("synthetic-access")
342                         public void actionPerformed(ActionEvent e) {
343                                 boolean selected = useCustomUserFontCheckBox.isSelected();
344                                 userFontList.setEnabled(selected);
345                                 userFontSizeSpinner.setEnabled(selected);
346                         }
347                 };
348                 useCustomLAFAction = new I18nAction("configurationDialog.page.interfaceTweaks.item.useCustomLAF") {
349
350                         /**
351                          * {@inheritDoc}
352                          */
353                         @SuppressWarnings("synthetic-access")
354                         public void actionPerformed(ActionEvent e) {
355                                 customLAFComboBox.setEnabled(useCustomLAFCheckBox.isSelected());
356                         }
357                 };
358         }
359
360         /**
361          * Creates all internal components.
362          */
363         private void initComponents() {
364                 JPanel contentPane = new JPanel(new BorderLayout(12, 12));
365                 contentPane.setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12));
366
367                 JTabbedPane tabbedPane = new JTabbedPane(SwingConstants.TOP, JTabbedPane.SCROLL_TAB_LAYOUT);
368                 contentPane.add(tabbedPane, BorderLayout.CENTER);
369
370                 JComponent interfaceConfig = createInterfaceConfig();
371                 tabbedPane.add(I18n.get("configurationDialog.page.interface.name"), interfaceConfig);
372
373                 JComponent interfaceTweaksConfig = createInterfaceTweaksConfig();
374                 tabbedPane.add(I18n.get("configurationDialog.page.interfaceTweaks.name"), interfaceTweaksConfig);
375
376                 JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING, 12, 12));
377                 contentPane.add(buttonPanel, BorderLayout.PAGE_END);
378                 buttonPanel.setBorder(BorderFactory.createEmptyBorder(-12, -12, -12, -12));
379                 buttonPanel.add(new JButton(cancelAction));
380                 JButton okayButton = new JButton(okayAction);
381                 buttonPanel.add(okayButton);
382                 getRootPane().setDefaultButton(okayButton);
383
384                 getContentPane().add(contentPane, BorderLayout.CENTER);
385         }
386
387         /**
388          * Creates the interface configuration panel.
389          * 
390          * @return The interface configuration panel
391          */
392         private JComponent createInterfaceConfig() {
393                 JPanel interfaceConfigPanel = new JPanel(new GridBagLayout());
394                 interfaceConfigPanel.setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12));
395
396                 advancedModeCheckBox = new JCheckBox(advancedModeAction);
397                 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));
398
399                 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));
400                 return interfaceConfigPanel;
401         }
402
403         /**
404          * Creates the panel for the interface tweaks configuration.
405          * 
406          * @return The interface tweaks configuration panel
407          */
408         private JComponent createInterfaceTweaksConfig() {
409                 JPanel interfaceTweaksConfigPanel = new JPanel(new GridBagLayout());
410                 interfaceTweaksConfigPanel.setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12));
411
412                 restartRequiredLabel = new I18nLabel("configurationDialog.page.interfaceTweaks.item.restartRequired");
413                 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));
414
415                 antialiasCheckBox = new JCheckBox(antialiasAction);
416                 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));
417
418                 useCustomControlFontCheckBox = new JCheckBox(useCustomControlFontAction);
419                 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));
420
421                 controlFontList = new FontComboBox();
422                 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));
423
424                 controlFontSizeSpinner = new JSpinner(new SpinnerNumberModel(12, 6, 80, 1));
425                 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));
426
427                 useCustomUserFontCheckBox = new JCheckBox(useCustomUserFontAction);
428                 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));
429
430                 userFontList = new FontComboBox();
431                 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));
432
433                 userFontSizeSpinner = new JSpinner(new SpinnerNumberModel(12, 6, 80, 1));
434                 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));
435
436                 useCustomLAFCheckBox = new JCheckBox(useCustomLAFAction);
437                 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));
438
439                 LookAndFeelInfo[] lookAndFeelInfos = UIManager.getInstalledLookAndFeels();
440                 List<LookAndFeelWrapper> lookAndFeelWrappers = new ArrayList<LookAndFeelWrapper>();
441                 for (LookAndFeelInfo lookAndFeelInfo: lookAndFeelInfos) {
442                         lookAndFeelWrappers.add(new LookAndFeelWrapper(lookAndFeelInfo.getClassName(), lookAndFeelInfo.getName()));
443                 }
444                 customLAFComboBox = new JComboBox(lookAndFeelWrappers.toArray(new LookAndFeelWrapper[0]));
445                 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));
446
447                 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));
448
449                 return interfaceTweaksConfigPanel;
450         }
451
452         //
453         // PRIVATE ACTIONS
454         //
455
456         /**
457          * Called when the “okay” button is clicked.
458          */
459         private void actionOkay() {
460                 if (useCustomControlFontCheckBox.isSelected()) {
461                         if (controlFontList.getSelectedItem() == null) {
462                                 JOptionPane.showMessageDialog(this, I18n.get("configurationDialog.error.noControlFontSelected.message"), I18n.get("configurationDialog.error.noControlFontSelected.title"), JOptionPane.ERROR_MESSAGE);
463                                 return;
464                         }
465                 }
466                 if (useCustomUserFontCheckBox.isSelected()) {
467                         if (userFontList.getSelectedItem() == null) {
468                                 JOptionPane.showMessageDialog(this, I18n.get("configurationDialog.error.noUserFontSelected.message"), I18n.get("configurationDialog.error.noUserFontSelected.title"), JOptionPane.ERROR_MESSAGE);
469                                 return;
470                         }
471                 }
472                 cancelled = false;
473                 setVisible(false);
474         }
475
476         /**
477          * Called when the “cancel” button is clicked.
478          */
479         private void actionCancel() {
480                 cancelled = true;
481                 setVisible(false);
482         }
483
484         //
485         // INTERFACE I18nable
486         //
487
488         /**
489          * @see net.pterodactylus.jsite.i18n.I18nable#updateI18n()
490          */
491         public void updateI18n() {
492                 okayAction.updateI18n();
493                 cancelAction.updateI18n();
494                 advancedModeAction.updateI18n();
495                 restartRequiredLabel.updateI18n();
496                 antialiasAction.updateI18n();
497                 useCustomControlFontAction.updateI18n();
498                 useCustomUserFontAction.updateI18n();
499                 useCustomLAFAction.updateI18n();
500                 SwingUtils.repackCentered(this);
501         }
502
503         /**
504          * Wrapper around class name and name of a {@link LookAndFeel}.
505          * 
506          * @author David ‘Bombe’ Roden &lt;bombe@freenetproject.org&gt;
507          */
508         private static class LookAndFeelWrapper {
509
510                 /** The class name of the look and feel. */
511                 private final String className;
512
513                 /** The name of a look and feel. */
514                 private final String lookAndFeelName;
515
516                 /**
517                  * Creates a new wrapper around the given class name and name of a look
518                  * and feel.
519                  * 
520                  * @param className
521                  *            The class name of the look and feel
522                  * @param lookAndFeelName
523                  *            The name of the look and feel
524                  */
525                 public LookAndFeelWrapper(String className, String lookAndFeelName) {
526                         this.className = className;
527                         this.lookAndFeelName = lookAndFeelName;
528                 }
529
530                 /**
531                  * Returns the class name of the look and feel.
532                  * 
533                  * @return The class name of the look and feel
534                  */
535                 public String getClassName() {
536                         return className;
537                 }
538
539                 /**
540                  * {@inheritDoc}
541                  */
542                 @Override
543                 public String toString() {
544                         return lookAndFeelName;
545                 }
546
547         }
548
549 }