Emit warning and abort insert if the selected node is not connected.
[jSite2.git] / src / net / pterodactylus / jsite / gui / SwingInterface.java
index 2f13df6..3df6402 100644 (file)
@@ -41,6 +41,8 @@ import java.util.logging.Level;
 import java.util.logging.LogRecord;
 import java.util.logging.Logger;
 
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JComboBox;
 import javax.swing.JOptionPane;
 import javax.swing.UIManager;
 import javax.swing.UnsupportedLookAndFeelException;
@@ -49,9 +51,9 @@ 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;
@@ -59,7 +61,7 @@ import net.pterodactylus.util.logging.LoggingListener;
 
 /**
  * The Swing user interface.
- * 
+ *
  * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
  */
 public class SwingInterface implements CoreListener, LoggingListener, PropertyChangeListener {
@@ -115,11 +117,14 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
        /** The “add project” action. */
        private I18nAction addProjectAction;
 
-       /** The “clone project” action. */
-       private I18nAction cloneProjectAction;
+       /** The “insert project” actions. */
+       private Map<Project, I18nAction> insertProjectActions = new HashMap<Project, I18nAction>();
+
+       /** The “clone project” actions. */
+       private Map<Project, I18nAction> cloneProjectActions = new HashMap<Project, I18nAction>();
 
-       /** The “delete project” action. */
-       private I18nAction deleteProjectAction;
+       /** The “delete project” actions. */
+       private Map<Project, I18nAction> deleteProjectActions = new HashMap<Project, I18nAction>();
 
        /** The “about” dialog. */
        private AboutDialog aboutDialog;
@@ -128,11 +133,14 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
        private ConfigurationDialog configurationDialog;
 
        /** The node editor dialog. */
-       private EditNodeDialog editNodeDialog;
+       private AddNodeDialog addNodeDialog;
 
        /** The list of all defined nodes. */
        private List<Node> nodeList = Collections.synchronizedList(new ArrayList<Node>());
 
+       /** The list of all projects. */
+       private List<Project> projectList = Collections.synchronizedList(new ArrayList<Project>());
+
        //
        // CONFIGURATION
        //
@@ -166,7 +174,7 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
 
        /**
         * Creates a new swing interface.
-        * 
+        *
         * @param core
         *            The core to operate on
         * @param configDirectory
@@ -216,7 +224,7 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
 
        /**
         * Returns the core that is controlled by the Swing interface.
-        * 
+        *
         * @return The core
         */
        Core getCore() {
@@ -225,7 +233,7 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
 
        /**
         * Returns the main window of the Swing interface.
-        * 
+        *
         * @return The main window
         */
        MainWindow getMainWindow() {
@@ -234,7 +242,7 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
 
        /**
         * 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
         */
@@ -244,7 +252,7 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
 
        /**
         * Returns the “configure” action.
-        * 
+        *
         * @return The “configure” action
         */
        I18nAction getConfigureAction() {
@@ -253,7 +261,7 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
 
        /**
         * Returns the “import config” action.
-        * 
+        *
         * @return The “import config” action
         */
        I18nAction getImportConfigAction() {
@@ -262,7 +270,7 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
 
        /**
         * Returns the “quit” action.
-        * 
+        *
         * @return The “quit” action
         */
        I18nAction getQuitAction() {
@@ -271,7 +279,7 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
 
        /**
         * Returns the “add node” action.
-        * 
+        *
         * @return The “add node” action
         */
        I18nAction getAddNodeAction() {
@@ -280,7 +288,7 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
 
        /**
         * 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
@@ -291,7 +299,7 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
 
        /**
         * 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
@@ -302,7 +310,7 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
 
        /**
         * Returns the “edit node” action for the given node.
-        * 
+        *
         * @param node
         *            The node to edit
         * @return The “edit node” action
@@ -313,7 +321,7 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
 
        /**
         * Returns the “delete node” action for the given node.
-        * 
+        *
         * @param node
         *            The node to delete
         * @return The “delete node” action
@@ -324,7 +332,7 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
 
        /**
         * Returns all language actions.
-        * 
+        *
         * @return All language actions
         */
        List<I18nAction> getLanguageActions() {
@@ -333,7 +341,7 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
 
        /**
         * Returns the “about” action.
-        * 
+        *
         * @return The “about” action
         */
        I18nAction getHelpAboutAction() {
@@ -342,7 +350,7 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
 
        /**
         * Returns the “add project” action.
-        * 
+        *
         * @return The “add project” action
         */
        I18nAction getAddProjectAction() {
@@ -350,26 +358,41 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
        }
 
        /**
-        * Returns the “clone project” action.
-        * 
+        * Returns the “insert project” action for the given project.
+        *
+        * @param project
+        *            The project to get the “insert project” action for
+        * @return The “insert project” action
+        */
+       I18nAction getInsertProjectAction(Project project) {
+               return insertProjectActions.get(project);
+       }
+
+       /**
+        * Returns the “clone project” action for the given project.
+        *
+        * @param project
+        *            The project to get the “clone project” action for
         * @return The “clone project” action
         */
-       I18nAction getCloneProjectAction() {
-               return cloneProjectAction;
+       I18nAction getCloneProjectAction(Project project) {
+               return cloneProjectActions.get(project);
        }
 
        /**
-        * Returns the “delete project” action.
-        * 
+        * Returns the “delete project” action for the given project.
+        *
+        * @param project
+        *            The project to get the “delete project” action for
         * @return The “delete project” action
         */
-       I18nAction getDeleteProjectAction() {
-               return deleteProjectAction;
+       I18nAction getDeleteProjectAction(Project project) {
+               return deleteProjectActions.get(project);
        }
 
        /**
         * Returns all currently configured nodes.
-        * 
+        *
         * @return All configured nodes
         */
        List<Node> getNodes() {
@@ -377,8 +400,17 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
        }
 
        /**
+        * Returns a list of all projects.
+        *
+        * @return All projects
+        */
+       List<Project> getProjects() {
+               return projectList;
+       }
+
+       /**
         * Returns the thread pool used for off-thread processes.
-        * 
+        *
         * @return The thread pool
         */
        Executor getThreadPool() {
@@ -530,8 +562,9 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
                        }
                };
                List<Locale> availableLanguages = I18n.findAvailableLanguages();
-               for (final Locale locale: availableLanguages) {
-                       I18nAction languageAction = new I18nAction("general.language." + locale.getLanguage()) {
+               for (final Locale locale : availableLanguages) {
+                       String language = locale.getLanguage();
+                       I18nAction languageAction = new I18nAction("general.language." + language, IconLoader.loadIcon("/flag-" + language + ".png")) {
 
                                @SuppressWarnings("synthetic-access")
                                public void actionPerformed(ActionEvent e) {
@@ -539,7 +572,7 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
                                }
 
                        };
-                       if (I18n.getLocale().getLanguage().equals(locale.getLanguage())) {
+                       if (I18n.getLocale().getLanguage().equals(language)) {
                                languageAction.setEnabled(false);
                        }
                        languageActions.add(languageAction);
@@ -574,26 +607,6 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
                                addProject();
                        }
                };
-               cloneProjectAction = new I18nAction("mainWindow.button.cloneProject") {
-
-                       /**
-                        * {@inheritDoc}
-                        */
-                       @SuppressWarnings("synthetic-access")
-                       public void actionPerformed(ActionEvent actionEvent) {
-                               cloneProject();
-                       }
-               };
-               deleteProjectAction = new I18nAction("mainWindow.button.deleteProject") {
-
-                       /**
-                        * {@inheritDoc}
-                        */
-                       @SuppressWarnings("synthetic-access")
-                       public void actionPerformed(ActionEvent actionEvent) {
-                               deleteProject();
-                       }
-               };
        }
 
        /**
@@ -602,7 +615,7 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
        private void initDialogs() {
                aboutDialog = new AboutDialog(this);
                configurationDialog = new ConfigurationDialog(this);
-               editNodeDialog = new EditNodeDialog(mainWindow);
+               addNodeDialog = new AddNodeDialog(mainWindow);
        }
 
        //
@@ -658,15 +671,15 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
         * Adds a node.
         */
        private void addNode() {
-               editNodeDialog.setNodeName(I18n.get(nodeList.isEmpty() ? "general.defaultNode.name" : "general.newNode.name"));
-               editNodeDialog.setNodeHostname("localhost");
-               editNodeDialog.setNodePort(9481);
-               editNodeDialog.setVisible(true);
-               if (!editNodeDialog.wasCancelled()) {
+               addNodeDialog.setNodeName(I18n.get(nodeList.isEmpty() ? "general.defaultNode.name" : "general.newNode.name"));
+               addNodeDialog.setNodeHostname("localhost");
+               addNodeDialog.setNodePort(9481);
+               addNodeDialog.setVisible(true);
+               if (!addNodeDialog.wasCancelled()) {
                        Node newNode = new Node();
-                       newNode.setName(editNodeDialog.getNodeName());
-                       newNode.setHostname(editNodeDialog.getNodeHostname());
-                       newNode.setPort(editNodeDialog.getNodePort());
+                       newNode.setName(addNodeDialog.getNodeName());
+                       newNode.setHostname(addNodeDialog.getNodeHostname());
+                       newNode.setPort(addNodeDialog.getNodePort());
                        try {
                                core.addNode(newNode);
                        } catch (UnknownHostException e) {
@@ -677,25 +690,25 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
 
        /**
         * Edits the given node.
-        * 
+        *
         * @param node
         *            The node to edit
         */
        private void editNode(Node node) {
-               editNodeDialog.setNodeName(node.getName());
-               editNodeDialog.setNodeHostname(node.getHostname());
-               editNodeDialog.setNodePort(node.getPort());
-               editNodeDialog.setVisible(true);
-               if (!editNodeDialog.wasCancelled()) {
-                       node.setName(editNodeDialog.getNodeName());
-                       node.setHostname(editNodeDialog.getNodeHostname());
-                       node.setPort(editNodeDialog.getNodePort());
+               addNodeDialog.setNodeName(node.getName());
+               addNodeDialog.setNodeHostname(node.getHostname());
+               addNodeDialog.setNodePort(node.getPort());
+               addNodeDialog.setVisible(true);
+               if (!addNodeDialog.wasCancelled()) {
+                       node.setName(addNodeDialog.getNodeName());
+                       node.setHostname(addNodeDialog.getNodeHostname());
+                       node.setPort(addNodeDialog.getNodePort());
                }
        }
 
        /**
         * Deletes the given node.
-        * 
+        *
         * @param node
         *            The node to delete
         */
@@ -708,7 +721,7 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
 
        /**
         * Connects to the node.
-        * 
+        *
         * @param node
         *            The node to connect to
         */
@@ -728,7 +741,7 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
 
        /**
         * Disconnects from the node.
-        * 
+        *
         * @param node
         *            The node to disconnect from
         */
@@ -740,14 +753,14 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
        /**
         * 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
         *            The action that triggered the change
         */
        private void changeLanguage(Locale newLocale, I18nAction languageAction) {
-               for (I18nAction i18nAction: languageActions) {
+               for (I18nAction i18nAction : languageActions) {
                        i18nAction.setEnabled(i18nAction != languageAction);
                }
                I18n.setLocale(newLocale);
@@ -765,14 +778,9 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
         */
        private void addProject() {
                try {
-                       Project project = core.createProject();
-                       project.setName(I18n.get("general.newProject.name"));
-                       project.setDescription(I18n.get("general.newProject.description", new Date()));
-                       project.setBasePath("");
-                       mainWindow.addProject(project, true);
-               } catch (JSiteException nne1) {
-                       /* TODO - add i18n */
-                       JOptionPane.showMessageDialog(mainWindow, I18n.get(""), I18n.get(""), JOptionPane.ERROR_MESSAGE);
+                       core.createProject();
+               } catch (JSiteException jse1) {
+                       JOptionPane.showMessageDialog(mainWindow, I18n.get("mainWindow.error.notConnected.message"), I18n.get("mainWindow.error.notConnected.title"), JOptionPane.ERROR_MESSAGE);
                } catch (IOException e) {
                        /* TODO - add i18n */
                        JOptionPane.showMessageDialog(mainWindow, I18n.get(""), I18n.get(""), JOptionPane.ERROR_MESSAGE);
@@ -780,17 +788,56 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
        }
 
        /**
+        * Inserts the given project.
+        *
+        * @param project
+        *            The project to insert
+        */
+       private void insertProject(Project project) {
+               Node targetNode = project.getNode();
+               if (targetNode == null) {
+                       JComboBox nodeComboBox = new JComboBox();
+                       for (Node node : nodeList) {
+                               ((DefaultComboBoxModel) nodeComboBox.getModel()).addElement(node.getName() + " (" + node.getHostname() + ":" + node.getPort() + ")");
+                       }
+                       int selectedOption = JOptionPane.showConfirmDialog(mainWindow, new Object[] { I18n.get("nodeSelectionDialog.selectNode.text"), nodeComboBox }, I18n.get("nodeSelectionDialog.noNodeSelected.text"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
+                       if (selectedOption == JOptionPane.CANCEL_OPTION) {
+                               return;
+                       }
+                       int selectedNodeIndex = nodeComboBox.getSelectedIndex();
+                       logger.log(Level.FINE, "selected node index: " + selectedNodeIndex);
+                       targetNode = nodeList.get(selectedNodeIndex);
+               }
+               logger.log(Level.INFO, "Inserting project “" + project.getName() + "” to node “" + targetNode.getName() + "”...");
+               if (!core.isNodeConnected(targetNode)) {
+                       JOptionPane.showMessageDialog(mainWindow, I18n.get("mainWindow.error.nodeNotConnected.message", targetNode.getName()), I18n.get("mainWindow.error.nodeNotConnected.title", targetNode.getName()), JOptionPane.ERROR_MESSAGE);
+                       return;
+               }
+               core.insertProject(targetNode, project);
+       }
+
+       /**
         * Clones a project.
+        *
+        * @param project
+        *            The project to clone
         */
-       private void cloneProject() {
-               /* TODO */
+       private void cloneProject(Project project) {
+               core.cloneProject(project);
        }
 
        /**
         * Deletes a project.
+        *
+        * @param project
+        *            The project to delete
         */
-       private void deleteProject() {
-               /* TODO */
+       private void deleteProject(Project project) {
+               int choice = JOptionPane.showConfirmDialog(mainWindow, I18n.get("mainWindow.question.deleteProject.message", project.getName()), I18n.get("mainWindow.question.deleteProject.title"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
+               if (choice == JOptionPane.NO_OPTION) {
+                       return;
+               }
+               core.removeProject(project);
        }
 
        //
@@ -802,8 +849,8 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
         */
        public void loadingProjectsDone(String directory) {
                mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.projectLoadingDone"));
-               for (Project project: core.getProjects()) {
-                       mainWindow.addProject(project, false);
+               for (Project project : core.getProjects()) {
+                       projectAdded(project, false);
                }
        }
 
@@ -831,6 +878,70 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
        /**
         * {@inheritDoc}
         */
+       public void projectAdded(Project project) {
+               project.setName(I18n.get("general.newProject.name"));
+               project.setDescription(I18n.get("general.newProject.description", new Date()));
+               projectAdded(project, true);
+       }
+
+       /**
+        * @param project
+        * @param switchToProject
+        */
+       private void projectAdded(final Project project, boolean switchToProject) {
+               insertProjectActions.put(project, new I18nAction("mainWindow.button.insertProject") {
+
+                       /**
+                        * {@inheritDoc}
+                        */
+                       @SuppressWarnings("synthetic-access")
+                       public void actionPerformed(ActionEvent actionEvent) {
+                               insertProject(project);
+                       }
+               });
+               cloneProjectActions.put(project, new I18nAction("mainWindow.button.cloneProject") {
+
+                       /**
+                        * {@inheritDoc}
+                        */
+                       @SuppressWarnings("synthetic-access")
+                       public void actionPerformed(ActionEvent actionEvent) {
+                               cloneProject(project);
+                       }
+               });
+               deleteProjectActions.put(project, new I18nAction("mainWindow.button.deleteProject") {
+
+                       /**
+                        * {@inheritDoc}
+                        */
+                       @SuppressWarnings("synthetic-access")
+                       public void actionPerformed(ActionEvent actionEvent) {
+                               deleteProject(project);
+                       }
+               });
+               projectList.add(project);
+               mainWindow.addProject(project, switchToProject);
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       public void projectCloned(Project clonedProject, Project projectClone) {
+               projectAdded(projectClone, true);
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       public void projectRemoved(Project project) {
+               mainWindow.removeProject(project);
+               cloneProjectActions.remove(project);
+               deleteProjectActions.remove(project);
+       }
+
+       /**
+        * {@inheritDoc}
+        */
        public void loadingNodesDone(String directory) {
                mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.loadingNodesDone"));
        }
@@ -981,14 +1092,14 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
        }
 
        /**
-        * @see net.pterodactylus.jsite.core.CoreListener#projectInsertStarted(net.pterodactylus.jsite.project.Project)
+        * @see net.pterodactylus.jsite.core.CoreListener#projectInsertStarted(net.pterodactylus.jsite.core.Project)
         */
        public void projectInsertStarted(Project project) {
                mainWindow.projectInsertStarted(project);
        }
 
        /**
-        * @see net.pterodactylus.jsite.core.CoreListener#projectInsertProgressed(net.pterodactylus.jsite.project.Project,
+        * @see net.pterodactylus.jsite.core.CoreListener#projectInsertProgressed(net.pterodactylus.jsite.core.Project,
         *      int, int, int, int, int, boolean)
         */
        public void projectInsertProgressed(Project project, int totalBlocks, int requiredBlocks, int successfulBlocks, int failedBlocks, int fatallyFailedBlocks, boolean finalizedTotal) {
@@ -996,7 +1107,7 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
        }
 
        /**
-        * @see net.pterodactylus.jsite.core.CoreListener#projectInsertGeneratedURI(net.pterodactylus.jsite.project.Project,
+        * @see net.pterodactylus.jsite.core.CoreListener#projectInsertGeneratedURI(net.pterodactylus.jsite.core.Project,
         *      java.lang.String)
         */
        public void projectInsertGeneratedURI(Project project, String uri) {
@@ -1004,7 +1115,7 @@ public class SwingInterface implements CoreListener, LoggingListener, PropertyCh
        }
 
        /**
-        * @see net.pterodactylus.jsite.core.CoreListener#projectInsertFinished(net.pterodactylus.jsite.project.Project,
+        * @see net.pterodactylus.jsite.core.CoreListener#projectInsertFinished(net.pterodactylus.jsite.core.Project,
         *      boolean)
         */
        public void projectInsertFinished(Project project, boolean success) {