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