/* * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) * Copyright (C) $$Year-Rel$$ The Jalview Authors * * This file is part of Jalview. * * Jalview is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * Jalview is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Jalview. If not, see . * The Jalview Authors are detailed in the 'AUTHORS' file. */ package jalview.gui; import jalview.util.Platform; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Image; import java.awt.Insets; import java.awt.MediaTracker; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.beans.PropertyVetoException; import javax.swing.JInternalFrame; import javax.swing.JLabel; import javax.swing.JLayeredPane; import javax.swing.JPanel; import javax.swing.JTextPane; import javax.swing.Timer; import javax.swing.border.EmptyBorder; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; /** * A class that serves both as an initial 5-second splash screen (interactive * false) as well as for the Help menu item action (interactive true). * * As a splash screen, the frame closes if clicked by the user. * * Closure loop converted from a while/sleep loop to a JavaScript-compatible * state machine by Bob Hanson 2019.11.26. * * TODO: get JTextPane working for read-only HTML. * */ @SuppressWarnings("serial") public class SplashScreen extends JPanel implements Runnable, HyperlinkListener { private static final int STATE_INIT = 0; private static final int STATE_LOOP = 1; private static final int STATE_DONE = 2; // boolean visible = true; private JPanel iconimg = new JPanel(new BorderLayout()); /** * Temporary SwingJS Hack: Either a JLabel in JavaScript or a JTextPane in * Java */ protected Component htmlPane; private JInternalFrame iframe; private Image image; private final static int fontSize = 11; protected final static Font largeFont = new Font("Verdana", Font.BOLD, fontSize + 6); int yoffset = 30; /** * Creates a new SplashScreen object. */ public SplashScreen() { this(false); } protected boolean isInteractive = false; /** * * @param interactive * if true - an internal dialog is opened rather than a free-floating * splash screen */ public SplashScreen(boolean isInteractive) { this.isInteractive = isInteractive; Thread t = new Thread(this, "SplashScreen"); t.start(); } MouseAdapter closer = new MouseAdapter() { @Override public void mousePressed(MouseEvent evt) { try { if (!isInteractive) { setVisible(false); closeSplash(); } } catch (Exception ex) { } } }; /** * ping the jalview version page then create and display the jalview * splashscreen window. */ protected void initSplashScreenWindow() { addMouseListener(closer); try { java.net.URL url = getClass().getResource("/images/Jalview_Logo.png"); image = java.awt.Toolkit.getDefaultToolkit().createImage(url); MediaTracker mt = new MediaTracker(this); mt.addImage(image, 0); Image logo = (Platform.isJS() ? null : java.awt.Toolkit.getDefaultToolkit().createImage(getClass() .getResource("/images/Jalview_Logo_small.png"))); if (logo != null) { mt.addImage(logo, 1); } do { try { mt.waitForAll(); } catch (InterruptedException x) { } if (mt.isErrorAny()) { System.err.println("Error when loading images!"); } } while (!mt.checkAll()); if (url != null) { Desktop.getInstance().setIconImage(logo); } } catch (Exception ex) { } iframe = new JInternalFrame(); iframe.setFrameIcon(null); iframe.setClosable(isInteractive); this.setLayout(new BorderLayout()); iframe.setContentPane(this); iframe.setLayer(JLayeredPane.PALETTE_LAYER); SplashImage splashimg = new SplashImage(image); iconimg.add(splashimg, BorderLayout.CENTER); add(iconimg, BorderLayout.NORTH); Desktop.getDesktopPane().add(iframe); refreshText(); } String oldtext; private int mainState; /** * update text in author text panel reflecting current version information */ protected boolean refreshText() { Desktop desktop = Desktop.getInstance(); String newtext = desktop.getAboutMessage(true).toString(); // System.err.println("Text found: \n"+newtext+"\nEnd of newtext."); if (!newtext.equals(oldtext)) { iframe.setVisible(false); oldtext = newtext; if (Platform.isJS()) // BH 2019 { // BH TODO SwingJS does not implement HTML style. Could rethink this. if (htmlPane == null) { htmlPane = new JLabel(); } JLabel l = (JLabel)htmlPane; l.setText(newtext); Font f = htmlPane.getFont(); l.setFont(new Font(f.getFamily(), Font.PLAIN, f.getSize())); l.setBorder(new EmptyBorder(new Insets(5, 5, 5, 5))); l.setOpaque(true); l.setBackground(Color.white); htmlPane = l; } else /** * Java only * * @j2sIgnore */ { if (htmlPane == null) { htmlPane = new JTextPane(); } JTextPane pane = (JTextPane)htmlPane; pane.setEditable(false); pane.setContentType("text/html"); pane.setText(newtext); pane.addHyperlinkListener(this); htmlPane = pane; } htmlPane.addMouseListener(closer); htmlPane.setSize(new Dimension(750, 375)); add(htmlPane, BorderLayout.CENTER); int h = htmlPane.getHeight() + iconimg.getHeight(); iframe.setBounds(Math.max(0, (desktop.getWidth() - 750) / 2), Math.max(0, (desktop.getHeight() - h) / 2), 750, h); iframe.setVisible(true); return true; } return false; } /** * Create splash screen, display it and clear it off again. */ @Override public void run() { mainState = STATE_INIT; mainLoop(); } protected long startTime; /** * A simple state machine with just three states: init, loop, and done. Ideal * for a simple while/sleep loop that works in Java and JavaScript * identically. * */ protected void mainLoop() { while (true) { switch (mainState) { case STATE_INIT: initSplashScreenWindow(); startTime = System.currentTimeMillis() / 1000; mainState = STATE_LOOP; continue; case STATE_LOOP: if (!isVisible()) { mainState = STATE_DONE; continue; } if (!isInteractive && ((System.currentTimeMillis() / 1000) - startTime) > 5) { setVisible(false); continue; } if (isVisible() && refreshText()) { iframe.repaint(); } if (isInteractive) { return; } Timer timer = new Timer(500, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { mainLoop(); } }); timer.setRepeats(false); timer.start(); return; case STATE_DONE: closeSplash(); Desktop.getInstance().startDialogQueue(); return; } } } /** * Close the internal frame, either from the timer expiring or from the mouse * action. */ public void closeSplash() { setVisible(false); try { iframe.setClosed(true); } catch (PropertyVetoException e) { } } private class SplashImage extends JPanel { private Image image; public SplashImage(Image todisplay) { image = todisplay; if (image != null) { setPreferredSize(new Dimension(image.getWidth(this) + 8, image.getHeight(this))); } } @Override public Dimension getPreferredSize() { return new Dimension(image.getWidth(this) + 8, image.getHeight(this)); } @Override public void paintComponent(Graphics g) { g.setColor(Color.white); g.fillRect(0, 0, getWidth(), getHeight()); g.setColor(Color.black); g.setFont(largeFont); if (image != null) { g.drawImage(image, (getWidth() - image.getWidth(this)) / 2, (getHeight() - image.getHeight(this)) / 2, this); } } /* * int y = yoffset; * * g.drawString("Jalview " + jalview.bin.Cache.getProperty("VERSION"), 50, * y); * * FontMetrics fm = g.getFontMetrics(); int vwidth = * fm.stringWidth("Jalview " + jalview.bin.Cache.getProperty("VERSION")); * g.setFont(new Font("Verdana", Font.BOLD, fontSize + 2)); g.drawString( * "Last updated: " + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"), * 50 + vwidth + 5, y); if (jalview.bin.Cache.getDefault("LATEST_VERSION", * "Checking").equals( "Checking")) { // Displayed when code version and * jnlp version do not match g.drawString("...Checking latest version...", * 50, y += fontSize + 10); y += 5; g.setColor(Color.black); } else if * (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking") * .equals(jalview.bin.Cache.getProperty("VERSION"))) { if * (jalview.bin.Cache.getProperty("VERSION").toLowerCase() * .indexOf("automated build") == -1) { // Displayed when code version and * jnlp version do not match and code // version is not a development build * g.setColor(Color.red); } g.drawString( "!! Jalview version " + * jalview.bin.Cache.getDefault("LATEST_VERSION", "..Checking..") + * " is available for download from " * +jalview.bin.Cache.getDefault("www.jalview.org" * ,"http://www.jalview.org")+" !!", 50, y += fontSize + 10); y += 5; * g.setColor(Color.black); } * * g.setFont(new Font("Verdana", Font.BOLD, fontSize)); g.drawString( * "Authors: Jim Procter, Andrew Waterhouse, Michele Clamp, James Cuff, Steve Searle," * , 50, y += fontSize + 4); g.drawString("David Martin & Geoff Barton.", * 60, y += fontSize + 4); g.drawString( * "Development managed by The Barton Group, University of Dundee.", 50, y * += fontSize + 4); g.drawString("If you use Jalview, please cite: ", 50, * y += fontSize + 4); g.drawString( * "Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)" * , 50, y += fontSize + 4); g.drawString( * "Jalview Version 2 - a multiple sequence alignment editor and analysis workbench" * , 50, y += fontSize + 4); * g.drawString("Bioinformatics doi: 10.1093/bioinformatics/btp033", 50, y * += fontSize + 4); } */ } @Override public void hyperlinkUpdate(HyperlinkEvent e) { Desktop.hyperlinkUpdate(e); } }