extend core listener
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Thu, 8 May 2008 21:53:55 +0000 (21:53 +0000)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Thu, 8 May 2008 21:53:55 +0000 (21:53 +0000)
make core implement node listener
implement connection and disconnection
add connect and disconnect menus in advanced mode
add log window

git-svn-id: http://trooper/svn/projects/jSite/trunk@790 c3eda9e8-030b-0410-8277-bc7414b0a119

src/net/pterodactylus/jsite/core/Core.java
src/net/pterodactylus/jsite/core/CoreImpl.java
src/net/pterodactylus/jsite/core/CoreListener.java
src/net/pterodactylus/jsite/gui/MainWindow.java
src/net/pterodactylus/jsite/gui/ManageNodesDialog.java
src/net/pterodactylus/jsite/gui/SwingInterface.java
src/net/pterodactylus/jsite/main/Main.java

index e6cad12..731076b 100644 (file)
@@ -80,4 +80,12 @@ public interface Core {
         */
        public void connectToNode(Node node);
 
+       /**
+        * Disconnects from the given node.
+        *
+        * @param node
+        *            The node to disconnect from
+        */
+       public void disconnectFromNode(Node node);
+
 }
\ No newline at end of file
index 8b79d3e..8fe64da 100644 (file)
@@ -29,7 +29,7 @@ import java.util.List;
  * @author David ‘Bombe’ Roden &lt;bombe@freenetproject.org&gt;
  * @version $Id$
  */
-public class CoreImpl implements Core {
+public class CoreImpl implements Core, NodeListener {
 
        /** The core listeners. */
        private final List<CoreListener> coreListeners = new ArrayList<CoreListener>();
@@ -181,6 +181,46 @@ public class CoreImpl implements Core {
                }
        }
 
+       /**
+        * Notifies all listeners that a connection to the given node is now being
+        * established.
+        *
+        * @param node
+        *            The node that is being connected to
+        */
+       private void fireNodeConnecting(Node node) {
+               for (CoreListener coreListener: coreListeners) {
+                       coreListener.nodeConnecting(node);
+               }
+       }
+
+       /**
+        * Notifies all listeners that the given node is now connected.
+        *
+        * @param node
+        *            The node that is now connected
+        */
+       private void fireNodeConnected(Node node) {
+               for (CoreListener coreListener: coreListeners) {
+                       coreListener.nodeConnected(node);
+               }
+       }
+
+       /**
+        * Notifies all listeners that the given node was disconnected.
+        *
+        * @param node
+        *            The node that is now disconnected
+        * @param throwable
+        *            The exception that caused the disconnect, or <code>null</code>
+        *            if there was no exception
+        */
+       private void fireNodeDisconnected(Node node, Throwable throwable) {
+               for (CoreListener coreListener: coreListeners) {
+                       coreListener.nodeDisconnected(node, throwable);
+               }
+       }
+
        //
        // ACCESSORS
        //
@@ -283,7 +323,16 @@ public class CoreImpl implements Core {
         * {@inheritDoc}
         */
        public void connectToNode(Node node) {
-               /* TODO */
+               fireNodeConnecting(node);
+               nodeManager.addNode(node);
+               nodeManager.connect(node);
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       public void disconnectFromNode(Node node) {
+               nodeManager.disconnect(node);
        }
 
        //
@@ -306,4 +355,22 @@ public class CoreImpl implements Core {
                /* TODO */
        }
 
+       //
+       // INTERFACE NodeListener
+       //
+
+       /**
+        * {@inheritDoc}
+        */
+       public void nodeConnected(Node node) {
+               fireNodeConnected(node);
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       public void nodeDisconnected(Node node, Throwable throwable) {
+               fireNodeDisconnected(node, throwable);
+       }
+
 }
index 812ce89..b4a2574 100644 (file)
@@ -148,7 +148,10 @@ public interface CoreListener {
         *
         * @param node
         *            The node that was diconnected
+        * @param throwable
+        *            The exception that caused the disconnect, or <code>null</code>
+        *            if there was no exception
         */
-       public void nodeDisconnected(Node node);
+       public void nodeDisconnected(Node node, Throwable throwable);
 
 }
index b5bc5fb..3d61638 100644 (file)
@@ -25,11 +25,13 @@ import java.awt.Dimension;
 import java.awt.event.WindowAdapter;
 import java.awt.event.WindowEvent;
 
+import javax.swing.Action;
 import javax.swing.Box;
 import javax.swing.BoxLayout;
 import javax.swing.JButton;
 import javax.swing.JFrame;
 import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
 import javax.swing.JPanel;
 import javax.swing.JTabbedPane;
 import javax.swing.JToolBar;
@@ -68,6 +70,18 @@ public class MainWindow extends JFrame implements I18nable {
        /** The node menu. */
        private I18nMenu nodeMenu;
 
+       /** The “connect” (advanced mode) menu. */
+       private I18nMenu connectMenu;
+
+       /** The “connect” (simple mode) menu. */
+       private JMenuItem connectMenuItem;
+
+       /** The “disconnect” (advanced mode) menu. */
+       private I18nMenu disconnectMenu;
+
+       /** The “diconnect” (simple mode) menu item. */
+       private JMenuItem disconnectMenuItem;
+
        /** The language menu. */
        private I18nMenu languageMenu;
 
@@ -113,6 +127,20 @@ public class MainWindow extends JFrame implements I18nable {
        }
 
        /**
+        * Sets whether the advanced mode is activated.
+        *
+        * @param advancedMode
+        *            <code>true</code> if the advanced mode is activated,
+        *            <code>false</code> if the simple mode is activated
+        */
+       public void setAdvancedMode(boolean advancedMode) {
+               connectMenu.setVisible(advancedMode);
+               connectMenuItem.setVisible(!advancedMode);
+               disconnectMenu.setVisible(advancedMode);
+               disconnectMenuItem.setVisible(!advancedMode);
+       }
+
+       /**
         * {@inheritDoc}
         */
        @Override
@@ -130,6 +158,24 @@ public class MainWindow extends JFrame implements I18nable {
        }
 
        //
+       // ACTIONS
+       //
+
+       /**
+        * Refreshes the menu items in the “connect” and “disconnect” menus.
+        */
+       void refreshNodeMenuItems() {
+               connectMenu.removeAll();
+               for (Action nodeConnectAction: swingInterface.getNodeConnectActions()) {
+                       connectMenu.add(nodeConnectAction);
+               }
+               disconnectMenu.removeAll();
+               for (Action nodeDisconnectAction: swingInterface.getNodeDisconnectActions()) {
+                       disconnectMenu.add(nodeDisconnectAction);
+               }
+       }
+
+       //
        // PRIVATE METHODS
        //
 
@@ -148,13 +194,18 @@ public class MainWindow extends JFrame implements I18nable {
                jSiteMenu.addSeparator();
                jSiteMenu.add(new FixedJMenuItem(swingInterface.getQuitAction()));
 
+               connectMenu = new I18nMenu("mainWindow.menu.connect");
+               disconnectMenu = new I18nMenu("mainWindow.menu.disconnect");
+
                nodeMenu = new I18nMenu("mainWindow.menu.node");
                menuBar.add(nodeMenu);
 
                nodeMenu.add(new FixedJMenuItem(swingInterface.getManageNodesAction()));
                nodeMenu.addSeparator();
-               nodeMenu.add(new FixedJMenuItem(swingInterface.getNodeConnectAction()));
-               nodeMenu.add(new FixedJMenuItem(swingInterface.getNodeDisconnectAction()));
+               nodeMenu.add(connectMenuItem = new FixedJMenuItem(swingInterface.getNodeConnectAction()));
+               nodeMenu.add(connectMenu);
+               nodeMenu.add(disconnectMenuItem = new FixedJMenuItem(swingInterface.getNodeDisconnectAction()));
+               nodeMenu.add(disconnectMenu);
 
                languageMenu = new I18nMenu("mainWindow.menu.language");
                menuBar.add(languageMenu);
@@ -244,7 +295,9 @@ public class MainWindow extends JFrame implements I18nable {
                swingInterface.getQuitAction().updateI18n();
                swingInterface.getManageNodesAction().updateI18n();
                swingInterface.getNodeConnectAction().updateI18n();
+               connectMenu.updateI18n();
                swingInterface.getNodeDisconnectAction().updateI18n();
+               disconnectMenu.updateI18n();
                swingInterface.getAddProjectAction().updateI18n();
                swingInterface.getCloneProjectAction().updateI18n();
                swingInterface.getDeleteProjectAction().updateI18n();
index 0ae270c..ea2b6c5 100644 (file)
@@ -131,7 +131,7 @@ public class ManageNodesDialog extends JDialog implements ListSelectionListener,
         *            The list of nodes
         */
        public void setNodeList(List<Node> nodeList) {
-               originalNodeList = nodeList;
+               originalNodeList = new ArrayList<Node>(nodeList);
                nodeListModel.clear();
                for (Node node: nodeList) {
                        nodeListModel.addNode(node);
index e022cf1..fb76cf0 100644 (file)
@@ -25,10 +25,20 @@ import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Properties;
-
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
 import javax.swing.JOptionPane;
 
 import net.pterodactylus.jsite.core.Core;
@@ -38,14 +48,19 @@ import net.pterodactylus.jsite.core.Project;
 import net.pterodactylus.jsite.i18n.I18n;
 import net.pterodactylus.jsite.i18n.gui.I18nAction;
 import net.pterodactylus.util.io.Closer;
+import net.pterodactylus.util.logging.Logging;
+import net.pterodactylus.util.logging.LoggingListener;
 
 /**
  * The Swing user interface.
- *
+ * 
  * @author David ‘Bombe’ Roden &lt;bombe@freenetproject.org&gt;
  * @version $Id$
  */
-public class SwingInterface implements CoreListener {
+public class SwingInterface implements CoreListener, LoggingListener {
+
+       /** The logger. */
+       private static final Logger logger = Logging.getLogger(SwingInterface.class.getName());
 
        /** The application core. */
        private final Core core;
@@ -56,6 +71,12 @@ public class SwingInterface implements CoreListener {
        /** The main window. */
        private MainWindow mainWindow;
 
+       /** Thread pool. */
+       private Executor threadPool = Executors.newCachedThreadPool();
+
+       /** The logger window. */
+       private LogWindow logWindow;
+
        /** The “configure” action. */
        private I18nAction configureAction;
 
@@ -68,12 +89,30 @@ public class SwingInterface implements CoreListener {
        /** The “manage nodes” action. */
        private I18nAction manageNodesAction;
 
-       /** The “connect to node” action. */
+       /** The “connect to node” (simple mode) action. */
        private I18nAction nodeConnectAction;
 
-       /** The “disconnect from node” action. */
+       /** The “disconnect from node” (simple mode) action. */
        private I18nAction nodeDisconnectAction;
 
+       /** All node menu items. */
+       private List<Action> nodeConnectActions = Collections.synchronizedList(new ArrayList<Action>());
+
+       /** Mapping from nodes to node connect actions. */
+       private Map<Node, Action> nodeNodeConnectActions = Collections.synchronizedMap(new HashMap<Node, Action>());
+
+       /** Mapping from node connect actions to nodes. */
+       private Map<Action, Node> nodeConnectActionNodes = Collections.synchronizedMap(new HashMap<Action, Node>());
+
+       /** All node disconnect actions. */
+       private List<Action> nodeDisconnectActions = Collections.synchronizedList(new ArrayList<Action>());
+
+       /** Mapping from nodes to node disconnect actions. */
+       private Map<Node, Action> nodeNodeDisconnectActions = Collections.synchronizedMap(new HashMap<Node, Action>());
+
+       /** Mapping from node disconnect actions to nodes. */
+       private Map<Action, Node> nodeDisconnectActionNodes = Collections.synchronizedMap(new HashMap<Action, Node>());
+
        /** The node manager dialog. */
        private ManageNodesDialog manageNodesDialog;
 
@@ -119,7 +158,7 @@ public class SwingInterface implements CoreListener {
 
        /**
         * Creates a new swing interface.
-        *
+        * 
         * @param core
         *            The core to operate on
         * @param configDirectory
@@ -141,6 +180,10 @@ public class SwingInterface implements CoreListener {
                }
                initActions();
                initDialogs();
+               mainWindow = new MainWindow(this);
+               mainWindow.setAdvancedMode(advancedMode);
+               logWindow = new LogWindow();
+               logWindow.setVisible(true); /* TODO - remove */
        }
 
        //
@@ -149,7 +192,7 @@ public class SwingInterface implements CoreListener {
 
        /**
         * Returns the core that is controlled by the Swing interface.
-        *
+        * 
         * @return The core
         */
        Core getCore() {
@@ -158,7 +201,7 @@ public class SwingInterface implements CoreListener {
 
        /**
         * Returns the main window of the Swing interface.
-        *
+        * 
         * @return The main window
         */
        MainWindow getMainWindow() {
@@ -166,8 +209,18 @@ public class SwingInterface implements CoreListener {
        }
 
        /**
+        * Returns whether the advanced mode is activated.
+        * 
+        * @return <code>true</code> if the advanced mode is activated,
+        *         <code>false</code> if the simple mode is activated
+        */
+       boolean isAdvancedMode() {
+               return advancedMode;
+       }
+
+       /**
         * Returns the “configure” action.
-        *
+        * 
         * @return The “configure” action
         */
        I18nAction getConfigureAction() {
@@ -176,7 +229,7 @@ public class SwingInterface implements CoreListener {
 
        /**
         * Returns the “import config” action.
-        *
+        * 
         * @return The “import config” action
         */
        I18nAction getImportConfigAction() {
@@ -185,7 +238,7 @@ public class SwingInterface implements CoreListener {
 
        /**
         * Returns the “quit” action.
-        *
+        * 
         * @return The “quit” action
         */
        I18nAction getQuitAction() {
@@ -194,7 +247,7 @@ public class SwingInterface implements CoreListener {
 
        /**
         * Returns the “manage nodes” action.
-        *
+        * 
         * @return The “manage nodes” action
         */
        I18nAction getManageNodesAction() {
@@ -203,7 +256,7 @@ public class SwingInterface implements CoreListener {
 
        /**
         * Returns the “connect to node” action.
-        *
+        * 
         * @return The “connect to node” action
         */
        I18nAction getNodeConnectAction() {
@@ -211,8 +264,17 @@ public class SwingInterface implements CoreListener {
        }
 
        /**
+        * Returns all “connect node” actions.
+        * 
+        * @return All “connect node” actions
+        */
+       List<Action> getNodeConnectActions() {
+               return nodeConnectActions;
+       }
+
+       /**
         * Returns the “disconnect from node” action.
-        *
+        * 
         * @return The “disconnect from node” action
         */
        I18nAction getNodeDisconnectAction() {
@@ -220,8 +282,17 @@ public class SwingInterface implements CoreListener {
        }
 
        /**
+        * Returns all “disconnect node” actions.
+        * 
+        * @return All “disconnect node” action
+        */
+       List<Action> getNodeDisconnectActions() {
+               return nodeDisconnectActions;
+       }
+
+       /**
         * Returns all language actions.
-        *
+        * 
         * @return All language actions
         */
        List<I18nAction> getLanguageActions() {
@@ -230,7 +301,7 @@ public class SwingInterface implements CoreListener {
 
        /**
         * Returns the “about” action.
-        *
+        * 
         * @return The “about” action
         */
        I18nAction getHelpAboutAction() {
@@ -239,7 +310,7 @@ public class SwingInterface implements CoreListener {
 
        /**
         * Returns the “add project” action.
-        *
+        * 
         * @return The “add project” action
         */
        I18nAction getAddProjectAction() {
@@ -248,7 +319,7 @@ public class SwingInterface implements CoreListener {
 
        /**
         * Returns the “clone project” action.
-        *
+        * 
         * @return The “clone project” action
         */
        I18nAction getCloneProjectAction() {
@@ -257,7 +328,7 @@ public class SwingInterface implements CoreListener {
 
        /**
         * Returns the “delete project” action.
-        *
+        * 
         * @return The “delete project” action
         */
        I18nAction getDeleteProjectAction() {
@@ -272,13 +343,6 @@ public class SwingInterface implements CoreListener {
        // SERVICE METHODS
        //
 
-       /**
-        * Starts the interface.
-        */
-       public void start() {
-               mainWindow = new MainWindow(this);
-       }
-
        //
        // PRIVATE METHODS
        //
@@ -407,7 +471,11 @@ public class SwingInterface implements CoreListener {
 
                        @SuppressWarnings("synthetic-access")
                        public void actionPerformed(ActionEvent actionEvent) {
-                               nodeConnect();
+                               List<Node> nodes = core.getNodes();
+                               if (nodes.isEmpty()) {
+                                       return;
+                               }
+                               nodeConnect(nodes.get(0));
                        }
 
                };
@@ -418,9 +486,14 @@ public class SwingInterface implements CoreListener {
                         */
                        @SuppressWarnings("synthetic-access")
                        public void actionPerformed(ActionEvent e) {
-                               nodeDisconnect();
+                               List<Node> nodes = core.getNodes();
+                               if (nodes.isEmpty()) {
+                                       return;
+                               }
+                               nodeDisconnect(nodes.get(0));
                        }
                };
+               rebuildNodeActions(core.getNodes());
                List<Locale> availableLanguages = I18n.findAvailableLanguages();
                for (final Locale locale: availableLanguages) {
                        I18nAction languageAction = new I18nAction("general.language." + locale.getLanguage()) {
@@ -505,6 +578,7 @@ public class SwingInterface implements CoreListener {
                        if (!advancedMode && (nodeList.size() > 1)) {
                                JOptionPane.showMessageDialog(mainWindow, I18n.get("mainWindow.warning.multipleNodesNotAdvancedMode.message"), I18n.get("mainWindow.warning.multipleNodesNotAdvancedMode.title"), JOptionPane.WARNING_MESSAGE);
                        }
+                       mainWindow.setAdvancedMode(advancedMode);
                        antialias = configurationDialog.isAntialias();
                        controlFont = configurationDialog.getControlFont();
                        userFont = configurationDialog.getUserFont();
@@ -528,6 +602,51 @@ public class SwingInterface implements CoreListener {
        }
 
        /**
+        * Rebuilds all node connect and disconnect actions.
+        * 
+        * @param nodes
+        *            The list of nodes
+        */
+       private void rebuildNodeActions(List<Node> nodes) {
+               nodeConnectActions.clear();
+               nodeNodeConnectActions.clear();
+               nodeConnectActionNodes.clear();
+               nodeDisconnectActions.clear();
+               nodeNodeDisconnectActions.clear();
+               nodeDisconnectActionNodes.clear();
+               for (Node node: nodes) {
+                       Action nodeConnectAction = new AbstractAction(node.getName()) {
+
+                               /**
+                                * {@inheritDoc}
+                                */
+                               @SuppressWarnings("synthetic-access")
+                               public void actionPerformed(ActionEvent e) {
+                                       Node node = nodeConnectActionNodes.get(this);
+                                       nodeConnect(node);
+                               }
+                       };
+                       nodeConnectActions.add(nodeConnectAction);
+                       nodeConnectActionNodes.put(nodeConnectAction, node);
+                       nodeNodeConnectActions.put(node, nodeConnectAction);
+                       Action nodeDisconnectAction = new AbstractAction(node.getName()) {
+
+                               /**
+                                * {@inheritDoc}
+                                */
+                               @SuppressWarnings("synthetic-access")
+                               public void actionPerformed(ActionEvent e) {
+                                       Node node = nodeDisconnectActionNodes.get(this);
+                                       nodeDisconnect(node);
+                               }
+                       };
+// nodeDisconnectActions.add(nodeDisconnectAction);
+                       nodeDisconnectActionNodes.put(nodeDisconnectAction, node);
+                       nodeNodeDisconnectActions.put(node, nodeDisconnectAction);
+               }
+       }
+
+       /**
         * Pops up the “manage nodes” dialog.
         */
        private void manageNodes() {
@@ -535,6 +654,8 @@ public class SwingInterface implements CoreListener {
                        manageNodesDialog.setNodeList(nodeList);
                        manageNodesDialog.setVisible(true);
                        nodeList = manageNodesDialog.getNodeList();
+                       rebuildNodeActions(nodeList);
+                       mainWindow.refreshNodeMenuItems();
                } else {
                        if (nodeList.isEmpty()) {
                                Node newNode = new Node();
@@ -560,22 +681,39 @@ public class SwingInterface implements CoreListener {
 
        /**
         * Connects to the node.
+        * 
+        * @param node
+        *            The node to connect to
         */
-       private void nodeConnect() {
-               /* TODO */
+       private void nodeConnect(final Node node) {
+               threadPool.execute(new Runnable() {
+
+                       /**
+                        * {@inheritDoc}
+                        */
+                       @SuppressWarnings("synthetic-access")
+                       public void run() {
+                               logger.log(Level.INFO, "connecting to node “" + node.getName() + "”…");
+                               core.connectToNode(node);
+                       }
+               });
        }
 
        /**
         * Disconnects from the node.
+        * 
+        * @param node
+        *            The node to disconnect from
         */
-       private void nodeDisconnect() {
-               /* TODO */
+       private void nodeDisconnect(Node node) {
+               logger.log(Level.INFO, "disconnecting from node “" + node.getName() + "”…");
+               core.disconnectFromNode(node);
        }
 
        /**
         * Changes the language of the interface. This method also disables the
         * action for the newly set language and enables all others.
-        *
+        * 
         * @param newLocale
         *            The new language
         * @param languageAction
@@ -622,7 +760,6 @@ public class SwingInterface implements CoreListener {
        // INTERFACE CoreListener
        //
 
-
        /**
         * {@inheritDoc}
         */
@@ -699,22 +836,42 @@ public class SwingInterface implements CoreListener {
        /**
         * {@inheritDoc}
         */
+       public void nodeConnecting(Node node) {
+               Action nodeConnectAction = nodeNodeConnectActions.get(node);
+               nodeConnectActions.remove(nodeConnectAction);
+               mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.connectingToNode", node.getName(), node.getHostname(), node.getPort()));
+               mainWindow.refreshNodeMenuItems();
+       }
+
+       /**
+        * {@inheritDoc}
+        */
        public void nodeConnected(Node node) {
-               /* TODO */
+               Action nodeDisconnectAction = nodeNodeDisconnectActions.get(node);
+               nodeDisconnectActions.add(nodeDisconnectAction);
+               mainWindow.refreshNodeMenuItems();
        }
 
        /**
         * {@inheritDoc}
         */
-       public void nodeConnecting(Node node) {
-               /* TODO */
+       public void nodeDisconnected(Node node, Throwable throwable) {
+               Action nodeConnectAction = nodeNodeConnectActions.get(node);
+               nodeConnectActions.add(nodeConnectAction);
+               Action nodeDisconnectAction = nodeNodeDisconnectActions.get(node);
+               nodeDisconnectActions.remove(nodeDisconnectAction);
+               mainWindow.refreshNodeMenuItems();
        }
 
+       //
+       // INTERFACE LoggingListener
+       //
+
        /**
         * {@inheritDoc}
         */
-       public void nodeDisconnected(Node node) {
-               /* TODO */
+       public void logged(LogRecord logRecord) {
+               logWindow.logged(logRecord);
        }
 
 }
index 42012e1..dab65f5 100644 (file)
@@ -25,6 +25,7 @@ import net.pterodactylus.jsite.core.CoreImpl;
 import net.pterodactylus.jsite.core.NodeManager;
 import net.pterodactylus.jsite.core.ProjectManager;
 import net.pterodactylus.jsite.gui.SwingInterface;
+import net.pterodactylus.util.logging.Logging;
 
 /**
  * Main class that is called by the VM.
@@ -48,6 +49,8 @@ public class Main {
         * Starts the core and the default {@link SwingInterface}.
         */
        private void start() {
+               Logging.setup("jSite");
+
                CoreImpl core = new CoreImpl();
 
                String configDirectory = System.getProperty("user.home") + File.separator + ".jSite";
@@ -57,10 +60,11 @@ public class Main {
 
                NodeManager nodeManager = new NodeManager("jSite-" + Version.getVersion(), configDirectory);
                core.setNodeManager(nodeManager);
+               nodeManager.addNodeListener(core);
 
                SwingInterface swingInterface = new SwingInterface(core, configDirectory);
                core.addCoreListener(swingInterface);
-               swingInterface.start();
+               Logging.addLoggingListener(swingInterface);
 
                core.start();
        }