add request management
[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.Collections;
29 import java.util.HashMap;
30 import java.util.List;
31 import java.util.Locale;
32 import java.util.Map;
33 import java.util.Properties;
34 import java.util.concurrent.Executor;
35 import java.util.concurrent.Executors;
36 import java.util.logging.Level;
37 import java.util.logging.LogRecord;
38 import java.util.logging.Logger;
39
40 import javax.swing.AbstractAction;
41 import javax.swing.Action;
42 import javax.swing.JOptionPane;
43 import javax.swing.UIManager;
44 import javax.swing.UnsupportedLookAndFeelException;
45
46 import net.pterodactylus.jsite.core.Core;
47 import net.pterodactylus.jsite.core.CoreListener;
48 import net.pterodactylus.jsite.core.Node;
49 import net.pterodactylus.jsite.core.Project;
50 import net.pterodactylus.jsite.core.Request;
51 import net.pterodactylus.jsite.i18n.I18n;
52 import net.pterodactylus.jsite.i18n.gui.I18nAction;
53 import net.pterodactylus.util.image.IconLoader;
54 import net.pterodactylus.util.io.Closer;
55 import net.pterodactylus.util.logging.Logging;
56 import net.pterodactylus.util.logging.LoggingListener;
57
58 /**
59  * The Swing user interface.
60  * 
61  * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
62  * @version $Id$
63  */
64 public class SwingInterface implements CoreListener, LoggingListener {
65
66         /** The logger. */
67         private static final Logger logger = Logging.getLogger(SwingInterface.class.getName());
68
69         /** The application core. */
70         private final Core core;
71
72         /** The configuration directory. */
73         private final String configDirectory;
74
75         /** The main window. */
76         private MainWindow mainWindow;
77
78         /** Thread pool. */
79         private Executor threadPool = Executors.newCachedThreadPool();
80
81         /** The logger window. */
82         private LogWindow logWindow;
83
84         /** The “configure” action. */
85         private I18nAction configureAction;
86
87         /** The “import config” action. */
88         private I18nAction importConfigAction;
89
90         /** The “quit” action. */
91         private I18nAction quitAction;
92
93         /** The “manage nodes” action. */
94         private I18nAction manageNodesAction;
95
96         /** The “connect to node” (simple mode) action. */
97         private I18nAction nodeConnectAction;
98
99         /** The “disconnect from node” (simple mode) action. */
100         private I18nAction nodeDisconnectAction;
101
102         /** All node menu items. */
103         private List<Action> nodeConnectActions = Collections.synchronizedList(new ArrayList<Action>());
104
105         /** Mapping from nodes to node connect actions. */
106         private Map<Node, Action> nodeNodeConnectActions = Collections.synchronizedMap(new HashMap<Node, Action>());
107
108         /** Mapping from node connect actions to nodes. */
109         private Map<Action, Node> nodeConnectActionNodes = Collections.synchronizedMap(new HashMap<Action, Node>());
110
111         /** All node disconnect actions. */
112         private List<Action> nodeDisconnectActions = Collections.synchronizedList(new ArrayList<Action>());
113
114         /** Mapping from nodes to node disconnect actions. */
115         private Map<Node, Action> nodeNodeDisconnectActions = Collections.synchronizedMap(new HashMap<Node, Action>());
116
117         /** Mapping from node disconnect actions to nodes. */
118         private Map<Action, Node> nodeDisconnectActionNodes = Collections.synchronizedMap(new HashMap<Action, Node>());
119
120         /** The node manager dialog. */
121         private ManageNodesDialog manageNodesDialog;
122
123         /** All lanugage menu items. */
124         private List<I18nAction> languageActions = new ArrayList<I18nAction>();
125
126         /** The “about” action. */
127         private I18nAction helpAboutAction;
128
129         /** The “add project” action. */
130         private I18nAction addProjectAction;
131
132         /** The “clone project” action. */
133         private I18nAction cloneProjectAction;
134
135         /** The “delete project” action. */
136         private I18nAction deleteProjectAction;
137
138         /** The “about” dialog. */
139         private AboutDialog aboutDialog;
140
141         /** The configuration dialog. */
142         private ConfigurationDialog configurationDialog;
143
144         /** The list of all defined nodes. */
145         private List<Node> nodeList;
146
147         //
148         // CONFIGURATION
149         //
150
151         /** The advanced mode. */
152         private boolean advancedMode;
153
154         /** Whether to antialias the GUI. */
155         private boolean antialias;
156
157         /** The control font. */
158         private String controlFont;
159
160         /** The user font. */
161         private String userFont;
162
163         /** The class name of the look and feel. */
164         private String lookAndFeel;
165
166         /**
167          * Creates a new swing interface.
168          * 
169          * @param core
170          *            The core to operate on
171          * @param configDirectory
172          *            The directory the configuration is stored in
173          */
174         public SwingInterface(Core core, String configDirectory) {
175                 this.core = core;
176                 this.configDirectory = configDirectory;
177                 I18n.setLocale(Locale.ENGLISH);
178                 loadConfig();
179                 if (lookAndFeel != null) {
180                         try {
181                                 UIManager.setLookAndFeel(lookAndFeel);
182                         } catch (ClassNotFoundException cnfe1) {
183                                 logger.log(Level.WARNING, "could not load look and feel", cnfe1);
184                         } catch (InstantiationException ie1) {
185                                 logger.log(Level.WARNING, "could not load look and feel", ie1);
186                         } catch (IllegalAccessException iae1) {
187                                 logger.log(Level.WARNING, "could not load look and feel", iae1);
188                         } catch (UnsupportedLookAndFeelException ulafe1) {
189                                 logger.log(Level.WARNING, "could not load look and feel", ulafe1);
190                         }
191                 }
192                 if (antialias) {
193                         System.setProperty("swing.aatext", "true");
194                 }
195                 if (controlFont != null) {
196                         System.setProperty("swing.plaf.metal.controlFont", controlFont);
197                 }
198                 if (userFont != null) {
199                         System.setProperty("swing.plaf.metal.userFont", userFont);
200                 }
201                 initActions();
202                 initDialogs();
203                 mainWindow = new MainWindow(this);
204                 mainWindow.setAdvancedMode(advancedMode);
205                 logWindow = new LogWindow();
206         }
207
208         //
209         // ACCESSORS
210         //
211
212         /**
213          * Returns the core that is controlled by the Swing interface.
214          * 
215          * @return The core
216          */
217         Core getCore() {
218                 return core;
219         }
220
221         /**
222          * Returns the main window of the Swing interface.
223          * 
224          * @return The main window
225          */
226         MainWindow getMainWindow() {
227                 return mainWindow;
228         }
229
230         /**
231          * Returns whether the advanced mode is activated.
232          * 
233          * @return <code>true</code> if the advanced mode is activated,
234          *         <code>false</code> if the simple mode is activated
235          */
236         boolean isAdvancedMode() {
237                 return advancedMode;
238         }
239
240         /**
241          * Returns the “configure” action.
242          * 
243          * @return The “configure” action
244          */
245         I18nAction getConfigureAction() {
246                 return configureAction;
247         }
248
249         /**
250          * Returns the “import config” action.
251          * 
252          * @return The “import config” action
253          */
254         I18nAction getImportConfigAction() {
255                 return importConfigAction;
256         }
257
258         /**
259          * Returns the “quit” action.
260          * 
261          * @return The “quit” action
262          */
263         I18nAction getQuitAction() {
264                 return quitAction;
265         }
266
267         /**
268          * Returns the “manage nodes” action.
269          * 
270          * @return The “manage nodes” action
271          */
272         I18nAction getManageNodesAction() {
273                 return manageNodesAction;
274         }
275
276         /**
277          * Returns the “connect to node” action.
278          * 
279          * @return The “connect to node” action
280          */
281         I18nAction getNodeConnectAction() {
282                 return nodeConnectAction;
283         }
284
285         /**
286          * Returns all “connect node” actions.
287          * 
288          * @return All “connect node” actions
289          */
290         List<Action> getNodeConnectActions() {
291                 return nodeConnectActions;
292         }
293
294         /**
295          * Returns the “disconnect from node” action.
296          * 
297          * @return The “disconnect from node” action
298          */
299         I18nAction getNodeDisconnectAction() {
300                 return nodeDisconnectAction;
301         }
302
303         /**
304          * Returns all “disconnect node” actions.
305          * 
306          * @return All “disconnect node” action
307          */
308         List<Action> getNodeDisconnectActions() {
309                 return nodeDisconnectActions;
310         }
311
312         /**
313          * Returns all language actions.
314          * 
315          * @return All language actions
316          */
317         List<I18nAction> getLanguageActions() {
318                 return languageActions;
319         }
320
321         /**
322          * Returns the “about” action.
323          * 
324          * @return The “about” action
325          */
326         I18nAction getHelpAboutAction() {
327                 return helpAboutAction;
328         }
329
330         /**
331          * Returns the “add project” action.
332          * 
333          * @return The “add project” action
334          */
335         I18nAction getAddProjectAction() {
336                 return addProjectAction;
337         }
338
339         /**
340          * Returns the “clone project” action.
341          * 
342          * @return The “clone project” action
343          */
344         I18nAction getCloneProjectAction() {
345                 return cloneProjectAction;
346         }
347
348         /**
349          * Returns the “delete project” action.
350          * 
351          * @return The “delete project” action
352          */
353         I18nAction getDeleteProjectAction() {
354                 return deleteProjectAction;
355         }
356
357         //
358         // ACTIONS
359         //
360
361         //
362         // SERVICE METHODS
363         //
364
365         //
366         // PRIVATE METHODS
367         //
368
369         /**
370          * Loads the configuration of the interface.
371          */
372         private void loadConfig() {
373                 /* initialize default stuff. */
374                 antialias = false;
375                 /* now read config. */
376                 File configFile = new File(configDirectory, "swing-interface.properties");
377                 if (!configFile.exists() || !configFile.canRead() || !configFile.isFile()) {
378                         System.err.println("could not find “" + configFile.getAbsolutePath() + "”!");
379                         return;
380                 }
381                 Properties configProperties = new Properties();
382                 FileInputStream configInputStream = null;
383                 try {
384                         configInputStream = new FileInputStream(configFile);
385                         configProperties.load(configInputStream);
386                 } catch (IOException ioe1) {
387                         System.err.println("could not load config, " + ioe1.getMessage());
388                 } finally {
389                         Closer.close(configInputStream);
390                 }
391                 if (configProperties.containsKey("advancedMode")) {
392                         advancedMode = Boolean.valueOf(configProperties.getProperty("advancedMode"));
393                 }
394                 if (configProperties.containsKey("antialias")) {
395                         antialias = Boolean.valueOf(configProperties.getProperty("antialias"));
396                 }
397                 if (configProperties.containsKey("controlFont")) {
398                         controlFont = configProperties.getProperty("controlFont");
399                 }
400                 if (configProperties.containsKey("userFont")) {
401                         userFont = configProperties.getProperty("userFont");
402                 }
403                 if (configProperties.containsKey("lookAndFeel")) {
404                         lookAndFeel = configProperties.getProperty("lookAndFeel");
405                 }
406                 if (configProperties.containsKey("language")) {
407                         I18n.setLocale(new Locale(configProperties.getProperty("language")));
408                 }
409         }
410
411         /**
412          * Saves the configuration.
413          */
414         private void saveConfig() {
415                 File configDirectory = new File(this.configDirectory);
416                 if (!configDirectory.exists()) {
417                         if (!configDirectory.mkdirs()) {
418                                 System.err.println("could not create “" + this.configDirectory + "”!");
419                                 return;
420                         }
421                 }
422                 if (!configDirectory.exists() || !configDirectory.isDirectory() || !configDirectory.canWrite()) {
423                         System.err.println("can not access “" + this.configDirectory + "”!");
424                         return;
425                 }
426                 File configFile = new File(configDirectory, "swing-interface.properties");
427                 Properties configProperties = new Properties();
428                 configProperties.setProperty("advancedMode", String.valueOf(advancedMode));
429                 configProperties.setProperty("antialias", String.valueOf(antialias));
430                 if (controlFont != null) {
431                         configProperties.setProperty("controlFont", controlFont);
432                 }
433                 if (userFont != null) {
434                         configProperties.setProperty("userFont", userFont);
435                 }
436                 if (lookAndFeel != null) {
437                         configProperties.setProperty("lookAndFeel", lookAndFeel);
438                 }
439                 configProperties.setProperty("language", I18n.getLocale().getLanguage());
440                 FileOutputStream configOutputStream = null;
441                 try {
442                         configOutputStream = new FileOutputStream(configFile);
443                         configProperties.store(configOutputStream, "configuration of swing interface");
444                 } catch (IOException ioe1) {
445                         System.err.println("could not save config, " + ioe1.getMessage());
446                 } finally {
447                         Closer.close(configOutputStream);
448                 }
449         }
450
451         /**
452          * Initializes all actions.
453          */
454         private void initActions() {
455                 configureAction = new I18nAction("mainWindow.menu.jSite.configure", IconLoader.loadIcon("/preferences-system.png")) {
456
457                         /**
458                          * {@inheritDoc}
459                          */
460                         @SuppressWarnings("synthetic-access")
461                         public void actionPerformed(ActionEvent actionEvent) {
462                                 configure();
463                         }
464                 };
465                 importConfigAction = new I18nAction("mainWindow.menu.jSite.importConfig") {
466
467                         /**
468                          * {@inheritDoc}
469                          */
470                         @SuppressWarnings("synthetic-access")
471                         public void actionPerformed(ActionEvent actionEvent) {
472                                 importConfig();
473                         }
474                 };
475                 quitAction = new I18nAction("mainWindow.menu.jSite.quit", IconLoader.loadIcon("/system-log-out.png")) {
476
477                         /**
478                          * {@inheritDoc}
479                          */
480                         @SuppressWarnings("synthetic-access")
481                         public void actionPerformed(ActionEvent actionEvent) {
482                                 quit();
483                         }
484                 };
485                 manageNodesAction = new I18nAction("mainWindow.menu.node.item.manageNodes") {
486
487                         /**
488                          * {@inheritDoc}
489                          */
490                         @SuppressWarnings("synthetic-access")
491                         public void actionPerformed(ActionEvent actionEvent) {
492                                 manageNodes();
493                         }
494                 };
495                 nodeConnectAction = new I18nAction("mainWindow.menu.node.item.connect", false) {
496
497                         @SuppressWarnings("synthetic-access")
498                         public void actionPerformed(ActionEvent actionEvent) {
499                                 List<Node> nodes = core.getNodes();
500                                 if (nodes.isEmpty()) {
501                                         return;
502                                 }
503                                 nodeConnect(nodes.get(0));
504                         }
505
506                 };
507                 nodeDisconnectAction = new I18nAction("mainWindow.menu.node.item.disconnect", false) {
508
509                         /**
510                          * {@inheritDoc}
511                          */
512                         @SuppressWarnings("synthetic-access")
513                         public void actionPerformed(ActionEvent e) {
514                                 List<Node> nodes = core.getNodes();
515                                 if (nodes.isEmpty()) {
516                                         return;
517                                 }
518                                 nodeDisconnect(nodes.get(0));
519                         }
520                 };
521                 rebuildNodeActions(core.getNodes());
522                 List<Locale> availableLanguages = I18n.findAvailableLanguages();
523                 for (final Locale locale: availableLanguages) {
524                         I18nAction languageAction = new I18nAction("general.language." + locale.getLanguage()) {
525
526                                 @SuppressWarnings("synthetic-access")
527                                 public void actionPerformed(ActionEvent e) {
528                                         changeLanguage(locale, this);
529                                 }
530
531                         };
532                         if (I18n.getLocale().getLanguage().equals(locale.getLanguage())) {
533                                 languageAction.setEnabled(false);
534                         }
535                         languageActions.add(languageAction);
536                 }
537                 helpAboutAction = new I18nAction("mainWindow.menu.help.item.about") {
538
539                         /**
540                          * {@inheritDoc}
541                          */
542                         @SuppressWarnings("synthetic-access")
543                         public void actionPerformed(ActionEvent actionEvent) {
544                                 helpAbout();
545                         }
546                 };
547                 addProjectAction = new I18nAction("mainWindow.button.addProject") {
548
549                         /**
550                          * {@inheritDoc}
551                          */
552                         @SuppressWarnings("synthetic-access")
553                         public void actionPerformed(ActionEvent actionEvent) {
554                                 addProject();
555                         }
556                 };
557                 cloneProjectAction = new I18nAction("mainWindow.button.cloneProject") {
558
559                         /**
560                          * {@inheritDoc}
561                          */
562                         @SuppressWarnings("synthetic-access")
563                         public void actionPerformed(ActionEvent actionEvent) {
564                                 cloneProject();
565                         }
566                 };
567                 deleteProjectAction = new I18nAction("mainWindow.button.deleteProject") {
568
569                         /**
570                          * {@inheritDoc}
571                          */
572                         @SuppressWarnings("synthetic-access")
573                         public void actionPerformed(ActionEvent actionEvent) {
574                                 deleteProject();
575                         }
576                 };
577         }
578
579         /**
580          * Initializes all child dialogs.
581          */
582         private void initDialogs() {
583                 manageNodesDialog = new ManageNodesDialog(this);
584                 aboutDialog = new AboutDialog(this);
585                 configurationDialog = new ConfigurationDialog(this);
586         }
587
588         //
589         // PRIVATE ACTIONS
590         //
591
592         /**
593          * Shows the configuration dialog.
594          */
595         private void configure() {
596                 configurationDialog.setAdvancedMode(advancedMode);
597                 configurationDialog.setAntialias(antialias);
598                 configurationDialog.setControlFont(controlFont);
599                 configurationDialog.setUserFont(userFont);
600                 configurationDialog.setLookAndFeel(lookAndFeel);
601                 configurationDialog.setVisible(true);
602                 if (!configurationDialog.wasCancelled()) {
603                         advancedMode = configurationDialog.isAdvancedMode();
604                         if (!advancedMode && (nodeList.size() > 1)) {
605                                 JOptionPane.showMessageDialog(mainWindow, I18n.get("mainWindow.warning.multipleNodesNotAdvancedMode.message"), I18n.get("mainWindow.warning.multipleNodesNotAdvancedMode.title"), JOptionPane.WARNING_MESSAGE);
606                         }
607                         mainWindow.setAdvancedMode(advancedMode);
608                         antialias = configurationDialog.isAntialias();
609                         controlFont = configurationDialog.getControlFont();
610                         userFont = configurationDialog.getUserFont();
611                         lookAndFeel = configurationDialog.getLookAndFeel();
612                         saveConfig();
613                 }
614         }
615
616         /**
617          * Imports old jSite configuration.
618          */
619         private void importConfig() {
620                 /* TODO */
621         }
622
623         /**
624          * Quits jSite.
625          */
626         private void quit() {
627                 saveConfig();
628                 System.exit(0);
629         }
630
631         /**
632          * Rebuilds all node connect and disconnect actions.
633          * 
634          * @param nodes
635          *            The list of nodes
636          */
637         private void rebuildNodeActions(List<Node> nodes) {
638                 nodeConnectActions.clear();
639                 nodeNodeConnectActions.clear();
640                 nodeConnectActionNodes.clear();
641                 nodeDisconnectActions.clear();
642                 nodeNodeDisconnectActions.clear();
643                 nodeDisconnectActionNodes.clear();
644                 for (Node node: nodes) {
645                         Action nodeConnectAction = new AbstractAction(node.getName()) {
646
647                                 /**
648                                  * {@inheritDoc}
649                                  */
650                                 @SuppressWarnings("synthetic-access")
651                                 public void actionPerformed(ActionEvent e) {
652                                         Node node = nodeConnectActionNodes.get(this);
653                                         nodeConnect(node);
654                                 }
655                         };
656                         nodeConnectActions.add(nodeConnectAction);
657                         nodeConnectActionNodes.put(nodeConnectAction, node);
658                         nodeNodeConnectActions.put(node, nodeConnectAction);
659                         Action nodeDisconnectAction = new AbstractAction(node.getName()) {
660
661                                 /**
662                                  * {@inheritDoc}
663                                  */
664                                 @SuppressWarnings("synthetic-access")
665                                 public void actionPerformed(ActionEvent e) {
666                                         Node node = nodeDisconnectActionNodes.get(this);
667                                         nodeDisconnect(node);
668                                 }
669                         };
670 // nodeDisconnectActions.add(nodeDisconnectAction);
671                         nodeDisconnectActionNodes.put(nodeDisconnectAction, node);
672                         nodeNodeDisconnectActions.put(node, nodeDisconnectAction);
673                 }
674         }
675
676         /**
677          * Pops up the “manage nodes” dialog.
678          */
679         private void manageNodes() {
680                 if (advancedMode) {
681                         manageNodesDialog.setNodeList(nodeList);
682                         manageNodesDialog.setVisible(true);
683                         nodeList = manageNodesDialog.getNodeList();
684                         rebuildNodeActions(nodeList);
685                         mainWindow.refreshNodeMenuItems();
686                 } else {
687                         if (nodeList.isEmpty()) {
688                                 Node newNode = new Node();
689                                 newNode.setName(I18n.get("general.defaultNode.name"));
690                                 newNode.setHostname("localhost");
691                                 newNode.setPort(9481);
692                                 nodeList.add(newNode);
693                         }
694                         Node firstNode = nodeList.get(0);
695                         EditNodeDialog editNodeDialog = manageNodesDialog.getEditNodeDialog();
696                         editNodeDialog.setNodeName(firstNode.getName());
697                         editNodeDialog.setNodeHostname(firstNode.getHostname());
698                         editNodeDialog.setNodePort(firstNode.getPort());
699                         editNodeDialog.setVisible(true);
700                         if (!editNodeDialog.wasCancelled()) {
701                                 firstNode.setName(editNodeDialog.getNodeName());
702                                 firstNode.setHostname(editNodeDialog.getNodeHostname());
703                                 firstNode.setPort(editNodeDialog.getNodePort());
704                                 /* TODO - give to core. */
705                         }
706                 }
707         }
708
709         /**
710          * Connects to the node.
711          * 
712          * @param node
713          *            The node to connect to
714          */
715         private void nodeConnect(final Node node) {
716                 threadPool.execute(new Runnable() {
717
718                         /**
719                          * {@inheritDoc}
720                          */
721                         @SuppressWarnings("synthetic-access")
722                         public void run() {
723                                 logger.log(Level.INFO, "connecting to node “" + node.getName() + "”…");
724                                 core.connectToNode(node);
725                         }
726                 });
727         }
728
729         /**
730          * Disconnects from the node.
731          * 
732          * @param node
733          *            The node to disconnect from
734          */
735         private void nodeDisconnect(Node node) {
736                 logger.log(Level.INFO, "disconnecting from node “" + node.getName() + "”…");
737                 core.disconnectFromNode(node);
738         }
739
740         /**
741          * Changes the language of the interface. This method also disables the
742          * action for the newly set language and enables all others.
743          * 
744          * @param newLocale
745          *            The new language
746          * @param languageAction
747          *            The action that triggered the change
748          */
749         private void changeLanguage(Locale newLocale, I18nAction languageAction) {
750                 for (I18nAction i18nAction: languageActions) {
751                         i18nAction.setEnabled(i18nAction != languageAction);
752                 }
753                 I18n.setLocale(newLocale);
754         }
755
756         /**
757          * Shows the “about” dialog.
758          */
759         private void helpAbout() {
760                 aboutDialog.setVisible(true);
761         }
762
763         /**
764          * Adds a project.
765          */
766         private void addProject() {
767                 Project project = new Project();
768                 project.setName("New Project");
769                 project.setDescription("");
770         }
771
772         /**
773          * Clones a project.
774          */
775         private void cloneProject() {
776                 /* TODO */
777         }
778
779         /**
780          * Deletes a project.
781          */
782         private void deleteProject() {
783                 /* TODO */
784         }
785
786         //
787         // INTERFACE CoreListener
788         //
789
790         /**
791          * {@inheritDoc}
792          */
793         public void loadingProjectsDone(String directory) {
794                 mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.projectLoadingDone"));
795         }
796
797         /**
798          * {@inheritDoc}
799          */
800         public void loadingProjectsFailed(String directory, Throwable throwable) {
801                 JOptionPane.showMessageDialog(mainWindow, I18n.get("mainWindow.error.projectLoadingFailed.message", directory), I18n.get("mainWindow.error.projectLoadingFailed.title"), JOptionPane.ERROR_MESSAGE);
802         }
803
804         /**
805          * {@inheritDoc}
806          */
807         public void savingProjectsDone(String directory) {
808                 mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.projectSavingDone"));
809         }
810
811         /**
812          * {@inheritDoc}
813          */
814         public void savingProjectsFailed(String directory, Throwable throwabled) {
815                 /* TODO */
816         }
817
818         /**
819          * {@inheritDoc}
820          */
821         public void loadingNodesDone(String directory) {
822                 mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.loadingNodesDone"));
823         }
824
825         /**
826          * {@inheritDoc}
827          */
828         public void loadingNodesFailed(String directory, Throwable throwable) {
829                 /* TODO */
830         }
831
832         /**
833          * {@inheritDoc}
834          */
835         public void savingNodesDone(String directory) {
836                 mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.savingNodesDone"));
837         }
838
839         /**
840          * {@inheritDoc}
841          */
842         public void savingNodesFailed(String directory, Throwable throwable) {
843                 /* TODO */
844         }
845
846         /**
847          * {@inheritDoc}
848          */
849         public void coreLoaded() {
850                 this.nodeList = core.getNodes();
851                 manageNodesDialog.setNodeList(nodeList);
852                 mainWindow.setVisible(true);
853                 mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.coreLoaded"));
854         }
855
856         /**
857          * {@inheritDoc}
858          */
859         public void coreStopped() {
860                 mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.coreStopped"));
861         }
862
863         /**
864          * {@inheritDoc}
865          */
866         public void nodeConnecting(Node node) {
867                 Action nodeConnectAction = nodeNodeConnectActions.get(node);
868                 nodeConnectActions.remove(nodeConnectAction);
869                 mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.connectingToNode", node.getName(), node.getHostname(), node.getPort()));
870                 mainWindow.refreshNodeMenuItems();
871         }
872
873         /**
874          * {@inheritDoc}
875          */
876         public void nodeConnected(Node node) {
877                 Action nodeDisconnectAction = nodeNodeDisconnectActions.get(node);
878                 nodeDisconnectActions.add(nodeDisconnectAction);
879                 mainWindow.refreshNodeMenuItems();
880         }
881
882         /**
883          * {@inheritDoc}
884          */
885         public void nodeDisconnected(Node node, Throwable throwable) {
886                 Action nodeConnectAction = nodeNodeConnectActions.get(node);
887                 nodeConnectActions.add(nodeConnectAction);
888                 Action nodeDisconnectAction = nodeNodeDisconnectActions.get(node);
889                 nodeDisconnectActions.remove(nodeDisconnectAction);
890                 mainWindow.refreshNodeMenuItems();
891         }
892
893         /**
894          * {@inheritDoc}
895          */
896         public void requestAdded(Node node, Request request) {
897                 logger.log(Level.INFO, "request added to node: " + request + ", " + node);
898                 /* TODO - implement */
899         }
900         
901         //
902         // INTERFACE LoggingListener
903         //
904
905         /**
906          * {@inheritDoc}
907          */
908         public void logged(LogRecord logRecord) {
909                 logWindow.logged(logRecord);
910         }
911
912 }