package jalview.schemes; import jalview.binding.JalviewUserColours; import jalview.datamodel.AnnotatedCollectionI; import jalview.datamodel.SequenceCollectionI; import jalview.datamodel.SequenceI; import java.awt.Color; import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; import java.util.LinkedHashMap; import java.util.Map; public class ColourSchemes { /* * singleton instance of this class */ private static ColourSchemes instance = new ColourSchemes(); /* * a map from scheme name to an instance of it */ private Map schemes; /** * Returns the singleton instance of this class * * @return */ public static ColourSchemes getInstance() { return instance; } private ColourSchemes() { loadColourSchemes(); } /** * Loads an instance of each standard or user-defined colour scheme * * @return */ void loadColourSchemes() { /* * store in an order-preserving map, so items can be added to menus * in the order in which they are 'discovered' */ schemes = new LinkedHashMap(); for (JalviewColourScheme cs : JalviewColourScheme.values()) { try { registerColourScheme(cs.getSchemeClass().newInstance()); } catch (InstantiationException | IllegalAccessException e) { System.err.println("Error instantiating colour scheme for " + cs.toString() + " " + e.getMessage()); } } } /** * Registers a colour scheme * * @param cs */ public void registerColourScheme(ColourSchemeI cs) { String name = cs.getSchemeName(); if (name == null) { System.err.println("ColourScheme name may not be null"); return; } /* * name is lower-case for non-case-sensitive lookup * (name in the colour keeps its true case) */ String lower = name.toLowerCase(); if (schemes.containsKey(lower)) { System.err .println("Warning: overwriting colour scheme named " + name); } schemes.put(lower, cs); } /** * Removes a colour scheme by name * * @param name */ public void removeColourScheme(String name) { schemes.remove(name); } /** * Returns an instance of the colour scheme with which the given view may be * coloured * * @param name * name of the colour scheme * @param forData * the data to be coloured * @param optional * map from hidden representative sequences to the sequences they * represent * @return */ public ColourSchemeI getColourScheme(String name, AnnotatedCollectionI forData, Map hiddenRepSequences) { if (name == null) { return null; } ColourSchemeI cs = schemes.get(name.toLowerCase()); return cs == null ? null : cs.getInstance(forData, hiddenRepSequences); } /** * Returns an instance of the colour scheme with which the given view may be * coloured * * @param name * name of the colour scheme * @param forData * the data to be coloured * @return */ public ColourSchemeI getColourScheme(String name, AnnotatedCollectionI forData) { return getColourScheme(name, forData, null); } /** * Returns an iterable set of the colour schemes, in the order in which they * were added * * @return */ public Iterable getColourSchemes() { return schemes.values(); } /** * Answers true if there is a scheme with the given name, else false. The test * is not case-sensitive. * * @param name * @return */ public boolean nameExists(String name) { if (name == null) { return false; } name = name.toLowerCase(); for (ColourSchemeI scheme : getColourSchemes()) { if (name.equals(scheme.getSchemeName().toLowerCase())) { return true; } } return false; } /** * Loads a user defined colour scheme from file. The file should contain a * definition of residue colours in XML format as defined in * JalviewUserColours.xsd. * * @param filePath * * @return */ public static UserColourScheme loadColourScheme(String filePath) { UserColourScheme ucs = null; Color[] newColours = null; File file = new File(filePath); try { InputStreamReader in = new InputStreamReader( new FileInputStream(file), "UTF-8"); jalview.schemabinding.version2.JalviewUserColours jucs = new jalview.schemabinding.version2.JalviewUserColours(); org.exolab.castor.xml.Unmarshaller unmar = new org.exolab.castor.xml.Unmarshaller( jucs); jucs = (jalview.schemabinding.version2.JalviewUserColours) unmar .unmarshal(in); /* * non-case-sensitive colours are for 20 amino acid codes, * B, Z, X and Gap * optionally, lower-case alternatives for all except Gap */ newColours = new Color[24]; Color[] lowerCase = new Color[23]; boolean caseSensitive = false; String name; int index; for (int i = 0; i < jucs.getColourCount(); i++) { name = jucs.getColour(i).getName(); if (ResidueProperties.aa3Hash.containsKey(name)) { index = ResidueProperties.aa3Hash.get(name).intValue(); } else { index = ResidueProperties.aaIndex[name.charAt(0)]; } if (index == -1) { continue; } Color color = new Color(Integer.parseInt(jucs.getColour(i) .getRGB(), 16)); if (name.toLowerCase().equals(name)) { caseSensitive = true; lowerCase[index] = color; } else { newColours[index] = color; } } /* * instantiate the colour scheme */ ucs = new UserColourScheme(newColours); ucs.setName(jucs.getSchemeName()); if (caseSensitive) { ucs.setLowerCaseColours(lowerCase); } } catch (Exception ex) { // Could be old Jalview Archive format try { InputStreamReader in = new InputStreamReader(new FileInputStream( file), "UTF-8"); jalview.binding.JalviewUserColours jucs = new jalview.binding.JalviewUserColours(); jucs = JalviewUserColours.unmarshal(in); newColours = new Color[jucs.getColourCount()]; for (int i = 0; i < 24; i++) { newColours[i] = new Color(Integer.parseInt(jucs.getColour(i) .getRGB(), 16)); } ucs = new UserColourScheme(newColours); ucs.setName(jucs.getSchemeName()); } catch (Exception ex2) { ex2.printStackTrace(); } if (newColours == null) { System.out.println("Error loading User ColourFile\n" + ex); } } return ucs; } }