/*
* 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 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.MediaTracker;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import jalview.util.ChannelProperties;
import jalview.util.Platform;
import javajs.async.SwingJSUtils.StateHelper;
import javajs.async.SwingJSUtils.StateMachine;
/**
* DOCUMENT ME!
*
* @author $author$
* @version $Revision$
*/
@SuppressWarnings("serial")
public class SplashScreen extends JPanel
implements HyperlinkListener, StateMachine
{
private static final int STATE_INIT = 0;
private static final int STATE_LOOP = 1;
private static final int STATE_DONE = 2;
private static final int SHOW_FOR_SECS = 5;
private static final int FONT_SIZE = (Platform.isJS() ? 14 : 11);
private boolean visible = true;
private JPanel iconimg = new JPanel(new BorderLayout());
// could change fg, bg, font later to use ChannelProperties (these are not
// actually being used!)
private static Color bg = Color.WHITE;
private static Color fg = Color.BLACK;
private static Font font = new Font("SansSerif", Font.PLAIN, FONT_SIZE);
private JPanel imgPanel = new JPanel(new BorderLayout());
/*
* as JTextPane in Java, JLabel in javascript
*/
private Component splashText;
private JInternalFrame iframe;
private Image image, logo;
private boolean transientDialog = false;
private long oldTextLength = -1;
private StateHelper helper;
public static int logoSize = 32;
/*
* allow click in the initial splash screen to dismiss it
* immediately (not if opened from About menu)
*/
private MouseAdapter closer = new MouseAdapter()
{
@Override
public void mousePressed(MouseEvent evt)
{
if (transientDialog)
{
try
{
closeSplash();
} catch (Exception ex)
{
}
}
}
};
/**
* Constructor that displays the splash screen
*
* @param isStartup
* if true the panel removes itself on click or after a few seconds;
* if false it stays up until closed by the user (from Help..About menu)
*/
public SplashScreen(boolean isStartup)
{
this.transientDialog = isStartup;
// we must get the image in JavaScript BEFORE starting the helper,
// as it will take a 1 ms clock tick to obtain width and height information.
image = ChannelProperties.getImage("banner");
logo = ChannelProperties.getImage("logo.48");
font = new Font("SansSerif", Font.PLAIN, FONT_SIZE);
helper = new StateHelper(this);
helper.next(STATE_INIT);
}
protected void initSplashScreenWindow()
{
addMouseListener(closer);
waitForImages();
setLayout(new BorderLayout());
iframe = new JInternalFrame();
iframe.setFrameIcon(null);
iframe.setClosable(true);
iframe.setContentPane(this);
iframe.setLayer(JLayeredPane.PALETTE_LAYER);
SplashImage splashimg = new SplashImage(image);
imgPanel.add(splashimg, BorderLayout.CENTER);
add(imgPanel, BorderLayout.NORTH);
Desktop.getDesktopPane().add(iframe);
refreshText();
}
/**
* Both Java and JavaScript have to wait for images, but this method will
* accomplish nothing for JavaScript. We have already taken care of image
* loading with our state loop in JavaScript.
*
*/
private void waitForImages()
{
if (Platform.isJS())
return;
MediaTracker mt = new MediaTracker(this);
mt.addImage(image, 0);
mt.addImage(logo, 1);
do
{
try
{
mt.waitForAll();
} catch (InterruptedException x)
{
}
if (mt.isErrorAny())
{
System.err.println("Error when loading images!");
break;
}
} while (!mt.checkAll());
if (logo != null)
{
Desktop.getInstance().setIconImage(logo);
}
this.setBackground(bg);
this.setForeground(fg);
this.setFont(font);
}
/**
* update text in author text panel reflecting current version information
*/
protected boolean refreshText()
{
String newtext = Desktop.getInstance().getAboutMessage();
// System.err.println("Text found: \n"+newtext+"\nEnd of newtext.");
if (oldTextLength == newtext.length())
{
return false;
}
iframe.setVisible(false);
oldTextLength = newtext.length();
if (Platform.isJS()) // BH 2019
{
/*
* SwingJS doesn't have HTMLEditorKit, required for a JTextPane
* to display formatted html, so we use a simple alternative
*/
String text = "
" + newtext
+ "
";
JLabel ta = new JLabel(text);
ta.setOpaque(true);
ta.setBackground(Color.white);
splashText = ta;
}
else
/**
* Java only
*
* @j2sIgnore
*/
{
JTextPane jtp = new JTextPane();
jtp.setEditable(false);
jtp.setBackground(bg);
jtp.setForeground(fg);
jtp.setFont(font);
jtp.setContentType("text/html");
jtp.setText("" + newtext + "");
jtp.addHyperlinkListener(this);
splashText = jtp;
}
splashText.addMouseListener(closer);
splashText.setVisible(true);
splashText.setSize(new Dimension(750,
375 + logoSize + (Platform.isJS() ? 40 : 0)));
splashText.setBackground(bg);
splashText.setForeground(fg);
splashText.setFont(font);
add(splashText, BorderLayout.CENTER);
revalidate();
int width = Math.max(splashText.getWidth(), iconimg.getWidth());
int height = splashText.getHeight() + iconimg.getHeight();
iframe.setBounds((iframe.getParent().getWidth() - width) / 2,
(iframe.getParent().getHeight() - height) / 2,
width,height);
iframe.validate();
iframe.setVisible(true);
return true;
}
protected void closeSplash()
{
try
{
iframe.setClosed(true);
} catch (Exception ex)
{
}
}
/**
* 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.
*
*/
@Override
public boolean stateLoop()
{
while (true)
{
switch (helper.getState())
{
case STATE_INIT:
initSplashScreenWindow();
helper.setState(STATE_LOOP);
continue;
case STATE_LOOP:
if (!isVisible())
{
helper.setState(STATE_DONE);
continue;
}
if (refreshText())
{
iframe.repaint();
}
if (transientDialog)
helper.delayedState(SHOW_FOR_SECS * 1000, STATE_DONE);
return true;
default:
case STATE_DONE:
setVisible(false);
closeSplash();
Desktop.getInstance().startDialogQueue();
return true;
}
}
}
private class SplashImage extends JPanel
{
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(bg);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(fg);
g.setFont(new Font(font.getFontName(), Font.BOLD, FONT_SIZE + 6));
if (image != null)
{
g.drawImage(image, (getWidth() - image.getWidth(this)) / 2,
(getHeight() - image.getHeight(this)) / 2, this);
}
}
}
@Override
public void hyperlinkUpdate(HyperlinkEvent e)
{
Desktop.hyperlinkUpdate(e);
}
}