JAL-2360 removed UserDefinedColours.userColourSchemes
[jalview.git] / src / jalview / schemes / ColourSchemes.java
1 package jalview.schemes;
2
3 import jalview.binding.JalviewUserColours;
4 import jalview.datamodel.AnnotatedCollectionI;
5 import jalview.datamodel.SequenceCollectionI;
6 import jalview.datamodel.SequenceI;
7
8 import java.awt.Color;
9 import java.io.FileInputStream;
10 import java.io.InputStreamReader;
11 import java.util.LinkedHashMap;
12 import java.util.Map;
13
14 public class ColourSchemes
15 {
16   /*
17    * singleton instance of this class
18    */
19   private static ColourSchemes instance = new ColourSchemes();
20
21   /*
22    * a map from scheme name to an instance of it
23    */
24   private Map<String, ColourSchemeI> schemes;
25
26   /**
27    * Returns the singleton instance of this class
28    * 
29    * @return
30    */
31   public static ColourSchemes getInstance()
32   {
33     return instance;
34   }
35
36   private ColourSchemes()
37   {
38     loadColourSchemes();
39   }
40
41   /**
42    * Loads an instance of each standard or user-defined colour scheme
43    * 
44    * @return
45    */
46   void loadColourSchemes()
47   {
48     /*
49      * store in an order-preserving map, so items can be added to menus 
50      * in the order in which they are 'discovered'
51      */
52     schemes = new LinkedHashMap<String, ColourSchemeI>();
53
54     for (JalviewColourScheme cs : JalviewColourScheme.values())
55     {
56       try
57       {
58         registerColourScheme(cs.getSchemeClass().newInstance());
59       } catch (InstantiationException | IllegalAccessException e)
60       {
61         System.err.println("Error instantiating colour scheme for "
62                 + cs.toString() + " " + e.getMessage());
63       }
64     }
65   }
66
67   /**
68    * Registers a colour scheme
69    * 
70    * @param cs
71    */
72   public void registerColourScheme(ColourSchemeI cs)
73   {
74     String name = cs.getSchemeName();
75     if (name == null)
76     {
77       System.err.println("ColourScheme name may not be null");
78       return;
79     }
80
81     /*
82      * name is lower-case for non-case-sensitive lookup
83      * (name in the colour keeps its true case)
84      */
85     String lower = name.toLowerCase();
86     if (schemes.containsKey(lower))
87     {
88       System.err
89               .println("Warning: overwriting colour scheme named " + name);
90     }
91     schemes.put(lower, cs);
92   }
93
94   /**
95    * Removes a colour scheme by name
96    * 
97    * @param name
98    */
99   public void removeColourScheme(String name)
100   {
101     schemes.remove(name);
102   }
103   
104   /**
105    * Returns an instance of the colour scheme with which the given view may be
106    * coloured
107    * 
108    * @param name
109    *          name of the colour scheme
110    * @param forData
111    *          the data to be coloured
112    * @param optional
113    *          map from hidden representative sequences to the sequences they
114    *          represent
115    * @return
116    */
117   public ColourSchemeI getColourScheme(String name,
118           AnnotatedCollectionI forData,
119           Map<SequenceI, SequenceCollectionI> hiddenRepSequences)
120   {
121     if (name == null)
122     {
123       return null;
124     }
125     ColourSchemeI cs = schemes.get(name.toLowerCase());
126     return cs == null ? null : cs.getInstance(forData, hiddenRepSequences);
127   }
128
129   /**
130    * Returns an instance of the colour scheme with which the given view may be
131    * coloured
132    * 
133    * @param name
134    *          name of the colour scheme
135    * @param forData
136    *          the data to be coloured
137    * @return
138    */
139   public ColourSchemeI getColourScheme(String name,
140           AnnotatedCollectionI forData)
141   {
142     return getColourScheme(name, forData, null);
143   }
144
145   /**
146    * Returns an iterable set of the colour schemes, in the order in which they
147    * were added
148    * 
149    * @return
150    */
151   public Iterable<ColourSchemeI> getColourSchemes()
152   {
153     return schemes.values();
154   }
155
156   /**
157    * Answers true if there is a scheme with the given name, else false. The test
158    * is not case-sensitive.
159    * 
160    * @param name
161    * @return
162    */
163   public boolean nameExists(String name)
164   {
165     if (name == null)
166     {
167       return false;
168     }
169     name = name.toLowerCase();
170     for (ColourSchemeI scheme : getColourSchemes())
171     {
172       if (name.equals(scheme.getSchemeName().toLowerCase()))
173       {
174         return true;
175       }
176     }
177     return false;
178   }
179
180   /**
181    * Loads a user defined colour scheme from file. The file should contain a
182    * definition of residue colours in XML format as defined in
183    * JalviewUserColours.xsd.
184    * 
185    * @param file
186    * 
187    * @return
188    */
189   public static UserColourScheme loadColourScheme(String file)
190   {
191     UserColourScheme ucs = null;
192     Color[] newColours = null;
193     try
194     {
195       InputStreamReader in = new InputStreamReader(
196               new FileInputStream(file), "UTF-8");
197   
198       jalview.schemabinding.version2.JalviewUserColours jucs = new jalview.schemabinding.version2.JalviewUserColours();
199   
200       org.exolab.castor.xml.Unmarshaller unmar = new org.exolab.castor.xml.Unmarshaller(
201               jucs);
202       jucs = (jalview.schemabinding.version2.JalviewUserColours) unmar
203               .unmarshal(in);
204   
205       /*
206        * non-case-sensitive colours are for 20 amino acid codes,
207        * B, Z, X and Gap
208        * optionally, lower-case alternatives for all except Gap
209        */
210       newColours = new Color[24];
211       Color[] lowerCase = new Color[23];
212       boolean caseSensitive = false;
213   
214       String name;
215       int index;
216       for (int i = 0; i < jucs.getColourCount(); i++)
217       {
218         name = jucs.getColour(i).getName();
219         if (ResidueProperties.aa3Hash.containsKey(name))
220         {
221           index = ResidueProperties.aa3Hash.get(name).intValue();
222         }
223         else
224         {
225           index = ResidueProperties.aaIndex[name.charAt(0)];
226         }
227         if (index == -1)
228         {
229           continue;
230         }
231   
232         Color color = new Color(Integer.parseInt(jucs.getColour(i)
233                 .getRGB(), 16));
234         if (name.toLowerCase().equals(name))
235         {
236           caseSensitive = true;
237           lowerCase[index] = color;
238         }
239         else
240         {
241           newColours[index] = color;
242         }
243       }
244   
245       /*
246        * instantiate the colour scheme
247        */
248       ucs = new UserColourScheme(newColours);
249       ucs.setName(jucs.getSchemeName());
250       if (caseSensitive)
251       {
252         ucs.setLowerCaseColours(lowerCase);
253       }
254     } catch (Exception ex)
255     {
256       // Could be old Jalview Archive format
257       try
258       {
259         InputStreamReader in = new InputStreamReader(new FileInputStream(
260                 file), "UTF-8");
261   
262         jalview.binding.JalviewUserColours jucs = new jalview.binding.JalviewUserColours();
263   
264         jucs = JalviewUserColours.unmarshal(in);
265   
266         newColours = new Color[jucs.getColourCount()];
267   
268         for (int i = 0; i < 24; i++)
269         {
270           newColours[i] = new Color(Integer.parseInt(jucs.getColour(i)
271                   .getRGB(), 16));
272         }
273         ucs = new UserColourScheme(newColours);
274         ucs.setName(jucs.getSchemeName());
275       } catch (Exception ex2)
276       {
277         ex2.printStackTrace();
278       }
279   
280       if (newColours == null)
281       {
282         System.out.println("Error loading User ColourFile\n" + ex);
283       }
284     }
285   
286     return ucs;
287   }
288 }