JAL-629 Change all stdout and stderr output to use Console.outPrintln and Console...
[jalview.git] / src / jalview / renderer / AnnotationRenderer.java
index 4d3445b..65631e3 100644 (file)
  */
 package jalview.renderer;
 
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.geom.AffineTransform;
+import java.awt.image.ImageObserver;
+import java.util.BitSet;
+import java.util.Hashtable;
+
 import jalview.analysis.AAFrequency;
 import jalview.analysis.CodingUtils;
 import jalview.analysis.Rna;
 import jalview.analysis.StructureFrequency;
 import jalview.api.AlignViewportI;
-import jalview.bin.Jalview;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.ProfilesI;
+import jalview.renderer.api.AnnotationRendererFactoryI;
+import jalview.renderer.api.AnnotationRowRendererI;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.NucleotideColourScheme;
 import jalview.schemes.ResidueProperties;
 import jalview.schemes.ZappoColourScheme;
 import jalview.util.Platform;
 
-import java.awt.BasicStroke;
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.FontMetrics;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.Image;
-import java.awt.geom.AffineTransform;
-import java.awt.image.ImageObserver;
-import java.util.BitSet;
-import java.util.Hashtable;
-
 public class AnnotationRenderer
 {
   private static final int UPPER_TO_LOWER = 'a' - 'A'; // 32
@@ -81,9 +82,9 @@ public class AnnotationRenderer
 
   private ProfilesI hconsensus;
 
-  private Hashtable[] complementConsensus;
+  private Hashtable<String, Object>[] complementConsensus;
 
-  private Hashtable[] hStrucConsensus;
+  private Hashtable<String, Object>[] hStrucConsensus;
 
   private boolean av_ignoreGapsConsensus;
 
@@ -150,11 +151,13 @@ public class AnnotationRenderer
    */
   public void dispose()
   {
+    hiddenColumns = null;
     hconsensus = null;
     complementConsensus = null;
     hStrucConsensus = null;
     fadedImage = null;
     annotationPanel = null;
+    rendererFactoryI = null;
   }
 
   void drawStemAnnot(Graphics g, Annotation[] row_annotations, int lastSSX,
@@ -226,7 +229,7 @@ public class AnnotationRenderer
           int iconOffset, int startRes, int column, boolean validRes,
           boolean validEnd)
   {
-    // System.out.println(nonCanColor);
+    // jalview.bin.Console.outPrintln(nonCanColor);
 
     g.setColor(nonCanColor);
     int sCol = (lastSSX / charWidth)
@@ -242,7 +245,7 @@ public class AnnotationRenderer
     boolean diffdownstream = !validRes || !validEnd
             || row_annotations[column] == null
             || !dc.equals(row_annotations[column].displayCharacter);
-    // System.out.println("Column "+column+" diff up: "+diffupstream+"
+    // jalview.bin.Console.outPrintln("Column "+column+" diff up: "+diffupstream+"
     // down:"+diffdownstream);
     // If a closing base pair half of the stem, display a backward arrow
     if (column > 0 && Rna.isClosingParenthesis(dc))
@@ -313,6 +316,7 @@ public class AnnotationRenderer
       useClip = false;
     }
 
+    rendererFactoryI = AnnotationRendererFactory.getRendererFactory();
     updateFromAlignViewport(av);
   }
 
@@ -419,6 +423,8 @@ public class AnnotationRenderer
 
   boolean rna = false;
 
+  private AnnotationRendererFactoryI rendererFactoryI;
+
   /**
    * Render the annotation rows associated with an alignment.
    * 
@@ -449,7 +455,7 @@ public class AnnotationRenderer
     updateFromAwtRenderPanel(annotPanel, av);
     fm = g.getFontMetrics();
     AlignmentAnnotation[] aa = av.getAlignment().getAlignmentAnnotation();
-    int temp = 0;
+    // int temp = 0;
     if (aa == null)
     {
       return false;
@@ -462,8 +468,8 @@ public class AnnotationRenderer
     boolean validRes = false;
     boolean validEnd = false;
     boolean labelAllCols = false;
-    boolean centreColLabels;
-    boolean centreColLabelsDef = av.isCentreColumnLabels();
+    // boolean centreColLabels;
+    // boolean centreColLabelsDef = av.isCentreColumnLabels();
     boolean scaleColLabel = false;
     final AlignmentAnnotation consensusAnnot = av
             .getAlignmentConsensusAnnotation();
@@ -471,8 +477,6 @@ public class AnnotationRenderer
             .getAlignmentStrucConsensusAnnotation();
     final AlignmentAnnotation complementConsensusAnnot = av
             .getComplementConsensusAnnotation();
-    boolean renderHistogram = true, renderProfile = true,
-            normaliseProfile = false, isRNA = rna;
 
     BitSet graphGroupDrawn = new BitSet();
     int charOffset = 0; // offset for a label
@@ -483,38 +487,35 @@ public class AnnotationRenderer
     for (int i = 0; i < aa.length; i++)
     {
       AlignmentAnnotation row = aa[i];
-      isRNA = row.isRNA();
+      boolean renderHistogram = true;
+      boolean renderProfile = false;
+      boolean normaliseProfile = false;
+      boolean isRNA = row.isRNA();
+
+      // check if this is a consensus annotation row and set the display
+      // settings appropriately
+      // TODO: generalise this to have render styles for consensus/profile
+      // data
+      if (row.groupRef != null && row == row.groupRef.getConsensus())
       {
-        // check if this is a consensus annotation row and set the display
-        // settings appropriately
-        // TODO: generalise this to have render styles for consensus/profile
-        // data
-        if (row.groupRef != null && row == row.groupRef.getConsensus())
-        {
-          renderHistogram = row.groupRef.isShowConsensusHistogram();
-          renderProfile = row.groupRef.isShowSequenceLogo();
-          normaliseProfile = row.groupRef.isNormaliseSequenceLogo();
-        }
-        else if (row == consensusAnnot || row == structConsensusAnnot
-                || row == complementConsensusAnnot)
-        {
-          renderHistogram = av_renderHistogram;
-          renderProfile = av_renderProfile;
-          normaliseProfile = av_normaliseProfile;
-        }
-        else
-        {
-          renderHistogram = true;
-          // don't need to set render/normaliseProfile since they are not
-          // currently used in any other annotation track renderer
-        }
+        renderHistogram = row.groupRef.isShowConsensusHistogram();
+        renderProfile = row.groupRef.isShowSequenceLogo();
+        normaliseProfile = row.groupRef.isNormaliseSequenceLogo();
+      }
+      else if (row == consensusAnnot || row == structConsensusAnnot
+              || row == complementConsensusAnnot)
+      {
+        renderHistogram = av_renderHistogram;
+        renderProfile = av_renderProfile;
+        normaliseProfile = av_normaliseProfile;
       }
+
       Annotation[] row_annotations = row.annotations;
       if (!row.visible)
       {
         continue;
       }
-      centreColLabels = row.centreColLabels || centreColLabelsDef;
+      // centreColLabels = row.centreColLabels || centreColLabelsDef;
       labelAllCols = row.showAllColLabels;
       scaleColLabel = row.scaleColLabel;
       lastSS = ' ';
@@ -782,8 +783,8 @@ public class AnnotationRenderer
               if (x > -1)
               {
 
-                int nb_annot = x - temp;
-                // System.out.println("\t type :"+lastSS+"\t x :"+x+"\t nbre
+                // int nb_annot = x - temp;
+                // jalview.bin.Console.outPrintln("\t type :"+lastSS+"\t x :"+x+"\t nbre
                 // annot :"+nb_annot);
                 switch (lastSS)
                 {
@@ -791,7 +792,7 @@ public class AnnotationRenderer
                 case ')': // and opposite direction
                   drawStemAnnot(g, row_annotations, lastSSX, x, y,
                           iconOffset, startRes, column, validRes, validEnd);
-                  temp = x;
+                  // temp = x;
                   break;
 
                 case 'H':
@@ -874,13 +875,13 @@ public class AnnotationRenderer
                   drawNotCanonicalAnnot(g, nonCanColor, row_annotations,
                           lastSSX, x, y, iconOffset, startRes, column,
                           validRes, validEnd);
-                  temp = x;
+                  // temp = x;
                   break;
                 default:
                   g.setColor(Color.gray);
                   g.fillRect(lastSSX, y + 6 + iconOffset,
                           (x * charWidth) - lastSSX, 2);
-                  temp = x;
+                  // temp = x;
                   break;
                 }
               }
@@ -1005,7 +1006,7 @@ public class AnnotationRenderer
           case 'y':
           case 'Z':
           case 'z':
-            // System.out.println(lastSS);
+            // jalview.bin.Console.outPrintln(lastSS);
             Color nonCanColor = getNotCanonicalColor(lastSS);
             drawNotCanonicalAnnot(g, nonCanColor, row_annotations, lastSSX,
                     x, y, iconOffset, startRes, column, validRes, validEnd);
@@ -1070,6 +1071,32 @@ public class AnnotationRenderer
                     row.graphMin, row.graphMax, y, renderHistogram,
                     renderProfile, normaliseProfile);
           }
+          else
+          {
+            AnnotationRowRendererI renderer = rendererFactoryI
+                    .getRendererFor(row);
+            if (renderer != null)
+            {
+              renderer.renderRow(g, charWidth, charHeight, hasHiddenColumns,
+                      av, hiddenColumns, columnSelection, row,
+                      row_annotations, startRes, endRes, row.graphMin,
+                      row.graphMax, y);
+            }
+            if (debugRedraw)
+            {
+              if (renderer == null)
+              {
+                System.err
+                        .println("No renderer found for " + row.toString());
+              }
+              else
+              {
+                jalview.bin.Console.errPrintln(
+                        "rendered with " + renderer.getClass().toString());
+              }
+            }
+
+          }
         }
       }
       else
@@ -1095,17 +1122,17 @@ public class AnnotationRenderer
       {
         if (clipst)
         {
-          System.err.println(
+          jalview.bin.Console.errPrintln(
                   "Start clip at : " + yfrom + " (index " + f_i + ")");
         }
         if (clipend)
         {
-          System.err.println(
+          jalview.bin.Console.errPrintln(
                   "End clip at : " + yto + " (index " + f_to + ")");
         }
       }
       ;
-      System.err.println("Annotation Rendering time:"
+      jalview.bin.Console.errPrintln("Annotation Rendering time:"
               + (System.currentTimeMillis() - stime));
     }
     ;
@@ -1121,7 +1148,7 @@ public class AnnotationRenderer
 
   public static final Color STEM_COLOUR = Color.blue;
 
-  private Color sdNOTCANONICAL_COLOUR;
+  // private Color sdNOTCANONICAL_COLOUR;
 
   void drawGlyphLine(Graphics g, Annotation[] row, int lastSSX, int x,
           int y, int iconOffset, int startRes, int column, boolean validRes,
@@ -1273,8 +1300,7 @@ public class AnnotationRenderer
         break;
       }
 
-      if (aa_annotations[column] == null
-              || aa_annotations[column - 1] == null)
+      if (aa_annotations[column] == null)
       {
         x++;
         continue;
@@ -1289,6 +1315,25 @@ public class AnnotationRenderer
         g.setColor(aa_annotations[column].colour);
       }
 
+      if (aa_annotations[column - 1] == null
+              && aa_annotations.length > column + 1
+              && aa_annotations[column + 1] == null)
+      {
+        // standalone value
+        y1 = y - (int) (((aa_annotations[column].value - min) / range)
+                * graphHeight);
+        g.drawLine(x * charWidth + charWidth / 4, y1,
+                x * charWidth + 3 * charWidth / 4, y1);
+        x++;
+        continue;
+      }
+
+      if (aa_annotations[column - 1] == null)
+      {
+        x++;
+        continue;
+      }
+
       y1 = y - (int) (((aa_annotations[column - 1].value - min) / range)
               * graphHeight);
       y2 = y - (int) (((aa_annotations[column].value - min) / range)
@@ -1397,7 +1442,8 @@ public class AnnotationRenderer
           boolean isStructureProfile = profl[0] == AlignmentAnnotation.STRUCTURE_PROFILE;
           boolean isCdnaProfile = profl[0] == AlignmentAnnotation.CDNA_PROFILE;
           float ht = normaliseProfile ? y - _aa.graphHeight : y1;
-          final double normaliseFactor = normaliseProfile ? _aa.graphHeight : (y2 - y1);
+          final double normaliseFactor = normaliseProfile ? _aa.graphHeight
+                  : (y2 - y1);
 
           /**
            * Render a single base for a sequence profile, a base pair for
@@ -1409,7 +1455,7 @@ public class AnnotationRenderer
           // lm is not necessary - we can just use fm - could be off by no more
           // than 0.5 px
           // LineMetrics lm = g.getFontMetrics(ofont).getLineMetrics("Q", g);
-          // System.out.println(asc + " " + dec + " " + (asc - lm.getAscent())
+          // jalview.bin.Console.outPrintln(asc + " " + dec + " " + (asc - lm.getAscent())
           // + " " + (dec - lm.getDescent()));
 
           double asc = fm.getAscent();
@@ -1448,8 +1494,14 @@ public class AnnotationRenderer
               s = new String(dc);
             }
             // next profl[] position is profile % for the character(s)
-            
-            double newHeight = normaliseFactor * scale * profl[c++];
+
+            int percent = profl[c++];
+            if (percent == 0)
+            {
+              // failsafe in case a count rounds down to 0%
+              continue;
+            }
+            double newHeight = normaliseFactor * scale * percent;
 
             /*
              * Set character colour as per alignment colour scheme; use the
@@ -1475,9 +1527,9 @@ public class AnnotationRenderer
             // (int)(scl));
             // g.setColor(profcolour.findColour(dc[0]).darker());
 
-            double sx = 1f * charWidth / fm.charsWidth(dc, 0, dc.length);            
+            double sx = 1f * charWidth / fm.charsWidth(dc, 0, dc.length);
             double sy = newHeight / asc;
-            double newAsc = asc * sy; 
+            double newAsc = asc * sy;
             double newDec = dec * sy;
             // it is not necessary to recalculate lm for the new font.
             // note: lm.getBaselineOffsets()[lm.getBaselineIndex()]) must be 0
@@ -1485,7 +1537,7 @@ public class AnnotationRenderer
             // int hght = (int) (ht + (newAsc - newDec);
             // - lm.getBaselineOffsets()[lm.getBaselineIndex()]));
 
-            if (Jalview.isJS())
+            if (Platform.isJS())
             {
               /*
                * SwingJS does not implement font.deriveFont()
@@ -1503,15 +1555,21 @@ public class AnnotationRenderer
               ht2 += newHeight;
             }
             else
+            /**
+             * Java only
+             * 
+             * @j2sIgnore
+             */
             {
-              /*
-               * Java ('normal') method is to scale the font to fit
-               */
+              // Java ('normal') method is to scale the font to fit
+
               final int hght = (int) (ht + (newAsc - newDec));
               Font font = ofont
                       .deriveFont(AffineTransform.getScaleInstance(sx, sy));
               g.setFont(font);
               g.drawChars(dc, 0, dc.length, x * charWidth, hght);
+              g.setFont(ofont);
+
               ht += newHeight;
             }
           }
@@ -1525,7 +1583,7 @@ public class AnnotationRenderer
       Graphics2D g2 = (Graphics2D) g;
       g2.setStroke(new BasicStroke(1, BasicStroke.CAP_SQUARE,
               BasicStroke.JOIN_ROUND, 3f, new float[]
-      { 5f, 3f }, 0f));
+              { 5f, 3f }, 0f));
 
       y2 = (int) (y
               - ((_aa.threshold.value - min) / range) * _aa.graphHeight);
@@ -1691,7 +1749,7 @@ public class AnnotationRenderer
       return new Color(0, 80, 255);
 
     default:
-      System.out.println("This is not a interaction : " + lastss);
+      jalview.bin.Console.outPrintln("This is not a interaction : " + lastss);
       return null;
 
     }