View Javadoc
1   package fr.ifremer.quadrige3.ui.swing;
2   
3   /*-
4    * #%L
5    * Quadrige3 Core :: UI Swing Common
6    * %%
7    * Copyright (C) 2017 - 2020 Ifremer
8    * %%
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU Affero General Public License as published by
11   * the Free Software Foundation, either version 3 of the License, or
12   * (at your option) any later version.
13   * 
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Public License for more details.
18   * 
19   * You should have received a copy of the GNU Affero General Public License
20   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21   * #L%
22   */
23  
24  import fr.ifremer.quadrige3.core.config.QuadrigeCoreConfiguration;
25  import org.apache.commons.collections4.CollectionUtils;
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  
29  import javax.swing.ImageIcon;
30  import javax.swing.Timer;
31  import java.awt.*;
32  import java.net.URL;
33  import java.util.List;
34  
35  /**
36   * @author peck7 on 18/02/2020.
37   */
38  public class ApplicationSplashScreen {
39  
40      private static final Log LOG = LogFactory.getLog(ApplicationSplashScreen.class);
41  
42      // the java.awt.SplashScreen reference
43      private static SplashScreen splash;
44      // the java.awt.SplashScreen graphics
45      private static Graphics2D graphics;
46      // flag indicating the cool down of the splash screen
47      private static boolean coolDown;
48      // the splash screen is shown for 3 seconds or until another component is shown
49      private static final int coolDownTime = 3000;
50  
51      /**
52       * Initialize the splash screen
53       *
54       * @param config the configuration
55       */
56      public static void init(QuadrigeCoreConfiguration config) {
57  
58          // get the splash screen instance and create graphics
59          if (create()) {
60  
61              // render the logos
62              render(
63                  config.getSplashScreenLeftLogos(),
64                  config.getSplashScreenRightLogos()
65              );
66  
67              // init the cool down timer
68              coolDown = true;
69              Timer t = new Timer(10, e -> {
70                  coolDown = false;
71                  ((Timer) e.getSource()).stop();
72              });
73              // the splash screen is shown for 3 seconds or until another component is shown
74              t.setInitialDelay(coolDownTime);
75              t.start();
76          }
77      }
78  
79      /**
80       * render the progress bar
81       *
82       * @param progress from 0 to 100
83       */
84      public static void progress(int progress) {
85          if (splash != null && splash.isVisible() && graphics != null) {
86              render(progress);
87          }
88      }
89  
90      /**
91       * pause the current thread until the cool down timer is done
92       */
93      public static void waitFor() {
94          do {
95              try {
96                  Thread.sleep(100);
97              } catch (InterruptedException ignored) {
98              }
99          } while (coolDown);
100     }
101 
102     /**
103      * hide the splash screen if not already
104      */
105     public static void hide() {
106         if (splash != null && splash.isVisible())
107             splash.close();
108     }
109 
110     /**
111      * get the splash screen instance and create its graphics
112      *
113      * @return true if correctly created
114      */
115     private static boolean create() {
116         splash = SplashScreen.getSplashScreen();
117         if (splash == null) {
118             LOG.error("splash screen cannot be shown");
119             return false;
120         }
121         graphics = splash.createGraphics();
122         if (graphics == null) {
123             LOG.error("splash screen graphics is null");
124             return false;
125         }
126 
127         return true;
128     }
129 
130     /**
131      * get an image from resources
132      * first search in current classpath, then in the application classpath (but should be equivalent)
133      *
134      * @param name the name of the image
135      * @return the Image from the resource or null if not found
136      */
137     private static Image getImage(String name) {
138         String resourceName = "/images/" + name;
139         URL logoUrl = ApplicationSplashScreen.class.getResource(resourceName);
140         if (logoUrl != null) {
141             return new ImageIcon(logoUrl).getImage();
142         }
143         logoUrl = Application.getInstance().getClass().getResource(resourceName);
144         if (logoUrl != null) {
145             return new ImageIcon(logoUrl).getImage();
146         }
147         LOG.warn(resourceName + " not found in resources");
148         return null;
149     }
150 
151     /**
152      * render logos on the splash screen graphics
153      *
154      * @param leftLogos  list of logos to render on the left part
155      * @param rightLogos list of logos to render on the right part
156      */
157     private static void render(List<String> leftLogos, List<String> rightLogos) {
158         // vertical placement
159         int y = splash.getBounds().height
160             - 12 // yellow bar
161             - 32 // logo size
162             - 2; // border
163 
164         if (CollectionUtils.isNotEmpty(leftLogos)) {
165             int x = 4;
166             // render from left to right direction
167             for (String logo : leftLogos) {
168                 Image image = getImage(logo);
169                 if (image != null) {
170                     if (LOG.isDebugEnabled()) {
171                         LOG.debug(String.format("render logo %s (width=%s height=%s) at x=%s y=%s", logo, image.getWidth(null), image.getHeight(null), x, y));
172                     }
173                     graphics.drawImage(image, x, y, null);
174                     x += image.getWidth(null) + 4;
175                 }
176             }
177         }
178 
179         if (CollectionUtils.isNotEmpty(rightLogos)) {
180             int x = splash.getBounds().width;
181             // render from right to left direction
182             for (String logo : rightLogos) {
183                 Image image = getImage(logo);
184                 if (image != null) {
185                     if (LOG.isDebugEnabled()) {
186                         LOG.debug(String.format("render logo %s (width=%s height=%s) at x=%s y=%s", logo, image.getWidth(null), image.getHeight(null), x, y));
187                     }
188                     x -= image.getWidth(null) + 4;
189                     graphics.drawImage(image, x, y, null);
190                 }
191             }
192         }
193 
194         splash.update();
195     }
196 
197     /**
198      * render the progress
199      *
200      * @param progress progress percentage
201      */
202     private static void render(int progress) {
203         int x = progress * splash.getBounds().width / 100;
204         int y = splash.getBounds().height - 1;
205 
206         // draw the 2px line with Ifremer blue color
207         graphics.setColor(new Color(0, 110, 171));
208         graphics.setStroke(new BasicStroke(2));
209         graphics.drawLine(0, y, x, y);
210 
211         splash.update();
212     }
213 
214 }