JAL-2360 ColourSchemes holds configured schemes, AlignFrame colour menu
[jalview.git] / src / jalview / schemes / ResidueColourScheme.java
index a15ca20..9cc4bd1 100755 (executable)
 package jalview.schemes;
 
 import jalview.analysis.Conservation;
-import jalview.analysis.Profile;
+import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AnnotatedCollectionI;
+import jalview.datamodel.ProfileI;
+import jalview.datamodel.ProfilesI;
 import jalview.datamodel.SequenceCollectionI;
 import jalview.datamodel.SequenceI;
 import jalview.util.ColorUtils;
 import jalview.util.Comparison;
-import jalview.util.MessageManager;
 
 import java.awt.Color;
 import java.util.Map;
 
 /**
- * DOCUMENT ME!
- * 
- * @author $author$
- * @version $Revision$
+ * Base class for residue-based colour schemes
  */
-public class ResidueColourScheme implements ColourSchemeI
+public abstract class ResidueColourScheme implements ColourSchemeI
 {
+  public static final String NONE = "None";
+
+  /*
+   * lookup up by character value e.g. 'G' to the colors array index
+   * e.g. if symbolIndex['K'] = 11 then colors[11] is the colour for K
+   */
   final int[] symbolIndex;
 
   boolean conservationColouring = false;
 
+  /*
+   * colour for residue characters as indexed by symbolIndex
+   */
   Color[] colors = null;
 
   int threshold = 0;
@@ -54,7 +61,7 @@ public class ResidueColourScheme implements ColourSchemeI
   /*
    * Consensus data indexed by column
    */
-  Profile[] consensus;
+  ProfilesI consensus;
 
   /*
    * Conservation string as a char array 
@@ -103,6 +110,17 @@ public class ResidueColourScheme implements ColourSchemeI
   }
 
   /**
+   * Returns the colour for symbol 'A'. Intended for use in a 'fixed colour'
+   * colour scheme (for example a feature colour).
+   */
+  @Override
+  public Color findColour()
+  {
+    // TODO delete this method in favour of ColorUtils.parseColourString()?
+    return findColour('A');
+  }
+
+  /**
    * Find a colour without an index in a sequence
    */
   @Override
@@ -182,19 +200,20 @@ public class ResidueColourScheme implements ColourSchemeI
       residue -= ('a' - 'A');
     }
 
-    if (consensus == null || consensus.length < column
-            || consensus[column] == null)
+    if (consensus == null)
     {
       return false;
     }
 
+    ProfileI profile = consensus.get(column);
+
     /*
      * test whether this is the consensus (or joint consensus) residue
      */
-    if (consensus[column].getModalResidue().contains(
-            String.valueOf(residue)))
+    if (profile != null
+            && profile.getModalResidue().contains(String.valueOf(residue)))
     {
-      if (consensus[column].getPercentageIdentity(ignoreGaps) >= threshold)
+      if (profile.getPercentageIdentity(ignoreGaps) >= threshold)
       {
         return true;
       }
@@ -234,7 +253,7 @@ public class ResidueColourScheme implements ColourSchemeI
    *          DOCUMENT ME!
    */
   @Override
-  public void setConsensus(Profile[] consensus)
+  public void setConsensus(ProfilesI consensus)
   {
     if (consensus == null)
     {
@@ -327,18 +346,69 @@ public class ResidueColourScheme implements ColourSchemeI
   {
   }
 
+  /**
+   * Answers false if the colour scheme is nucleotide or peptide specific, and
+   * the data does not match, else true. Override to modify or extend this test
+   * as required.
+   */
   @Override
-  public ColourSchemeI applyTo(AnnotatedCollectionI sg,
-          Map<SequenceI, SequenceCollectionI> hiddenRepSequences)
+  public boolean isApplicableTo(AnnotatedCollectionI ac)
   {
-    try
+    if (!isPeptideSpecific() && !isNucleotideSpecific())
     {
-      return getClass().newInstance();
-    } catch (Exception q)
+      return true;
+    }
+
+    /*
+     * inspect the data context (alignment dataset) for residue type
+     */
+    boolean nucleotide = false;
+    AnnotatedCollectionI context = ac.getContext();
+    if (context != null)
     {
-      throw new Error(MessageManager.formatMessage(
-              "error.implementation_error_cannot_duplicate_colour_scheme",
-              new String[] { getClass().getName() }), q);
+      if (context instanceof AlignmentI)
+      {
+        nucleotide = ((AlignmentI) context).isNucleotide();
+      }
+      else
+      {
+        // not sure what's going on, play safe
+        return true;
+      }
     }
+    else if (ac instanceof AlignmentI)
+    {
+      nucleotide = ((AlignmentI) ac).isNucleotide();
+    }
+    else
+    {
+      return true;
+    }
+
+    /*
+     * does data type match colour scheme type?
+     */
+    return (nucleotide && isNucleotideSpecific())
+            || (!nucleotide && isPeptideSpecific());
+  }
+
+  /**
+   * Answers true if the colour scheme is normally only for peptide data
+   * 
+   * @return
+   */
+  public boolean isPeptideSpecific()
+  {
+    return false;
+  }
+
+  /**
+   * Answers true if the colour scheme is normally only for nucleotide data
+   * 
+   * @return
+   */
+  public boolean isNucleotideSpecific()
+  {
+    return false;
   }
 }