2 * jSite2 - SwingInterface.java -
3 * Copyright © 2008 David Roden
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 package net.pterodactylus.jsite.gui;
22 import java.awt.event.ActionEvent;
23 import java.beans.PropertyChangeEvent;
24 import java.beans.PropertyChangeListener;
26 import java.io.FileInputStream;
27 import java.io.FileOutputStream;
28 import java.io.IOException;
29 import java.net.UnknownHostException;
30 import java.util.ArrayList;
31 import java.util.Collections;
32 import java.util.Date;
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.Locale;
37 import java.util.Properties;
38 import java.util.concurrent.Executor;
39 import java.util.concurrent.Executors;
40 import java.util.logging.Level;
41 import java.util.logging.LogRecord;
42 import java.util.logging.Logger;
44 import javax.swing.JOptionPane;
45 import javax.swing.UIManager;
46 import javax.swing.UnsupportedLookAndFeelException;
48 import net.pterodactylus.jsite.core.Core;
49 import net.pterodactylus.jsite.core.CoreListener;
50 import net.pterodactylus.jsite.core.JSiteException;
51 import net.pterodactylus.jsite.core.Node;
52 import net.pterodactylus.jsite.i18n.I18n;
53 import net.pterodactylus.jsite.i18n.gui.I18nAction;
54 import net.pterodactylus.jsite.project.Project;
55 import net.pterodactylus.util.image.IconLoader;
56 import net.pterodactylus.util.io.Closer;
57 import net.pterodactylus.util.logging.Logging;
58 import net.pterodactylus.util.logging.LoggingListener;
61 * The Swing user interface.
63 * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
65 public class SwingInterface implements CoreListener, LoggingListener, PropertyChangeListener {
68 private static final Logger logger = Logging.getLogger(SwingInterface.class.getName());
70 /** The application core. */
71 private final Core core;
73 /** The configuration directory. */
74 private final String configDirectory;
76 /** The main window. */
77 private MainWindow mainWindow;
80 private Executor threadPool = Executors.newCachedThreadPool();
82 /** The logger window. */
83 private LogWindow logWindow;
85 /** The “configure” action. */
86 private I18nAction configureAction;
88 /** The “import config” action. */
89 private I18nAction importConfigAction;
91 /** The “quit” action. */
92 private I18nAction quitAction;
94 /** The “add node” action. */
95 private I18nAction addNodeAction;
97 /** All node menu items. */
98 private Map<Node, I18nAction> nodeConnectActions = Collections.synchronizedMap(new HashMap<Node, I18nAction>());
100 /** All node disconnect actions. */
101 private Map<Node, I18nAction> nodeDisconnectActions = Collections.synchronizedMap(new HashMap<Node, I18nAction>());
103 /** All node edit actions. */
104 private Map<Node, I18nAction> nodeEditActions = Collections.synchronizedMap(new HashMap<Node, I18nAction>());
106 /** All node removal actions. */
107 private Map<Node, I18nAction> nodeDeleteActions = Collections.synchronizedMap(new HashMap<Node, I18nAction>());
109 /** All lanugage menu items. */
110 private List<I18nAction> languageActions = new ArrayList<I18nAction>();
112 /** The “about” action. */
113 private I18nAction helpAboutAction;
115 /** The “add project” action. */
116 private I18nAction addProjectAction;
118 /** The “clone project” action. */
119 private I18nAction cloneProjectAction;
121 /** The “delete project” action. */
122 private I18nAction deleteProjectAction;
124 /** The “about” dialog. */
125 private AboutDialog aboutDialog;
127 /** The configuration dialog. */
128 private ConfigurationDialog configurationDialog;
130 /** The node editor dialog. */
131 private EditNodeDialog editNodeDialog;
133 /** The list of all defined nodes. */
134 private List<Node> nodeList = Collections.synchronizedList(new ArrayList<Node>());
140 /** The advanced mode. */
141 private boolean advancedMode;
143 /** Whether to antialias the GUI. */
144 private boolean antialias;
146 /** The control font. */
147 private String controlFont;
149 /** The user font. */
150 private String userFont;
152 /** The class name of the look and feel. */
153 private String lookAndFeel;
155 /** X coordinate of the main window. */
156 private int mainWindowX = -1;
158 /** Y coordinate of the main window. */
159 private int mainWindowY = -1;
161 /** Width of the main window. */
162 private int mainWindowWidth = -1;
164 /** Height of the main window. */
165 private int mainWindowHeight = -1;
168 * Creates a new swing interface.
171 * The core to operate on
172 * @param configDirectory
173 * The directory the configuration is stored in
175 public SwingInterface(Core core, String configDirectory) {
177 this.configDirectory = configDirectory;
178 I18n.setLocale(Locale.ENGLISH);
180 if (lookAndFeel != null) {
182 UIManager.setLookAndFeel(lookAndFeel);
183 } catch (ClassNotFoundException cnfe1) {
184 logger.log(Level.WARNING, "could not load look and feel", cnfe1);
185 } catch (InstantiationException ie1) {
186 logger.log(Level.WARNING, "could not load look and feel", ie1);
187 } catch (IllegalAccessException iae1) {
188 logger.log(Level.WARNING, "could not load look and feel", iae1);
189 } catch (UnsupportedLookAndFeelException ulafe1) {
190 logger.log(Level.WARNING, "could not load look and feel", ulafe1);
194 System.setProperty("swing.aatext", "true");
196 if (controlFont != null) {
197 System.setProperty("swing.plaf.metal.controlFont", controlFont);
199 if (userFont != null) {
200 System.setProperty("swing.plaf.metal.userFont", userFont);
204 mainWindow = new MainWindow(this);
205 mainWindow.setAdvancedMode(advancedMode);
206 if ((mainWindowX != -1) && (mainWindowY != -1) && (mainWindowWidth != -1) && (mainWindowHeight != -1)) {
207 mainWindow.setLocation(mainWindowX, mainWindowY);
208 mainWindow.setSize(mainWindowWidth, mainWindowHeight);
210 logWindow = new LogWindow();
218 * Returns the core that is controlled by the Swing interface.
227 * Returns the main window of the Swing interface.
229 * @return The main window
231 MainWindow getMainWindow() {
236 * Returns whether the advanced mode is activated.
238 * @return <code>true</code> if the advanced mode is activated,
239 * <code>false</code> if the simple mode is activated
241 boolean isAdvancedMode() {
246 * Returns the “configure” action.
248 * @return The “configure” action
250 I18nAction getConfigureAction() {
251 return configureAction;
255 * Returns the “import config” action.
257 * @return The “import config” action
259 I18nAction getImportConfigAction() {
260 return importConfigAction;
264 * Returns the “quit” action.
266 * @return The “quit” action
268 I18nAction getQuitAction() {
273 * Returns the “add node” action.
275 * @return The “add node” action
277 I18nAction getAddNodeAction() {
278 return addNodeAction;
282 * Returns the “connect to node” action for the given node.
285 * The node go get the “connect” action for
286 * @return The “connect to node” action
288 I18nAction getNodeConnectAction(Node node) {
289 return nodeConnectActions.get(node);
293 * Returns the “disconnect from node” action for the given node.
296 * The node go get the “disconnect” action for
297 * @return The “disconnect from node” action
299 I18nAction getNodeDisconnectAction(Node node) {
300 return nodeDisconnectActions.get(node);
304 * Returns the “edit node” action for the given node.
308 * @return The “edit node” action
310 I18nAction getNodeEditAction(Node node) {
311 return nodeEditActions.get(node);
315 * Returns the “delete node” action for the given node.
319 * @return The “delete node” action
321 I18nAction getNodeDeleteAction(Node node) {
322 return nodeDeleteActions.get(node);
326 * Returns all language actions.
328 * @return All language actions
330 List<I18nAction> getLanguageActions() {
331 return languageActions;
335 * Returns the “about” action.
337 * @return The “about” action
339 I18nAction getHelpAboutAction() {
340 return helpAboutAction;
344 * Returns the “add project” action.
346 * @return The “add project” action
348 I18nAction getAddProjectAction() {
349 return addProjectAction;
353 * Returns the “clone project” action.
355 * @return The “clone project” action
357 I18nAction getCloneProjectAction() {
358 return cloneProjectAction;
362 * Returns the “delete project” action.
364 * @return The “delete project” action
366 I18nAction getDeleteProjectAction() {
367 return deleteProjectAction;
371 * Returns all currently configured nodes.
373 * @return All configured nodes
375 List<Node> getNodes() {
380 * Returns the thread pool used for off-thread processes.
382 * @return The thread pool
384 Executor getThreadPool() {
401 * Loads the configuration of the interface.
403 private void loadConfig() {
404 /* initialize default stuff. */
406 /* now read config. */
407 File configFile = new File(configDirectory, "swing-interface.properties");
408 if (!configFile.exists() || !configFile.canRead() || !configFile.isFile()) {
409 System.err.println("could not find “" + configFile.getAbsolutePath() + "”!");
412 Properties configProperties = new Properties();
413 FileInputStream configInputStream = null;
415 configInputStream = new FileInputStream(configFile);
416 configProperties.load(configInputStream);
417 } catch (IOException ioe1) {
418 System.err.println("could not load config, " + ioe1.getMessage());
420 Closer.close(configInputStream);
422 if (configProperties.containsKey("advancedMode")) {
423 advancedMode = Boolean.valueOf(configProperties.getProperty("advancedMode"));
425 if (configProperties.containsKey("antialias")) {
426 antialias = Boolean.valueOf(configProperties.getProperty("antialias"));
428 if (configProperties.containsKey("controlFont")) {
429 controlFont = configProperties.getProperty("controlFont");
431 if (configProperties.containsKey("userFont")) {
432 userFont = configProperties.getProperty("userFont");
434 if (configProperties.containsKey("lookAndFeel")) {
435 lookAndFeel = configProperties.getProperty("lookAndFeel");
437 if (configProperties.containsKey("language")) {
438 I18n.setLocale(new Locale(configProperties.getProperty("language")));
440 if (configProperties.containsKey("mainWindowX")) {
441 mainWindowX = Integer.valueOf(configProperties.getProperty("mainWindowX"));
443 if (configProperties.containsKey("mainWindowY")) {
444 mainWindowY = Integer.valueOf(configProperties.getProperty("mainWindowY"));
446 if (configProperties.containsKey("mainWindowWidth")) {
447 mainWindowWidth = Integer.valueOf(configProperties.getProperty("mainWindowWidth"));
449 if (configProperties.containsKey("mainWindowHeight")) {
450 mainWindowHeight = Integer.valueOf(configProperties.getProperty("mainWindowHeight"));
455 * Saves the configuration.
457 private void saveConfig() {
458 File configDirectory = new File(this.configDirectory);
459 if (!configDirectory.exists()) {
460 if (!configDirectory.mkdirs()) {
461 System.err.println("could not create “" + this.configDirectory + "”!");
465 if (!configDirectory.exists() || !configDirectory.isDirectory() || !configDirectory.canWrite()) {
466 System.err.println("can not access “" + this.configDirectory + "”!");
469 File configFile = new File(configDirectory, "swing-interface.properties");
470 Properties configProperties = new Properties();
471 configProperties.setProperty("advancedMode", String.valueOf(advancedMode));
472 configProperties.setProperty("antialias", String.valueOf(antialias));
473 if (controlFont != null) {
474 configProperties.setProperty("controlFont", controlFont);
476 if (userFont != null) {
477 configProperties.setProperty("userFont", userFont);
479 if (lookAndFeel != null) {
480 configProperties.setProperty("lookAndFeel", lookAndFeel);
482 configProperties.setProperty("language", I18n.getLocale().getLanguage());
483 configProperties.setProperty("mainWindowX", String.valueOf(mainWindowX));
484 configProperties.setProperty("mainWindowY", String.valueOf(mainWindowY));
485 configProperties.setProperty("mainWindowWidth", String.valueOf(mainWindowWidth));
486 configProperties.setProperty("mainWindowHeight", String.valueOf(mainWindowHeight));
487 FileOutputStream configOutputStream = null;
489 configOutputStream = new FileOutputStream(configFile);
490 configProperties.store(configOutputStream, "configuration of swing interface");
491 } catch (IOException ioe1) {
492 System.err.println("could not save config, " + ioe1.getMessage());
494 Closer.close(configOutputStream);
499 * Initializes all actions.
501 private void initActions() {
502 configureAction = new I18nAction("mainWindow.menu.jSite.configure", IconLoader.loadIcon("/preferences-system.png")) {
507 @SuppressWarnings("synthetic-access")
508 public void actionPerformed(ActionEvent actionEvent) {
512 importConfigAction = new I18nAction("mainWindow.menu.jSite.importConfig") {
517 @SuppressWarnings("synthetic-access")
518 public void actionPerformed(ActionEvent actionEvent) {
522 quitAction = new I18nAction("mainWindow.menu.jSite.quit", IconLoader.loadIcon("/system-log-out.png")) {
527 @SuppressWarnings("synthetic-access")
528 public void actionPerformed(ActionEvent actionEvent) {
532 List<Locale> availableLanguages = I18n.findAvailableLanguages();
533 for (final Locale locale: availableLanguages) {
534 I18nAction languageAction = new I18nAction("general.language." + locale.getLanguage()) {
536 @SuppressWarnings("synthetic-access")
537 public void actionPerformed(ActionEvent e) {
538 changeLanguage(locale, this);
542 if (I18n.getLocale().getLanguage().equals(locale.getLanguage())) {
543 languageAction.setEnabled(false);
545 languageActions.add(languageAction);
547 addNodeAction = new I18nAction("mainWindow.menu.node.item.addNode", IconLoader.loadIcon("/node-new.png")) {
552 @SuppressWarnings("synthetic-access")
553 public void actionPerformed(ActionEvent actionEvent) {
557 helpAboutAction = new I18nAction("mainWindow.menu.help.item.about") {
562 @SuppressWarnings("synthetic-access")
563 public void actionPerformed(ActionEvent actionEvent) {
567 addProjectAction = new I18nAction("mainWindow.button.addProject") {
572 @SuppressWarnings("synthetic-access")
573 public void actionPerformed(ActionEvent actionEvent) {
577 cloneProjectAction = new I18nAction("mainWindow.button.cloneProject") {
582 @SuppressWarnings("synthetic-access")
583 public void actionPerformed(ActionEvent actionEvent) {
587 deleteProjectAction = new I18nAction("mainWindow.button.deleteProject") {
592 @SuppressWarnings("synthetic-access")
593 public void actionPerformed(ActionEvent actionEvent) {
600 * Initializes all child dialogs.
602 private void initDialogs() {
603 aboutDialog = new AboutDialog(this);
604 configurationDialog = new ConfigurationDialog(this);
605 editNodeDialog = new EditNodeDialog(mainWindow);
613 * Shows the configuration dialog.
615 private void configure() {
616 configurationDialog.setAdvancedMode(advancedMode);
617 configurationDialog.setAntialias(antialias);
618 configurationDialog.setControlFont(controlFont);
619 configurationDialog.setUserFont(userFont);
620 configurationDialog.setLookAndFeel(lookAndFeel);
621 configurationDialog.setVisible(true);
622 if (!configurationDialog.wasCancelled()) {
623 advancedMode = configurationDialog.isAdvancedMode();
624 if (!advancedMode && (nodeList.size() > 1)) {
625 JOptionPane.showMessageDialog(mainWindow, I18n.get("mainWindow.warning.multipleNodesNotAdvancedMode.message"), I18n.get("mainWindow.warning.multipleNodesNotAdvancedMode.title"), JOptionPane.WARNING_MESSAGE);
627 mainWindow.setAdvancedMode(advancedMode);
628 antialias = configurationDialog.isAntialias();
629 controlFont = configurationDialog.getControlFont();
630 userFont = configurationDialog.getUserFont();
631 lookAndFeel = configurationDialog.getLookAndFeel();
637 * Imports old jSite configuration.
639 private void importConfig() {
646 private void quit() {
649 mainWindowX = mainWindow.getX();
650 mainWindowY = mainWindow.getY();
651 mainWindowWidth = mainWindow.getWidth();
652 mainWindowHeight = mainWindow.getHeight();
660 private void addNode() {
661 editNodeDialog.setNodeName(I18n.get(nodeList.isEmpty() ? "general.defaultNode.name" : "general.newNode.name"));
662 editNodeDialog.setNodeHostname("localhost");
663 editNodeDialog.setNodePort(9481);
664 editNodeDialog.setVisible(true);
665 if (!editNodeDialog.wasCancelled()) {
666 Node newNode = new Node();
667 newNode.setName(editNodeDialog.getNodeName());
668 newNode.setHostname(editNodeDialog.getNodeHostname());
669 newNode.setPort(editNodeDialog.getNodePort());
671 core.addNode(newNode);
672 } catch (UnknownHostException e) {
673 JOptionPane.showMessageDialog(mainWindow, I18n.get("mainWindow.error.hostnameUnresolvable.message"), I18n.get("mainWindow.error.hostnameUnresolvable.title"), JOptionPane.ERROR_MESSAGE);
679 * Edits the given node.
684 private void editNode(Node node) {
685 editNodeDialog.setNodeName(node.getName());
686 editNodeDialog.setNodeHostname(node.getHostname());
687 editNodeDialog.setNodePort(node.getPort());
688 editNodeDialog.setVisible(true);
689 if (!editNodeDialog.wasCancelled()) {
690 node.setName(editNodeDialog.getNodeName());
691 node.setHostname(editNodeDialog.getNodeHostname());
692 node.setPort(editNodeDialog.getNodePort());
697 * Deletes the given node.
702 private void deleteNode(Node node) {
703 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);
704 if (option == JOptionPane.OK_OPTION) {
705 core.removeNode(node);
710 * Connects to the node.
713 * The node to connect to
715 private void nodeConnect(final Node node) {
716 threadPool.execute(new Runnable() {
721 @SuppressWarnings("synthetic-access")
723 logger.log(Level.INFO, "connecting to node “" + node.getName() + "”…");
724 core.connectToNode(node);
730 * Disconnects from the node.
733 * The node to disconnect from
735 private void nodeDisconnect(Node node) {
736 logger.log(Level.INFO, "disconnecting from node “" + node.getName() + "”…");
737 core.disconnectFromNode(node);
741 * Changes the language of the interface. This method also disables the
742 * action for the newly set language and enables all others.
746 * @param languageAction
747 * The action that triggered the change
749 private void changeLanguage(Locale newLocale, I18nAction languageAction) {
750 for (I18nAction i18nAction: languageActions) {
751 i18nAction.setEnabled(i18nAction != languageAction);
753 I18n.setLocale(newLocale);
757 * Shows the “about” dialog.
759 private void helpAbout() {
760 aboutDialog.setVisible(true);
766 private void addProject() {
768 Project project = core.createProject();
769 project.setName(I18n.get("general.newProject.name"));
770 project.setDescription(I18n.get("general.newProject.description", new Date()));
771 project.setBasePath("");
772 mainWindow.addProject(project, true);
773 } catch (JSiteException nne1) {
774 /* TODO - add i18n */
775 JOptionPane.showMessageDialog(mainWindow, I18n.get(""), I18n.get(""), JOptionPane.ERROR_MESSAGE);
776 } catch (IOException e) {
777 /* TODO - add i18n */
778 JOptionPane.showMessageDialog(mainWindow, I18n.get(""), I18n.get(""), JOptionPane.ERROR_MESSAGE);
785 private void cloneProject() {
792 private void deleteProject() {
797 // INTERFACE CoreListener
803 public void loadingProjectsDone(String directory) {
804 mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.projectLoadingDone"));
805 for (Project project: core.getProjects()) {
806 mainWindow.addProject(project, false);
813 public void loadingProjectsFailed(String directory, Throwable throwable) {
814 JOptionPane.showMessageDialog(mainWindow, I18n.get("mainWindow.error.projectLoadingFailed.message", directory), I18n.get("mainWindow.error.projectLoadingFailed.title"), JOptionPane.ERROR_MESSAGE);
820 public void savingProjectsDone(String directory) {
821 mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.projectSavingDone"));
827 public void savingProjectsFailed(String directory, Throwable throwabled) {
834 public void loadingNodesDone(String directory) {
835 mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.loadingNodesDone"));
841 public void loadingNodesFailed(String directory, Throwable throwable) {
848 public void savingNodesDone(String directory) {
849 mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.savingNodesDone"));
855 public void savingNodesFailed(String directory, Throwable throwable) {
862 public void coreLoaded() {
863 mainWindow.setVisible(true);
864 mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.coreLoaded"));
870 public void coreStopped() {
871 mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.coreStopped"));
877 public void nodeAdded(final Node node) {
878 logger.log(Level.INFO, "node added: " + node);
880 node.addPropertyChangeListener(this);
881 logger.log(Level.FINE, "nodeList.size(): " + nodeList.size());
882 nodeConnectActions.put(node, new I18nAction("mainWindow.menu.node.item.connect") {
887 @SuppressWarnings("synthetic-access")
888 public void actionPerformed(ActionEvent e) {
892 nodeDisconnectActions.put(node, new I18nAction("mainWindow.menu.node.item.disconnect") {
897 @SuppressWarnings("synthetic-access")
898 public void actionPerformed(ActionEvent e) {
899 nodeDisconnect(node);
902 nodeDisconnectActions.get(node).setEnabled(false);
903 nodeEditActions.put(node, new I18nAction("mainWindow.menu.node.item.edit") {
908 @SuppressWarnings("synthetic-access")
909 public void actionPerformed(ActionEvent actionEvent) {
913 nodeDeleteActions.put(node, new I18nAction("mainWindow.menu.node.item.remove") {
918 @SuppressWarnings("synthetic-access")
919 public void actionPerformed(ActionEvent actionEvent) {
923 mainWindow.addNode(node);
929 public void nodeRemoved(Node node) {
930 logger.log(Level.INFO, "node removed: " + node);
931 nodeList.remove(node);
932 node.removePropertyChangeListener(this);
933 nodeConnectActions.remove(node);
934 nodeDisconnectActions.remove(node);
935 nodeEditActions.remove(node);
936 nodeDeleteActions.remove(node);
937 mainWindow.removeNode(node);
943 public void nodeConnecting(Node node) {
944 nodeConnectActions.get(node).setEnabled(false);
945 nodeEditActions.get(node).setEnabled(false);
946 nodeDeleteActions.get(node).setEnabled(false);
947 mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.connectingToNode", node.getName(), node.getHostname(), node.getPort()));
953 public void nodeConnected(Node node) {
954 nodeDisconnectActions.get(node).setEnabled(true);
955 mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.connectedToNode", node.getName(), node.getHostname(), node.getPort()));
956 mainWindow.setOnline(node);
962 public void nodeConnectionFailed(Node node, Throwable cause) {
963 nodeConnectActions.get(node).setEnabled(true);
964 nodeEditActions.get(node).setEnabled(true);
965 nodeDeleteActions.get(node).setEnabled(true);
966 mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.connectionToNodeFailed", node.getName(), node.getHostname(), node.getPort(), (cause != null) ? cause.getMessage() : "no reason given"));
967 mainWindow.setError(node);
968 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);
974 public void nodeDisconnected(Node node, Throwable throwable) {
975 nodeDisconnectActions.get(node).setEnabled(false);
976 nodeConnectActions.get(node).setEnabled(true);
977 nodeEditActions.get(node).setEnabled(true);
978 nodeDeleteActions.get(node).setEnabled(true);
979 mainWindow.setStatusBarText(I18n.get("mainWindow.statusBar.disconnectedFromNode", node.getName(), node.getHostname(), node.getPort()));
980 mainWindow.setOffline(node);
984 * @see net.pterodactylus.jsite.core.CoreListener#projectInsertStarted(net.pterodactylus.jsite.project.Project)
986 public void projectInsertStarted(Project project) {
987 mainWindow.projectInsertStarted(project);
991 * @see net.pterodactylus.jsite.core.CoreListener#projectInsertProgressed(net.pterodactylus.jsite.project.Project,
992 * int, int, int, int, int, boolean)
994 public void projectInsertProgressed(Project project, int totalBlocks, int requiredBlocks, int successfulBlocks, int failedBlocks, int fatallyFailedBlocks, boolean finalizedTotal) {
995 mainWindow.projectInsertProgressed(project, totalBlocks, requiredBlocks, successfulBlocks, failedBlocks, fatallyFailedBlocks, finalizedTotal);
999 * @see net.pterodactylus.jsite.core.CoreListener#projectInsertGeneratedURI(net.pterodactylus.jsite.project.Project,
1002 public void projectInsertGeneratedURI(Project project, String uri) {
1003 mainWindow.projectInsertGeneratedURI(project);
1007 * @see net.pterodactylus.jsite.core.CoreListener#projectInsertFinished(net.pterodactylus.jsite.project.Project,
1010 public void projectInsertFinished(Project project, boolean success) {
1011 mainWindow.projectInsertFinished(project, success);
1015 // INTERFACE LoggingListener
1021 public void logged(LogRecord logRecord) {
1022 logWindow.logged(logRecord);
1026 // INTERFACE PropertyChangeListener
1032 public void propertyChange(PropertyChangeEvent propertyChangeEvent) {
1033 /* do not react to anything (yet). */