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