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