X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=src%2Fnet%2Fpterodactylus%2Fjsite%2Fgui%2FSwingInterface.java;h=3df6402153204d4579d7c45a84ed004b6961b3c1;hb=2c2e370f0d6c24654a39e8d5657cb6c216ec9651;hp=1f41af1022dadca22957b111fa56207793ffb184;hpb=e2ea5a1eac8809b3a3d0c4e48dad26c9cae14961;p=jSite2.git diff --git a/src/net/pterodactylus/jsite/gui/SwingInterface.java b/src/net/pterodactylus/jsite/gui/SwingInterface.java index 1f41af1..3df6402 100644 --- a/src/net/pterodactylus/jsite/gui/SwingInterface.java +++ b/src/net/pterodactylus/jsite/gui/SwingInterface.java @@ -20,32 +20,70 @@ 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.net.UnknownHostException; import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +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.DefaultComboBoxModel; +import javax.swing.JComboBox; 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.util.image.IconLoader; +import net.pterodactylus.util.io.Closer; +import net.pterodactylus.util.logging.Logging; +import net.pterodactylus.util.logging.LoggingListener; /** - * TODO - * + * The Swing user interface. + * * @author David ‘Bombe’ Roden <bombe@freenetproject.org> - * @version $Id$ */ -public class SwingInterface implements CoreListener { +public class SwingInterface implements CoreListener, LoggingListener, PropertyChangeListener { + + /** The logger. */ + private static final Logger logger = Logging.getLogger(SwingInterface.class.getName()); /** The application core. */ private final Core core; + /** The configuration directory. */ + private final String configDirectory; + /** 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; @@ -55,17 +93,20 @@ public class SwingInterface implements CoreListener { /** The “quit” action. */ private I18nAction quitAction; - /** The “manage nodes” action. */ - private I18nAction manageNodesAction; + /** The “add node” action. */ + private I18nAction addNodeAction; + + /** All node menu items. */ + private Map nodeConnectActions = Collections.synchronizedMap(new HashMap()); - /** The “connect to node” action. */ - private I18nAction nodeConnectAction; + /** All node disconnect actions. */ + private Map nodeDisconnectActions = Collections.synchronizedMap(new HashMap()); - /** The “disconnect from node” action. */ - private I18nAction nodeDisconnectAction; + /** All node edit actions. */ + private Map nodeEditActions = Collections.synchronizedMap(new HashMap()); - /** The node manager dialog. */ - private ManageNodesDialog manageNodesDialog; + /** All node removal actions. */ + private Map nodeDeleteActions = Collections.synchronizedMap(new HashMap()); /** All lanugage menu items. */ private List languageActions = new ArrayList(); @@ -76,39 +117,105 @@ public class SwingInterface implements CoreListener { /** The “add project” action. */ private I18nAction addProjectAction; + /** The “insert project” actions. */ + private Map insertProjectActions = new HashMap(); + + /** The “clone project” actions. */ + private Map cloneProjectActions = new HashMap(); + + /** The “delete project” actions. */ + private Map deleteProjectActions = new HashMap(); + /** The “about” dialog. */ private AboutDialog aboutDialog; /** The configuration dialog. */ private ConfigurationDialog configurationDialog; + /** The node editor dialog. */ + private AddNodeDialog addNodeDialog; + /** The list of all defined nodes. */ - private List nodeList; + private List nodeList = Collections.synchronizedList(new ArrayList()); + + /** The list of all projects. */ + private List projectList = Collections.synchronizedList(new ArrayList()); // // CONFIGURATION // - /** Whether to beautify the GUI. */ - private boolean beautify; + /** The advanced mode. */ + private boolean advancedMode; + + /** Whether to antialias the GUI. */ + private boolean antialias; + + /** The control font. */ + private String controlFont; + + /** The user font. */ + private String userFont; + + /** 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. - * + * * @param core * The core to operate on + * @param configDirectory + * The directory the configuration is stored in */ - public SwingInterface(Core core) { + public SwingInterface(Core core, String configDirectory) { this.core = core; - I18n.setLocale(Locale.ENGLISH); /* TODO - load config */ + this.configDirectory = configDirectory; + I18n.setLocale(Locale.ENGLISH); loadConfig(); - if (beautify) { + if (lookAndFeel != null) { + try { + UIManager.setLookAndFeel(lookAndFeel); + } catch (ClassNotFoundException cnfe1) { + logger.log(Level.WARNING, "could not load look and feel", cnfe1); + } catch (InstantiationException ie1) { + logger.log(Level.WARNING, "could not load look and feel", ie1); + } catch (IllegalAccessException iae1) { + logger.log(Level.WARNING, "could not load look and feel", iae1); + } catch (UnsupportedLookAndFeelException ulafe1) { + logger.log(Level.WARNING, "could not load look and feel", ulafe1); + } + } + if (antialias) { System.setProperty("swing.aatext", "true"); - System.setProperty("swing.plaf.metal.controlFont", "Tahoma"); - System.setProperty("swing.plaf.metal.userFont", "Tahoma"); + } + if (controlFont != null) { + System.setProperty("swing.plaf.metal.controlFont", controlFont); + } + if (userFont != null) { + System.setProperty("swing.plaf.metal.userFont", userFont); } initActions(); 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(); } // @@ -117,7 +224,7 @@ public class SwingInterface implements CoreListener { /** * Returns the core that is controlled by the Swing interface. - * + * * @return The core */ Core getCore() { @@ -126,7 +233,7 @@ public class SwingInterface implements CoreListener { /** * Returns the main window of the Swing interface. - * + * * @return The main window */ MainWindow getMainWindow() { @@ -134,8 +241,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() { @@ -144,7 +261,7 @@ public class SwingInterface implements CoreListener { /** * Returns the “import config” action. - * + * * @return The “import config” action */ I18nAction getImportConfigAction() { @@ -153,7 +270,7 @@ public class SwingInterface implements CoreListener { /** * Returns the “quit” action. - * + * * @return The “quit” action */ I18nAction getQuitAction() { @@ -161,35 +278,61 @@ public class SwingInterface implements CoreListener { } /** - * Returns the “manage nodes” action. - * - * @return The “manage nodes” action + * Returns the “add node” action. + * + * @return The “add node” action */ - I18nAction getManageNodesAction() { - return manageNodesAction; + I18nAction getAddNodeAction() { + return addNodeAction; } /** - * 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; + 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; + I18nAction getNodeDisconnectAction(Node node) { + return nodeDisconnectActions.get(node); + } + + /** + * Returns the “edit node” action for the given node. + * + * @param node + * The node to edit + * @return The “edit node” action + */ + I18nAction getNodeEditAction(Node node) { + return nodeEditActions.get(node); + } + + /** + * Returns the “delete node” action for the given node. + * + * @param node + * The node to delete + * @return The “delete node” action + */ + I18nAction getNodeDeleteAction(Node node) { + return nodeDeleteActions.get(node); } /** * Returns all language actions. - * + * * @return All language actions */ List getLanguageActions() { @@ -198,7 +341,7 @@ public class SwingInterface implements CoreListener { /** * Returns the “about” action. - * + * * @return The “about” action */ I18nAction getHelpAboutAction() { @@ -207,13 +350,73 @@ public class SwingInterface implements CoreListener { /** * Returns the “add project” action. - * + * * @return The “add project” action */ I18nAction getAddProjectAction() { return addProjectAction; } + /** + * 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(Project project) { + return cloneProjectActions.get(project); + } + + /** + * 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(Project project) { + return deleteProjectActions.get(project); + } + + /** + * Returns all currently configured nodes. + * + * @return All configured nodes + */ + List getNodes() { + return nodeList; + } + + /** + * Returns a list of all projects. + * + * @return All projects + */ + List getProjects() { + return projectList; + } + + /** + * Returns the thread pool used for off-thread processes. + * + * @return The thread pool + */ + Executor getThreadPool() { + return threadPool; + } + // // ACTIONS // @@ -222,13 +425,6 @@ public class SwingInterface implements CoreListener { // SERVICE METHODS // - /** - * Starts the interface. - */ - public void start() { - mainWindow = new MainWindow(this); - } - // // PRIVATE METHODS // @@ -237,14 +433,105 @@ public class SwingInterface implements CoreListener { * Loads the configuration of the interface. */ private void loadConfig() { - beautify = true; + /* initialize default stuff. */ + antialias = false; + /* now read config. */ + File configFile = new File(configDirectory, "swing-interface.properties"); + if (!configFile.exists() || !configFile.canRead() || !configFile.isFile()) { + System.err.println("could not find “" + configFile.getAbsolutePath() + "”!"); + return; + } + Properties configProperties = new Properties(); + FileInputStream configInputStream = null; + try { + configInputStream = new FileInputStream(configFile); + configProperties.load(configInputStream); + } catch (IOException ioe1) { + System.err.println("could not load config, " + ioe1.getMessage()); + } finally { + Closer.close(configInputStream); + } + if (configProperties.containsKey("advancedMode")) { + advancedMode = Boolean.valueOf(configProperties.getProperty("advancedMode")); + } + if (configProperties.containsKey("antialias")) { + antialias = Boolean.valueOf(configProperties.getProperty("antialias")); + } + if (configProperties.containsKey("controlFont")) { + controlFont = configProperties.getProperty("controlFont"); + } + if (configProperties.containsKey("userFont")) { + userFont = configProperties.getProperty("userFont"); + } + if (configProperties.containsKey("lookAndFeel")) { + lookAndFeel = configProperties.getProperty("lookAndFeel"); + } + 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")); + } + } + + /** + * Saves the configuration. + */ + private void saveConfig() { + File configDirectory = new File(this.configDirectory); + if (!configDirectory.exists()) { + if (!configDirectory.mkdirs()) { + System.err.println("could not create “" + this.configDirectory + "”!"); + return; + } + } + if (!configDirectory.exists() || !configDirectory.isDirectory() || !configDirectory.canWrite()) { + System.err.println("can not access “" + this.configDirectory + "”!"); + return; + } + File configFile = new File(configDirectory, "swing-interface.properties"); + Properties configProperties = new Properties(); + configProperties.setProperty("advancedMode", String.valueOf(advancedMode)); + configProperties.setProperty("antialias", String.valueOf(antialias)); + if (controlFont != null) { + configProperties.setProperty("controlFont", controlFont); + } + if (userFont != null) { + configProperties.setProperty("userFont", userFont); + } + if (lookAndFeel != null) { + 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); + configProperties.store(configOutputStream, "configuration of swing interface"); + } catch (IOException ioe1) { + System.err.println("could not save config, " + ioe1.getMessage()); + } finally { + Closer.close(configOutputStream); + } } /** * 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} @@ -264,7 +551,7 @@ public class SwingInterface implements CoreListener { importConfig(); } }; - quitAction = new I18nAction("mainWindow.menu.jSite.quit") { + quitAction = new I18nAction("mainWindow.menu.jSite.quit", IconLoader.loadIcon("/system-log-out.png")) { /** * {@inheritDoc} @@ -274,37 +561,10 @@ public class SwingInterface implements CoreListener { quit(); } }; - manageNodesAction = new I18nAction("mainWindow.menu.node.item.manageNodes") { - - /** - * {@inheritDoc} - */ - @SuppressWarnings("synthetic-access") - public void actionPerformed(ActionEvent actionEvent) { - manageNodes(); - } - }; - nodeConnectAction = new I18nAction("mainWindow.menu.node.item.connect", false) { - - @SuppressWarnings("synthetic-access") - public void actionPerformed(ActionEvent actionEvent) { - nodeConnect(); - } - - }; - nodeDisconnectAction = new I18nAction("mainWindow.menu.node.item.disconnect", false) { - - /** - * {@inheritDoc} - */ - @SuppressWarnings("synthetic-access") - public void actionPerformed(ActionEvent e) { - nodeDisconnect(); - } - }; List 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) { @@ -312,11 +572,21 @@ public class SwingInterface implements CoreListener { } }; - if (I18n.getLocale().getLanguage().equals(locale.getLanguage())) { + if (I18n.getLocale().getLanguage().equals(language)) { languageAction.setEnabled(false); } languageActions.add(languageAction); } + addNodeAction = new I18nAction("mainWindow.menu.node.item.addNode", IconLoader.loadIcon("/node-new.png")) { + + /** + * {@inheritDoc} + */ + @SuppressWarnings("synthetic-access") + public void actionPerformed(ActionEvent actionEvent) { + addNode(); + } + }; helpAboutAction = new I18nAction("mainWindow.menu.help.item.about") { /** @@ -343,9 +613,9 @@ public class SwingInterface implements CoreListener { * Initializes all child dialogs. */ private void initDialogs() { - manageNodesDialog = new ManageNodesDialog(this); aboutDialog = new AboutDialog(this); configurationDialog = new ConfigurationDialog(this); + addNodeDialog = new AddNodeDialog(mainWindow); } // @@ -356,10 +626,23 @@ public class SwingInterface implements CoreListener { * Shows the configuration dialog. */ private void configure() { - configurationDialog.setBeautify(beautify); + configurationDialog.setAdvancedMode(advancedMode); + configurationDialog.setAntialias(antialias); + configurationDialog.setControlFont(controlFont); + configurationDialog.setUserFont(userFont); + configurationDialog.setLookAndFeel(lookAndFeel); configurationDialog.setVisible(true); if (!configurationDialog.wasCancelled()) { - beautify = configurationDialog.getBeautify(); + advancedMode = configurationDialog.isAdvancedMode(); + 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(); + lookAndFeel = configurationDialog.getLookAndFeel(); + saveConfig(); } } @@ -367,47 +650,117 @@ public class SwingInterface implements CoreListener { * Imports old jSite configuration. */ private void importConfig() { + /* TODO */ } /** * 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); } /** - * Pops up the “manage nodes” dialog. + * Adds a node. + */ + private void addNode() { + 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(addNodeDialog.getNodeName()); + newNode.setHostname(addNodeDialog.getNodeHostname()); + newNode.setPort(addNodeDialog.getNodePort()); + try { + core.addNode(newNode); + } catch (UnknownHostException e) { + JOptionPane.showMessageDialog(mainWindow, I18n.get("mainWindow.error.hostnameUnresolvable.message"), I18n.get("mainWindow.error.hostnameUnresolvable.title"), JOptionPane.ERROR_MESSAGE); + } + } + } + + /** + * Edits the given node. + * + * @param node + * The node to edit + */ + private void editNode(Node node) { + 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 */ - private void manageNodes() { - manageNodesDialog.setNodeList(nodeList); - manageNodesDialog.setVisible(true); - nodeList = manageNodesDialog.getNodeList(); + private void deleteNode(Node node) { + int option = JOptionPane.showConfirmDialog(mainWindow, I18n.get("mainWindow.question.deleteNode.message", node.getName()), I18n.get("mainWindow.question.deleteNode.title"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); + if (option == JOptionPane.OK_OPTION) { + core.removeNode(node); + } } /** * Connects to the node. + * + * @param node + * The node to connect to */ - private void nodeConnect() { + 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() { + 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 * 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); @@ -424,6 +777,67 @@ public class SwingInterface implements CoreListener { * Adds a project. */ private void addProject() { + try { + 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); + } + } + + /** + * 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(Project project) { + core.cloneProject(project); + } + + /** + * Deletes a project. + * + * @param project + * The project to delete + */ + 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); } // @@ -433,36 +847,301 @@ public class SwingInterface implements CoreListener { /** * {@inheritDoc} */ - public void loadingProjectsFailed(String directory) { + public void loadingProjectsDone(String directory) { + mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.projectLoadingDone")); + for (Project project : core.getProjects()) { + projectAdded(project, false); + } + } + + /** + * {@inheritDoc} + */ + public void loadingProjectsFailed(String directory, Throwable throwable) { JOptionPane.showMessageDialog(mainWindow, I18n.get("mainWindow.error.projectLoadingFailed.message", directory), I18n.get("mainWindow.error.projectLoadingFailed.title"), JOptionPane.ERROR_MESSAGE); } /** * {@inheritDoc} */ + public void savingProjectsDone(String directory) { + mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.projectSavingDone")); + } + + /** + * {@inheritDoc} + */ + public void savingProjectsFailed(String directory, Throwable throwabled) { + /* TODO */ + } + + /** + * {@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")); + } + + /** + * {@inheritDoc} + */ + public void loadingNodesFailed(String directory, Throwable throwable) { + /* TODO */ + } + + /** + * {@inheritDoc} + */ + public void savingNodesDone(String directory) { + mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.savingNodesDone")); + } + + /** + * {@inheritDoc} + */ + public void savingNodesFailed(String directory, Throwable throwable) { + /* TODO */ + } + + /** + * {@inheritDoc} + */ public void coreLoaded() { - this.nodeList = core.getNodes(); - manageNodesDialog.setNodeList(nodeList); mainWindow.setVisible(true); - mainWindow.setStatusBarText("Core loaded."); + mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.coreLoaded")); } /** * {@inheritDoc} */ - public void nodeConnected(Node node) { + public void coreStopped() { + mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.coreStopped")); + } + + /** + * {@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()); + nodeConnectActions.put(node, new I18nAction("mainWindow.menu.node.item.connect") { + + /** + * {@inheritDoc} + */ + @SuppressWarnings("synthetic-access") + public void actionPerformed(ActionEvent e) { + nodeConnect(node); + } + }); + nodeDisconnectActions.put(node, new I18nAction("mainWindow.menu.node.item.disconnect") { + + /** + * {@inheritDoc} + */ + @SuppressWarnings("synthetic-access") + public void actionPerformed(ActionEvent e) { + nodeDisconnect(node); + } + }); + nodeDisconnectActions.get(node).setEnabled(false); + nodeEditActions.put(node, new I18nAction("mainWindow.menu.node.item.edit") { + + /** + * {@inheritDoc} + */ + @SuppressWarnings("synthetic-access") + public void actionPerformed(ActionEvent actionEvent) { + editNode(node); + } + }); + nodeDeleteActions.put(node, new I18nAction("mainWindow.menu.node.item.remove") { + + /** + * {@inheritDoc} + */ + @SuppressWarnings("synthetic-access") + public void actionPerformed(ActionEvent actionEvent) { + deleteNode(node); + } + }); + 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); + nodeEditActions.remove(node); + nodeDeleteActions.remove(node); + mainWindow.removeNode(node); } /** * {@inheritDoc} */ public void nodeConnecting(Node node) { + nodeConnectActions.get(node).setEnabled(false); + nodeEditActions.get(node).setEnabled(false); + nodeDeleteActions.get(node).setEnabled(false); + mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.connectingToNode", node.getName(), node.getHostname(), node.getPort())); + } + + /** + * {@inheritDoc} + */ + public void nodeConnected(Node node) { + nodeDisconnectActions.get(node).setEnabled(true); + mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.connectedToNode", node.getName(), node.getHostname(), node.getPort())); + mainWindow.setOnline(node); + } + + /** + * {@inheritDoc} + */ + public void nodeConnectionFailed(Node node, Throwable cause) { + nodeConnectActions.get(node).setEnabled(true); + nodeEditActions.get(node).setEnabled(true); + nodeDeleteActions.get(node).setEnabled(true); + mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.connectionToNodeFailed", node.getName(), node.getHostname(), node.getPort(), (cause != null) ? cause.getMessage() : "no reason given")); + mainWindow.setError(node); + 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) { + nodeDisconnectActions.get(node).setEnabled(false); + nodeConnectActions.get(node).setEnabled(true); + nodeEditActions.get(node).setEnabled(true); + nodeDeleteActions.get(node).setEnabled(true); + mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.disconnectedFromNode", node.getName(), node.getHostname(), node.getPort())); + mainWindow.setOffline(node); + } + + /** + * @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.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) { + mainWindow.projectInsertProgressed(project, totalBlocks, requiredBlocks, successfulBlocks, failedBlocks, fatallyFailedBlocks, finalizedTotal); } /** + * @see net.pterodactylus.jsite.core.CoreListener#projectInsertGeneratedURI(net.pterodactylus.jsite.core.Project, + * java.lang.String) + */ + public void projectInsertGeneratedURI(Project project, String uri) { + mainWindow.projectInsertGeneratedURI(project); + } + + /** + * @see net.pterodactylus.jsite.core.CoreListener#projectInsertFinished(net.pterodactylus.jsite.core.Project, + * boolean) + */ + public void projectInsertFinished(Project project, boolean success) { + mainWindow.projectInsertFinished(project, success); + } + + // + // INTERFACE LoggingListener + // + + /** + * {@inheritDoc} + */ + public void logged(LogRecord logRecord) { + logWindow.logged(logRecord); + } + + // + // INTERFACE PropertyChangeListener + // + + /** * {@inheritDoc} */ - public void nodeDisconnected(Node node) { + public void propertyChange(PropertyChangeEvent propertyChangeEvent) { + /* do not react to anything (yet). */ } }