/* * Copyright (C) 2012 Brockmann Consult GmbH (info@brockmann-consult.de) * * This program 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. * 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 General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see http://www.gnu.org/licenses/ */ package com.bc.ceres.core.runtime.internal; import com.bc.ceres.core.Assert; import com.bc.ceres.core.NullProgressMonitor; import com.bc.ceres.core.ProgressMonitor; import com.bc.ceres.core.runtime.RuntimeConfig; import javax.imageio.ImageIO; import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.SplashScreen; import java.awt.Toolkit; import java.awt.Window; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.StringTokenizer; /** * A progress monitor which uses a splash screen. */ public class SplashScreenProgressMonitor extends NullProgressMonitor { private static final String CONFIG_KEY_SPLASH_IMAGE = "splash.image"; private static final String CONFIG_KEY_SPLASH_PROGRESS_BAR_COLOR = "splash.progressBar.color"; private static final String CONFIG_KEY_SPLASH_PROGRESS_BAR_AREA = "splash.progressBar.area"; private static final String CONFIG_KEY_TASK_LABEL_ENABLED = "splash.taskLabel.enabled"; private static final String CONFIG_KEY_TASK_LABEL_FONT = "splash.taskLabel.font"; private static final String CONFIG_KEY_TASK_LABEL_COLOR = "splash.taskLabel.color"; private static final String CONFIG_KEY_TASK_LABEL_POS = "splash.taskLabel.pos"; private static final String CONFIG_KEY_SPLASH_VERSION_TEXT = "splash.version.text"; private static final String CONFIG_KEY_VERSION_ENABLED = "splash.version.enabled"; private static final String CONFIG_KEY_VERSION_FONT = "splash.version.font"; private static final String CONFIG_KEY_VERSION_COLOR = "splash.version.color"; private static final String CONFIG_KEY_VERSION_POS = "splash.version.pos"; private Splash splashScreen; private String taskName; private String subTaskName; private double totalWork; private double currentWork; private int lastPixelsWorked; private Graphics2D graphics; private Rectangle splashArea; private int progressBarHeight; private boolean taskLabelEnabled; private Font taskLabelFont; private Color taskLabelColor; private Point taskLabelPos; private boolean versionLabelEnabled; private Font versionLabelFont; private Color versionLabelColor; private Point versionLabelPos; private Color progressBarColor; private Rectangle progressBarArea; private int pixelsWorked; private String message; private String versionText; /** * Creates a {@link SplashScreenProgressMonitor} only if a splash screen exists. * * @param config The runtime configuration * @return an instance of {@link SplashScreenProgressMonitor} or {@link NullProgressMonitor} */ public static ProgressMonitor createProgressMonitor(RuntimeConfig config) { String imageFilePath = config.getContextProperty(CONFIG_KEY_SPLASH_IMAGE); if (imageFilePath != null) { BufferedImage bufferedImage = loadImage(imageFilePath); if (bufferedImage != null) { return new SplashScreenProgressMonitor(new CeresSplash(bufferedImage), config); } } else { SplashScreen splashScreen = null; try { splashScreen = SplashScreen.getSplashScreen(); } catch (Throwable t) { // } if (splashScreen != null) { return new SplashScreenProgressMonitor(new AwtSplash(splashScreen), config); } } return ProgressMonitor.NULL; } public SplashScreenProgressMonitor(Splash splashScreen, RuntimeConfig config) { Assert.notNull(splashScreen, "splashScreen"); this.splashScreen = splashScreen; Dimension size = this.splashScreen.getSize(); splashArea = new Rectangle(size); progressBarColor = getConfiguredColor(config, CONFIG_KEY_SPLASH_PROGRESS_BAR_COLOR, Color.GREEN); progressBarArea = getConfiguredSplashProgressBarArea(config); if (progressBarArea != null) { progressBarHeight = progressBarArea.height; } else { progressBarHeight = 5; progressBarArea = new Rectangle(0, splashArea.height - progressBarHeight - 4, splashArea.width, progressBarHeight); } taskLabelColor = getConfiguredColor(config, CONFIG_KEY_TASK_LABEL_COLOR, Color.WHITE); taskLabelEnabled = getConfiguredOptionEnabled(config, CONFIG_KEY_TASK_LABEL_ENABLED); if (taskLabelEnabled) { taskLabelFont = getConfiguredFont(config, CONFIG_KEY_TASK_LABEL_FONT); taskLabelPos = getConfiguredPos(config, CONFIG_KEY_TASK_LABEL_POS); if (taskLabelPos == null) { taskLabelPos = new Point(progressBarArea.x, progressBarArea.y + progressBarArea.height + 10); } } versionLabelEnabled = getConfiguredOptionEnabled(config, CONFIG_KEY_VERSION_ENABLED); if (versionLabelEnabled) { versionText = config.getContextProperty(CONFIG_KEY_SPLASH_VERSION_TEXT); if (versionText == null) { versionText = config.getContextProperty("version"); } versionLabelFont = getConfiguredFont(config, CONFIG_KEY_VERSION_FONT); versionLabelColor = getConfiguredColor(config, CONFIG_KEY_VERSION_COLOR, taskLabelColor); versionLabelPos = getConfiguredPos(config, CONFIG_KEY_VERSION_POS); if (versionLabelPos == null) { versionLabelPos = new Point(progressBarArea.x, progressBarArea.y + progressBarArea.height + 30); } } graphics = this.splashScreen.createGraphics(); graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); message = ""; } public Splash getSplash() { return splashScreen; } @Override public void beginTask(String taskName, int totalWork) { this.totalWork = totalWork; this.currentWork = 0; this.lastPixelsWorked = 0; setTaskName(taskName); } @Override public void done() { internalWorked(totalWork); if (graphics != null) { graphics.dispose(); graphics = null; } if (splashScreen.isVisible()) { splashScreen.close(); } } @Override public void worked(int work) { internalWorked(work); } @Override public void internalWorked(double work) { currentWork += work; double progress = currentWork / totalWork; pixelsWorked = (int) ((double) progressBarArea.width * progress); if (pixelsWorked > lastPixelsWorked) { lastPixelsWorked = pixelsWorked; update(); } } @Override public void setTaskName(String taskName) { this.taskName = taskName; this.message = createMessage(); update(); } @Override public void setSubTaskName(String subTaskName) { this.subTaskName = subTaskName; this.message = createMessage(); update(); } private String createMessage() { boolean validTaskName = taskName != null && taskName.length() > 0; boolean validSubTaskName = subTaskName != null && subTaskName.length() > 0; String message; if (validTaskName && validSubTaskName) { message = taskName + " - " + subTaskName; } else if (validTaskName) { message = taskName; } else if (validSubTaskName) { message = subTaskName; } else { message = ""; } return message; } private void update() { if (graphics == null || !splashScreen.isVisible()) { return; } graphics.setComposite(AlphaComposite.Clear); graphics.fill(splashArea); graphics.setPaintMode(); if (taskLabelEnabled) { paintTaskLabel(); } if (versionLabelEnabled) { paintVersionLabel(); } paintBar(); splashScreen.update(); } private void paintBar() { // graphics.setColor(Color.DARK_GRAY); // graphics.fillRect(progressBarArea.x, // progressBarArea.y, // progressBarArea.width, // progressBarArea.height); graphics.setColor(progressBarColor); graphics.fillRect(progressBarArea.x, progressBarArea.y, pixelsWorked, progressBarArea.height); // graphics.setColor(Color.BLACK); // graphics.drawLine(progressBarArea.x, // progressBarArea.y, // progressBarArea.x + progressBarArea.width, // progressBarArea.y); // graphics.drawLine(progressBarArea.x, // progressBarArea.y + progressBarHeight - 1, // progressBarArea.x + progressBarArea.width, // progressBarArea.y + progressBarHeight - 1); } private void paintTaskLabel() { graphics.setColor(taskLabelColor); graphics.setFont(taskLabelFont); graphics.drawString(message, taskLabelPos.x, taskLabelPos.y); } private void paintVersionLabel() { graphics.setColor(versionLabelColor); graphics.setFont(versionLabelFont); graphics.drawString(versionText, versionLabelPos.x, versionLabelPos.y); } private static BufferedImage loadImage(String imageFilePath) { try { return ImageIO.read(new File(imageFilePath)); } catch (IOException e) { return null; } } private boolean getConfiguredOptionEnabled(RuntimeConfig config, String key) { return Boolean.parseBoolean(config.getContextProperty(key, "false")); } private static Color getConfiguredColor(RuntimeConfig config, String key, Color defaultValue) { String colorStr = config.getContextProperty(key); if (colorStr != null && !colorStr.isEmpty()) { if (colorStr.startsWith("#")) { return Color.decode(colorStr); } StringTokenizer st = new StringTokenizer(colorStr, ","); int n = st.countTokens(); if (n == 3 || n == 4) { try { int r = Integer.parseInt(st.nextToken()); int g = Integer.parseInt(st.nextToken()); int b = Integer.parseInt(st.nextToken()); int a = 255; if (st.hasMoreTokens()) { a = Integer.parseInt(st.nextToken()); } return new Color(r, g, b, a); } catch (Exception e) { // defaultValue is returned } } } return defaultValue; } private static Rectangle getConfiguredSplashProgressBarArea(RuntimeConfig config) { String areaStr = config.getContextProperty(CONFIG_KEY_SPLASH_PROGRESS_BAR_AREA); if (areaStr != null && !areaStr.isEmpty()) { StringTokenizer st = new StringTokenizer(areaStr, ","); int n = st.countTokens(); if (n == 4) { try { int x = Integer.parseInt(st.nextToken()); int y = Integer.parseInt(st.nextToken()); int w = Integer.parseInt(st.nextToken()); int h = Integer.parseInt(st.nextToken()); return new Rectangle(x, y, w, h); } catch (Exception e) { // null is returned } } } return null; } private static Point getConfiguredPos(RuntimeConfig config, String key) { String posStr = config.getContextProperty(key); if (posStr != null && !posStr.isEmpty()) { StringTokenizer st = new StringTokenizer(posStr, ","); int n = st.countTokens(); if (n == 2) { try { int x = Integer.parseInt(st.nextToken()); int y = Integer.parseInt(st.nextToken()); return new Point(x, y); } catch (Exception e) { // null is returned } } } return null; } private static Font getConfiguredFont(RuntimeConfig config, String key) { String fontDesc = config.getContextProperty(key); if (fontDesc == null || fontDesc.isEmpty()) { return new Font("Verdana", Font.ITALIC, 10); } return Font.decode(fontDesc.replace(",", "-")); } public static interface Splash { boolean isVisible(); void close(); void update(); Graphics2D createGraphics(); Dimension getSize(); Rectangle getBounds(); } private static class AwtSplash implements Splash { private final SplashScreen splashScreen; public AwtSplash(SplashScreen splashScreen) { this.splashScreen = splashScreen; } public void close() { splashScreen.close(); } public boolean isVisible() { return splashScreen.isVisible(); } public void update() { splashScreen.update(); } public Graphics2D createGraphics() { return splashScreen.createGraphics(); } public Dimension getSize() { return splashScreen.getSize(); } public Rectangle getBounds() { return splashScreen.getBounds(); } } private static class CeresSplash extends Window implements Splash { private BufferedImage bufferImage; private BufferedImage backgroundImage; private BufferedImage updateImage; private Graphics2D bufferGraphics; public CeresSplash(BufferedImage image) { super(null); backgroundImage = image; Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Rectangle bounds = new Rectangle((screenSize.width - image.getWidth()) / 2, (screenSize.height - image.getHeight()) / 2, image.getWidth(), image.getHeight()); bufferImage = new BufferedImage(bounds.width, bounds.height, BufferedImage.TYPE_INT_ARGB); bufferGraphics = bufferImage.createGraphics(); setBounds(bounds); setFocusable(false); setAlwaysOnTop(false); setVisible(true); } public void close() { if (bufferGraphics != null) { dispose(); bufferGraphics.dispose(); bufferGraphics = null; bufferImage = null; backgroundImage = null; updateImage = null; } } public void update() { repaint(); } public Graphics2D createGraphics() throws IllegalStateException { if (updateImage == null) { Dimension dim = getSize(); updateImage = new BufferedImage(dim.width, dim.height, BufferedImage.TYPE_INT_ARGB); } return updateImage.createGraphics(); } @Override public void update(Graphics g) { bufferGraphics.drawImage(backgroundImage, null, 0, 0); if (updateImage != null) { bufferGraphics.drawImage(updateImage, null, 0, 0); } g.drawImage(bufferImage, 0, 0, null); } } }