add advanced mode
[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         /** The advanced mode. */
109         private boolean advancedMode;
110
111         /** Whether to antialias the GUI. */
112         private boolean antialias;
113
114         /** The control font. */
115         private String controlFont;
116
117         /** The user font. */
118         private String userFont;
119
120         /**
121          * Creates a new swing interface.
122          *
123          * @param core
124          *            The core to operate on
125          * @param configDirectory
126          *            The directory the configuration is stored in
127          */
128         public SwingInterface(Core core, String configDirectory) {
129                 this.core = core;
130                 this.configDirectory = configDirectory;
131                 I18n.setLocale(Locale.ENGLISH);
132                 loadConfig();
133                 if (antialias) {
134                         System.setProperty("swing.aatext", "true");
135                 }
136                 if (controlFont != null) {
137                         System.setProperty("swing.plaf.metal.controlFont", controlFont);
138                 }
139                 if (userFont != null) {
140                         System.setProperty("swing.plaf.metal.userFont", userFont);
141                 }
142                 initActions();
143                 initDialogs();
144         }
145
146         //
147         // ACCESSORS
148         //
149
150         /**
151          * Returns the core that is controlled by the Swing interface.
152          *
153          * @return The core
154          */
155         Core getCore() {
156                 return core;
157         }
158
159         /**
160          * Returns the main window of the Swing interface.
161          *
162          * @return The main window
163          */
164         MainWindow getMainWindow() {
165                 return mainWindow;
166         }
167
168         /**
169          * Returns the “configure” action.
170          *
171          * @return The “configure” action
172          */
173         I18nAction getConfigureAction() {
174                 return configureAction;
175         }
176
177         /**
178          * Returns the “import config” action.
179          *
180          * @return The “import config” action
181          */
182         I18nAction getImportConfigAction() {
183                 return importConfigAction;
184         }
185
186         /**
187          * Returns the “quit” action.
188          *
189          * @return The “quit” action
190          */
191         I18nAction getQuitAction() {
192                 return quitAction;
193         }
194
195         /**
196          * Returns the “manage nodes” action.
197          *
198          * @return The “manage nodes” action
199          */
200         I18nAction getManageNodesAction() {
201                 return manageNodesAction;
202         }
203
204         /**
205          * Returns the “connect to node” action.
206          *
207          * @return The “connect to node” action
208          */
209         I18nAction getNodeConnectAction() {
210                 return nodeConnectAction;
211         }
212
213         /**
214          * Returns the “disconnect from node” action.
215          *
216          * @return The “disconnect from node” action
217          */
218         I18nAction getNodeDisconnectAction() {
219                 return nodeDisconnectAction;
220         }
221
222         /**
223          * Returns all language actions.
224          *
225          * @return All language actions
226          */
227         List<I18nAction> getLanguageActions() {
228                 return languageActions;
229         }
230
231         /**
232          * Returns the “about” action.
233          *
234          * @return The “about” action
235          */
236         I18nAction getHelpAboutAction() {
237                 return helpAboutAction;
238         }
239
240         /**
241          * Returns the “add project” action.
242          *
243          * @return The “add project” action
244          */
245         I18nAction getAddProjectAction() {
246                 return addProjectAction;
247         }
248
249         /**
250          * Returns the “clone project” action.
251          *
252          * @return The “clone project” action
253          */
254         I18nAction getCloneProjectAction() {
255                 return cloneProjectAction;
256         }
257
258         /**
259          * Returns the “delete project” action.
260          *
261          * @return The “delete project” action
262          */
263         I18nAction getDeleteProjectAction() {
264                 return deleteProjectAction;
265         }
266
267         //
268         // ACTIONS
269         //
270
271         //
272         // SERVICE METHODS
273         //
274
275         /**
276          * Starts the interface.
277          */
278         public void start() {
279                 mainWindow = new MainWindow(this);
280         }
281
282         //
283         // PRIVATE METHODS
284         //
285
286         /**
287          * Loads the configuration of the interface.
288          */
289         private void loadConfig() {
290                 /* initialize default stuff. */
291                 antialias = false;
292                 /* now read config. */
293                 File configFile = new File(configDirectory, "swing-interface.properties");
294                 if (!configFile.exists() || !configFile.canRead() || !configFile.isFile()) {
295                         System.err.println("could not find “" + configFile.getAbsolutePath() + "”!");
296                         return;
297                 }
298                 Properties configProperties = new Properties();
299                 FileInputStream configInputStream = null;
300                 try {
301                         configInputStream = new FileInputStream(configFile);
302                         configProperties.load(configInputStream);
303                 } catch (IOException ioe1) {
304                         System.err.println("could not load config, " + ioe1.getMessage());
305                 } finally {
306                         Closer.close(configInputStream);
307                 }
308                 if (configProperties.containsKey("advancedMode")) {
309                         advancedMode = Boolean.valueOf(configProperties.getProperty("advancedMode"));
310                 }
311                 if (configProperties.containsKey("antialias")) {
312                         antialias = Boolean.valueOf(configProperties.getProperty("antialias"));
313                 }
314                 if (configProperties.containsKey("controlFont")) {
315                         controlFont = configProperties.getProperty("controlFont");
316                 }
317                 if (configProperties.containsKey("userFont")) {
318                         userFont = configProperties.getProperty("userFont");
319                 }
320                 if (configProperties.containsKey("language")) {
321                         I18n.setLocale(new Locale(configProperties.getProperty("language")));
322                 }
323         }
324
325         /**
326          * Saves the configuration.
327          */
328         private void saveConfig() {
329                 File configDirectory = new File(this.configDirectory);
330                 if (!configDirectory.exists()) {
331                         if (!configDirectory.mkdirs()) {
332                                 System.err.println("could not create “" + this.configDirectory + "”!");
333                                 return;
334                         }
335                 }
336                 if (!configDirectory.exists() || !configDirectory.isDirectory() || !configDirectory.canWrite()) {
337                         System.err.println("can not access “" + this.configDirectory + "”!");
338                         return;
339                 }
340                 File configFile = new File(configDirectory, "swing-interface.properties");
341                 Properties configProperties = new Properties();
342                 configProperties.setProperty("advancedMode", String.valueOf(advancedMode));
343                 configProperties.setProperty("antialias", String.valueOf(antialias));
344                 if (controlFont != null) {
345                         configProperties.setProperty("controlFont", controlFont);
346                 }
347                 if (userFont != null) {
348                         configProperties.setProperty("userFont", userFont);
349                 }
350                 configProperties.setProperty("language", I18n.getLocale().getLanguage());
351                 FileOutputStream configOutputStream = null;
352                 try {
353                         configOutputStream = new FileOutputStream(configFile);
354                         configProperties.store(configOutputStream, "configuration of swing interface");
355                 } catch (IOException ioe1) {
356                         System.err.println("could not save config, " + ioe1.getMessage());
357                 } finally {
358                         Closer.close(configOutputStream);
359                 }
360         }
361
362         /**
363          * Initializes all actions.
364          */
365         private void initActions() {
366                 configureAction = new I18nAction("mainWindow.menu.jSite.configure") {
367
368                         /**
369                          * {@inheritDoc}
370                          */
371                         @SuppressWarnings("synthetic-access")
372                         public void actionPerformed(ActionEvent actionEvent) {
373                                 configure();
374                         }
375                 };
376                 importConfigAction = new I18nAction("mainWindow.menu.jSite.importConfig") {
377
378                         /**
379                          * {@inheritDoc}
380                          */
381                         @SuppressWarnings("synthetic-access")
382                         public void actionPerformed(ActionEvent actionEvent) {
383                                 importConfig();
384                         }
385                 };
386                 quitAction = new I18nAction("mainWindow.menu.jSite.quit") {
387
388                         /**
389                          * {@inheritDoc}
390                          */
391                         @SuppressWarnings("synthetic-access")
392                         public void actionPerformed(ActionEvent actionEvent) {
393                                 quit();
394                         }
395                 };
396                 manageNodesAction = new I18nAction("mainWindow.menu.node.item.manageNodes") {
397
398                         /**
399                          * {@inheritDoc}
400                          */
401                         @SuppressWarnings("synthetic-access")
402                         public void actionPerformed(ActionEvent actionEvent) {
403                                 manageNodes();
404                         }
405                 };
406                 nodeConnectAction = new I18nAction("mainWindow.menu.node.item.connect", false) {
407
408                         @SuppressWarnings("synthetic-access")
409                         public void actionPerformed(ActionEvent actionEvent) {
410                                 nodeConnect();
411                         }
412
413                 };
414                 nodeDisconnectAction = new I18nAction("mainWindow.menu.node.item.disconnect", false) {
415
416                         /**
417                          * {@inheritDoc}
418                          */
419                         @SuppressWarnings("synthetic-access")
420                         public void actionPerformed(ActionEvent e) {
421                                 nodeDisconnect();
422                         }
423                 };
424                 List<Locale> availableLanguages = I18n.findAvailableLanguages();
425                 for (final Locale locale: availableLanguages) {
426                         I18nAction languageAction = new I18nAction("general.language." + locale.getLanguage()) {
427
428                                 @SuppressWarnings("synthetic-access")
429                                 public void actionPerformed(ActionEvent e) {
430                                         changeLanguage(locale, this);
431                                 }
432
433                         };
434                         if (I18n.getLocale().getLanguage().equals(locale.getLanguage())) {
435                                 languageAction.setEnabled(false);
436                         }
437                         languageActions.add(languageAction);
438                 }
439                 helpAboutAction = new I18nAction("mainWindow.menu.help.item.about") {
440
441                         /**
442                          * {@inheritDoc}
443                          */
444                         @SuppressWarnings("synthetic-access")
445                         public void actionPerformed(ActionEvent actionEvent) {
446                                 helpAbout();
447                         }
448                 };
449                 addProjectAction = new I18nAction("mainWindow.button.addProject") {
450
451                         /**
452                          * {@inheritDoc}
453                          */
454                         @SuppressWarnings("synthetic-access")
455                         public void actionPerformed(ActionEvent actionEvent) {
456                                 addProject();
457                         }
458                 };
459                 cloneProjectAction = new I18nAction("mainWindow.button.cloneProject") {
460
461                         /**
462                          * {@inheritDoc}
463                          */
464                         @SuppressWarnings("synthetic-access")
465                         public void actionPerformed(ActionEvent actionEvent) {
466                                 cloneProject();
467                         }
468                 };
469                 deleteProjectAction = new I18nAction("mainWindow.button.deleteProject") {
470
471                         /**
472                          * {@inheritDoc}
473                          */
474                         @SuppressWarnings("synthetic-access")
475                         public void actionPerformed(ActionEvent actionEvent) {
476                                 deleteProject();
477                         }
478                 };
479         }
480
481         /**
482          * Initializes all child dialogs.
483          */
484         private void initDialogs() {
485                 manageNodesDialog = new ManageNodesDialog(this);
486                 aboutDialog = new AboutDialog(this);
487                 configurationDialog = new ConfigurationDialog(this);
488         }
489
490         //
491         // PRIVATE ACTIONS
492         //
493
494         /**
495          * Shows the configuration dialog.
496          */
497         private void configure() {
498                 configurationDialog.setAdvancedMode(advancedMode);
499                 configurationDialog.setAntialias(antialias);
500                 configurationDialog.setControlFont(controlFont);
501                 configurationDialog.setUserFont(userFont);
502                 configurationDialog.setVisible(true);
503                 if (!configurationDialog.wasCancelled()) {
504                         advancedMode = configurationDialog.isAdvancedMode();
505                         if (!advancedMode && (nodeList.size() > 1)) {
506                                 JOptionPane.showMessageDialog(mainWindow, I18n.get("mainWindow.warning.multipleNodesNotAdvancedMode.message"), I18n.get("mainWindow.warning.multipleNodesNotAdvancedMode.title"), JOptionPane.WARNING_MESSAGE);
507                         }
508                         antialias = configurationDialog.isAntialias();
509                         controlFont = configurationDialog.getControlFont();
510                         userFont = configurationDialog.getUserFont();
511                         saveConfig();
512                 }
513         }
514
515         /**
516          * Imports old jSite configuration.
517          */
518         private void importConfig() {
519                 /* TODO */
520         }
521
522         /**
523          * Quits jSite.
524          */
525         private void quit() {
526                 saveConfig();
527                 System.exit(0);
528         }
529
530         /**
531          * Pops up the “manage nodes” dialog.
532          */
533         private void manageNodes() {
534                 if (advancedMode) {
535                         manageNodesDialog.setNodeList(nodeList);
536                         manageNodesDialog.setVisible(true);
537                         nodeList = manageNodesDialog.getNodeList();
538                 } else {
539                         if (nodeList.isEmpty()) {
540                                 Node newNode = new Node();
541                                 newNode.setName(I18n.get("general.defaultNode.name"));
542                                 newNode.setHostname("localhost");
543                                 newNode.setPort(9481);
544                                 nodeList.add(newNode);
545                         }
546                         Node firstNode = nodeList.get(0);
547                         EditNodeDialog editNodeDialog = manageNodesDialog.getEditNodeDialog();
548                         editNodeDialog.setNodeName(firstNode.getName());
549                         editNodeDialog.setNodeHostname(firstNode.getHostname());
550                         editNodeDialog.setNodePort(firstNode.getPort());
551                         editNodeDialog.setVisible(true);
552                         if (!editNodeDialog.wasCancelled()) {
553                                 firstNode.setName(editNodeDialog.getNodeName());
554                                 firstNode.setHostname(editNodeDialog.getNodeHostname());
555                                 firstNode.setPort(editNodeDialog.getNodePort());
556                                 /* TODO - give to core. */
557                         }
558                 }
559         }
560
561         /**
562          * Connects to the node.
563          */
564         private void nodeConnect() {
565                 /* TODO */
566         }
567
568         /**
569          * Disconnects from the node.
570          */
571         private void nodeDisconnect() {
572                 /* TODO */
573         }
574
575         /**
576          * Changes the language of the interface. This method also disables the
577          * action for the newly set language and enables all others.
578          *
579          * @param newLocale
580          *            The new language
581          * @param languageAction
582          *            The action that triggered the change
583          */
584         private void changeLanguage(Locale newLocale, I18nAction languageAction) {
585                 for (I18nAction i18nAction: languageActions) {
586                         i18nAction.setEnabled(i18nAction != languageAction);
587                 }
588                 I18n.setLocale(newLocale);
589         }
590
591         /**
592          * Shows the “about” dialog.
593          */
594         private void helpAbout() {
595                 aboutDialog.setVisible(true);
596         }
597
598         /**
599          * Adds a project.
600          */
601         private void addProject() {
602                 Project project = new Project();
603                 project.setName("New Project");
604                 project.setDescription("");
605         }
606
607         /**
608          * Clones a project.
609          */
610         private void cloneProject() {
611                 /* TODO */
612         }
613
614         /**
615          * Deletes a project.
616          */
617         private void deleteProject() {
618                 /* TODO */
619         }
620
621         //
622         // INTERFACE CoreListener
623         //
624
625         /**
626          * {@inheritDoc}
627          */
628         public void loadingProjectsFailed(String directory, Throwable throwable) {
629                 JOptionPane.showMessageDialog(mainWindow, I18n.get("mainWindow.error.projectLoadingFailed.message", directory), I18n.get("mainWindow.error.projectLoadingFailed.title"), JOptionPane.ERROR_MESSAGE);
630         }
631
632         /**
633          * {@inheritDoc}
634          */
635         public void savingProjectsDone(String directory) {
636                 mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.projectSavingDone"));
637         }
638
639         /**
640          * {@inheritDoc}
641          */
642         public void savingProjectsFailed(String directory, Throwable throwabled) {
643                 /* TODO */
644         }
645
646         /**
647          * {@inheritDoc}
648          */
649         public void coreLoaded() {
650                 this.nodeList = core.getNodes();
651                 manageNodesDialog.setNodeList(nodeList);
652                 mainWindow.setVisible(true);
653                 mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.coreLoaded"));
654         }
655
656         /**
657          * {@inheritDoc}
658          */
659         public void coreStopped() {
660                 mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.coreStopped"));
661         }
662
663         /**
664          * {@inheritDoc}
665          */
666         public void nodeConnected(Node node) {
667                 /* TODO */
668         }
669
670         /**
671          * {@inheritDoc}
672          */
673         public void nodeConnecting(Node node) {
674                 /* TODO */
675         }
676
677         /**
678          * {@inheritDoc}
679          */
680         public void nodeDisconnected(Node node) {
681                 /* TODO */
682         }
683
684 }