enhance configuration dialog with font selection
[jSite2.git] / src / net / pterodactylus / jsite / gui / SwingInterface.java
1 /*
2  * jSite2 - SwingInterface.java -
3  * Copyright © 2008 David Roden
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 package net.pterodactylus.jsite.gui;
21
22 import java.awt.event.ActionEvent;
23 import java.io.File;
24 import java.io.FileInputStream;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.util.ArrayList;
28 import java.util.List;
29 import java.util.Locale;
30 import java.util.Properties;
31
32 import javax.swing.JOptionPane;
33
34 import net.pterodactylus.jsite.core.Core;
35 import net.pterodactylus.jsite.core.CoreListener;
36 import net.pterodactylus.jsite.core.Node;
37 import net.pterodactylus.jsite.core.Project;
38 import net.pterodactylus.jsite.i18n.I18n;
39 import net.pterodactylus.jsite.i18n.gui.I18nAction;
40 import net.pterodactylus.util.io.Closer;
41
42 /**
43  * The Swing user interface.
44  *
45  * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
46  * @version $Id$
47  */
48 public class SwingInterface implements CoreListener {
49
50         /** The application core. */
51         private final Core core;
52
53         /** The configuration directory. */
54         private final String configDirectory;
55
56         /** The main window. */
57         private MainWindow mainWindow;
58
59         /** The “configure” action. */
60         private I18nAction configureAction;
61
62         /** The “import config” action. */
63         private I18nAction importConfigAction;
64
65         /** The “quit” action. */
66         private I18nAction quitAction;
67
68         /** The “manage nodes” action. */
69         private I18nAction manageNodesAction;
70
71         /** The “connect to node” action. */
72         private I18nAction nodeConnectAction;
73
74         /** The “disconnect from node” action. */
75         private I18nAction nodeDisconnectAction;
76
77         /** The node manager dialog. */
78         private ManageNodesDialog manageNodesDialog;
79
80         /** All lanugage menu items. */
81         private List<I18nAction> languageActions = new ArrayList<I18nAction>();
82
83         /** The “about” action. */
84         private I18nAction helpAboutAction;
85
86         /** The “add project” action. */
87         private I18nAction addProjectAction;
88
89         /** The “clone project” action. */
90         private I18nAction cloneProjectAction;
91
92         /** The “delete project” action. */
93         private I18nAction deleteProjectAction;
94
95         /** The “about” dialog. */
96         private AboutDialog aboutDialog;
97
98         /** The configuration dialog. */
99         private ConfigurationDialog configurationDialog;
100
101         /** The list of all defined nodes. */
102         private List<Node> nodeList;
103
104         //
105         // CONFIGURATION
106         //
107
108         /** Whether to beautify the GUI. */
109         private boolean beautify;
110
111         /** The control font. */
112         private String controlFont;
113
114         /** The user font. */
115         private String userFont;
116
117         /**
118          * Creates a new swing interface.
119          *
120          * @param core
121          *            The core to operate on
122          * @param configDirectory
123          *            The directory the configuration is stored in
124          */
125         public SwingInterface(Core core, String configDirectory) {
126                 this.core = core;
127                 this.configDirectory = configDirectory;
128                 I18n.setLocale(Locale.ENGLISH);
129                 loadConfig();
130                 if (beautify) {
131                         System.setProperty("swing.aatext", "true");
132                         if (controlFont != null) {
133                                 System.setProperty("swing.plaf.metal.controlFont", controlFont);
134                         }
135                         if (userFont != null) {
136                                 System.setProperty("swing.plaf.metal.userFont", userFont);
137                         }
138                 }
139                 initActions();
140                 initDialogs();
141         }
142
143         //
144         // ACCESSORS
145         //
146
147         /**
148          * Returns the core that is controlled by the Swing interface.
149          *
150          * @return The core
151          */
152         Core getCore() {
153                 return core;
154         }
155
156         /**
157          * Returns the main window of the Swing interface.
158          *
159          * @return The main window
160          */
161         MainWindow getMainWindow() {
162                 return mainWindow;
163         }
164
165         /**
166          * Returns the “configure” action.
167          *
168          * @return The “configure” action
169          */
170         I18nAction getConfigureAction() {
171                 return configureAction;
172         }
173
174         /**
175          * Returns the “import config” action.
176          *
177          * @return The “import config” action
178          */
179         I18nAction getImportConfigAction() {
180                 return importConfigAction;
181         }
182
183         /**
184          * Returns the “quit” action.
185          *
186          * @return The “quit” action
187          */
188         I18nAction getQuitAction() {
189                 return quitAction;
190         }
191
192         /**
193          * Returns the “manage nodes” action.
194          *
195          * @return The “manage nodes” action
196          */
197         I18nAction getManageNodesAction() {
198                 return manageNodesAction;
199         }
200
201         /**
202          * Returns the “connect to node” action.
203          *
204          * @return The “connect to node” action
205          */
206         I18nAction getNodeConnectAction() {
207                 return nodeConnectAction;
208         }
209
210         /**
211          * Returns the “disconnect from node” action.
212          *
213          * @return The “disconnect from node” action
214          */
215         I18nAction getNodeDisconnectAction() {
216                 return nodeDisconnectAction;
217         }
218
219         /**
220          * Returns all language actions.
221          *
222          * @return All language actions
223          */
224         List<I18nAction> getLanguageActions() {
225                 return languageActions;
226         }
227
228         /**
229          * Returns the “about” action.
230          *
231          * @return The “about” action
232          */
233         I18nAction getHelpAboutAction() {
234                 return helpAboutAction;
235         }
236
237         /**
238          * Returns the “add project” action.
239          *
240          * @return The “add project” action
241          */
242         I18nAction getAddProjectAction() {
243                 return addProjectAction;
244         }
245
246         /**
247          * Returns the “clone project” action.
248          *
249          * @return The “clone project” action
250          */
251         I18nAction getCloneProjectAction() {
252                 return cloneProjectAction;
253         }
254
255         /**
256          * Returns the “delete project” action.
257          *
258          * @return The “delete project” action
259          */
260         I18nAction getDeleteProjectAction() {
261                 return deleteProjectAction;
262         }
263
264         //
265         // ACTIONS
266         //
267
268         //
269         // SERVICE METHODS
270         //
271
272         /**
273          * Starts the interface.
274          */
275         public void start() {
276                 mainWindow = new MainWindow(this);
277         }
278
279         //
280         // PRIVATE METHODS
281         //
282
283         /**
284          * Loads the configuration of the interface.
285          */
286         private void loadConfig() {
287                 /* initialize default stuff. */
288                 beautify = false;
289                 /* now read config. */
290                 File configFile = new File(configDirectory, "swing-interface.properties");
291                 if (!configFile.exists() || !configFile.canRead() || !configFile.isFile()) {
292                         System.err.println("could not find “" + configFile.getAbsolutePath() + "”!");
293                         return;
294                 }
295                 Properties configProperties = new Properties();
296                 FileInputStream configInputStream = null;
297                 try {
298                         configInputStream = new FileInputStream(configFile);
299                         configProperties.load(configInputStream);
300                 } catch (IOException ioe1) {
301                         System.err.println("could not load config, " + ioe1.getMessage());
302                 } finally {
303                         Closer.close(configInputStream);
304                 }
305                 if (configProperties.containsKey("beautify")) {
306                         beautify = Boolean.valueOf(configProperties.getProperty("beautify"));
307                 }
308                 if (configProperties.containsKey("controlFont")) {
309                         controlFont = configProperties.getProperty("controlFont");
310                 }
311                 if (configProperties.containsKey("userFont")) {
312                         userFont = configProperties.getProperty("userFont");
313                 }
314         }
315
316         /**
317          * Saves the configuration.
318          */
319         private void saveConfig() {
320                 File configDirectory = new File(this.configDirectory);
321                 if (!configDirectory.exists()) {
322                         if (!configDirectory.mkdirs()) {
323                                 System.err.println("could not create “" + this.configDirectory + "”!");
324                                 return;
325                         }
326                 }
327                 if (!configDirectory.exists() || !configDirectory.isDirectory() || !configDirectory.canWrite()) {
328                         System.err.println("can not access “" + this.configDirectory + "”!");
329                         return;
330                 }
331                 File configFile = new File(configDirectory, "swing-interface.properties");
332                 Properties configProperties = new Properties();
333                 configProperties.setProperty("beautify", String.valueOf(beautify));
334                 if (controlFont != null) {
335                         configProperties.setProperty("controlFont", controlFont);
336                 }
337                 if (userFont != null) {
338                         configProperties.setProperty("userFont", userFont);
339                 }
340                 FileOutputStream configOutputStream = null;
341                 try {
342                         configOutputStream = new FileOutputStream(configFile);
343                         configProperties.store(configOutputStream, "configuration of swing interface");
344                 } catch (IOException ioe1) {
345                         System.err.println("could not save config, " + ioe1.getMessage());
346                 } finally {
347                         Closer.close(configOutputStream);
348                 }
349         }
350
351         /**
352          * Initializes all actions.
353          */
354         private void initActions() {
355                 configureAction = new I18nAction("mainWindow.menu.jSite.configure") {
356
357                         /**
358                          * {@inheritDoc}
359                          */
360                         @SuppressWarnings("synthetic-access")
361                         public void actionPerformed(ActionEvent actionEvent) {
362                                 configure();
363                         }
364                 };
365                 importConfigAction = new I18nAction("mainWindow.menu.jSite.importConfig") {
366
367                         /**
368                          * {@inheritDoc}
369                          */
370                         @SuppressWarnings("synthetic-access")
371                         public void actionPerformed(ActionEvent actionEvent) {
372                                 importConfig();
373                         }
374                 };
375                 quitAction = new I18nAction("mainWindow.menu.jSite.quit") {
376
377                         /**
378                          * {@inheritDoc}
379                          */
380                         @SuppressWarnings("synthetic-access")
381                         public void actionPerformed(ActionEvent actionEvent) {
382                                 quit();
383                         }
384                 };
385                 manageNodesAction = new I18nAction("mainWindow.menu.node.item.manageNodes") {
386
387                         /**
388                          * {@inheritDoc}
389                          */
390                         @SuppressWarnings("synthetic-access")
391                         public void actionPerformed(ActionEvent actionEvent) {
392                                 manageNodes();
393                         }
394                 };
395                 nodeConnectAction = new I18nAction("mainWindow.menu.node.item.connect", false) {
396
397                         @SuppressWarnings("synthetic-access")
398                         public void actionPerformed(ActionEvent actionEvent) {
399                                 nodeConnect();
400                         }
401
402                 };
403                 nodeDisconnectAction = new I18nAction("mainWindow.menu.node.item.disconnect", false) {
404
405                         /**
406                          * {@inheritDoc}
407                          */
408                         @SuppressWarnings("synthetic-access")
409                         public void actionPerformed(ActionEvent e) {
410                                 nodeDisconnect();
411                         }
412                 };
413                 List<Locale> availableLanguages = I18n.findAvailableLanguages();
414                 for (final Locale locale: availableLanguages) {
415                         I18nAction languageAction = new I18nAction("general.language." + locale.getLanguage()) {
416
417                                 @SuppressWarnings("synthetic-access")
418                                 public void actionPerformed(ActionEvent e) {
419                                         changeLanguage(locale, this);
420                                 }
421
422                         };
423                         if (I18n.getLocale().getLanguage().equals(locale.getLanguage())) {
424                                 languageAction.setEnabled(false);
425                         }
426                         languageActions.add(languageAction);
427                 }
428                 helpAboutAction = new I18nAction("mainWindow.menu.help.item.about") {
429
430                         /**
431                          * {@inheritDoc}
432                          */
433                         @SuppressWarnings("synthetic-access")
434                         public void actionPerformed(ActionEvent actionEvent) {
435                                 helpAbout();
436                         }
437                 };
438                 addProjectAction = new I18nAction("mainWindow.button.addProject") {
439
440                         /**
441                          * {@inheritDoc}
442                          */
443                         @SuppressWarnings("synthetic-access")
444                         public void actionPerformed(ActionEvent actionEvent) {
445                                 addProject();
446                         }
447                 };
448                 cloneProjectAction = new I18nAction("mainWindow.button.cloneProject") {
449
450                         /**
451                          * {@inheritDoc}
452                          */
453                         @SuppressWarnings("synthetic-access")
454                         public void actionPerformed(ActionEvent actionEvent) {
455                                 cloneProject();
456                         }
457                 };
458                 deleteProjectAction = new I18nAction("mainWindow.button.deleteProject") {
459
460                         /**
461                          * {@inheritDoc}
462                          */
463                         @SuppressWarnings("synthetic-access")
464                         public void actionPerformed(ActionEvent actionEvent) {
465                                 deleteProject();
466                         }
467                 };
468         }
469
470         /**
471          * Initializes all child dialogs.
472          */
473         private void initDialogs() {
474                 manageNodesDialog = new ManageNodesDialog(this);
475                 aboutDialog = new AboutDialog(this);
476                 configurationDialog = new ConfigurationDialog(this);
477         }
478
479         //
480         // PRIVATE ACTIONS
481         //
482
483         /**
484          * Shows the configuration dialog.
485          */
486         private void configure() {
487                 configurationDialog.setBeautify(beautify);
488                 configurationDialog.setControlFont(controlFont);
489                 configurationDialog.setUserFont(userFont);
490                 configurationDialog.setVisible(true);
491                 if (!configurationDialog.wasCancelled()) {
492                         beautify = configurationDialog.getBeautify();
493                         controlFont = configurationDialog.getControlFont();
494                         userFont = configurationDialog.getUserFont();
495                         saveConfig();
496                 }
497         }
498
499         /**
500          * Imports old jSite configuration.
501          */
502         private void importConfig() {
503         }
504
505         /**
506          * Quits jSite.
507          */
508         private void quit() {
509                 saveConfig();
510                 System.exit(0);
511         }
512
513         /**
514          * Pops up the “manage nodes” dialog.
515          */
516         private void manageNodes() {
517                 manageNodesDialog.setNodeList(nodeList);
518                 manageNodesDialog.setVisible(true);
519                 nodeList = manageNodesDialog.getNodeList();
520         }
521
522         /**
523          * Connects to the node.
524          */
525         private void nodeConnect() {
526         }
527
528         /**
529          * Disconnects from the node.
530          */
531         private void nodeDisconnect() {
532         }
533
534         /**
535          * Changes the language of the interface. This method also disables the
536          * action for the newly set language and enables all others.
537          *
538          * @param newLocale
539          *            The new language
540          * @param languageAction
541          *            The action that triggered the change
542          */
543         private void changeLanguage(Locale newLocale, I18nAction languageAction) {
544                 for (I18nAction i18nAction: languageActions) {
545                         i18nAction.setEnabled(i18nAction != languageAction);
546                 }
547                 I18n.setLocale(newLocale);
548         }
549
550         /**
551          * Shows the “about” dialog.
552          */
553         private void helpAbout() {
554                 aboutDialog.setVisible(true);
555         }
556
557         /**
558          * Adds a project.
559          */
560         private void addProject() {
561                 Project project = new Project();
562                 project.setName("New Project");
563                 project.setDescription("");
564         }
565
566         /**
567          * Clones a project.
568          */
569         private void cloneProject() {
570         }
571
572         /**
573          * Deletes a project.
574          */
575         private void deleteProject() {
576         }
577
578         //
579         // INTERFACE CoreListener
580         //
581
582         /**
583          * {@inheritDoc}
584          */
585         public void loadingProjectsFailed(String directory) {
586                 JOptionPane.showMessageDialog(mainWindow, I18n.get("mainWindow.error.projectLoadingFailed.message", directory), I18n.get("mainWindow.error.projectLoadingFailed.title"), JOptionPane.ERROR_MESSAGE);
587         }
588
589         /**
590          * {@inheritDoc}
591          */
592         public void coreLoaded() {
593                 this.nodeList = core.getNodes();
594                 manageNodesDialog.setNodeList(nodeList);
595                 mainWindow.setVisible(true);
596                 mainWindow.setStatusBarText("Core loaded.");
597         }
598
599         /**
600          * {@inheritDoc}
601          */
602         public void nodeConnected(Node node) {
603         }
604
605         /**
606          * {@inheritDoc}
607          */
608         public void nodeConnecting(Node node) {
609         }
610
611         /**
612          * {@inheritDoc}
613          */
614         public void nodeDisconnected(Node node) {
615         }
616
617 }