package com.onaro.sanscreen.client.login; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.Icon; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JLayeredPane; import javax.swing.JPanel; import javax.swing.JWindow; import javax.swing.Timer; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.onaro.commons.swing.OnaroSwingUtilities; import com.onaro.sanscreen.client.Resources; import com.onaro.sanscreen.client.SANscreenClientPlugin; /** * Displays a border less window with an image and a progress indicator. Used * to pass the time while the application initializes. */ /*package*/ class SplashWindow extends JWindow { /** * Initializes a splash screen and displays it in the center of the screen. */ public SplashWindow (JFrame owner) { super (owner); /* * Make splash window non-opaque if possible, so there isn't a white rectangle under the image. * Use new Java 7 methods to do this. */ try { setBackground (OnaroSwingUtilities.TRANSPARENT); } catch (Exception e) { // Not that big a deal if window has to be opaque. Just a visual artifact. logger.info ("Can't make splash screen non-opaque. " + e.getMessage()); //$NON-NLS-1$ } // Create back panel and make it the content pane; Icon splashIcon = SANscreenClientPlugin.getDefault().getBranding().getSplashScreenIcon(); backPanel = new BackPanel (splashIcon); setSize(backPanel.getSize()); setContentPane (backPanel); // Put on top of other windows, in center of screen. setVisible (true); setLocationRelativeTo (null); toFront(); } /** * Show a message indicating that login is in process */ public void showMessageLoggingIn() { // Make sure copyright or login prompt isn't visible. showProgressBackground(); // Display image for message. JLabel label = getMessageLabel(); startMessageAnimation ( Resources.INSTANCE.getLoggingIn0(), Resources.INSTANCE.getLoggingIn1(), Resources.INSTANCE.getLoggingIn2(), Resources.INSTANCE.getLoggingIn3() ); label.setVisible (true); } /** * Show a message indicating that initialization is in process */ public void showMessageInitializing() { // Make sure copyright or login prompt isn't visible. showProgressBackground(); // Display image for message. JLabel label = getMessageLabel(); startMessageAnimation ( Resources.INSTANCE.getInitializing0(), Resources.INSTANCE.getInitializing1(), Resources.INSTANCE.getInitializing2(), Resources.INSTANCE.getInitializing3() ); label.setVisible (true); } /** * If a message is currently being displayed, change the message icon * @param icon message icon or {@code null} to display no icon * @see #showMessage */ public void setMessage (Icon icon) { if (icon == null) { stopMessageAnimation(); } if (messageLabel != null && messageLabel.isVisible()) { messageLabel.setIcon (icon); messageLabel.repaint(); } } /** * If a message is currently being displayed, change the status text * @param text status text or {@code null} to display no text * @see #showMessage */ public void setStatus (String text) { if (messageLabel != null && messageLabel.isVisible()) { getStatusLabel().setText (text); getStatusLabel().repaint(); } } /** * Hide any message that is displayed */ public void hideMessage() { stopMessageAnimation(); if (messageLabel != null) { messageLabel.setVisible (false); messageLabel.repaint(); } if (statusLabel != null) { statusLabel.setVisible (false); statusLabel.repaint(); } } /** * Hides and disposes the splash window and its owner frame. */ public void done() { stopMessageAnimation(); setVisible (false); dispose(); } private JLabel getMessageLabel() { if (messageLabel == null) { // Create message label. messageLabel = new JLabel(); messageLabel.setBackground (Color.white); // Add label to dialog. messageLabel.setBounds (MESSAGE_LABEL_X, MESSAGE_LABEL_Y, MESSAGE_LABEL_WIDTH, MESSAGE_LABEL_HEIGHT); messageLabel.setOpaque (true); JLayeredPane layer = getLayeredPane(); layer.add (messageLabel, JLayeredPane.POPUP_LAYER); } return messageLabel; } private JLabel getStatusLabel() { if (statusLabel == null) { // Create status label. statusLabel = new JLabel(); statusLabel.setForeground (Color.gray); statusLabel.setBackground (Color.white); // Add label to dialog. statusLabel.setBounds (STATUS_LABEL_X, STATUS_LABEL_Y, STATUS_LABEL_WIDTH, STATUS_LABEL_HEIGHT); statusLabel.setOpaque (true); JLayeredPane layer = getLayeredPane(); layer.add (statusLabel, JLayeredPane.POPUP_LAYER); } return statusLabel; } private void showProgressBackground() { backPanel.setIcon (Resources.INSTANCE.getSplashNoCopyright()); } public void showLoginBackground() { backPanel.setIcon (Resources.INSTANCE.getSplashLogin()); } /* * The resource bundle mechanism doesn't handle required animated GIFs * correctly (because it relies on MediaTracker to find out when loading is done) * so we load the icons individually and animate them ourself. * */ private void startMessageAnimation (final Icon... icons) { // Stop previous animation, if any. stopMessageAnimation(); // Start by showing last icon. final int nIcons = icons.length; setMessage (icons[nIcons - 1]); // Display first icon after initial timer delay. iIcon = 0; // Create Swing timer to show each icon for about half a second. timer = new Timer (500, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setMessage (icons[iIcon]); if (++iIcon == nIcons) { iIcon = 0; } } }); timer.start(); } private void stopMessageAnimation() { if (timer != null) { timer.stop(); timer = null; if (messageLabel != null) { messageLabel.setIcon (null); messageLabel.repaint(); } } } private class BackPanel extends JPanel { private static final long serialVersionUID = 1L; private final Dimension size; private Icon icon; public BackPanel (Icon icon) { this.size = new Dimension (icon.getIconWidth(), icon.getIconHeight()); this.icon = icon; this.setBackground (OnaroSwingUtilities.TRANSPARENT); } public void setIcon (Icon newIcon) { // May often be called with same icon. Don't repaint unnecessarily. if (this.icon != newIcon) { this.icon = newIcon; // Note this will darken any translucent image areas, such as shadows in the image. // Work-around to this was to only draw a shadow in the initial image. repaint(); } } @Override public Dimension getSize() { return size; } @Override protected void paintComponent (Graphics graphics) { icon.paintIcon (this, graphics, 0, 0); } } private static final long serialVersionUID = 1L; private static final Logger logger = LogManager.getLogger (SplashWindow.class); private static final int MESSAGE_LABEL_X = 205; private static final int MESSAGE_LABEL_Y = 180; private static final int MESSAGE_LABEL_WIDTH = 300; private static final int MESSAGE_LABEL_HEIGHT = 40; private static final int STATUS_LABEL_X = 205; private static final int STATUS_LABEL_Y = 215; private static final int STATUS_LABEL_WIDTH = 300; private static final int STATUS_LABEL_HEIGHT = 30; private BackPanel backPanel = null; private JLabel messageLabel = null; private JLabel statusLabel = null; private Timer timer = null; private int iIcon = 0; }