From 2bd90a148fe17a4f091d148586d67eb69f4122f6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Thu, 8 May 2008 21:53:55 +0000 Subject: [PATCH] extend core listener 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 | 8 + src/net/pterodactylus/jsite/core/CoreImpl.java | 71 ++++++- src/net/pterodactylus/jsite/core/CoreListener.java | 5 +- src/net/pterodactylus/jsite/gui/MainWindow.java | 57 ++++- .../pterodactylus/jsite/gui/ManageNodesDialog.java | 2 +- .../pterodactylus/jsite/gui/SwingInterface.java | 235 +++++++++++++++++---- src/net/pterodactylus/jsite/main/Main.java | 6 +- 7 files changed, 338 insertions(+), 46 deletions(-) diff --git a/src/net/pterodactylus/jsite/core/Core.java b/src/net/pterodactylus/jsite/core/Core.java index e6cad12..731076b 100644 --- a/src/net/pterodactylus/jsite/core/Core.java +++ b/src/net/pterodactylus/jsite/core/Core.java @@ -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 diff --git a/src/net/pterodactylus/jsite/core/CoreImpl.java b/src/net/pterodactylus/jsite/core/CoreImpl.java index 8b79d3e..8fe64da 100644 --- a/src/net/pterodactylus/jsite/core/CoreImpl.java +++ b/src/net/pterodactylus/jsite/core/CoreImpl.java @@ -29,7 +29,7 @@ import java.util.List; * @author David ‘Bombe’ Roden <bombe@freenetproject.org> * @version $Id$ */ -public class CoreImpl implements Core { +public class CoreImpl implements Core, NodeListener { /** The core listeners. */ private final List coreListeners = new ArrayList(); @@ -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 null + * 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); + } + } diff --git a/src/net/pterodactylus/jsite/core/CoreListener.java b/src/net/pterodactylus/jsite/core/CoreListener.java index 812ce89..b4a2574 100644 --- a/src/net/pterodactylus/jsite/core/CoreListener.java +++ b/src/net/pterodactylus/jsite/core/CoreListener.java @@ -148,7 +148,10 @@ public interface CoreListener { * * @param node * The node that was diconnected + * @param throwable + * The exception that caused the disconnect, or null + * if there was no exception */ - public void nodeDisconnected(Node node); + public void nodeDisconnected(Node node, Throwable throwable); } diff --git a/src/net/pterodactylus/jsite/gui/MainWindow.java b/src/net/pterodactylus/jsite/gui/MainWindow.java index b5bc5fb..3d61638 100644 --- a/src/net/pterodactylus/jsite/gui/MainWindow.java +++ b/src/net/pterodactylus/jsite/gui/MainWindow.java @@ -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 + * true if the advanced mode is activated, + * false 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(); diff --git a/src/net/pterodactylus/jsite/gui/ManageNodesDialog.java b/src/net/pterodactylus/jsite/gui/ManageNodesDialog.java index 0ae270c..ea2b6c5 100644 --- a/src/net/pterodactylus/jsite/gui/ManageNodesDialog.java +++ b/src/net/pterodactylus/jsite/gui/ManageNodesDialog.java @@ -131,7 +131,7 @@ public class ManageNodesDialog extends JDialog implements ListSelectionListener, * The list of nodes */ public void setNodeList(List nodeList) { - originalNodeList = nodeList; + originalNodeList = new ArrayList(nodeList); nodeListModel.clear(); for (Node node: nodeList) { nodeListModel.addNode(node); diff --git a/src/net/pterodactylus/jsite/gui/SwingInterface.java b/src/net/pterodactylus/jsite/gui/SwingInterface.java index e022cf1..fb76cf0 100644 --- a/src/net/pterodactylus/jsite/gui/SwingInterface.java +++ b/src/net/pterodactylus/jsite/gui/SwingInterface.java @@ -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 <bombe@freenetproject.org> * @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 nodeConnectActions = Collections.synchronizedList(new ArrayList()); + + /** Mapping from nodes to node connect actions. */ + private Map nodeNodeConnectActions = Collections.synchronizedMap(new HashMap()); + + /** Mapping from node connect actions to nodes. */ + private Map nodeConnectActionNodes = Collections.synchronizedMap(new HashMap()); + + /** All node disconnect actions. */ + private List nodeDisconnectActions = Collections.synchronizedList(new ArrayList()); + + /** Mapping from nodes to node disconnect actions. */ + private Map nodeNodeDisconnectActions = Collections.synchronizedMap(new HashMap()); + + /** Mapping from node disconnect actions to nodes. */ + private Map nodeDisconnectActionNodes = Collections.synchronizedMap(new HashMap()); + /** 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 true if the advanced mode is activated, + * false 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 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 getNodeDisconnectActions() { + return nodeDisconnectActions; + } + + /** * Returns all language actions. - * + * * @return All language actions */ List 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 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 nodes = core.getNodes(); + if (nodes.isEmpty()) { + return; + } + nodeDisconnect(nodes.get(0)); } }; + rebuildNodeActions(core.getNodes()); List 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 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); } } diff --git a/src/net/pterodactylus/jsite/main/Main.java b/src/net/pterodactylus/jsite/main/Main.java index 42012e1..dab65f5 100644 --- a/src/net/pterodactylus/jsite/main/Main.java +++ b/src/net/pterodactylus/jsite/main/Main.java @@ -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(); } -- 2.7.4