implement base path changing
[jSite2.git] / src / net / pterodactylus / jsite / gui / SwingInterface.java
index dff6f3a..c79c37d 100644 (file)
 package net.pterodactylus.jsite.gui;
 
 import java.awt.event.ActionEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
@@ -37,18 +40,18 @@ 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 javax.swing.UIManager;
 import javax.swing.UnsupportedLookAndFeelException;
 
 import net.pterodactylus.jsite.core.Core;
 import net.pterodactylus.jsite.core.CoreListener;
+import net.pterodactylus.jsite.core.JSiteException;
 import net.pterodactylus.jsite.core.Node;
-import net.pterodactylus.jsite.core.Project;
 import net.pterodactylus.jsite.i18n.I18n;
 import net.pterodactylus.jsite.i18n.gui.I18nAction;
+import net.pterodactylus.jsite.project.Project;
+import net.pterodactylus.util.image.IconLoader;
 import net.pterodactylus.util.io.Closer;
 import net.pterodactylus.util.logging.Logging;
 import net.pterodactylus.util.logging.LoggingListener;
@@ -59,7 +62,7 @@ import net.pterodactylus.util.logging.LoggingListener;
  * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
  * @version $Id$
  */
-public class SwingInterface implements CoreListener, LoggingListener {
+public class SwingInterface implements CoreListener, LoggingListener, PropertyChangeListener {
 
        /** The logger. */
        private static final Logger logger = Logging.getLogger(SwingInterface.class.getName());
@@ -91,29 +94,11 @@ public class SwingInterface implements CoreListener, LoggingListener {
        /** The “manage nodes” action. */
        private I18nAction manageNodesAction;
 
-       /** The “connect to node” (simple mode) action. */
-       private I18nAction nodeConnectAction;
-
-       /** 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>());
+       private Map<Node, I18nAction> nodeConnectActions = Collections.synchronizedMap(new HashMap<Node, I18nAction>());
 
        /** 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>());
+       private Map<Node, I18nAction> nodeDisconnectActions = Collections.synchronizedMap(new HashMap<Node, I18nAction>());
 
        /** The node manager dialog. */
        private ManageNodesDialog manageNodesDialog;
@@ -140,7 +125,7 @@ public class SwingInterface implements CoreListener, LoggingListener {
        private ConfigurationDialog configurationDialog;
 
        /** The list of all defined nodes. */
-       private List<Node> nodeList;
+       private List<Node> nodeList = Collections.synchronizedList(new ArrayList<Node>());
 
        //
        // CONFIGURATION
@@ -161,6 +146,18 @@ public class SwingInterface implements CoreListener, LoggingListener {
        /** The class name of the look and feel. */
        private String lookAndFeel;
 
+       /** X coordinate of the main window. */
+       private int mainWindowX = -1;
+
+       /** Y coordinate of the main window. */
+       private int mainWindowY = -1;
+
+       /** Width of the main window. */
+       private int mainWindowWidth = -1;
+
+       /** Height of the main window. */
+       private int mainWindowHeight = -1;
+
        /**
         * Creates a new swing interface.
         * 
@@ -200,6 +197,10 @@ public class SwingInterface implements CoreListener, LoggingListener {
                initDialogs();
                mainWindow = new MainWindow(this);
                mainWindow.setAdvancedMode(advancedMode);
+               if ((mainWindowX != -1) && (mainWindowY != -1) && (mainWindowWidth != -1) && (mainWindowHeight != -1)) {
+                       mainWindow.setLocation(mainWindowX, mainWindowY);
+                       mainWindow.setSize(mainWindowWidth, mainWindowHeight);
+               }
                logWindow = new LogWindow();
        }
 
@@ -272,39 +273,25 @@ public class SwingInterface implements CoreListener, LoggingListener {
        }
 
        /**
-        * Returns the “connect to node” action.
+        * Returns the “connect to node” action for the given node.
         * 
+        * @param node
+        *            The node go get the “connect” action for
         * @return The “connect to node” action
         */
-       I18nAction getNodeConnectAction() {
-               return nodeConnectAction;
-       }
-
-       /**
-        * Returns all “connect node” actions.
-        * 
-        * @return All “connect node” actions
-        */
-       List<Action> getNodeConnectActions() {
-               return nodeConnectActions;
+       I18nAction getNodeConnectAction(Node node) {
+               return nodeConnectActions.get(node);
        }
 
        /**
-        * Returns the “disconnect from node” action.
+        * Returns the “disconnect from node” action for the given node.
         * 
+        * @param node
+        *            The node go get the “disconnect” action for
         * @return The “disconnect from node” action
         */
-       I18nAction getNodeDisconnectAction() {
-               return nodeDisconnectAction;
-       }
-
-       /**
-        * Returns all “disconnect node” actions.
-        * 
-        * @return All “disconnect node” action
-        */
-       List<Action> getNodeDisconnectActions() {
-               return nodeDisconnectActions;
+       I18nAction getNodeDisconnectAction(Node node) {
+               return nodeDisconnectActions.get(node);
        }
 
        /**
@@ -352,6 +339,24 @@ public class SwingInterface implements CoreListener, LoggingListener {
                return deleteProjectAction;
        }
 
+       /**
+        * Returns all currently configured nodes.
+        * 
+        * @return All configured nodes
+        */
+       List<Node> getNodes() {
+               return nodeList;
+       }
+
+       /**
+        * Returns the thread pool used for off-thread processes.
+        * 
+        * @return The thread pool
+        */
+       Executor getThreadPool() {
+               return threadPool;
+       }
+
        //
        // ACTIONS
        //
@@ -404,6 +409,18 @@ public class SwingInterface implements CoreListener, LoggingListener {
                if (configProperties.containsKey("language")) {
                        I18n.setLocale(new Locale(configProperties.getProperty("language")));
                }
+               if (configProperties.containsKey("mainWindowX")) {
+                       mainWindowX = Integer.valueOf(configProperties.getProperty("mainWindowX"));
+               }
+               if (configProperties.containsKey("mainWindowY")) {
+                       mainWindowY = Integer.valueOf(configProperties.getProperty("mainWindowY"));
+               }
+               if (configProperties.containsKey("mainWindowWidth")) {
+                       mainWindowWidth = Integer.valueOf(configProperties.getProperty("mainWindowWidth"));
+               }
+               if (configProperties.containsKey("mainWindowHeight")) {
+                       mainWindowHeight = Integer.valueOf(configProperties.getProperty("mainWindowHeight"));
+               }
        }
 
        /**
@@ -435,6 +452,10 @@ public class SwingInterface implements CoreListener, LoggingListener {
                        configProperties.setProperty("lookAndFeel", lookAndFeel);
                }
                configProperties.setProperty("language", I18n.getLocale().getLanguage());
+               configProperties.setProperty("mainWindowX", String.valueOf(mainWindowX));
+               configProperties.setProperty("mainWindowY", String.valueOf(mainWindowY));
+               configProperties.setProperty("mainWindowWidth", String.valueOf(mainWindowWidth));
+               configProperties.setProperty("mainWindowHeight", String.valueOf(mainWindowHeight));
                FileOutputStream configOutputStream = null;
                try {
                        configOutputStream = new FileOutputStream(configFile);
@@ -450,7 +471,7 @@ public class SwingInterface implements CoreListener, LoggingListener {
         * Initializes all actions.
         */
        private void initActions() {
-               configureAction = new I18nAction("mainWindow.menu.jSite.configure") {
+               configureAction = new I18nAction("mainWindow.menu.jSite.configure", IconLoader.loadIcon("/preferences-system.png")) {
 
                        /**
                         * {@inheritDoc}
@@ -470,7 +491,7 @@ public class SwingInterface implements CoreListener, LoggingListener {
                                importConfig();
                        }
                };
-               quitAction = new I18nAction("mainWindow.menu.jSite.quit") {
+               quitAction = new I18nAction("mainWindow.menu.jSite.quit", IconLoader.loadIcon("/system-log-out.png")) {
 
                        /**
                         * {@inheritDoc}
@@ -490,33 +511,6 @@ public class SwingInterface implements CoreListener, LoggingListener {
                                manageNodes();
                        }
                };
-               nodeConnectAction = new I18nAction("mainWindow.menu.node.item.connect", false) {
-
-                       @SuppressWarnings("synthetic-access")
-                       public void actionPerformed(ActionEvent actionEvent) {
-                               List<Node> nodes = core.getNodes();
-                               if (nodes.isEmpty()) {
-                                       return;
-                               }
-                               nodeConnect(nodes.get(0));
-                       }
-
-               };
-               nodeDisconnectAction = new I18nAction("mainWindow.menu.node.item.disconnect", false) {
-
-                       /**
-                        * {@inheritDoc}
-                        */
-                       @SuppressWarnings("synthetic-access")
-                       public void actionPerformed(ActionEvent e) {
-                               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()) {
@@ -622,56 +616,17 @@ public class SwingInterface implements CoreListener, LoggingListener {
         * Quits jSite.
         */
        private void quit() {
+               /* TODO - ask */
+               core.stop();
+               mainWindowX = mainWindow.getX();
+               mainWindowY = mainWindow.getY();
+               mainWindowWidth = mainWindow.getWidth();
+               mainWindowHeight = mainWindow.getHeight();
                saveConfig();
                System.exit(0);
        }
 
        /**
-        * 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() {
@@ -679,8 +634,7 @@ public class SwingInterface implements CoreListener, LoggingListener {
                        manageNodesDialog.setNodeList(nodeList);
                        manageNodesDialog.setVisible(true);
                        nodeList = manageNodesDialog.getNodeList();
-                       rebuildNodeActions(nodeList);
-                       mainWindow.refreshNodeMenuItems();
+                       /* TODO - notify main window of changes */
                } else {
                        if (nodeList.isEmpty()) {
                                Node newNode = new Node();
@@ -762,9 +716,18 @@ public class SwingInterface implements CoreListener, LoggingListener {
         * Adds a project.
         */
        private void addProject() {
-               Project project = new Project();
-               project.setName("New Project");
-               project.setDescription("");
+               try {
+                       Project project = core.createProject();
+                       project.setName(I18n.get("general.newProject.name"));
+                       project.setDescription(I18n.get("general.newProject.description", new Date()));
+                       mainWindow.addProject(project, true);
+               } catch (JSiteException nne1) {
+                       /* TODO - add i18n */
+                       JOptionPane.showMessageDialog(mainWindow, I18n.get(""), I18n.get(""), JOptionPane.ERROR_MESSAGE);
+               } catch (IOException e) {
+                       /* TODO - add i18n */
+                       JOptionPane.showMessageDialog(mainWindow, I18n.get(""), I18n.get(""), JOptionPane.ERROR_MESSAGE);
+               }
        }
 
        /**
@@ -790,6 +753,9 @@ public class SwingInterface implements CoreListener, LoggingListener {
         */
        public void loadingProjectsDone(String directory) {
                mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.projectLoadingDone"));
+               for (Project project: core.getProjects()) {
+                       mainWindow.addProject(project, false);
+               }
        }
 
        /**
@@ -845,8 +811,6 @@ public class SwingInterface implements CoreListener, LoggingListener {
         * {@inheritDoc}
         */
        public void coreLoaded() {
-               this.nodeList = core.getNodes();
-               manageNodesDialog.setNodeList(nodeList);
                mainWindow.setVisible(true);
                mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.coreLoaded"));
        }
@@ -861,31 +825,111 @@ public class SwingInterface implements CoreListener, LoggingListener {
        /**
         * {@inheritDoc}
         */
+       public void nodeAdded(final Node node) {
+               logger.log(Level.INFO, "node added: " + node);
+               nodeList.add(node);
+               node.addPropertyChangeListener(this);
+               logger.log(Level.FINE, "nodeList.size(): " + nodeList.size());
+               manageNodesDialog.setNodeList(nodeList);
+               nodeConnectActions.put(node, new I18nAction("mainWindow.menu.connect") {
+
+                       /**
+                        * {@inheritDoc}
+                        */
+                       @SuppressWarnings("synthetic-access")
+                       public void actionPerformed(ActionEvent e) {
+                               nodeConnect(node);
+                       }
+               });
+               nodeDisconnectActions.put(node, new I18nAction("mainWindow.menu.disconnect") {
+
+                       /**
+                        * {@inheritDoc}
+                        */
+                       @SuppressWarnings("synthetic-access")
+                       public void actionPerformed(ActionEvent e) {
+                               nodeDisconnect(node);
+                       }
+               });
+               nodeDisconnectActions.get(node).setEnabled(false);
+               mainWindow.addNode(node);
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       public void nodeRemoved(Node node) {
+               logger.log(Level.INFO, "node removed: " + node);
+               nodeList.remove(node);
+               node.removePropertyChangeListener(this);
+               nodeConnectActions.remove(node);
+               nodeDisconnectActions.remove(node);
+               mainWindow.removeNode(node);
+       }
+
+       /**
+        * {@inheritDoc}
+        */
        public void nodeConnecting(Node node) {
-               Action nodeConnectAction = nodeNodeConnectActions.get(node);
-               nodeConnectActions.remove(nodeConnectAction);
+               nodeConnectActions.get(node).setEnabled(false);
                mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.connectingToNode", node.getName(), node.getHostname(), node.getPort()));
-               mainWindow.refreshNodeMenuItems();
        }
 
        /**
         * {@inheritDoc}
         */
        public void nodeConnected(Node node) {
-               Action nodeDisconnectAction = nodeNodeDisconnectActions.get(node);
-               nodeDisconnectActions.add(nodeDisconnectAction);
-               mainWindow.refreshNodeMenuItems();
+               nodeDisconnectActions.get(node).setEnabled(true);
+               mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.connectedToNode", node.getName(), node.getHostname(), node.getPort()));
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       public void nodeConnectionFailed(Node node, Throwable cause) {
+               nodeConnectActions.get(node).setEnabled(true);
+               mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.connectionToNodeFailed", node.getName(), node.getHostname(), node.getPort(), (cause != null) ? cause.getMessage() : "no reason given"));
+               JOptionPane.showMessageDialog(mainWindow, I18n.get("mainWindow.error.nodeConnectionFailed.message", node.getName(), node.getHostname(), node.getPort(), (cause != null) ? cause.getMessage() : "no reason given"), I18n.get("mainWindow.error.nodeConnectionFailed.title"), JOptionPane.ERROR_MESSAGE);
        }
 
        /**
         * {@inheritDoc}
         */
        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();
+               nodeDisconnectActions.get(node).setEnabled(false);
+               nodeConnectActions.get(node).setEnabled(true);
+               mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.disconnectedFromNode", node.getName(), node.getHostname(), node.getPort()));
+       }
+
+       /**
+        * @see net.pterodactylus.jsite.core.CoreListener#projectInsertStarted(net.pterodactylus.jsite.project.Project)
+        */
+       public void projectInsertStarted(Project project) {
+               mainWindow.projectInsertStarted(project);
+       }
+
+       /**
+        * @see net.pterodactylus.jsite.core.CoreListener#projectInsertProgressed(net.pterodactylus.jsite.project.Project,
+        *      int, int, int, int, int, boolean)
+        */
+       public void projectInsertProgressed(Project project, int totalBlocks, int requiredBlocks, int successfulBlocks, int failedBlocks, int fatallyFailedBlocks, boolean finalizedTotal) {
+               mainWindow.projectInsertProgressed(project, totalBlocks, requiredBlocks, successfulBlocks, failedBlocks, fatallyFailedBlocks, finalizedTotal);
+       }
+
+       /**
+        * @see net.pterodactylus.jsite.core.CoreListener#projectInsertGeneratedURI(net.pterodactylus.jsite.project.Project,
+        *      java.lang.String)
+        */
+       public void projectInsertGeneratedURI(Project project, String uri) {
+               mainWindow.projectInsertGeneratedURI(project);
+       }
+
+       /**
+        * @see net.pterodactylus.jsite.core.CoreListener#projectInsertFinished(net.pterodactylus.jsite.project.Project,
+        *      boolean)
+        */
+       public void projectInsertFinished(Project project, boolean success) {
+               mainWindow.projectInsertFinished(project, success);
        }
 
        //
@@ -899,4 +943,15 @@ public class SwingInterface implements CoreListener, LoggingListener {
                logWindow.logged(logRecord);
        }
 
+       //
+       // INTERFACE PropertyChangeListener
+       //
+
+       /**
+        * {@inheritDoc}
+        */
+       public void propertyChange(PropertyChangeEvent propertyChangeEvent) {
+               /* do not react to anything (yet). */
+       }
+
 }