add virtual entries
[jSite2.git] / src / net / pterodactylus / jsite / gui / ManageNodesDialog.java
index d4c8397..0598144 100644 (file)
@@ -22,27 +22,33 @@ package net.pterodactylus.jsite.gui;
 import java.awt.BorderLayout;
 import java.awt.FlowLayout;
 import java.awt.event.ActionEvent;
+import java.net.UnknownHostException;
 import java.util.ArrayList;
-import java.util.Collections;
+import java.util.Collection;
+import java.util.Iterator;
 import java.util.List;
+import java.util.logging.Logger;
 
 import javax.swing.AbstractListModel;
-import javax.swing.Action;
 import javax.swing.BorderFactory;
 import javax.swing.JButton;
 import javax.swing.JDialog;
-import javax.swing.JFrame;
 import javax.swing.JList;
+import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
-import javax.swing.ListCellRenderer;
 import javax.swing.border.EtchedBorder;
 import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;
 
+import net.pterodactylus.jsite.core.Core;
 import net.pterodactylus.jsite.core.Node;
 import net.pterodactylus.jsite.i18n.I18n;
+import net.pterodactylus.jsite.i18n.I18nable;
+import net.pterodactylus.jsite.i18n.gui.I18nAction;
+import net.pterodactylus.jsite.i18n.gui.I18nLabel;
 import net.pterodactylus.jsite.main.Version;
+import net.pterodactylus.util.logging.Logging;
 import net.pterodactylus.util.swing.SwingUtils;
 
 /**
@@ -51,38 +57,39 @@ import net.pterodactylus.util.swing.SwingUtils;
  * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
  * @version $Id$
  */
-public class ManageNodesDialog extends JDialog implements ListSelectionListener {
+public class ManageNodesDialog extends JDialog implements ListSelectionListener, I18nable {
 
-       /** The original list of nodes. */
-       private List<Node> originalNodeList;
+       /** The logger.  */
+       @SuppressWarnings("unused")
+       private static final Logger logger = Logging.getLogger(ManageNodesDialog.class.getName());
 
-       /** The current list of wrapped nodes. */
-       private List<NodeWrapper> wrappedNodeList = new ArrayList<NodeWrapper>();
+       /** The core. */
+       private final Core core;
 
-       /** The current default node. */
-       private Node defaultNode;
+       /** The original list of nodes. */
+       private List<Node> originalNodeList;
 
        /** The “add node” action. */
-       private Action addNodeAction;
+       private I18nAction addNodeAction;
 
        /** The “edit node” action. */
-       private Action editNodeAction;
+       private I18nAction editNodeAction;
 
        /** The “delete node” action. */
-       private Action deleteNodeAction;
-
-       /** The “set default node” action. */
-       private Action setDefaultNodeAction;
+       private I18nAction deleteNodeAction;
 
        /** The “okay” action. */
-       private Action okayAction;
+       private I18nAction okayAction;
 
        /** The “cancel” action. */
-       private Action cancelAction;
+       private I18nAction cancelAction;
 
        /** The “edit node” dialog. */
        private EditNodeDialog editNodeDialog;
 
+       /** The warning label. */
+       private I18nLabel immediatelyEffectiveLabel;
+
        /** The node list. */
        private JList nodeList;
 
@@ -92,15 +99,17 @@ public class ManageNodesDialog extends JDialog implements ListSelectionListener
        /**
         * Creates a new node manager dialog.
         * 
-        * @param parentFrame
-        *            The parent frame of the dialog
+        * @param swingInterface
+        *            The Swing interface
         */
-       public ManageNodesDialog(JFrame parentFrame) {
-               super(parentFrame, I18n.get("manageNodesDialog.title") + " – jSite " + Version.getVersion(), true);
+       public ManageNodesDialog(SwingInterface swingInterface) {
+               super(swingInterface.getMainWindow(), I18n.get("manageNodesDialog.title") + " – jSite " + Version.getVersion(), true);
+               this.core = swingInterface.getCore();
                initActions();
                initComponents();
                initDialogs();
                pack();
+               I18n.registerI18nable(this);
                SwingUtils.center(this);
        }
 
@@ -109,24 +118,12 @@ public class ManageNodesDialog extends JDialog implements ListSelectionListener
        //
 
        /**
-        * Returns the default node.
-        * 
-        * @return The default node, or <code>null</code> if no default node has
-        *         been set
-        */
-       public Node getDefaultNode() {
-               return defaultNode;
-       }
-
-       /**
-        * Sets the default node.
+        * Expose the edit node dialog for the simple mode.
         * 
-        * @param defaultNode
-        *            The default node, or <code>null</code> if no default node
-        *            has been set
+        * @return The edit node dialog
         */
-       public void setDefaultNode(Node defaultNode) {
-               this.defaultNode = defaultNode;
+       EditNodeDialog getEditNodeDialog() {
+               return editNodeDialog;
        }
 
        /**
@@ -145,12 +142,11 @@ public class ManageNodesDialog extends JDialog implements ListSelectionListener
         *            The list of nodes
         */
        public void setNodeList(List<Node> nodeList) {
-               originalNodeList = nodeList;
-               wrappedNodeList.clear();
+               originalNodeList = new ArrayList<Node>(nodeList);
+               nodeListModel.clear();
                for (Node node: nodeList) {
-                       wrappedNodeList.add(new NodeWrapper(node));
+                       nodeListModel.addNode(node);
                }
-               nodeListModel.setNodeList(wrappedNodeList);
        }
 
        //
@@ -208,17 +204,7 @@ public class ManageNodesDialog extends JDialog implements ListSelectionListener
                         */
                        @SuppressWarnings("synthetic-access")
                        public void actionPerformed(ActionEvent e) {
-                               deleteNode();
-                       }
-               };
-               setDefaultNodeAction = new I18nAction("manageNodesDialog.button.setDefaultNode", false) {
-
-                       /**
-                        * {@inheritDoc}
-                        */
-                       @SuppressWarnings("synthetic-access")
-                       public void actionPerformed(ActionEvent e) {
-                               setDefaultNode();
+                               deleteNodes();
                        }
                };
        }
@@ -243,13 +229,17 @@ public class ManageNodesDialog extends JDialog implements ListSelectionListener
                rootPanel.add(contentPanel, BorderLayout.CENTER);
                contentPanel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), BorderFactory.createEmptyBorder(12, 12, 12, 12)));
 
+               JPanel warningPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 12, 12));
+               warningPanel.setBorder(BorderFactory.createEmptyBorder(-12, -12, -12, -12));
+               warningPanel.add(immediatelyEffectiveLabel = new I18nLabel("manageNodesDialog.label.immediatelyEffective"));
+               contentPanel.add(warningPanel, BorderLayout.PAGE_START);
+
                JPanel listButtonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 12, 12));
                contentPanel.add(listButtonPanel, BorderLayout.PAGE_END);
                listButtonPanel.setBorder(BorderFactory.createEmptyBorder(-12, -12, -12, -12));
                listButtonPanel.add(new JButton(addNodeAction));
                listButtonPanel.add(new JButton(editNodeAction));
                listButtonPanel.add(new JButton(deleteNodeAction));
-               listButtonPanel.add(new JButton(setDefaultNodeAction));
 
                nodeList = new JList(nodeListModel);
                nodeList.addListSelectionListener(this);
@@ -273,23 +263,26 @@ public class ManageNodesDialog extends JDialog implements ListSelectionListener
         * Adds a new node via {@link #editNodeDialog}.
         */
        private void addNode() {
-               editNodeDialog.setNodeName("New Node");
+               editNodeDialog.setNodeName(I18n.get("general.newNode.name"));
                editNodeDialog.setNodeHostname("localhost");
                editNodeDialog.setNodePort(9481);
-               editNodeDialog.setNodeOnSameMachine(true);
                editNodeDialog.setVisible(true);
                if (!editNodeDialog.wasCancelled()) {
                        Node newNode = new Node();
                        newNode.setName(editNodeDialog.getNodeName());
                        newNode.setHostname(editNodeDialog.getNodeHostname());
                        newNode.setPort(editNodeDialog.getNodePort());
-                       NodeWrapper newNodeWrapper = new NodeWrapper(newNode);
-                       if (wrappedNodeList.isEmpty()) {
-                               defaultNode = newNode;
-                               newNodeWrapper.setDefaultNode(true);
+                       try {
+                               if (!core.addNode(newNode)) {
+                                       JOptionPane.showMessageDialog(this, I18n.get("manageNodesDialog.error.nodeAlreadyKnown.message", newNode.getHostname(), newNode.getPort()), I18n.get("manageNodesDialog.error.nodeAlreadyKnown.title"), JOptionPane.ERROR_MESSAGE);
+                               }
+                       } catch (UnknownHostException e) {
+                               /*
+                                * normally this shouldn't throw because the node editor catches
+                                * it.
+                                */
+                               JOptionPane.showMessageDialog(this, I18n.get("manageNodesDialog.error.nodeUnresolvable.message", newNode.getHostname()), I18n.get("manageNodesDialog.error.nodeUnresolvable.title"), JOptionPane.ERROR_MESSAGE);
                        }
-                       wrappedNodeList.add(new NodeWrapper(newNode));
-                       nodeListModel.setNodeList(wrappedNodeList);
                }
        }
 
@@ -297,18 +290,15 @@ public class ManageNodesDialog extends JDialog implements ListSelectionListener
         * Edits a node via {@link #editNodeDialog}.
         */
        private void editNode() {
-               NodeWrapper selectedNodeWrapper = (NodeWrapper) nodeList.getSelectedValue();
-               Node selectedNode = selectedNodeWrapper.getWrappedNode();
+               Node selectedNode = (Node) nodeList.getSelectedValue();
                editNodeDialog.setNodeName(selectedNode.getName());
                editNodeDialog.setNodeHostname(selectedNode.getHostname());
                editNodeDialog.setNodePort(selectedNode.getPort());
-               editNodeDialog.setNodeOnSameMachine(selectedNode.isSameMachine());
                editNodeDialog.setVisible(true);
                if (!editNodeDialog.wasCancelled()) {
                        selectedNode.setName(editNodeDialog.getNodeName());
                        selectedNode.setHostname(editNodeDialog.getNodeHostname());
                        selectedNode.setPort(editNodeDialog.getNodePort());
-                       selectedNode.setSameMachine(editNodeDialog.isNodeOnSameMachine());
                        nodeList.repaint();
                }
        }
@@ -316,38 +306,47 @@ public class ManageNodesDialog extends JDialog implements ListSelectionListener
        /**
         * Deletes the selected node.
         */
-       private void deleteNode() {
-               NodeWrapper selectedNode = (NodeWrapper) nodeList.getSelectedValue();
-               wrappedNodeList.remove(selectedNode);
+       private void deleteNodes() {
+               Object[] selectedNodes = nodeList.getSelectedValues();
+               for (Object node: selectedNodes) {
+                       Node selectedNode = (Node) node;
+                       if (core.isNodeConnected(selectedNode)) {
+                               int response = JOptionPane.showConfirmDialog(this, I18n.get("manageNodesDialog.error.nodeConnected.message", selectedNode.getName()), I18n.get("manageNodesDialog.error.nodeConnected.title"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);
+                               if (response == JOptionPane.CANCEL_OPTION) {
+                                       break;
+                               } else if (response == JOptionPane.NO_OPTION) {
+                                       continue;
+                               }
+                       }
+                       nodeListModel.removeNode(selectedNode);
+               }
                nodeList.clearSelection();
-               nodeList.repaint();
        }
 
        /**
-        * Sets the default node to the selected node.
+        * Checks whether the list of nodes is not empty.
+        * 
+        * @return <code>true</code> if there is at least one node defined,
+        *         <code>false</code> otherwise
         */
-       private void setDefaultNode() {
-               NodeWrapper selectedNode = (NodeWrapper) nodeList.getSelectedValue();
-               for (NodeWrapper nodeWrapper: wrappedNodeList) {
-                       nodeWrapper.setDefaultNode(nodeWrapper == selectedNode);
-               }
-               nodeList.repaint();
+       private boolean verifyNodesExist() {
+               return nodeListModel.getSize() > 0;
        }
 
        /**
         * This method is called when the “okay” button is pressed. The nodes from
-        * the list are read and the {@link #wrappedNodeList} and
-        * {@link #defaultNode} members are set so that the calling code can use
-        * {@link #getNodeList()} and {@link #getDefaultNode()} to get the changed
+        * the list are read and the {@link #originalNodeList} member is set so that
+        * the calling code can use {@link #getNodeList()} to get the changed
         * values.
         */
        private void confirm() {
+               if (!verifyNodesExist()) {
+                       JOptionPane.showMessageDialog(this, I18n.get("manageNodesDialog.error.nodeListEmpty.message"), I18n.get("manageNodesDialog.error.nodeListEmpty.title"), JOptionPane.ERROR_MESSAGE);
+                       return;
+               }
                originalNodeList.clear();
-               for (NodeWrapper nodeWrapper: wrappedNodeList) {
-                       originalNodeList.add(nodeWrapper.getWrappedNode());
-                       if (nodeWrapper.isDefaultNode()) {
-                               defaultNode = nodeWrapper.getWrappedNode();
-                       }
+               for (Node node: nodeListModel) {
+                       originalNodeList.add(node);
                }
                setVisible(false);
        }
@@ -371,102 +370,88 @@ public class ManageNodesDialog extends JDialog implements ListSelectionListener
                int selectCount = list.getSelectedIndices().length;
                editNodeAction.setEnabled(selectCount == 1);
                deleteNodeAction.setEnabled(selectCount >= 1);
-               setDefaultNodeAction.setEnabled(selectCount == 1);
        }
 
+       //
+       // INTERFACE I18nable
+       //
+
        /**
-        * Wrapper around a {@link Node} to store whether a node is the default
-        * node. This frees us from having to write a {@link ListCellRenderer} for
-        * {@link ManageNodesDialog#nodeList}.
+        * {@inheritDoc}
+        */
+       public void updateI18n() {
+               okayAction.updateI18n();
+               cancelAction.updateI18n();
+               addNodeAction.updateI18n();
+               editNodeAction.updateI18n();
+               deleteNodeAction.updateI18n();
+               immediatelyEffectiveLabel.updateI18n();
+               setTitle(I18n.get("manageNodesDialog.title") + " – jSite " + Version.getVersion());
+               SwingUtils.repackCentered(this);
+       }
+
+       /**
+        * List model for the {@link ManageNodesDialog#nodeList}.
         * 
         * @author David ‘Bombe’ Roden &lt;bombe@freenetproject.org&gt;
         * @version $Id$
         */
-       private static class NodeWrapper {
-
-               /** The wrapped node. */
-               private final Node wrappedNode;
+       private class NodeListModel extends AbstractListModel implements Iterable<Node> {
 
-               /** The default node. */
-               private boolean defaultNode;
+               /** The list of nodes. */
+               @SuppressWarnings("hiding")
+               private final List<Node> nodeList = new ArrayList<Node>();
 
                /**
-                * Creates a new node wrapper around the given node.
-                * 
-                * @param wrappedNode
-                *            The node to wrap
+                * Creates a new node list model.
                 */
-               public NodeWrapper(Node wrappedNode) {
-                       this.wrappedNode = wrappedNode;
+               public NodeListModel() {
+                       /* do nothing. */
                }
 
                /**
-                * Returns the wrapped node.
+                * Adds the given node to the list model.
                 * 
-                * @return The wrapped node
+                * @see Collection#add(Object)
+                * @param node
+                *            The node to add
                 */
-               public Node getWrappedNode() {
-                       return wrappedNode;
+               public void addNode(Node node) {
+                       nodeList.add(node);
+                       fireIntervalAdded(this, nodeList.size() - 1, nodeList.size() - 1);
                }
 
                /**
-                * Returns whether the wrapped node is the default node.
+                * Removes the given node from the list model.
                 * 
-                * @return <code>true</code> if the wrapped node is the default node,
-                *         <code>false</code> otherwise
+                * @see Collection#remove(Object)
+                * @param node
+                *            The node to remove
                 */
-               public boolean isDefaultNode() {
-                       return defaultNode;
+               public void removeNode(Node node) {
+                       int nodeIndex = nodeList.indexOf(node);
+                       nodeList.remove(node);
+                       fireIntervalRemoved(this, nodeIndex, nodeIndex);
                }
 
                /**
-                * Sets whether the wrapped node is the default node.
+                * Removes all nodes from the list model.
                 * 
-                * @param defaultNode
-                *            <code>true</code> if the wrapped node is the default
-                *            node, <code>false</code> otherwise
+                * @see Collection#clear()
                 */
-               public void setDefaultNode(boolean defaultNode) {
-                       this.defaultNode = defaultNode;
+               public void clear() {
+                       int nodeCount = nodeList.size();
+                       if (nodeCount > 0) {
+                               nodeList.clear();
+                               fireIntervalRemoved(this, 0, nodeCount - 1);
+                       }
                }
 
                /**
                 * {@inheritDoc}
                 */
-               @Override
-               public String toString() {
-                       return wrappedNode.toString() + (defaultNode ? " (default)" : "");
-               }
-
-       }
-
-       /**
-        * List model for the {@link ManageNodesDialog#nodeList}. TODO
-        * 
-        * @author David ‘Bombe’ Roden &lt;bombe@freenetproject.org&gt;
-        * @version $Id$
-        */
-       private class NodeListModel extends AbstractListModel {
-
-               /** The list of wrapped nodes. */
-               @SuppressWarnings("hiding")
-               private List<NodeWrapper> nodeList = Collections.emptyList();
-
-               /**
-                * Creates a new node list model.
-                */
-               public NodeListModel() {
-               }
-
-               /**
-                * Sets the new node list.
-                * 
-                * @param nodeList
-                *            The list of nodes to display
-                */
-               public void setNodeList(List<NodeWrapper> nodeList) {
-                       this.nodeList = nodeList;
-                       fireContentsChanged(this, 0, nodeList.size() - 1);
+               public Iterator<Node> iterator() {
+                       return nodeList.iterator();
                }
 
                /**
@@ -474,8 +459,7 @@ public class ManageNodesDialog extends JDialog implements ListSelectionListener
                 */
                @SuppressWarnings("synthetic-access")
                public Object getElementAt(int index) {
-                       NodeWrapper currentNodeWrapper = nodeList.get(index);
-                       return currentNodeWrapper;
+                       return nodeList.get(index);
                }
 
                /**