Merge branch 'develop' into merged_2_11_2_0_to_2_12
[jalview.git] / src / jalview / schemes / ColourSchemes.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.schemes;
22
23 import java.util.Locale;
24
25 import jalview.api.AlignViewportI;
26 import jalview.bin.ApplicationSingletonProvider;
27 import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI;
28 import jalview.datamodel.AnnotatedCollectionI;
29 import jalview.datamodel.SequenceCollectionI;
30 import jalview.datamodel.SequenceI;
31 import jalview.util.ColorUtils;
32
33 import java.awt.Color;
34 import java.util.LinkedHashMap;
35 import java.util.Map;
36
37 public class ColourSchemes implements ApplicationSingletonI
38 {
39
40   /**
41    * Returns the singleton instance of this class
42    * 
43    * @return
44    */
45   public static ColourSchemes getInstance()
46   {
47     return (ColourSchemes) ApplicationSingletonProvider
48             .getInstance(ColourSchemes.class);
49   }
50
51   private ColourSchemes()
52   {
53     loadColourSchemes();
54   }
55
56   /**
57    * ColourSchemeProperty "static"
58    */
59   public Color[] rnaHelices = null;
60
61   /**
62    * delete the existing cached RNA helices colours
63    */
64   public static void resetRnaHelicesShading()
65   {
66     getInstance().rnaHelices = null;
67   }
68
69   public static void initRnaHelicesShading(int n)
70   {
71     int i = 0;
72     ColourSchemes j = getInstance();
73
74     if (j.rnaHelices == null)
75     {
76       j.rnaHelices = new Color[n + 1];
77     }
78     else if (j.rnaHelices != null && j.rnaHelices.length <= n)
79     {
80       Color[] t = new Color[n + 1];
81       System.arraycopy(j.rnaHelices, 0, t, 0, j.rnaHelices.length);
82       i = j.rnaHelices.length;
83       j.rnaHelices = t;
84     }
85     else
86     {
87       return;
88     }
89     // Generate random colors and store
90     for (; i <= n; i++)
91     {
92       j.rnaHelices[i] = ColorUtils.generateRandomColor(Color.white);
93     }
94   }
95
96   /**
97    * a map from scheme name (lower-cased) to an instance of it
98    */
99   private Map<String, ColourSchemeI> schemes;
100
101   /**
102    * Loads an instance of each standard or user-defined colour scheme
103    * 
104    * @return
105    */
106   void loadColourSchemes()
107   {
108     /*
109      * store in an order-preserving map, so items can be added to menus 
110      * in the order in which they are 'discovered'
111      */
112     schemes = new LinkedHashMap<>();
113
114     for (JalviewColourScheme cs : JalviewColourScheme.values())
115     {
116       try
117       {
118         registerColourScheme(
119                 cs.getSchemeClass().getDeclaredConstructor().newInstance());
120       } catch (InstantiationException | IllegalAccessException e)
121       {
122         System.err.println("Error instantiating colour scheme for "
123                 + cs.toString() + " " + e.getMessage());
124         e.printStackTrace();
125       } catch (ReflectiveOperationException roe)
126       {
127         roe.printStackTrace();
128       }
129     }
130   }
131
132   /**
133    * Registers a colour scheme
134    * 
135    * @param cs
136    */
137   public void registerColourScheme(ColourSchemeI cs)
138   {
139     String name = cs.getSchemeName();
140     if (name == null)
141     {
142       System.err.println("ColourScheme name may not be null");
143       return;
144     }
145
146     /*
147      * name is lower-case for non-case-sensitive lookup
148      * (name in the colour keeps its true case)
149      */
150     String lower = name.toLowerCase(Locale.ROOT);
151     if (schemes.containsKey(lower))
152     {
153       System.err
154               .println("Warning: overwriting colour scheme named " + name);
155     }
156     schemes.put(lower, cs);
157   }
158
159   /**
160    * Removes a colour scheme by name
161    * 
162    * @param name
163    */
164   public void removeColourScheme(String name)
165   {
166     if (name != null)
167     {
168       schemes.remove(name.toLowerCase(Locale.ROOT));
169     }
170   }
171
172   /**
173    * Returns an instance of the colour scheme with which the given view may be
174    * coloured
175    * 
176    * @param name
177    *          name of the colour scheme
178    * @param viewport
179    * @param forData
180    *          the data to be coloured
181    * @param optional
182    *          map from hidden representative sequences to the sequences they
183    *          represent
184    * @return
185    */
186   public ColourSchemeI getColourScheme(String name, AlignViewportI viewport,
187           AnnotatedCollectionI forData,
188           Map<SequenceI, SequenceCollectionI> hiddenRepSequences)
189   {
190     if (name == null)
191     {
192       return null;
193     }
194     ColourSchemeI cs = schemes.get(name.toLowerCase(Locale.ROOT));
195     return cs == null ? null : cs.getInstance(viewport, forData);
196   }
197
198   /**
199    * Returns an instance of the colour scheme with which the given view may be
200    * coloured
201    * 
202    * @param name
203    *          name of the colour scheme
204    * @param forData
205    *          the data to be coloured
206    * @return
207    */
208   public ColourSchemeI getColourScheme(String name,
209           AnnotatedCollectionI forData)
210   {
211     return getColourScheme(name, null, forData, null);
212   }
213
214   /**
215    * Returns an iterable set of the colour schemes, in the order in which they
216    * were added
217    * 
218    * @return
219    */
220   public Iterable<ColourSchemeI> getColourSchemes()
221   {
222     return schemes.values();
223   }
224
225   /**
226    * Answers true if there is a scheme with the given name, else false. The test
227    * is not case-sensitive.
228    * 
229    * @param name
230    * @return
231    */
232   public boolean nameExists(String name)
233   {
234     if (name == null)
235     {
236       return false;
237     }
238     return schemes.containsKey(name.toLowerCase(Locale.ROOT));
239   }
240 }