/*
* RapidMiner
*
* Copyright (C) 2001-2011 by Rapid-I and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapid-i.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.rapidminer.gui.tools;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Paint;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import com.rapidminer.tools.LogService;
import com.rapidminer.tools.Tools;
import com.rapidminer.tools.container.Pair;
import com.rapidminer.tools.plugin.Plugin;
/**
* The splash screen is displayed during start up of RapidMiner. It displays the logo and the some start information.
* The product logo should have a size of approximately 270 times 70 pixels.
*
* @author Ingo Mierswa
*/
public class SplashScreen extends JPanel implements ActionListener {
private static final int EXTENSION_GAP = 400;
private static final float EXTENSION_FADE_TIME = 1000;
private static final int MAX_NUMBER_EXTENSION_ICONS = 7;
private static final long serialVersionUID = -1525644776910410809L;
private static final Paint MAIN_PAINT = Color.BLACK;
public static Image backgroundImage = null;
private static final int MARGIN = 10;
private static final String PROPERTY_FILE = "splash_infos.properties";
static {
try {
if (backgroundImage == null) {
URL url = Tools.getResource("splashscreen_community.png");
if (url != null)
backgroundImage = ImageIO.read(url);
}
} catch (IOException e) {
LogService.getGlobal().logWarning("Cannot load images for splash screen. Using empty splash screen...");
}
}
private transient Image productLogo;
private Properties properties;
private JFrame splashScreenFrame = new JFrame();
private String message = "Starting...";
private boolean infosVisible;
private Timer animationTimer;
private List<Runnable> animationRenderers = new LinkedList<Runnable>();
private List<Pair<BufferedImage, Long>> extensionIcons = Collections.synchronizedList(new LinkedList<Pair<BufferedImage, Long>>());
private long lastExtensionAdd = 0;
public SplashScreen(String productVersion, Image productLogo) {
this(productLogo, createDefaultProperties(productVersion));
}
public SplashScreen(String productVersion, Image productLogo, URL propertyFile) {
this(productLogo, createProperties(productVersion, propertyFile));
}
public SplashScreen(Image productLogo, Properties properties) {
super();
this.properties = properties;
this.productLogo = productLogo;
splashScreenFrame = new JFrame(properties.getProperty("name"));
splashScreenFrame.getContentPane().add(this);
SwingTools.setFrameIcon(splashScreenFrame);
splashScreenFrame.setUndecorated(true);
if (backgroundImage != null)
splashScreenFrame.setSize(backgroundImage.getWidth(this), backgroundImage.getHeight(this));
else
splashScreenFrame.setSize(450, 350);
splashScreenFrame.setLocationRelativeTo(null);
animationTimer = new Timer(10, this);
animationTimer.setRepeats(true);
animationTimer.start();
}
private static Properties createDefaultProperties(String productVersion) {
return createProperties(productVersion, Tools.getResource(PROPERTY_FILE));
}
private static Properties createProperties(String productVersion, URL propertyFile) {
Properties properties = new Properties();
if (propertyFile != null) {
try {
InputStream in = propertyFile.openStream();
properties.load(in);
in.close();
} catch (Exception e) {
LogService.getGlobal().logError("Cannot read splash screen infos: " + e.getMessage());
}
}
properties.setProperty("version", productVersion);
return properties;
}
public void showSplashScreen() {
splashScreenFrame.setVisible(true);
}
public JFrame getSplashScreenFrame() {
return splashScreenFrame;
}
public void dispose() {
splashScreenFrame.dispose();
splashScreenFrame = null;
}
@Override
public void paint(Graphics g) {
super.paint(g);
drawMain((Graphics2D) g);
g.setColor(Color.black);
g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
// draw extensions
List<Pair<BufferedImage, Long>> currentExtensionIcons = getSynchronizedExtensionIcons();
int size = currentExtensionIcons.size();
if (size > 0) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.translate(400, 140);
g2d.scale(0.5, 0.5);
long currentTimeMillis = System.currentTimeMillis();
int numberToShow = 0;
for (Pair<BufferedImage, Long> pair : currentExtensionIcons) {
if (currentTimeMillis > pair.getSecond())
numberToShow++;
}
// now paint other icons
int shiftX = 51;
for (int i = 0; i < numberToShow; i++) {
if (numberToShow > i + MAX_NUMBER_EXTENSION_ICONS) {
// then we have to fade out again
Pair<BufferedImage, Long> pair = currentExtensionIcons.get(i + MAX_NUMBER_EXTENSION_ICONS);
float min = Math.min((currentTimeMillis - pair.getSecond()) / EXTENSION_FADE_TIME, 1f);
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1-min));
} else {
// fade in
Pair<BufferedImage, Long> pair = currentExtensionIcons.get(i);
float min = Math.min((currentTimeMillis - pair.getSecond()) / EXTENSION_FADE_TIME, 1f);
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, min));
}
g2d.drawImage(currentExtensionIcons.get(i).getFirst(), null, -(i % MAX_NUMBER_EXTENSION_ICONS) * shiftX, 0);
}
}
}
public void drawMain(Graphics2D g) {
g.setPaint(MAIN_PAINT);
g.fillRect(0, 0, getWidth(), getHeight());
if (backgroundImage != null)
g.drawImage(backgroundImage, 0, 0, this);
if (productLogo != null)
g.drawImage(productLogo, getWidth() / 2 - productLogo.getWidth(this) / 2, 90, this);
g.setColor(SwingTools.BROWN_FONT_COLOR);
if (message != null) {
g.setFont(new java.awt.Font("SansSerif", java.awt.Font.BOLD, 11));
drawString(g, message, 255);
}
if (infosVisible) {
g.setFont(new java.awt.Font("SansSerif", java.awt.Font.PLAIN, 10));
drawString(g, properties.getProperty("name") + " " + properties.getProperty("version"), 275);
drawString(g, properties.getProperty("license"), 290);
drawString(g, properties.getProperty("warranty"), 305);
drawString(g, properties.getProperty("copyright"), 320);
drawString(g, properties.getProperty("more"), 335);
}
}
private void drawString(Graphics2D g, String text, int height) {
if (text == null)
return;
// Rectangle2D stringBounds = g.getFontMetrics().getStringBounds(text, g);
// float xPos = (float)(getWidth() - MARGIN - stringBounds.getWidth());
float xPos = MARGIN;
float yPos = height;
g.drawString(text, xPos, yPos);
}
public void setMessage(String message) {
this.message = message;
}
public void setProperty(String key, String value) {
properties.setProperty(key, value);
}
public void setInfosVisible(boolean b) {
this.infosVisible = b;
}
public void addExtension(Plugin plugin) {
ImageIcon extensionIcon = plugin.getExtensionIcon();
if (extensionIcon != null) {
long currentTimeMillis = System.currentTimeMillis();
if (currentTimeMillis < lastExtensionAdd + EXTENSION_GAP)
currentTimeMillis = lastExtensionAdd + EXTENSION_GAP;
lastExtensionAdd = currentTimeMillis;
BufferedImage bufferedImage = new BufferedImage(48, 48, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = bufferedImage.createGraphics();
graphics.drawImage(extensionIcon.getImage(), 0, 0, null);
synchronized (extensionIcons) {
extensionIcons.add(new Pair<BufferedImage, Long>(bufferedImage, currentTimeMillis));
}
}
}
private List<Pair<BufferedImage, Long>> getSynchronizedExtensionIcons() {
synchronized (extensionIcons) {
return new ArrayList<Pair<BufferedImage, Long>>(extensionIcons);
}
}
public void addAnimationRenderer(Runnable runable) {
this.animationRenderers.add(runable);
}
@Override
/**
* This method is used for being repainted for
* splash animation.
*/
public void actionPerformed(ActionEvent e) {
for (Runnable runnable: animationRenderers)
runnable.run();
repaint();
}
}