diff --git a/LICENSE b/LICENSE index f658775fb3e65a6c76ff0742f877deb813d40bde..999aac02e9526f088c2e1099fbe3601abb6904d6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2007, Distributed Computing Group (DCG), ETH Zurich, Switzerland, http://dcg.ethz.ch +Copyright (c) 2007, Distributed Computing Group (DCG), ETH Zurich, Switzerland, https://dcg.ethz.ch All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/README.md b/README.md index 6f61bd8e8e8f29f6c3f45e44aacd278b74a8b1a3..3d33c40f459a766d18ff411001e9e30e35fc6fa0 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ message whether it should arrive or not. E.g. drop one percent of all messages. arrives at its destination. DISCLAIMER: -Sinalgo was originally developed by the [DCG (Distributed Computing Group)](https://disco.ethz.ch/) at [ETHzürich](http://www.ethz.ch/). +Sinalgo was originally developed by the [DCG (Distributed Computing Group)](https://disco.ethz.ch/) at [ETHzürich](https://www.ethz.ch/). ## Installation and usage diff --git a/VERSION b/VERSION index a68038caee9d2155bae97b75f12c7786432c2673..1799be57810e62c070c836dde322063f9d5501eb 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0-beta4 \ No newline at end of file +1.0.0-beta5 \ No newline at end of file diff --git a/WEB_PAGE_URL b/WEB_PAGE_URL new file mode 100644 index 0000000000000000000000000000000000000000..4414018ba3a300014210b73a171424beb28f3752 --- /dev/null +++ b/WEB_PAGE_URL @@ -0,0 +1 @@ +https://sinalgo.github.io \ No newline at end of file diff --git a/WEB_REPOSITORY_URL b/WEB_REPOSITORY_URL new file mode 100644 index 0000000000000000000000000000000000000000..d6135e318b438f8c4cd60049c42d24e06a931546 --- /dev/null +++ b/WEB_REPOSITORY_URL @@ -0,0 +1 @@ +https://github.com/Sinalgo/sinalgo \ No newline at end of file diff --git a/build.gradle b/build.gradle index d36688d19f360e38bf4a4ee05133daeca98e284d..20bf720e18aaf7d93e665e00322877688f6b5f9b 100644 --- a/build.gradle +++ b/build.gradle @@ -89,6 +89,8 @@ task wrapper(type: Wrapper) { processResources { with copySpec { from 'VERSION' + from 'WEB_PAGE_URL' + from 'WEB_REPOSITORY_URL' } with copySpec { diff --git a/src/main/java/sinalgo/configuration/Configuration.java b/src/main/java/sinalgo/configuration/Configuration.java index eec441a36dfee557f822fbaa5f6f85f9b539d7a4..77fa9090666f5193dc88604683616a489643414a 100644 --- a/src/main/java/sinalgo/configuration/Configuration.java +++ b/src/main/java/sinalgo/configuration/Configuration.java @@ -69,14 +69,7 @@ import java.util.List; import java.util.Map.Entry; import java.util.Scanner; -import static sinalgo.configuration.Configuration.ImplementationChoiceInConfigFile.ImplementationType.MODELS_CONNECTIVITY; -import static sinalgo.configuration.Configuration.ImplementationChoiceInConfigFile.ImplementationType.MODELS_DISTRIBUTION; -import static sinalgo.configuration.Configuration.ImplementationChoiceInConfigFile.ImplementationType.MODELS_INTERFERENCE; -import static sinalgo.configuration.Configuration.ImplementationChoiceInConfigFile.ImplementationType.MODELS_MESSAGE_TRANSMISSION; -import static sinalgo.configuration.Configuration.ImplementationChoiceInConfigFile.ImplementationType.MODELS_MOBILITY; -import static sinalgo.configuration.Configuration.ImplementationChoiceInConfigFile.ImplementationType.MODELS_RELIABILITY; -import static sinalgo.configuration.Configuration.ImplementationChoiceInConfigFile.ImplementationType.NODES_EDGES; -import static sinalgo.configuration.Configuration.ImplementationChoiceInConfigFile.ImplementationType.NODES_IMPLEMENTATIONS; +import static sinalgo.configuration.Configuration.ImplementationChoiceInConfigFile.ImplementationType.*; /** * This class provides globally visible constants and access to the custom @@ -111,6 +104,34 @@ public class Configuration { } } + /** + * The repository which contains the latest code changes for Sinalgo + */ + public static final String SINALGO_REPO = getRepoString(); + + private static String getRepoString() { + try { + return new Scanner(Thread.currentThread().getContextClassLoader().getResourceAsStream("WEB_REPOSITORY_URL"), + StandardCharsets.UTF_8.displayName()).useDelimiter("\\A").next().trim(); + } catch (Exception e) { + throw new SinalgoFatalException("Could not read version information from the WEB_REPOSITORY_URL file.\n\n" + e); + } + } + + /** + * The webpage that contains Sinalgo's tutorial and help files + */ + public static final String SINALGO_WEB_PAGE = getWebPageString(); + + private static String getWebPageString() { + try { + return new Scanner(Thread.currentThread().getContextClassLoader().getResourceAsStream("WEB_PAGE_URL"), + StandardCharsets.UTF_8.displayName()).useDelimiter("\\A").next().trim(); + } catch (Exception e) { + throw new SinalgoFatalException("Could not read version information from the WEB_PAGE_URL file.\n\n" + e); + } + } + /** * The annotation to be used for fields that are included by default in the * configuration file. The description contains a brief description of this diff --git a/src/main/java/sinalgo/gui/dialogs/AboutDialog.java b/src/main/java/sinalgo/gui/dialogs/AboutDialog.java index fdfbc430a00529d6b3fdfe328b6ad6f8340bb81a..62f49e8a813c4bf5288fc8e23e2cd27a258e7cc1 100644 --- a/src/main/java/sinalgo/gui/dialogs/AboutDialog.java +++ b/src/main/java/sinalgo/gui/dialogs/AboutDialog.java @@ -49,6 +49,9 @@ import java.awt.datatransfer.StringSelection; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; public class AboutDialog extends JDialog implements ActionListener { @@ -75,11 +78,11 @@ public class AboutDialog extends JDialog implements ActionListener { + "<center><h1><span class='red'>Si</span>mulator for <span class='red'>N</span>etwork <span class='red'>Algo</span>rithms</h1></center>" + "" + "<center>Version " + Configuration.VERSION_STRING + "</center><center><small><a href='TestVersion'>Test for newer version</a></small></center>" - + "<p>Visit <a href='https://github.com/Sinalgo/sinalgo'>https://github.com/Sinalgo/sinalgo</a> to obtain the latest version, report bugs or problems, " - + "and visit <a href='https://github.com/Sinalgo/sinalgo'>https://github.com/Sinalgo/sinalgo</a> for a documentation of Sinalgo" + + "<p>Visit <a href='" + Configuration.SINALGO_REPO + "'>" + Configuration.SINALGO_REPO + "</a> to obtain the latest version, report bugs or problems, " + + "and visit <a href='" + Configuration.SINALGO_WEB_PAGE + "'>" + Configuration.SINALGO_WEB_PAGE + "</a> for a documentation of Sinalgo" + "<p>" - + "Sinalgo is brought to you by the Distributed Computing Group of ETH Zurich <a href='http://dcg.ethz.ch'>http://dcg.ethz.ch</a>" - + "<p>" + "<small>Hint: Click on a link to copy it to the clip board.</small>" + "</body>" + "</html>"); + + "Sinalgo is brought to you by the Distributed Computing Group of ETH Zurich <a href='https://dcg.ethz.ch'>https://dcg.ethz.ch</a>" + + "<p>" + "</body>" + "</html>"); html.setEditable(false); html.setBackground(this.getBackground()); this.add(html); @@ -90,19 +93,14 @@ public class AboutDialog extends JDialog implements ActionListener { VersionTester.testVersion(false, true); return; } - Clipboard cp = Toolkit.getDefaultToolkit().getSystemClipboard(); - cp.setContents(new StringSelection(e.getDescription()), null); - // With Java 1.6, we could open the 'default' browser - // Desktop dt = Desktop.getDesktop(); - // try { - // dt.browse(url.toURI()); - // } catch (IOException e1) { - // // TODO Auto-generated catch block - // e1.printStackTrace(); - // } catch (URISyntaxException e1) { - // // TODO Auto-generated catch block - // e1.printStackTrace(); - // } + Desktop dt = Desktop.getDesktop(); + try { + dt.browse(new URL(e.getDescription()).toURI()); + } catch (IOException | URISyntaxException ex) { + Clipboard cp = Toolkit.getDefaultToolkit().getSystemClipboard(); + cp.setContents(new StringSelection(e.getDescription()), null); + JOptionPane.showMessageDialog(this, "The link was copied to the clipboard!"); + } } }); diff --git a/src/main/java/sinalgo/gui/dialogs/HelpDialog.java b/src/main/java/sinalgo/gui/dialogs/HelpDialog.java index 5810c17922892d1d6e48ca5b60aa03bedfc9c627..677f4b0855bf3043fd86a29685acc80a29901f57 100644 --- a/src/main/java/sinalgo/gui/dialogs/HelpDialog.java +++ b/src/main/java/sinalgo/gui/dialogs/HelpDialog.java @@ -37,25 +37,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package sinalgo.gui.dialogs; +import javafx.application.Platform; +import javafx.embed.swing.JFXPanel; +import javafx.scene.Scene; +import javafx.scene.input.KeyCode; +import javafx.scene.web.WebHistory; +import javafx.scene.web.WebView; import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; import sinalgo.configuration.AppConfig; -import sinalgo.gui.GuiHelper; +import sinalgo.configuration.Configuration; import javax.swing.*; -import javax.swing.event.HyperlinkEvent; -import javax.swing.event.HyperlinkListener; -import javax.swing.text.html.HTMLDocument; -import javax.swing.text.html.HTMLFrameHyperlinkEvent; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyEvent; -import java.awt.event.WindowEvent; -import java.awt.event.WindowListener; -import java.io.IOException; -import java.net.URL; +import java.awt.event.*; @Getter(AccessLevel.PRIVATE) @Setter(AccessLevel.PRIVATE) @@ -63,188 +59,50 @@ public class HelpDialog extends JFrame implements ActionListener, WindowListener private static final long serialVersionUID = 5648555963120786571L; - private JEditorPane html; - private JButton menuButton = new JButton("Menu"); - - private URL currentURL; - private URL defaultURL; + private JFXPanel fxPanel; private HelpDialog(JFrame parent) { // is private, use showHelp() to create it in a new thread - this.setTitle("Sinalgo Help (source: https://github.com/Sinalgo/sinalgo)"); - GuiHelper.setWindowIcon(this); - this.addWindowListener(this); - this.restoreWindowState(); - - this.setLayout(new BorderLayout()); - this.setResizable(true); - - JPanel topPanel = new JPanel(); - this.add(topPanel, BorderLayout.NORTH); - topPanel.setLayout(new BorderLayout()); - topPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); - topPanel.add(this.getMenuButton(), BorderLayout.WEST); - this.getMenuButton().addActionListener(this); - - this.setHtml(new JEditorPane()); - JScrollPane scroller = new JScrollPane(); - JViewport vp = scroller.getViewport(); - vp.add(this.getHtml()); - this.add(scroller, BorderLayout.CENTER); - - try { - this.setDefaultURL(new URL("https://sinalgo.github.io")); - this.setCurrentURL(this.getDefaultURL()); - this.getHtml().setPage(this.getCurrentURL()); - this.getHtml().setEditable(false); - this.getHtml().addHyperlinkListener(this.getLinkListener()); - } catch (IOException e1) { - this.getHtml().setText("Cannot display the page.\n" + e1.getMessage()); - } + super("Sinalgo Help (source: " + Configuration.SINALGO_WEB_PAGE + ")"); + fxPanel = new JFXPanel(); + Platform.runLater(() -> { + WebView wv = new WebView(); + wv.getEngine().load(Configuration.SINALGO_WEB_PAGE); + wv.setContextMenuEnabled(false); + getFxPanel().setScene(new Scene(wv, 500, 500)); + HelpDialog.this.setMinimumSize(new Dimension(500, 500)); + HelpDialog.this.setIconImage(parent.getIconImage()); + HelpDialog.this.add(new JScrollPane(fxPanel)); + HelpDialog.this.addWindowListener(this); + HelpDialog.this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + HelpDialog.this.restoreWindowState(); + wv.setOnKeyPressed(e -> { + if (!e.isConsumed()) { + if (e.getCode() == KeyCode.LEFT && e.isAltDown()) { + WebHistory h = wv.getEngine().getHistory(); + if (h.getCurrentIndex() > 0) { + h.go(-1); + } + } else if (e.getCode() == KeyCode.RIGHT && e.isAltDown()) { + WebHistory h = wv.getEngine().getHistory(); + if (h.getCurrentIndex() < h.getEntries().size() - 1) { + h.go(1); + } + } + } + }); + HelpDialog.this.setVisible(true); + HelpDialog.this.pack(); + }); // Detect ESCAPE button KeyboardFocusManager focusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); focusManager.addKeyEventPostProcessor(e -> { if (!e.isConsumed() && e.getID() == KeyEvent.KEY_PRESSED && e.getKeyCode() == KeyEvent.VK_ESCAPE) { - HelpDialog.this.setVisible(false); + HelpDialog.this.dispose(); } return false; }); - this.pack(); - this.setVisible(true); - } - - private HyperlinkListener getLinkListener() { - return e -> { - if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { - if (e instanceof HTMLFrameHyperlinkEvent) { - ((HTMLDocument) this.getHtml().getDocument()) - .processHTMLFrameHyperlinkEvent((HTMLFrameHyperlinkEvent) e); - } else { - try { - this.setCurrentURL(e.getURL()); - String s = this.getCurrentURL().toString(); - int offset = s.indexOf(".html"); - if (offset > 0) { // .html is in the string - s = s.substring(0, offset + 5); - s += "?help"; - if (this.getCurrentURL().getRef() != null) { - s += "#" + this.getCurrentURL().getRef(); - } - this.setCurrentURL(new URL(s)); - HelpDialog.this.setEnabled(true); - if (this.getMenuDlg() != null) { - this.getMenuDlg().setVisible(false); - this.setMenuDlg(null); - } - } - this.getHtml().setPage(this.getCurrentURL()); - } catch (IOException e1) { - this.getHtml().setText("Cannot display the page.\n" + e1.getMessage()); - } - } - } - }; - } - - private MenuDialog menuDlg; // The menu dialog if its currently shown, otherwise null - - private void showMenu() { - Point p = this.getMenuButton().getLocationOnScreen(); - this.setMenuDlg(new MenuDialog(this, p)); - this.setEnabled(false); - } - - @Override - public void actionPerformed(ActionEvent e) { - if (e.getSource().equals(this.getMenuButton())) { - this.showMenu(); - } - } - - @Getter(AccessLevel.PACKAGE) - @Setter(AccessLevel.PACKAGE) - class MenuDialog extends JWindow implements ActionListener { - - private static final long serialVersionUID = -950395591867596455L; - - private JFrame parentFrame; - - private JButton closeButton = new JButton("Close"); - private JButton resetButton = new JButton("Reset"); - private JEditorPane ePane; - private String defaultMenuURL = "https://github.com/Sinalgo/sinalgo/"; - - MenuDialog(JFrame owner, Point pos) { - super(owner); - this.setParentFrame(owner); - this.setLayout(new BorderLayout()); - - this.setEPane(new JEditorPane()); - // ePane.getEditorKit(). - this.getEPane().setPreferredSize(new Dimension(250, 400)); - this.getEPane().setEditable(false); - JScrollPane scroller = new JScrollPane(); - JViewport vp = scroller.getViewport(); - vp.add(this.getEPane()); - this.add(scroller, BorderLayout.CENTER); - - try { - // create the URL for the menu (ensure that the url still points to a Sinalgo - // page - String s = (HelpDialog.this.getCurrentURL() == null ? this.getDefaultMenuURL() : HelpDialog.this.getCurrentURL().toString()); - URL myURL; - int offset = s.indexOf(".html"); - if (offset > 0) { // .html is in the string - if (!s.contains("github.com/andrebrait/sinalgo/")) { // went to a different site - myURL = new URL(this.getDefaultMenuURL()); - } else { // add the ?menu option - s = s.substring(0, offset + 5); - s += "?menu"; - myURL = new URL(s); - } - } else { - myURL = new URL(this.getDefaultMenuURL()); - } - this.getEPane().setPage(myURL); // load the page - this.getEPane().addHyperlinkListener(HelpDialog.this.getLinkListener()); - } catch (IOException e1) { - this.getEPane().setText("Cannot display the page.\n" + e1.getMessage()); - } - - JPanel menuPanel = new JPanel(); - menuPanel.setLayout(new BoxLayout(menuPanel, BoxLayout.X_AXIS)); - this.add(menuPanel, BorderLayout.NORTH); - this.getCloseButton().addActionListener(this); - menuPanel.add(this.getCloseButton()); - this.getResetButton().addActionListener(this); - menuPanel.add(this.getResetButton()); - - this.setLocation(pos); - this.pack(); - this.setVisible(true); - } - - @Override - public void actionPerformed(ActionEvent e) { - if (e.getSource().equals(this.getCloseButton())) { - this.setVisible(false); - this.getParentFrame().setEnabled(true); - HelpDialog.this.setMenuDlg(null); - } - if (e.getSource().equals(this.getResetButton())) { - this.setVisible(false); - this.getParentFrame().setEnabled(true); - HelpDialog.this.setMenuDlg(null); - try { - HelpDialog.this.setCurrentURL(HelpDialog.this.getDefaultURL()); - HelpDialog.this.getHtml().setPage(HelpDialog.this.getCurrentURL()); - } catch (IOException e1) { - HelpDialog.this.getHtml().setText("Cannot display the page.\n" + e1.getMessage()); - } - } - } - } private void saveWindowState() { @@ -257,14 +115,20 @@ public class HelpDialog extends JFrame implements ActionListener, WindowListener } private void restoreWindowState() { - - this.setPreferredSize(new Dimension(AppConfig.getAppConfig().getHelpWindowWidth(), AppConfig.getAppConfig().getHelpWindowHeight())); - this.setLocation(new Point(AppConfig.getAppConfig().getHelpWindowPosX(), AppConfig.getAppConfig().getHelpWindowPosY())); + this.setPreferredSize(new Dimension(AppConfig.getAppConfig().getHelpWindowWidth(), + AppConfig.getAppConfig().getHelpWindowHeight())); + this.setLocation(new Point(AppConfig.getAppConfig().getHelpWindowPosX(), + AppConfig.getAppConfig().getHelpWindowPosY())); if (AppConfig.getAppConfig().isHelpWindowIsMaximized()) { this.setExtendedState(Frame.MAXIMIZED_BOTH); } } + @Override + public void actionPerformed(ActionEvent e) { + + } + @Override public void windowClosed(WindowEvent e) { this.saveWindowState(); @@ -297,25 +161,7 @@ public class HelpDialog extends JFrame implements ActionListener, WindowListener } public static void showHelp(JFrame parent) { - Runner r = new Runner(parent); - r.start(); - } - - @Getter(AccessLevel.PRIVATE) - @Setter(AccessLevel.PRIVATE) - static class Runner extends Thread { - - private JFrame p; - - Runner(JFrame parent) { - this.setP(parent); - } - - @Override - public void run() { - new HelpDialog(this.getP()); - } - + new HelpDialog(parent); } } diff --git a/src/main/java/sinalgo/io/versionTest/VersionTester.java b/src/main/java/sinalgo/io/versionTest/VersionTester.java index 810a28097ec4ea7ae3ba18267c8d7f55c6b3672d..55fb949299fe66a244f8d449ddf8780a7c42380f 100644 --- a/src/main/java/sinalgo/io/versionTest/VersionTester.java +++ b/src/main/java/sinalgo/io/versionTest/VersionTester.java @@ -53,7 +53,7 @@ public class VersionTester extends Thread { public void run() { setRunning(true); try { - URL url = new URL("https://github.com/Sinalgo/sinalgo/raw/master/VERSION"); + URL url = new URL(Configuration.SINALGO_REPO + "/raw/master/VERSION"); URLConnection con = url.openConnection(); con.setDoOutput(true); con.setDoInput(true); @@ -77,7 +77,7 @@ public class VersionTester extends Thread { + "| A more recent version of Sinalgo is available (" + line + ")\n" + "+---------------------------------------------------------------------\n" + "| To download the latest version, please visit\n" - + "| https://github.com/Sinalgo/sinalgo/\n" + + "| " + Configuration.SINALGO_REPO + "/\n" + "+---------------------------------------------------------------------\n" + "| You may turn off these version checks through the 'Settings' dialog.\n" + "| Note: Sinalgo automatically tests for updates at most once\n" @@ -92,7 +92,7 @@ public class VersionTester extends Thread { + Configuration.VERSION_STRING + "\n" + ">---------------------------------------------------------------------\n" + "> To check for more recent versions, please visit\n" - + "> https://github.com/Sinalgo/sinalgo/\n" + + "> " + Configuration.SINALGO_REPO + "/\n" + ">---------------------------------------------------------------------\n" + "> You may turn off these version checks through the 'Settings' dialog.\n" + "| Note: Sinalgo automatically tests for updates at most once\n" + "| every 24 hours.\n" diff --git a/src/main/java/sinalgo/runtime/GUIRuntime.java b/src/main/java/sinalgo/runtime/GUIRuntime.java index 50c42ef06de0763d885329ee7c2ec22fb9b326aa..1660a0681c61df3358deda8c354700fd737ab4f0 100644 --- a/src/main/java/sinalgo/runtime/GUIRuntime.java +++ b/src/main/java/sinalgo/runtime/GUIRuntime.java @@ -36,6 +36,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package sinalgo.runtime; +import javafx.application.Platform; import lombok.Getter; import sinalgo.configuration.AppConfig; import sinalgo.configuration.Configuration; @@ -50,6 +51,14 @@ import sinalgo.gui.dialogs.ProgressBarUser; */ public class GUIRuntime extends SinalgoRuntime implements ProgressBarUser { + /** + * Default GUI Constructor + */ + GUIRuntime() { + super(); + Platform.setImplicitExit(false); + } + /** * The gui instance. *