JAL-2446 merged to spike branch
[jalview.git] / src / jalview / renderer / AnnotationRenderer.java
index 9610a79..518c179 100644 (file)
@@ -1,6 +1,6 @@
 /*
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.9)
- * Copyright (C) 2015 The Jalview Authors
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
  * 
  * This file is part of Jalview.
  * 
  * 
  * This file is part of Jalview.
  * 
@@ -22,13 +22,19 @@ package jalview.renderer;
 
 import jalview.analysis.AAFrequency;
 import jalview.analysis.CodingUtils;
 
 import jalview.analysis.AAFrequency;
 import jalview.analysis.CodingUtils;
+import jalview.analysis.Rna;
 import jalview.analysis.StructureFrequency;
 import jalview.api.AlignViewportI;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.ColumnSelection;
 import jalview.analysis.StructureFrequency;
 import jalview.api.AlignViewportI;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.ProfilesI;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ColourSchemeI;
+import jalview.schemes.NucleotideColourScheme;
 import jalview.schemes.ResidueProperties;
 import jalview.schemes.ResidueProperties;
+import jalview.schemes.ZappoColourScheme;
+import jalview.util.Platform;
 
 import java.awt.BasicStroke;
 import java.awt.Color;
 
 import java.awt.BasicStroke;
 import java.awt.Color;
@@ -43,8 +49,6 @@ import java.awt.image.ImageObserver;
 import java.util.BitSet;
 import java.util.Hashtable;
 
 import java.util.BitSet;
 import java.util.Hashtable;
 
-import com.stevesoft.pat.Regex;
-
 public class AnnotationRenderer
 {
   private static final int UPPER_TO_LOWER = 'a' - 'A'; // 32
 public class AnnotationRenderer
 {
   private static final int UPPER_TO_LOWER = 'a' - 'A'; // 32
@@ -58,6 +62,72 @@ public class AnnotationRenderer
    */
   private final boolean debugRedraw;
 
    */
   private final boolean debugRedraw;
 
+  private int charWidth, endRes, charHeight;
+
+  private boolean validCharWidth, hasHiddenColumns;
+
+  private FontMetrics fm;
+
+  private final boolean MAC = Platform.isAMac();
+
+  boolean av_renderHistogram = true, av_renderProfile = true,
+          av_normaliseProfile = false;
+
+  ResidueShaderI profcolour = null;
+
+  private ColumnSelection columnSelection;
+  
+  private HiddenColumns hiddenColumns;
+
+  private ProfilesI hconsensus;
+
+  private Hashtable[] complementConsensus;
+
+  private Hashtable[] hStrucConsensus;
+
+  private boolean av_ignoreGapsConsensus;
+
+  /**
+   * attributes set from AwtRenderPanelI
+   */
+  /**
+   * old image used when data is currently being calculated and cannot be
+   * rendered
+   */
+  private Image fadedImage;
+
+  /**
+   * panel being rendered into
+   */
+  private ImageObserver annotationPanel;
+
+  /**
+   * width of image to render in panel
+   */
+  private int imgWidth;
+
+  /**
+   * offset to beginning of visible area
+   */
+  private int sOffset;
+
+  /**
+   * offset to end of visible area
+   */
+  private int visHeight;
+
+  /**
+   * indicate if the renderer should only render the visible portion of the
+   * annotation given the current view settings
+   */
+  private boolean useClip = true;
+
+  /**
+   * master flag indicating if renderer should ever try to clip. not enabled for
+   * jalview 2.8.1
+   */
+  private boolean canClip = false;
+
   public AnnotationRenderer()
   {
     this(false);
   public AnnotationRenderer()
   {
     this(false);
@@ -75,15 +145,26 @@ public class AnnotationRenderer
     this.debugRedraw = debugRedraw;
   }
 
     this.debugRedraw = debugRedraw;
   }
 
-  public void drawStemAnnot(Graphics g, Annotation[] row_annotations,
-          int lastSSX, int x, int y, int iconOffset, int startRes,
-          int column, boolean validRes, boolean validEnd)
+  /**
+   * Remove any references and resources when this object is no longer required
+   */
+  public void dispose()
+  {
+    hconsensus = null;
+    complementConsensus = null;
+    hStrucConsensus = null;
+    fadedImage = null;
+    annotationPanel = null;
+  }
+
+  void drawStemAnnot(Graphics g, Annotation[] row_annotations, int lastSSX,
+          int x, int y, int iconOffset, int startRes, int column,
+          boolean validRes, boolean validEnd)
   {
     g.setColor(STEM_COLOUR);
     int sCol = (lastSSX / charWidth) + startRes;
     int x1 = lastSSX;
     int x2 = (x * charWidth);
   {
     g.setColor(STEM_COLOUR);
     int sCol = (lastSSX / charWidth) + startRes;
     int x1 = lastSSX;
     int x2 = (x * charWidth);
-    Regex closeparen = new Regex("(\\))");
 
     char dc = (column == 0 || row_annotations[column - 1] == null) ? ' '
             : row_annotations[column - 1].secondaryStructure;
 
     char dc = (column == 0 || row_annotations[column - 1] == null) ? ' '
             : row_annotations[column - 1].secondaryStructure;
@@ -93,15 +174,17 @@ public class AnnotationRenderer
     boolean diffdownstream = !validRes || !validEnd
             || row_annotations[column] == null
             || dc != row_annotations[column].secondaryStructure;
     boolean diffdownstream = !validRes || !validEnd
             || row_annotations[column] == null
             || dc != row_annotations[column].secondaryStructure;
-    // System.out.println("Column "+column+" diff up: "+diffupstream+" down:"+diffdownstream);
-    // If a closing base pair half of the stem, display a backward arrow
-    if (column > 0 && ResidueProperties.isCloseParenRNA(dc))
-    {
 
 
+    if (column > 0 && Rna.isClosingParenthesis(dc))
+    {
       if (diffupstream)
       // if (validRes && column>1 && row_annotations[column-2]!=null &&
       // dc.equals(row_annotations[column-2].displayCharacter))
       {
       if (diffupstream)
       // if (validRes && column>1 && row_annotations[column-2]!=null &&
       // dc.equals(row_annotations[column-2].displayCharacter))
       {
+        /*
+         * if new annotation with a closing base pair half of the stem, 
+         * display a backward arrow
+         */
         g.fillPolygon(new int[] { lastSSX + 5, lastSSX + 5, lastSSX },
                 new int[] { y + iconOffset, y + 14 + iconOffset,
                     y + 8 + iconOffset }, 3);
         g.fillPolygon(new int[] { lastSSX + 5, lastSSX + 5, lastSSX },
                 new int[] { y + iconOffset, y + 14 + iconOffset,
                     y + 8 + iconOffset }, 3);
@@ -114,10 +197,13 @@ public class AnnotationRenderer
     }
     else
     {
     }
     else
     {
-
       // display a forward arrow
       if (diffdownstream)
       {
       // display a forward arrow
       if (diffdownstream)
       {
+        /*
+         * if annotation ending with an opeing base pair half of the stem, 
+         * display a forward arrow
+         */
         g.fillPolygon(new int[] { x2 - 5, x2 - 5, x2 }, new int[] {
             y + iconOffset, y + 14 + iconOffset, y + 8 + iconOffset }, 3);
         x2 -= 5;
         g.fillPolygon(new int[] { x2 - 5, x2 - 5, x2 }, new int[] {
             y + iconOffset, y + 14 + iconOffset, y + 8 + iconOffset }, 3);
         x2 -= 5;
@@ -131,71 +217,7 @@ public class AnnotationRenderer
     g.fillRect(x1, y + 4 + iconOffset, x2 - x1, 7);
   }
 
     g.fillRect(x1, y + 4 + iconOffset, x2 - x1, 7);
   }
 
-  private int charWidth, endRes, charHeight;
-
-  private boolean validCharWidth, hasHiddenColumns;
-
-  private FontMetrics fm;
-
-  private final boolean MAC = jalview.util.Platform.isAMac();
-
-  boolean av_renderHistogram = true, av_renderProfile = true,
-          av_normaliseProfile = false;
-
-  ColourSchemeI profcolour = null;
-
-  private ColumnSelection columnSelection;
-
-  private Hashtable[] hconsensus;
-
-  private Hashtable[] complementConsensus;
-
-  private Hashtable[] hStrucConsensus;
-
-  private boolean av_ignoreGapsConsensus;
-
-  /**
-   * attributes set from AwtRenderPanelI
-   */
-  /**
-   * old image used when data is currently being calculated and cannot be
-   * rendered
-   */
-  private Image fadedImage;
-
-  /**
-   * panel being rendered into
-   */
-  private ImageObserver annotationPanel;
-
-  /**
-   * width of image to render in panel
-   */
-  private int imgWidth;
-
-  /**
-   * offset to beginning of visible area
-   */
-  private int sOffset;
-
-  /**
-   * offset to end of visible area
-   */
-  private int visHeight;
-
-  /**
-   * indicate if the renderer should only render the visible portion of the
-   * annotation given the current view settings
-   */
-  private boolean useClip = true;
-
-  /**
-   * master flag indicating if renderer should ever try to clip. not enabled for
-   * jalview 2.8.1
-   */
-  private boolean canClip = false;
-
-  public void drawNotCanonicalAnnot(Graphics g, Color nonCanColor,
+  void drawNotCanonicalAnnot(Graphics g, Color nonCanColor,
           Annotation[] row_annotations, int lastSSX, int x, int y,
           int iconOffset, int startRes, int column, boolean validRes,
           boolean validEnd)
           Annotation[] row_annotations, int lastSSX, int x, int y,
           int iconOffset, int startRes, int column, boolean validRes,
           boolean validEnd)
@@ -206,7 +228,6 @@ public class AnnotationRenderer
     int sCol = (lastSSX / charWidth) + startRes;
     int x1 = lastSSX;
     int x2 = (x * charWidth);
     int sCol = (lastSSX / charWidth) + startRes;
     int x1 = lastSSX;
     int x2 = (x * charWidth);
-    Regex closeparen = new Regex("}|]|<|[a-z]");
 
     String dc = (column == 0 || row_annotations[column - 1] == null) ? ""
             : row_annotations[column - 1].displayCharacter;
 
     String dc = (column == 0 || row_annotations[column - 1] == null) ? ""
             : row_annotations[column - 1].displayCharacter;
@@ -218,8 +239,7 @@ public class AnnotationRenderer
             || !dc.equals(row_annotations[column].displayCharacter);
     // System.out.println("Column "+column+" diff up: "+diffupstream+" down:"+diffdownstream);
     // If a closing base pair half of the stem, display a backward arrow
             || !dc.equals(row_annotations[column].displayCharacter);
     // System.out.println("Column "+column+" diff up: "+diffupstream+" down:"+diffdownstream);
     // If a closing base pair half of the stem, display a backward arrow
-    if (column > 0 && closeparen.search(dc))// closeletter_b.search(dc)||closeletter_c.search(dc)||closeletter_d.search(dc)||closecrochet.search(dc))
-                                            // )
+    if (column > 0 && Rna.isClosingParenthesis(dc))
     {
 
       if (diffupstream)
     {
 
       if (diffupstream)
@@ -290,22 +310,27 @@ public class AnnotationRenderer
   public void updateFromAlignViewport(AlignViewportI av)
   {
     charWidth = av.getCharWidth();
   public void updateFromAlignViewport(AlignViewportI av)
   {
     charWidth = av.getCharWidth();
-    endRes = av.getEndRes();
+    endRes = av.getRanges().getEndRes();
     charHeight = av.getCharHeight();
     hasHiddenColumns = av.hasHiddenColumns();
     validCharWidth = av.isValidCharWidth();
     av_renderHistogram = av.isShowConsensusHistogram();
     av_renderProfile = av.isShowSequenceLogo();
     av_normaliseProfile = av.isNormaliseSequenceLogo();
     charHeight = av.getCharHeight();
     hasHiddenColumns = av.hasHiddenColumns();
     validCharWidth = av.isValidCharWidth();
     av_renderHistogram = av.isShowConsensusHistogram();
     av_renderProfile = av.isShowSequenceLogo();
     av_normaliseProfile = av.isNormaliseSequenceLogo();
-    profcolour = av.getGlobalColourScheme();
-    if (profcolour == null)
+    profcolour = av.getResidueShading();
+    if (profcolour == null || profcolour.getColourScheme() == null)
     {
     {
-      // Set the default colour for sequence logo if the alignnent has no
-      // colourscheme set
-      profcolour = av.getAlignment().isNucleotide() ? new jalview.schemes.NucleotideColourScheme()
-              : new jalview.schemes.ZappoColourScheme();
+      /*
+       * Use default colour for sequence logo if 
+       * the alignment has no colourscheme set
+       * (would like to use user preference but n/a for applet)
+       */
+      ColourSchemeI col = av.getAlignment().isNucleotide() ? new NucleotideColourScheme()
+              : new ZappoColourScheme();
+      profcolour = new ResidueShader(col);
     }
     columnSelection = av.getColumnSelection();
     }
     columnSelection = av.getColumnSelection();
+    hiddenColumns = av.getAlignment().getHiddenColumns();
     hconsensus = av.getSequenceConsensusHash();
     complementConsensus = av.getComplementConsensusHash();
     hStrucConsensus = av.getRnaStructureConsensusHash();
     hconsensus = av.getSequenceConsensusHash();
     complementConsensus = av.getComplementConsensusHash();
     hStrucConsensus = av.getRnaStructureConsensusHash();
@@ -321,7 +346,7 @@ public class AnnotationRenderer
    * @param column
    * @return
    */
    * @param column
    * @return
    */
-  public int[] getProfileFor(AlignmentAnnotation aa, int column)
+  int[] getProfileFor(AlignmentAnnotation aa, int column)
   {
     // TODO : consider refactoring the global alignment calculation
     // properties/rendering attributes as a global 'alignment group' which holds
   {
     // TODO : consider refactoring the global alignment calculation
     // properties/rendering attributes as a global 'alignment group' which holds
@@ -337,7 +362,7 @@ public class AnnotationRenderer
       {
         // TODO? group consensus for cDNA complement
         return AAFrequency.extractProfile(
       {
         // TODO? group consensus for cDNA complement
         return AAFrequency.extractProfile(
-                aa.groupRef.consensusData[column],
+                aa.groupRef.consensusData.get(column),
                 aa.groupRef.getIgnoreGapsConsensus());
       }
       // TODO extend annotation row to enable dynamic and static profile data to
                 aa.groupRef.getIgnoreGapsConsensus());
       }
       // TODO extend annotation row to enable dynamic and static profile data to
@@ -351,7 +376,8 @@ public class AnnotationRenderer
         }
         else
         {
         }
         else
         {
-          return AAFrequency.extractProfile(hconsensus[column],
+          return AAFrequency.extractProfile(
+hconsensus.get(column),
                   av_ignoreGapsConsensus);
         }
       }
                   av_ignoreGapsConsensus);
         }
       }
@@ -567,7 +593,7 @@ public class AnnotationRenderer
         {
           if (hasHiddenColumns)
           {
         {
           if (hasHiddenColumns)
           {
-            column = columnSelection.adjustForHiddenColumns(startRes + x);
+            column = hiddenColumns.adjustForHiddenColumns(startRes + x);
             if (column > row_annotations.length - 1)
             {
               break;
             if (column > row_annotations.length - 1)
             {
               break;
@@ -598,14 +624,9 @@ public class AnnotationRenderer
 
               if (columnSelection != null)
               {
 
               if (columnSelection != null)
               {
-                for (int n = 0; n < columnSelection.size(); n++)
+                if (columnSelection.contains(column))
                 {
                 {
-                  int v = columnSelection.columnAt(n);
-
-                  if (v == column)
-                  {
-                    g.fillRect(x * charWidth, y, charWidth, charHeight);
-                  }
+                  g.fillRect(x * charWidth, y, charWidth, charHeight);
                 }
               }
             }
                 }
               }
             }
@@ -755,7 +776,7 @@ public class AnnotationRenderer
                             validEnd);
                     break;
                   }
                             validEnd);
                     break;
                   }
-
+                  // no break if isRNA - falls through to drawNotCanonicalAnnot!
                 case 'E':
                   if (!isRNA)
                   {
                 case 'E':
                   if (!isRNA)
                   {
@@ -764,6 +785,7 @@ public class AnnotationRenderer
                             validEnd);
                     break;
                   }
                             validEnd);
                     break;
                   }
+                  // no break if isRNA - fall through to drawNotCanonicalAnnot!
 
                 case '{':
                 case '}':
 
                 case '{':
                 case '}':
@@ -871,7 +893,6 @@ public class AnnotationRenderer
         {
           validRes = true;
         }
         {
           validRes = true;
         }
-
         // x ++;
 
         if (row.hasIcons)
         // x ++;
 
         if (row.hasIcons)
@@ -886,6 +907,7 @@ public class AnnotationRenderer
                       startRes, column, validRes, validEnd);
               break;
             }
                       startRes, column, validRes, validEnd);
               break;
             }
+            // no break if isRNA - fall through to drawNotCanonicalAnnot!
 
           case 'E':
             if (!isRNA)
 
           case 'E':
             if (!isRNA)
@@ -894,6 +916,7 @@ public class AnnotationRenderer
                       startRes, column, validRes, validEnd);
               break;
             }
                       startRes, column, validRes, validEnd);
               break;
             }
+            // no break if isRNA - fall through to drawNotCanonicalAnnot!
 
           case '(':
           case ')': // Stem case for RNA secondary structure
 
           case '(':
           case ')': // Stem case for RNA secondary structure
@@ -1074,15 +1097,15 @@ public class AnnotationRenderer
 
   private Color sdNOTCANONICAL_COLOUR;
 
 
   private Color sdNOTCANONICAL_COLOUR;
 
-  public void drawGlyphLine(Graphics g, Annotation[] row, int lastSSX,
-          int x, int y, int iconOffset, int startRes, int column,
+  void drawGlyphLine(Graphics g, Annotation[] row, int lastSSX, int x,
+          int y, int iconOffset, int startRes, int column,
           boolean validRes, boolean validEnd)
   {
     g.setColor(GLYPHLINE_COLOR);
     g.fillRect(lastSSX, y + 6 + iconOffset, (x * charWidth) - lastSSX, 2);
   }
 
           boolean validRes, boolean validEnd)
   {
     g.setColor(GLYPHLINE_COLOR);
     g.fillRect(lastSSX, y + 6 + iconOffset, (x * charWidth) - lastSSX, 2);
   }
 
-  public void drawSheetAnnot(Graphics g, Annotation[] row,
+  void drawSheetAnnot(Graphics g, Annotation[] row,
 
   int lastSSX, int x, int y, int iconOffset, int startRes, int column,
           boolean validRes, boolean validEnd)
 
   int lastSSX, int x, int y, int iconOffset, int startRes, int column,
           boolean validRes, boolean validEnd)
@@ -1106,8 +1129,8 @@ public class AnnotationRenderer
 
   }
 
 
   }
 
-  public void drawHelixAnnot(Graphics g, Annotation[] row, int lastSSX,
-          int x, int y, int iconOffset, int startRes, int column,
+  void drawHelixAnnot(Graphics g, Annotation[] row, int lastSSX, int x,
+          int y, int iconOffset, int startRes, int column,
           boolean validRes, boolean validEnd)
   {
     g.setColor(HELIX_COLOUR);
           boolean validRes, boolean validEnd)
   {
     g.setColor(HELIX_COLOUR);
@@ -1166,7 +1189,7 @@ public class AnnotationRenderer
     g.fillRect(x1, y + 4 + iconOffset, x2 - x1, 8);
   }
 
     g.fillRect(x1, y + 4 + iconOffset, x2 - x1, 8);
   }
 
-  public void drawLineGraph(Graphics g, AlignmentAnnotation _aa,
+  void drawLineGraph(Graphics g, AlignmentAnnotation _aa,
           Annotation[] aa_annotations, int sRes, int eRes, int y,
           float min, float max, int graphHeight)
   {
           Annotation[] aa_annotations, int sRes, int eRes, int y,
           float min, float max, int graphHeight)
   {
@@ -1212,7 +1235,7 @@ public class AnnotationRenderer
       column = sRes + x;
       if (hasHiddenColumns)
       {
       column = sRes + x;
       if (hasHiddenColumns)
       {
-        column = columnSelection.adjustForHiddenColumns(column);
+        column = hiddenColumns.adjustForHiddenColumns(column);
       }
 
       if (column > aaMax)
       }
 
       if (column > aaMax)
@@ -1259,7 +1282,7 @@ public class AnnotationRenderer
     }
   }
 
     }
   }
 
-  public void drawBarGraph(Graphics g, AlignmentAnnotation _aa,
+  void drawBarGraph(Graphics g, AlignmentAnnotation _aa,
           Annotation[] aa_annotations, int sRes, int eRes, float min,
           float max, int y, boolean renderHistogram, boolean renderProfile,
           boolean normaliseProfile)
           Annotation[] aa_annotations, int sRes, int eRes, float min,
           float max, int y, boolean renderHistogram, boolean renderProfile,
           boolean normaliseProfile)
@@ -1291,7 +1314,7 @@ public class AnnotationRenderer
       column = sRes + x;
       if (hasHiddenColumns)
       {
       column = sRes + x;
       if (hasHiddenColumns)
       {
-        column = columnSelection.adjustForHiddenColumns(column);
+        column = hiddenColumns.adjustForHiddenColumns(column);
       }
 
       if (column > aaMax)
       }
 
       if (column > aaMax)
@@ -1390,8 +1413,9 @@ public class AnnotationRenderer
             scl = htn * scale * profl[c++];
             lm = ofont.getLineMetrics(dc, 0, 1, g.getFontMetrics()
                     .getFontRenderContext());
             scl = htn * scale * profl[c++];
             lm = ofont.getLineMetrics(dc, 0, 1, g.getFontMetrics()
                     .getFontRenderContext());
-            g.setFont(ofont.deriveFont(AffineTransform.getScaleInstance(
-                    wdth, scl / lm.getAscent())));
+            Font font = ofont.deriveFont(AffineTransform.getScaleInstance(
+                    wdth, scl / lm.getAscent()));
+            g.setFont(font);
             lm = g.getFontMetrics().getLineMetrics(dc, 0, 1, g);
 
             // Debug - render boxes around characters
             lm = g.getFontMetrics().getLineMetrics(dc, 0, 1, g);
 
             // Debug - render boxes around characters