JAL-3438 spotless for 2.11.2.0
[jalview.git] / src / jalview / gui / SequenceRenderer.java
index bcbebbd..43fef15 100755 (executable)
@@ -1,6 +1,6 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
- * Copyright (C) 2014 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.
  * 
  */
 package jalview.gui;
 
-import jalview.datamodel.AlignmentAnnotation;
+import jalview.api.AlignViewportI;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
-import jalview.schemes.ColourSchemeI;
+import jalview.renderer.ResidueColourFinder;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
 
 import java.awt.Color;
 import java.awt.FontMetrics;
 import java.awt.Graphics;
 
-/**
- * DOCUMENT ME!
- * 
- * @author $author$
- * @version $Revision$
- */
+import org.jfree.graphics2d.svg.SVGGraphics2D;
+import org.jibble.epsgraphics.EpsGraphics2D;
+
 public class SequenceRenderer implements jalview.api.SequenceRenderer
 {
-  AlignViewport av;
+  final static int CHAR_TO_UPPER = 'A' - 'a';
+
+  AlignViewportI av;
 
   FontMetrics fm;
 
   boolean renderGaps = true;
 
-  SequenceGroup currentSequenceGroup = null;
-
   SequenceGroup[] allGroups = null;
 
-  Color resBoxColour;
+  // Color resBoxColour;
 
   Graphics graphics;
 
   boolean monospacedFont;
 
-  boolean forOverview = false;
+  ResidueColourFinder resColourFinder;
 
   /**
-   * Creates a new SequenceRenderer object.
+   * Creates a new SequenceRenderer object
    * 
-   * @param av
-   *          DOCUMENT ME!
+   * @param viewport
    */
-  public SequenceRenderer(AlignViewport av)
+  public SequenceRenderer(AlignViewportI viewport)
   {
-    this.av = av;
+    this.av = viewport;
+    resColourFinder = new ResidueColourFinder();
   }
 
   /**
@@ -80,55 +78,29 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
     // If EPS graphics, stringWidth will be a double, not an int
     double dwidth = fm.getStringBounds("M", g).getWidth();
 
-    monospacedFont = (dwidth == fm.getStringBounds("|", g).getWidth() && (float) av.charWidth == dwidth);
+    monospacedFont = (dwidth == fm.getStringBounds("|", g).getWidth()
+            && av.getCharWidth() == dwidth);
 
     this.renderGaps = renderGaps;
   }
 
-  public Color getResidueBoxColour(SequenceI seq, int i)
-  {
-    allGroups = av.getAlignment().findAllGroups(seq);
-
-    if (inCurrentSequenceGroup(i))
-    {
-      if (currentSequenceGroup.getDisplayBoxes())
-      {
-        getBoxColour(currentSequenceGroup.cs, seq, i);
-      }
-    }
-    else if (av.getShowBoxes())
-    {
-      getBoxColour(av.getGlobalColourScheme(), seq, i);
-    }
-
-    return resBoxColour;
-  }
-
   /**
-   * DOCUMENT ME!
+   * Get the residue colour at the given sequence position - as determined by
+   * the sequence group colour (if any), else the colour scheme, possibly
+   * overridden by a feature colour.
    * 
-   * @param cs
-   *          DOCUMENT ME!
    * @param seq
-   *          DOCUMENT ME!
-   * @param i
-   *          DOCUMENT ME!
+   * @param position
+   * @param finder
+   * @return
    */
-  void getBoxColour(ColourSchemeI cs, SequenceI seq, int i)
+  @Override
+  public Color getResidueColour(final SequenceI seq, int position,
+          FeatureColourFinder finder)
   {
-    if (cs != null)
-    {
-      resBoxColour = cs.findColour(seq.getCharAt(i), i, seq);
-    }
-    else if (forOverview
-            && !jalview.util.Comparison.isGap(seq.getCharAt(i)))
-    {
-      resBoxColour = Color.lightGray;
-    }
-    else
-    {
-      resBoxColour = Color.white;
-    }
+    allGroups = av.getAlignment().findAllGroups(seq);
+    return resColourFinder.getResidueColour(av.getShowBoxes(),
+            av.getResidueShading(), allGroups, seq, position, finder);
   }
 
   /**
@@ -160,7 +132,7 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
 
     drawBoxes(seq, start, end, y1);
 
-    if (av.validCharWidth)
+    if (av.isValidCharWidth())
     {
       drawText(seq, start, end, y1);
     }
@@ -187,13 +159,18 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
   public synchronized void drawBoxes(SequenceI seq, int start, int end,
           int y1)
   {
+    Color resBoxColour = Color.white;
+
     if (seq == null)
+    {
       return; // fix for racecondition
+    }
     int i = start;
     int length = seq.getLength();
 
     int curStart = -1;
-    int curWidth = av.charWidth;
+    int curWidth = av.getCharWidth(), avWidth = av.getCharWidth(),
+            avHeight = av.getCharHeight();
 
     Color tempColour = null;
 
@@ -203,44 +180,46 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
 
       if (i < length)
       {
-        if (inCurrentSequenceGroup(i))
+        SequenceGroup currentSequenceGroup = resColourFinder
+                .getCurrentSequenceGroup(allGroups, i);
+        if (currentSequenceGroup != null)
         {
           if (currentSequenceGroup.getDisplayBoxes())
           {
-            getBoxColour(currentSequenceGroup.cs, seq, i);
+            resBoxColour = resColourFinder.getBoxColour(
+                    currentSequenceGroup.getGroupColourScheme(), seq, i);
           }
         }
         else if (av.getShowBoxes())
         {
-          getBoxColour(av.getGlobalColourScheme(), seq, i);
+          resBoxColour = resColourFinder
+                  .getBoxColour(av.getResidueShading(), seq, i);
         }
-
       }
 
       if (resBoxColour != tempColour)
       {
         if (tempColour != null)
         {
-          graphics.fillRect(av.charWidth * (curStart - start), y1,
-                  curWidth, av.charHeight);
+          graphics.fillRect(avWidth * (curStart - start), y1, curWidth,
+                  avHeight);
         }
 
         graphics.setColor(resBoxColour);
 
         curStart = i;
-        curWidth = av.charWidth;
+        curWidth = avWidth;
         tempColour = resBoxColour;
       }
       else
       {
-        curWidth += av.charWidth;
+        curWidth += avWidth;
       }
 
       i++;
     }
 
-    graphics.fillRect(av.charWidth * (curStart - start), y1, curWidth,
-            av.charHeight);
+    graphics.fillRect(avWidth * (curStart - start), y1, curWidth, avHeight);
 
   }
 
@@ -264,7 +243,7 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
    */
   public void drawText(SequenceI seq, int start, int end, int y1)
   {
-    y1 += av.charHeight - av.charHeight / 5; // height/5 replaces pady
+    y1 += av.getCharHeight() - av.getCharHeight() / 5; // height/5 replaces pady
     int charOffset = 0;
     char s;
 
@@ -272,36 +251,57 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
     {
       end = seq.getLength() - 1;
     }
-    graphics.setColor(av.textColour);
-
-    if (monospacedFont && av.showText && allGroups.length == 0
-            && !av.getColourText() && av.thresholdTextColour == 0)
+    graphics.setColor(av.getTextColour());
+
+    boolean drawAllText = monospacedFont && av.getShowText()
+            && allGroups.length == 0 && !av.getColourText()
+            && av.getThresholdTextColour() == 0;
+
+    /*
+     * EPS or SVG misaligns monospaced strings (JAL-3239)
+     * so always draw these one character at a time
+     */
+    if (graphics instanceof EpsGraphics2D
+            || graphics instanceof SVGGraphics2D)
+    {
+      drawAllText = false;
+    }
+    if (drawAllText)
     {
-      if (av.renderGaps)
+      if (av.isRenderGaps())
       {
         graphics.drawString(seq.getSequenceAsString(start, end + 1), 0, y1);
       }
       else
       {
         char gap = av.getGapCharacter();
-        graphics.drawString(seq.getSequenceAsString(start, end + 1)
-                .replace(gap, ' '), 0, y1);
+        graphics.drawString(
+                seq.getSequenceAsString(start, end + 1).replace(gap, ' '),
+                0, y1);
       }
     }
     else
     {
+      boolean srep = av.isDisplayReferenceSeq();
       boolean getboxColour = false;
+      boolean isarep = av.getAlignment().getSeqrep() == seq;
+      Color resBoxColour = Color.white;
+
       for (int i = start; i <= end; i++)
       {
-        graphics.setColor(av.textColour);
+
+        graphics.setColor(av.getTextColour());
         getboxColour = false;
         s = seq.getCharAt(i);
+
         if (!renderGaps && jalview.util.Comparison.isGap(s))
         {
           continue;
         }
 
-        if (inCurrentSequenceGroup(i))
+        SequenceGroup currentSequenceGroup = resColourFinder
+                .getCurrentSequenceGroup(allGroups, i);
+        if (currentSequenceGroup != null)
         {
           if (!currentSequenceGroup.getDisplayText())
           {
@@ -312,7 +312,8 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
                   || currentSequenceGroup.getColourText())
           {
             getboxColour = true;
-            getBoxColour(currentSequenceGroup.cs, seq, i);
+            resBoxColour = resColourFinder.getBoxColour(
+                    currentSequenceGroup.getGroupColourScheme(), seq, i);
 
             if (currentSequenceGroup.getColourText())
             {
@@ -322,7 +323,8 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
             if (currentSequenceGroup.thresholdTextColour > 0)
             {
               if (resBoxColour.getRed() + resBoxColour.getBlue()
-                      + resBoxColour.getGreen() < currentSequenceGroup.thresholdTextColour)
+                      + resBoxColour
+                              .getGreen() < currentSequenceGroup.thresholdTextColour)
               {
                 graphics.setColor(currentSequenceGroup.textColour2);
               }
@@ -332,11 +334,15 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
           {
             graphics.setColor(currentSequenceGroup.textColour);
           }
-          if (currentSequenceGroup.getShowNonconserved()) // todo optimize
+          boolean isgrep = currentSequenceGroup != null
+                  ? currentSequenceGroup.getSeqrep() == seq
+                  : false;
+          if (!isarep && !isgrep
+                  && currentSequenceGroup.getShowNonconserved()) // todo
+                                                                 // optimize
           {
             // todo - use sequence group consensus
-            s = getDisplayChar(av.getAlignmentConsensusAnnotation(), i, s,
-                    '.');
+            s = getDisplayChar(srep, i, s, '.', currentSequenceGroup);
 
           }
 
@@ -351,7 +357,8 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
           if (av.getColourText())
           {
             getboxColour = true;
-            getBoxColour(av.getGlobalColourScheme(), seq, i);
+            resBoxColour = resColourFinder
+                    .getBoxColour(av.getResidueShading(), seq, i);
 
             if (av.getShowBoxes())
             {
@@ -363,75 +370,77 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
             }
           }
 
-          if (av.thresholdTextColour > 0)
+          if (av.getThresholdTextColour() > 0)
           {
             if (!getboxColour)
             {
-              getBoxColour(av.getGlobalColourScheme(), seq, i);
+              resBoxColour = resColourFinder
+                      .getBoxColour(av.getResidueShading(), seq, i);
             }
 
             if (resBoxColour.getRed() + resBoxColour.getBlue()
-                    + resBoxColour.getGreen() < av.thresholdTextColour)
+                    + resBoxColour.getGreen() < av.getThresholdTextColour())
             {
-              graphics.setColor(av.textColour2);
+              graphics.setColor(av.getTextColour2());
             }
           }
-          if (av.getShowUnconserved())
+          if (!isarep && av.getShowUnconserved())
           {
-            s = getDisplayChar(av.getAlignmentConsensusAnnotation(), i, s,
-                    '.');
+            s = getDisplayChar(srep, i, s, '.', null);
 
           }
 
         }
 
-        charOffset = (av.charWidth - fm.charWidth(s)) / 2;
-        graphics.drawString(String.valueOf(s), charOffset + av.charWidth
-                * (i - start), y1);
+        charOffset = (av.getCharWidth() - fm.charWidth(s)) / 2;
+        graphics.drawString(String.valueOf(s),
+                charOffset + av.getCharWidth() * (i - start), y1);
 
       }
     }
   }
 
-  private char getDisplayChar(AlignmentAnnotation consensus, int position,
-          char s, char c)
-  {
-    char conschar = consensus.annotations[position].displayCharacter
-            .charAt(0);
-    if (conschar != '-' && s == conschar)
-    {
-      s = c;
-    }
-    return s;
-  }
-
   /**
-   * DOCUMENT ME!
-   * 
-   * @param res
-   *          DOCUMENT ME!
+   * Returns 'conservedChar' to represent the given position if the sequence
+   * character at that position is equal to the consensus (ignoring case), else
+   * returns the sequence character
    * 
-   * @return DOCUMENT ME!
+   * @param usesrep
+   * @param position
+   * @param sequenceChar
+   * @param conservedChar
+   * @return
    */
-  boolean inCurrentSequenceGroup(int res)
+  private char getDisplayChar(final boolean usesrep, int position,
+          char sequenceChar, char conservedChar, SequenceGroup currentGroup)
   {
-    if (allGroups == null)
+    // TODO - use currentSequenceGroup rather than alignment
+    // currentSequenceGroup.getConsensus()
+    char conschar = (usesrep) ? (currentGroup == null
+            || position < currentGroup.getStartRes()
+            || position > currentGroup.getEndRes()
+                    ? av.getAlignment().getSeqrep().getCharAt(position)
+                    : (currentGroup.getSeqrep() != null
+                            ? currentGroup.getSeqrep().getCharAt(position)
+                            : av.getAlignment().getSeqrep()
+                                    .getCharAt(position)))
+            : (currentGroup != null && currentGroup.getConsensus() != null
+                    && position >= currentGroup.getStartRes()
+                    && position <= currentGroup.getEndRes()
+                    && currentGroup
+                            .getConsensus().annotations.length > position)
+                                    ? currentGroup
+                                            .getConsensus().annotations[position].displayCharacter
+                                                    .charAt(0)
+                                    : av.getAlignmentConsensusAnnotation().annotations[position].displayCharacter
+                                            .charAt(0);
+    if (!jalview.util.Comparison.isGap(conschar)
+            && (sequenceChar == conschar
+                    || sequenceChar + CHAR_TO_UPPER == conschar))
     {
-      return false;
+      sequenceChar = conservedChar;
     }
-
-    for (int i = 0; i < allGroups.length; i++)
-    {
-      if ((allGroups[i].getStartRes() <= res)
-              && (allGroups[i].getEndRes() >= res))
-      {
-        currentSequenceGroup = allGroups[i];
-
-        return true;
-      }
-    }
-
-    return false;
+    return sequenceChar;
   }
 
   /**
@@ -452,20 +461,20 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
    * @param height
    *          DOCUMENT ME!
    */
-  public void drawHighlightedText(SequenceI seq, int start, int end,
-          int x1, int y1)
+  public void drawHighlightedText(SequenceI seq, int start, int end, int x1,
+          int y1)
   {
-    int pady = av.charHeight / 5;
+    int pady = av.getCharHeight() / 5;
     int charOffset = 0;
     graphics.setColor(Color.BLACK);
-    graphics.fillRect(x1, y1, av.charWidth * (end - start + 1),
-            av.charHeight);
+    graphics.fillRect(x1, y1, av.getCharWidth() * (end - start + 1),
+            av.getCharHeight());
     graphics.setColor(Color.white);
 
     char s = '~';
 
     // Need to find the sequence position here.
-    if (av.validCharWidth)
+    if (av.isValidCharWidth())
     {
       for (int i = start; i <= end; i++)
       {
@@ -474,29 +483,39 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
           s = seq.getCharAt(i);
         }
 
-        charOffset = (av.charWidth - fm.charWidth(s)) / 2;
-        graphics.drawString(String.valueOf(s), charOffset + x1
-                + (av.charWidth * (i - start)), (y1 + av.charHeight) - pady);
+        charOffset = (av.getCharWidth() - fm.charWidth(s)) / 2;
+        graphics.drawString(String.valueOf(s),
+                charOffset + x1 + (av.getCharWidth() * (i - start)),
+                (y1 + av.getCharHeight()) - pady);
       }
     }
   }
 
-  public void drawCursor(SequenceI seq, int res, int x1, int y1)
+  /**
+   * Draw a sequence canvas cursor
+   * 
+   * @param g
+   *          graphics context to draw on
+   * @param s
+   *          character to draw at cursor
+   * @param x1
+   *          x position of cursor in graphics context
+   * @param y1
+   *          y position of cursor in graphics context
+   */
+  public void drawCursor(Graphics g, char s, int x1, int y1)
   {
-    int pady = av.charHeight / 5;
+    int pady = av.getCharHeight() / 5;
     int charOffset = 0;
-    graphics.setColor(Color.black);
-    graphics.fillRect(x1, y1, av.charWidth, av.charHeight);
+    g.setColor(Color.black);
+    g.fillRect(x1, y1, av.getCharWidth(), av.getCharHeight());
 
-    if (av.validCharWidth)
+    if (av.isValidCharWidth())
     {
-      graphics.setColor(Color.white);
-
-      char s = seq.getCharAt(res);
-
-      charOffset = (av.charWidth - fm.charWidth(s)) / 2;
-      graphics.drawString(String.valueOf(s), charOffset + x1,
-              (y1 + av.charHeight) - pady);
+      g.setColor(Color.white);
+      charOffset = (av.getCharWidth() - fm.charWidth(s)) / 2;
+      g.drawString(String.valueOf(s), charOffset + x1,
+              (y1 + av.getCharHeight()) - pady);
     }
 
   }