JAL-3487 Splash screen
[jalview.git] / src / jalview / gui / SplashScreen.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.gui;
22
23 import java.awt.BorderLayout;
24 import java.awt.Color;
25 import java.awt.Dimension;
26 import java.awt.Font;
27 import java.awt.Graphics;
28 import java.awt.Image;
29 import java.awt.MediaTracker;
30 import java.awt.Toolkit;
31 import java.awt.event.MouseAdapter;
32 import java.awt.event.MouseEvent;
33 import java.net.URL;
34
35 import javax.swing.JInternalFrame;
36 import javax.swing.JLayeredPane;
37 import javax.swing.JPanel;
38 import javax.swing.JTextPane;
39 import javax.swing.event.HyperlinkEvent;
40 import javax.swing.event.HyperlinkListener;
41
42 import jalview.util.Platform;
43 import javajs.async.SwingJSUtils.StateHelper;
44 import javajs.async.SwingJSUtils.StateMachine;
45
46 /**
47  * DOCUMENT ME!
48  * 
49  * @author $author$
50  * @version $Revision$
51  */
52 @SuppressWarnings("serial")
53 public class SplashScreen extends JPanel
54         implements HyperlinkListener, StateMachine
55 {
56   
57   private static final int STATE_INIT = 0;
58
59   private static final int STATE_LOOP = 1;
60
61   private static final int STATE_DONE = 2;
62
63   private static final int SHOW_FOR_SECS = 5;
64
65   private int FONT_SIZE = (Platform.isJS() ? 14 : 11);
66
67   private JPanel imgPanel = new JPanel(new BorderLayout());
68
69   private JInternalFrame iframe;
70
71   private Image image;
72
73   protected boolean isInteractive = false;
74
75   private long oldTextLength = -1;
76
77   /*
78    * allow click in the initial splash screen to dismiss it
79    * immediately (not if opened from About menu)
80    */
81   private MouseAdapter closer = new MouseAdapter()
82   {
83     @Override
84     public void mousePressed(MouseEvent evt)
85     {
86       if (isInteractive)
87       {
88         try
89         {
90           closeSplash();
91         } catch (Exception ex)
92         {
93         }
94       }
95     }
96   };
97
98   private Image logo;
99
100   private StateHelper helper;
101
102   /**
103    * Constructor that displays the splash screen
104    * 
105    * @param isTransient
106    *          if true the panel removes itself on click or after a few seconds;
107    *          if false it stays up until closed by the user
108    */
109   public SplashScreen(boolean isTransient)
110   {
111     this.isInteractive = isTransient;
112
113     getImages();
114     helper = new StateHelper(this);
115     helper.next(STATE_INIT);
116   }
117
118   private void getImages()
119   {
120     URL url = getClass().getResource("/images/Jalview_Logo.png");
121     URL urllogo = getClass()
122             .getResource("/images/Jalview_Logo_small.png");
123     image = Toolkit.getDefaultToolkit().createImage(url);
124     if (!Platform.isJS())
125       logo = Toolkit.getDefaultToolkit().createImage(urllogo);
126   }
127
128   /**
129    * ping the jalview version page then create and display the jalview
130    * splashscreen window.
131    */
132   void initSplashScreenWindow()
133   {
134     addMouseListener(closer);
135
136     try
137     {
138       MediaTracker mt = new MediaTracker(this);
139       mt.addImage(image, 0);
140       if (logo != null)
141       {
142         mt.addImage(logo, 1);
143       }
144       do
145       {
146         try
147         {
148           mt.waitForAll();
149         } catch (InterruptedException x)
150         {
151         }
152         if (mt.isErrorAny())
153         {
154           System.err.println("Error when loading images!");
155         }
156       } while (!mt.checkAll());
157       if (logo != null)
158       {
159         Desktop.getInstance().setIconImage(logo);
160       }
161     } catch (Exception ex)
162     {
163     }
164     iframe = new JInternalFrame();
165     iframe.setFrameIcon(null);
166     iframe.setClosable(true);
167     this.setLayout(new BorderLayout());
168     iframe.setContentPane(this);
169     iframe.setLayer(JLayeredPane.PALETTE_LAYER);
170     
171     SplashImage splashimg = new SplashImage(image);
172     imgPanel.add(splashimg, BorderLayout.CENTER);
173     add(imgPanel, BorderLayout.NORTH);
174     Desktop.getDesktopPane().add(iframe);
175     refreshText();
176   }
177
178   /**
179    * update text in author text panel reflecting current version information
180    */
181   protected boolean refreshText()
182   {
183     String newtext = Desktop.getInstance().getAboutMessage();
184     if (oldTextLength == newtext.length())
185     {
186       return false;
187     }
188     oldTextLength = newtext.length();
189     iframe.setVisible(false);
190     JTextPane jtp = new JTextPane();
191     jtp.setEditable(false);
192     jtp.setContentType("text/html");
193     jtp.setText("<html>" + newtext + "</html>");
194     
195     
196     System.out.println("Text found: \n"+newtext+"\nEnd of newtext.");
197     
198     jtp.addHyperlinkListener(this);
199     jtp.setFont(new Font("Verdana", Font.PLAIN, FONT_SIZE));
200     jtp.addMouseListener(closer);
201     jtp.setVisible(true);
202     jtp.setSize(new Dimension(750, 425));
203     add(jtp, BorderLayout.CENTER);
204     revalidate();
205     iframe.setBounds((Desktop.getInstance().getWidth() - 750) / 2,
206            50, 750,
207             jtp.getHeight() + imgPanel.getHeight());
208     iframe.validate();
209     iframe.setVisible(true);
210     return true;
211   }
212
213   
214   protected long startTime;
215
216   /**
217    * A simple state machine with just three states: init, loop, and done. Ideal
218    * for a simple while/sleep loop that works in Java and JavaScript
219    * identically.
220    * 
221    */
222   public boolean stateLoop()
223   {
224     while (true)
225     {
226       switch (helper.getState())
227       {
228       case STATE_INIT:
229         initSplashScreenWindow();
230         startTime = System.currentTimeMillis() / 1000;
231         helper.setState(STATE_LOOP);
232         continue;
233       case STATE_LOOP:
234         if (!isVisible())
235         {
236           helper.setState(STATE_DONE);
237           continue;
238         }
239         if (refreshText())
240         {
241           iframe.repaint();
242         }
243         if (!isInteractive)
244         {
245           return false;
246         }
247         helper.delayedState(SHOW_FOR_SECS * 1000, STATE_DONE);
248         return true;
249       default:
250       case STATE_DONE:
251         setVisible(false);
252         closeSplash();
253         Desktop.getInstance().startDialogQueue();
254         return true;
255       }
256     }
257   }
258
259   public void closeSplash()
260   {
261     try
262     {
263
264       iframe.setClosed(true);
265     } catch (Exception ex)
266     {
267     }
268   }
269
270   public class SplashImage extends JPanel
271   {
272     Image image;
273
274     public SplashImage(Image todisplay)
275     {
276       image = todisplay;
277       if (image != null)
278       {
279         setPreferredSize(new Dimension(image.getWidth(this) + 8,
280                 image.getHeight(this)));
281       }
282     }
283
284     @Override
285     public Dimension getPreferredSize()
286     {
287       return new Dimension(image.getWidth(this) + 8, image.getHeight(this));
288     }
289
290     @Override
291     public void paintComponent(Graphics g)
292     {
293       g.setColor(Color.white);
294       g.fillRect(0, 0, getWidth(), getHeight());
295       g.setColor(Color.black);
296
297       if (image != null)
298       {
299         g.drawImage(image, (getWidth() - image.getWidth(this)) / 2,
300                 (getHeight() - image.getHeight(this)) / 2, this);
301       }
302     }
303   }
304
305   @Override
306   public void hyperlinkUpdate(HyperlinkEvent e)
307   {
308     Desktop.hyperlinkUpdate(e);
309
310   }
311 }