1 /* ErrorPainter.java
2 Copyright (C) 2012 Red Hat, Inc.
3 
4 This file is part of IcedTea.
5 
6 IcedTea is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 IcedTea is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with IcedTea; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 package net.sourceforge.jnlp.splashscreen.impls.defaultsplashscreen2012;
38 
39 import java.awt.Color;
40 import java.awt.Font;
41 import java.awt.FontMetrics;
42 import java.awt.Graphics;
43 import java.awt.Graphics2D;
44 import java.awt.Point;
45 import java.awt.RenderingHints;
46 import java.util.Observable;
47 
48 import net.sourceforge.jnlp.runtime.Translator;
49 import net.sourceforge.jnlp.splashscreen.parts.BasicComponentSplashScreen;
50 import net.sourceforge.jnlp.splashscreen.parts.InformationElement;
51 import net.sourceforge.jnlp.splashscreen.parts.extensions.ExtensionManager;
52 import net.sourceforge.jnlp.util.logging.OutputController;
53 
54 public final class ErrorPainter extends BasePainter {
55 
56     //colors
57     private static final Color TEA_DEAD_COLOR = Color.darkGray;
58     private static final Color BACKGROUND_DEAD_COLOR = Color.gray;
59     private static final Color TEA_LEAFS_STALKS_DEAD_COLOR = new Color(100, 100, 100);
60     private static final Color PLUGIN_DEAD_COLOR = Color.darkGray;
61     private static final Color WATER_DEAD_COLOR = Color.darkGray;
62     private static final Color PLAIN_TEXT_DEAD_COLOR = Color.white;
63     private static final String ERROR_MESSAGE_KEY = "SPLASHerror";
64     private static final String ERROR_FLY_MESSAGE_KEY = "SPLASH_ERROR";
65     private static final Color ERROR_FLY_COLOR = Color.red;
66     //for clicking ot error message
67     private Point errorCorner = null;
68     private boolean errorIsFlying = false;
69     private int errorFlyPercentage = 100;
70 
71     /**
72      * Interpolation is root ratior is r= (currentSize / origSize)
73      * then value to-from is interpolaed from to to from accroding to ratio
74      *
75      * @param origSize
76      * @param currentSize
77      * @param from
78      * @param to
79      * @return interpolated value
80      */
interpol(double origSize, double currentSize, double from, double to)81     public static double interpol(double origSize, double currentSize, double from, double to) {
82         return getRatio(origSize, currentSize) * (to - from) + from;
83     }
84 
85     /**
86      * is interpolating one color to another based on ration current/orig
87      * Each (r,g,b,a) part of color is interpolated separately
88      * resturned is new color composed form new r,g,b,a
89      * @param origSize
90      * @param currentSize
91      * @param from
92      * @param to
93      * @return interpolated {@link Color}
94      */
interpolateColor(double origSize, double currentSize, Color from, Color to)95     public static Color interpolateColor(double origSize, double currentSize, Color from, Color to) {
96         double r = interpol(origSize, currentSize, to.getRed(), from.getRed());
97         double g = interpol(origSize, currentSize, to.getGreen(), from.getGreen());
98         double b = interpol(origSize, currentSize, to.getBlue(), from.getBlue());
99         double a = interpol(origSize, currentSize, to.getAlpha(), from.getAlpha());
100         return new Color((int) r, (int) g, (int) b, (int) a);
101     }
102     //scaling end
103 
ErrorPainter(BasicComponentSplashScreen master)104     public ErrorPainter(BasicComponentSplashScreen master) {
105         this(master, false);
106     }
107 
ErrorPainter(BasicComponentSplashScreen master, boolean startScream)108     public ErrorPainter(BasicComponentSplashScreen master, boolean startScream) {
109         super(master);
110         if (startScream) {
111             startErrorScream();
112         }
113 
114     }
115 
startErrorScream()116     public void startErrorScream() {
117         errorIsFlying = true;
118         getFlyingRedErrorTextThread().start();
119     }
120 
121     @Override
paint(Graphics g)122     public void paint(Graphics g) {
123         Graphics2D g2d = (Graphics2D) g;
124         ensurePrerenderedStuff();
125         if (errorIsFlying) {
126             paintStillTo(g2d, master.getInformationElement(), master.getVersion());
127         } else {
128             if (prerenderedStuff != null) {
129                 g2d.drawImage(prerenderedStuff, 0, 0, null);
130             }
131         }
132 
133         if (super.showNiceTexts) {
134             ExtensionManager.getExtension().paint(g, this);
135             paintNiceTexts(g2d);
136         } else {
137             paintPlainTexts(g2d);
138         }
139 
140         if (errorIsFlying) {
141             g2d.setClip(0, 0, master.getSplashWidth(), master.getSplashHeight());
142             drawBigError(g2d);
143         }
144 
145 
146     }
147 
drawBigError(Graphics2D g2d)148     private void drawBigError(Graphics2D g2d) {
149         Font f = new Font("Serif", Font.PLAIN, (int) scale(100, errorFlyPercentage, master.getSplashHeight()));
150         g2d.setColor(ERROR_FLY_COLOR);
151         g2d.setFont(f);
152         drawTextAroundCenter(g2d, 0, geFlyingErrorMessage());
153     }
154 
getErrorCorner()155     public Point getErrorCorner() {
156         return errorCorner;
157     }
158 
setColors()159     private void setColors() {
160 
161         teaColor = TEA_DEAD_COLOR;
162         backgroundColor = BACKGROUND_DEAD_COLOR;
163         teaLeafsStalksColor = TEA_LEAFS_STALKS_DEAD_COLOR;
164         pluginColor = PLUGIN_DEAD_COLOR;
165         waterColor = WATER_DEAD_COLOR;
166 
167     }
168 
interpolateColor(int origSize, int currentSize)169     private void interpolateColor(int origSize, int currentSize) {
170         teaColor = interpolateColor(origSize, currentSize, TEA_LIVE_COLOR, TEA_DEAD_COLOR);
171         backgroundColor = interpolateColor(origSize, currentSize, BACKGROUND_LIVE_COLOR, BACKGROUND_DEAD_COLOR);
172         teaLeafsStalksColor = interpolateColor(origSize, currentSize, TEA_LEAFS_STALKS_LIVE_COLOR, TEA_LEAFS_STALKS_DEAD_COLOR);
173         pluginColor = interpolateColor(origSize, currentSize, PLUGIN_LIVE_COLOR, PLUGIN_DEAD_COLOR);
174         waterColor = interpolateColor(origSize, currentSize, WATER_LIVE_COLOR, WATER_DEAD_COLOR);
175         plainTextColor = interpolateColor(origSize, currentSize, PLAIN_TEXT_LIVE_COLOR, PLAIN_TEXT_DEAD_COLOR);
176     }
177 
178     @Override
paintStillTo(Graphics2D g2d, InformationElement ic, String version)179     protected void paintStillTo(Graphics2D g2d, InformationElement ic, String version) {
180         RenderingHints r = g2d.getRenderingHints();
181         FontMetrics fm = drawBase(g2d, ic, version);
182         drawError(g2d, ic, version, fm);
183         g2d.setRenderingHints(r);
184     }
185 
getErrorMessage()186     private String getErrorMessage() {
187         String localised = Translator.R(ERROR_MESSAGE_KEY);
188         //if (localised==null)return errorMessage;
189         return localised;
190     }
191 
geFlyingErrorMessage()192     private String geFlyingErrorMessage() {
193         String localised = Translator.R(ERROR_FLY_MESSAGE_KEY);
194         return localised;
195     }
196 
getFlyingRedErrorTextThread()197     private Thread getFlyingRedErrorTextThread() {
198         // Create a new thread to draw big flying error in case of failure
199         Thread t = new Thread(new FlyingRedErrorTextRunner(this));
200         //t.setDaemon(true);
201         return t;
202     }
203 
204     private final class FlyingRedErrorTextRunner extends Observable implements Runnable {
205 
206         private static final int FLYING_ERROR_PERCENTAGE_INCREMENT = -3;
207         private static final int FLYING_ERROR_PERCENTAGE_MINIMUM = 5;
208         private static final int FLYING_ERROR_PERCENTAGE_LOWER_BOUND = 80;
209         private static final int FLYING_ERROR_PERCENTAGE_UPPER_BOUND = 90;
210         private static final int FLYING_ERROR_DELAY = 75;
211 
FlyingRedErrorTextRunner(ErrorPainter o)212         private FlyingRedErrorTextRunner(ErrorPainter o) {
213             this.addObserver(o);
214         }
215 
216         @Override
run()217         public void run() {
218             try {
219                 while (errorIsFlying) {
220                     errorFlyPercentage += FLYING_ERROR_PERCENTAGE_INCREMENT;
221                     interpolateColor(100, errorFlyPercentage);
222                     if (errorFlyPercentage <= FLYING_ERROR_PERCENTAGE_MINIMUM) {
223                         errorIsFlying = false;
224                         setColors();
225                         prerenderedStuff = null;
226                     }
227                     this.setChanged();
228                     this.notifyObservers();
229                     Thread.sleep(FLYING_ERROR_DELAY);
230                     if (errorFlyPercentage < FLYING_ERROR_PERCENTAGE_UPPER_BOUND
231                             && errorFlyPercentage > FLYING_ERROR_PERCENTAGE_LOWER_BOUND) {
232                         clearCachedWaterTextImage();
233                         canWave = false;
234                     }
235                 }
236             } catch (Exception e) {
237                 OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
238             } finally {
239                 canWave = true;
240                 errorIsFlying = false;
241                 setColors();
242                 prerenderedStuff = null;
243                 master.repaint();
244 
245             }
246         }
247     };
248 
drawError(Graphics2D g2d, InformationElement ic, String version, FontMetrics fm)249     private void drawError(Graphics2D g2d, InformationElement ic, String version, FontMetrics fm) {
250         int minh = fm.getHeight();
251         int minw = fm.stringWidth(getErrorMessage());
252         int space = 5;
253         g2d.setColor(backgroundColor);
254         errorCorner = new Point(master.getSplashWidth() - space * 4 - minw, master.getSplashHeight() - space * 4 - minh);
255         if (errorCorner.x < 0) {
256             errorCorner.x = 0;
257         }
258         g2d.fillRect(errorCorner.x, errorCorner.y, space * 4 + minw, space * 4 + minh);
259         g2d.setColor(plainTextColor);
260         g2d.drawRect(errorCorner.x + space, errorCorner.y + space, space * 2 + minw, space * 2 + minh);
261         g2d.drawString(getErrorMessage(), errorCorner.x + 2 * space, errorCorner.y + 5 * space);
262     }
263 }
264