JAL-3594 Adjustments to allow JalviewJS to use ChannelProperties, and new utils/chann...
[jalview.git] / src / jalview / util / ChannelProperties.java
1 package jalview.util;
2
3 import java.awt.Image;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.net.URL;
7 import java.util.ArrayList;
8 import java.util.Arrays;
9 import java.util.HashMap;
10 import java.util.List;
11 import java.util.Map;
12 import java.util.Properties;
13
14 import javax.swing.ImageIcon;
15
16 import jalview.bin.Cache;
17
18 public class ChannelProperties
19 {
20
21   private static final String CHANNEL_PROPERTIES_FILENAME = "/channel.props";
22
23   private static final Properties channelProps;
24
25   private static final Properties defaultProps;
26
27   private static Map<String, Image> imageMap = new HashMap<String, Image>();
28
29   private static Map<String, URL> urlMap = new HashMap<String, URL>();
30
31   private static final ArrayList<Image> iconList;
32
33   static
34   {
35     defaultProps = new Properties();
36     // these should be kept up to date, but in real life they should never
37     // actually be used anyway.
38     defaultProps.put("app_name", "Jalview");
39     defaultProps.put("banner", "/default_images/jalview_banner.png");
40     defaultProps.put("logo.16", "/default_images/jalview_logo-16.png");
41     defaultProps.put("logo.32", "/default_images/jalview_logo-32.png");
42     defaultProps.put("logo.38", "/default_images/jalview_logo-38.png");
43     defaultProps.put("logo.48", "/default_images/jalview_logo-48.png");
44     defaultProps.put("logo.64", "/default_images/jalview_logo-64.png");
45     defaultProps.put("logo.128", "/default_images/jalview_logo-128.png");
46     defaultProps.put("logo.256", "/default_images/jalview_logo-256.png");
47     defaultProps.put("logo.512", "/default_images/jalview_logo-512.png");
48     defaultProps.put("rotatable_logo.48",
49             "/default_images/rotatable_jalview_logo-38.png");
50     defaultProps.put("bg_logo.28", "/default_images/barton_group-28.png");
51     defaultProps.put("bg_logo.30", "/default_images/barton_group-30.png");
52     defaultProps.put("bg_logo.32", "/default_images/barton_group-32.png");
53     defaultProps.put("uod_banner.28", "/default_images/UoD_banner-28.png");
54     defaultProps.put("uod_banner.30", "/default_images/UoD_banner-30.png");
55     defaultProps.put("uod_banner.32", "/default_images/UoD_banner-32.png");
56     defaultProps.put("default_appbase",
57             "https://www.jalview.org/getdown/release/1.8");
58
59     // load channel_properties
60     Properties tryChannelProps = new Properties();
61     URL channelPropsURL = ChannelProperties.class
62             .getResource(CHANNEL_PROPERTIES_FILENAME);
63     if (channelPropsURL == null)
64     {
65       // complete failure of channel_properties, set all properties to defaults
66       System.err
67               .println("Failed to find '" + CHANNEL_PROPERTIES_FILENAME
68                       + "' file at '"
69                       + (channelPropsURL == null ? "null"
70                               : channelPropsURL.toString())
71                       + "'. Using class defaultProps.");
72       tryChannelProps = defaultProps;
73     }
74     else
75     {
76       try
77       {
78         InputStream channelPropsIS = channelPropsURL.openStream();
79         tryChannelProps.load(channelPropsIS);
80         channelPropsIS.close();
81       } catch (IOException e)
82       {
83         Cache.log.warn(e.getMessage());
84         // return false;
85       }
86     }
87     channelProps = tryChannelProps;
88
89     /*
90      * The following slight palava for caching an icon list is so that all sizes of icons
91      * are the same. i.e. if there are /any/ channel_properties icons to use, then _only_
92      * use those channel_properties icons, don't mix in class default icons for missing
93      * sizes.  If there are _no_ (usable) channel icons then we can use the class default icons.
94      */
95     iconList = new ArrayList<Image>();
96     List<String> sizes = Arrays.asList("16", "32", "48", "64", "128", "256",
97             "512");
98     for (String size : sizes)
99     {
100       Image logo = null;
101       // not using defaults or class props first time through
102       logo = ChannelProperties.getImage("logo." + size, null, false);
103       if (logo != null)
104       {
105         iconList.add(logo);
106       }
107     }
108     // now add the class defaults if there were no channel icons defined
109     if (iconList.size() == 0)
110     {
111       for (String size : sizes)
112       {
113         Image logo = null;
114         String path = defaultProps.getProperty("logo." + size);
115         URL imageURL = ChannelProperties.class.getResource(path);
116         logo = new ImageIcon(imageURL).getImage();
117         if (logo != null)
118         {
119           iconList.add(logo);
120         }
121       }
122     }
123   }
124
125   private static Properties channelProps()
126   {
127     return channelProps;
128   }
129
130   private static Map<String, Image> imageMap()
131   {
132     return imageMap;
133   }
134
135   private static Map<String, URL> urlMap()
136   {
137     return urlMap;
138   }
139
140   /*
141    * getProperty(key) will get property value from channel_properties for key.
142    * If no property for key is found, it will fall back to using the defaultProps defined for this class.
143    */
144   public static String getProperty(String key)
145   {
146     return getProperty(key, null, true);
147   }
148
149   /*
150    * getProperty(key, defaultVal) will get property value from channel_properties for key.
151    * If no property for key is found, it will return defaultVal and NOT fall back to the class defaultProps.
152    */
153   public static String getProperty(String key, String defaultVal)
154   {
155     return getProperty(key, defaultVal, false);
156   }
157
158   /*
159    * internal method.  note that setting useClassDefaultProps=true will ignore the provided defaultVal
160    */
161   private static String getProperty(String key, String defaultVal,
162           boolean useClassDefaultProps)
163   {
164     if (channelProps() != null)
165     {
166       if (channelProps().containsKey(key))
167       {
168         return channelProps().getProperty(key,
169                 useClassDefaultProps ? defaultProps.getProperty(key)
170                         : defaultVal);
171       }
172       else
173       {
174         System.err.println("Failed to get channel property '" + key + "'");
175       }
176     }
177     return null;
178   }
179
180   /*
181    * getImage(key) returns the channel defined image for property key. If that is null (e.g. due to
182    * no defined channel image or the image file being corrupt/unusable/missing) it uses the image
183    * defined in defaultChannelProps
184    */
185   public static Image getImage(String key)
186   {
187     return getImage(key, null, true);
188   }
189
190   /*
191    * getImage(key, defaultImg) will get image associated with value from channel_properties for key.
192    * If no property or associated image for key is found (or is usable), it will return defaultImg
193    * and NOT fall back to the class defaultProps.
194    */
195   public static Image getImage(String key, Image defaultImg)
196   {
197     return getImage(key, defaultImg, false);
198   }
199
200   /*
201    * internal method.  note that setting useClassDefaultImage=true will ignore the provided defaultImg
202    */
203   private static Image getImage(String key, Image defaultImg,
204           boolean useClassDefaultImage)
205   {
206     Image img = null;
207     if (imageMap().containsKey(key))
208     {
209       img = imageMap().get(key);
210     }
211     // Catch a previously untried or failed load
212     if (img == null)
213     {
214       String path = getProperty(key, null, useClassDefaultImage);
215       if (path == null) // no channel property or class default property (if
216                         // requested)
217       {
218         return useClassDefaultImage ? null : defaultImg;
219       }
220
221       URL imageURL = ChannelProperties.class.getResource(path);
222       img = new ImageIcon(imageURL).getImage();
223       if (img == null)
224       {
225         System.err.println(
226                 "Failed to load channel image " + key + "=" + path);
227         if (!useClassDefaultImage)
228         {
229           return defaultImg;
230         }
231       }
232       else
233       {
234         imageMap().put(key, img);
235         urlMap.put(key, imageURL);
236       }
237     }
238     return img;
239   }
240
241   /*
242    * Public method to get the URL object pointing to a cached image.
243    */
244   public static URL getImageURL(String key)
245   {
246     if (getImage(key) != null)
247     {
248       if (urlMap().containsKey(key))
249       {
250         return urlMap().getOrDefault(key, null);
251       }
252       System.err.println(
253               "Do not use getImageURL(key) before using getImage(key...)");
254     }
255     return null;
256   }
257
258   /*
259    * Get a List of Icon images of different sizes.
260    */
261   public static ArrayList<Image> getIconList()
262   {
263     return iconList;
264   }
265 }