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