JAL-2327 disulfide bond abstracted to SequenceFeature.isContactFeature
[jalview.git] / src / jalview / gui / AlignmentPanel.java
index 3031cd5..687361d 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.9.0b2)
- * 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.
  * 
@@ -101,6 +101,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
    */
   private boolean dontScrollComplement;
 
+  private PropertyChangeListener propertyChangeListener;
+
   /**
    * Creates a new AlignmentPanel object.
    * 
@@ -135,8 +137,9 @@ public class AlignmentPanel extends GAlignmentPanel implements
     vscroll.addAdjustmentListener(this);
 
     final AlignmentPanel ap = this;
-    av.addPropertyChangeListener(new PropertyChangeListener()
+    propertyChangeListener = new PropertyChangeListener()
     {
+      @Override
       public void propertyChange(PropertyChangeEvent evt)
       {
         if (evt.getPropertyName().equals("alignment"))
@@ -145,7 +148,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
           alignmentChanged();
         }
       }
-    });
+    };
+    av.addPropertyChangeListener(propertyChangeListener);
     fontChanged();
     adjustAnnotationHeight();
     updateLayout();
@@ -509,6 +513,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
    * automatically adjust annotation panel height for new annotation whilst
    * ensuring the alignment is still visible.
    */
+  @Override
   public void adjustAnnotationHeight()
   {
     // TODO: display vertical annotation scrollbar if necessary
@@ -749,6 +754,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
    * @param evt
    *          DOCUMENT ME!
    */
+  @Override
   public void adjustmentValueChanged(AdjustmentEvent evt)
   {
     int oldX = av.getStartRes();
@@ -782,6 +788,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
           // as preference setting
           SwingUtilities.invokeLater(new Runnable()
           {
+            @Override
             public void run()
             {
               setScrollValues(av.getStartRes(), av.getStartSeq());
@@ -852,6 +859,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
    * Repaint the alignment including the annotations and overview panels (if
    * shown).
    */
+  @Override
   public void paintAlignment(boolean updateOverview)
   {
     final AnnotationSorter sorter = new AnnotationSorter(getAlignment(),
@@ -878,6 +886,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
    * @param g
    *          DOCUMENT ME!
    */
+  @Override
   public void paintComponent(Graphics g)
   {
     invalidate();
@@ -936,6 +945,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
    * @throws PrinterException
    *           DOCUMENT ME!
    */
+  @Override
   public int print(Graphics pg, PageFormat pf, int pi)
           throws PrinterException
   {
@@ -946,11 +956,11 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
     if (av.getWrapAlignment())
     {
-      return printWrappedAlignment(pg, pwidth, pheight, pi);
+      return printWrappedAlignment(pwidth, pheight, pi, pg);
     }
     else
     {
-      return printUnwrapped(pg, pwidth, pheight, pi);
+      return printUnwrapped(pwidth, pheight, pi, pg);
     }
   }
 
@@ -971,16 +981,28 @@ public class AlignmentPanel extends GAlignmentPanel implements
    * @throws PrinterException
    *           DOCUMENT ME!
    */
-  public int printUnwrapped(Graphics pg, int pwidth, int pheight, int pi)
+  public int printUnwrapped(int pwidth, int pheight, int pi,
+          Graphics... pg)
           throws PrinterException
   {
+    boolean isMultiGraphics = pg.length > 1;
+    int G0 = 0; // Graphic index of idPanel graphics in multi-graphics mode or
+                // entire graphics for non mulit-graphics mode
+    int G1 = 0; // Graphic index of alignmentPanel graphics for multi-graphics
+                // mode
+    if (isMultiGraphics)
+    {
+      G0 = 0;
+      G1 = 1;
+    }
+
     int idWidth = getVisibleIdWidth(false);
     FontMetrics fm = getFontMetrics(av.getFont());
     int scaleHeight = av.getCharHeight() + fm.getDescent();
 
-    pg.setColor(Color.white);
-    pg.fillRect(0, 0, pwidth, pheight);
-    pg.setFont(av.getFont());
+    pg[G0].setColor(Color.white);
+    pg[G0].fillRect(0, 0, pwidth, pheight);
+    pg[G0].setFont(av.getFont());
 
     // //////////////////////////////////
     // / How many sequences and residues can we fit on a printable page?
@@ -1037,17 +1059,31 @@ public class AlignmentPanel extends GAlignmentPanel implements
     }
 
     // draw Scale
-    pg.translate(idWidth, 0);
-    getScalePanel().drawScale(pg, startRes, endRes, pwidth - idWidth,
-            scaleHeight);
-    pg.translate(-idWidth, scaleHeight);
+    if (isMultiGraphics)
+    {
+      pg[G1].translate(0, 0);
+      getScalePanel().drawScale(pg[G1], startRes, endRes,
+              pwidth - idWidth, scaleHeight);
+      pg[G1].translate(-idWidth, scaleHeight);
+    }
+    else
+    {
+      pg[G0].translate(idWidth, 0);
+      getScalePanel().drawScale(pg[G0], startRes, endRes, pwidth - idWidth,
+              scaleHeight);
+      pg[G0].translate(-idWidth, scaleHeight);
+    }
 
     // //////////////
     // Draw the ids
     Color currentColor = null;
     Color currentTextColor = null;
 
-    pg.setFont(getIdPanel().getIdCanvas().getIdfont());
+    if (isMultiGraphics)
+    {
+      pg[G0].translate(0, scaleHeight);
+    }
+    pg[G0].setFont(getIdPanel().getIdCanvas().getIdfont());
 
     SequenceI seq;
     for (int i = startSeq; i < endSeq; i++)
@@ -1065,45 +1101,70 @@ public class AlignmentPanel extends GAlignmentPanel implements
         currentTextColor = Color.black;
       }
 
-      pg.setColor(currentColor);
-      pg.fillRect(0, (i - startSeq) * av.getCharHeight(), idWidth,
+      pg[G0].setColor(currentColor);
+      pg[G0].fillRect(0, (i - startSeq) * av.getCharHeight(), idWidth,
               av.getCharHeight());
 
-      pg.setColor(currentTextColor);
+      pg[G0].setColor(currentTextColor);
 
       int xPos = 0;
       if (av.isRightAlignIds())
       {
-        fm = pg.getFontMetrics();
+        fm = pg[G0].getFontMetrics();
         xPos = idWidth
                 - fm.stringWidth(seq.getDisplayId(av.getShowJVSuffix()))
                 - 4;
       }
 
-      pg.drawString(seq.getDisplayId(av.getShowJVSuffix()), xPos,
+      pg[G0].drawString(seq.getDisplayId(av.getShowJVSuffix()), xPos,
               (((i - startSeq) * av.getCharHeight()) + av.getCharHeight())
                       - (av.getCharHeight() / 5));
     }
 
-    pg.setFont(av.getFont());
+    pg[G0].setFont(av.getFont());
+
 
     // draw main sequence panel
-    pg.translate(idWidth, 0);
-    getSeqPanel().seqCanvas.drawPanel(pg, startRes, endRes, startSeq,
-            endSeq, 0);
+    pg[G0].translate(idWidth, 0);
+    if (isMultiGraphics)
+    {
+      pg[G1].translate(idWidth, 0);
+      getSeqPanel().seqCanvas.drawPanel(pg[G1], startRes, endRes,
+              startSeq, endSeq, 0);
+    }
+    else
+    {
+      getSeqPanel().seqCanvas.drawPanel(pg[G0], startRes, endRes, startSeq,
+              endSeq, 0);
+    }
 
     if (av.isShowAnnotation() && (endSeq == av.getAlignment().getHeight()))
     {
-      // draw annotation - need to offset for current scroll position
+      // draw annotation label - need to offset for current scroll position
       int offset = -getAlabels().getScrollOffset();
-      pg.translate(0, offset);
-      pg.translate(-idWidth - 3, (endSeq - startSeq) * av.getCharHeight()
-              + 3);
-      getAlabels().drawComponent(pg, idWidth);
-      pg.translate(idWidth + 3, 0);
-      getAnnotationPanel().renderer.drawComponent(getAnnotationPanel(), av,
-              pg, -1, startRes, endRes + 1);
-      pg.translate(0, -offset);
+      pg[G0].translate(0, offset);
+      pg[G0].translate(-idWidth - 3,
+              (endSeq - startSeq) * av.getCharHeight() + 3);
+      getAlabels().drawComponent(pg[G0], idWidth);
+      pg[G0].translate(idWidth + 3, 0);
+      pg[G0].translate(0, -offset);
+      if (isMultiGraphics)
+      {
+        // draw annotation - need to offset for current scroll position
+        pg[G1].translate(0, offset);
+        pg[G1].translate(-idWidth - 3,
+                (endSeq - startSeq) * av.getCharHeight() + 3);
+        pg[G1].translate(idWidth + 3, 0);
+        getAnnotationPanel().renderer.drawComponent(getAnnotationPanel(),
+                av, pg[G1], -1, startRes, endRes + 1);
+        pg[G1].translate(0, -offset);
+      }
+      else
+      {
+        getAnnotationPanel().renderer.drawComponent(getAnnotationPanel(),
+                av, pg[G0], -1, startRes, endRes + 1);
+        pg[G0].translate(0, -offset);
+      }
     }
 
     return Printable.PAGE_EXISTS;
@@ -1126,8 +1187,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
    * @throws PrinterException
    *           DOCUMENT ME!
    */
-  public int printWrappedAlignment(Graphics pg, int pwidth, int pheight,
-          int pi) throws PrinterException
+  public int printWrappedAlignment(int pwidth, int pheight, int pi,
+          Graphics pg) throws PrinterException
   {
     int annotationHeight = 0;
     AnnotationLabels labels = null;
@@ -1254,22 +1315,26 @@ public class AlignmentPanel extends GAlignmentPanel implements
     if (onscreen
             || (idwidth = Cache.getIntegerProperty("FIGURE_FIXEDIDWIDTH")) == null)
     {
-      return (getIdPanel().getWidth() > 0 ? getIdPanel().getWidth()
-              : calculateIdWidth().width + 4);
+      int w = getIdPanel().getWidth();
+      return (w > 0 ? w : calculateIdWidth().width + 4);
     }
     return idwidth.intValue() + 4;
   }
 
   void makeAlignmentImage(jalview.util.ImageMaker.TYPE type, File file)
   {
-    long progress = System.currentTimeMillis();
+    int boarderBottomOffset = 5;
+    long pSessionId = System.currentTimeMillis();
     headless = (System.getProperty("java.awt.headless") != null && System
             .getProperty("java.awt.headless").equals("true"));
     if (alignFrame != null && !headless)
     {
-      alignFrame.setProgressBar(MessageManager.formatMessage(
-              "status.saving_file", new Object[] { type.getLabel() }),
-              progress);
+      if (file != null)
+      {
+        alignFrame.setProgressBar(MessageManager.formatMessage(
+                "status.saving_file", new Object[] { type.getLabel() }),
+                pSessionId);
+      }
     }
     try
     {
@@ -1295,14 +1360,16 @@ public class AlignmentPanel extends GAlignmentPanel implements
         }
 
         im = new jalview.util.ImageMaker(this, type, imageAction,
-                aDimension.getWidth(), aDimension.getHeight(), file,
-                imageTitle);
+                aDimension.getWidth(), aDimension.getHeight()
+                        + boarderBottomOffset, file, imageTitle,
+                alignFrame, pSessionId, headless);
         if (av.getWrapAlignment())
         {
           if (im.getGraphics() != null)
           {
-            printWrappedAlignment(im.getGraphics(), aDimension.getWidth(),
-                    aDimension.getHeight(), 0);
+            printWrappedAlignment(aDimension.getWidth(),
+                    aDimension.getHeight() + boarderBottomOffset, 0,
+                    im.getGraphics());
             im.writeImage();
           }
         }
@@ -1310,11 +1377,12 @@ public class AlignmentPanel extends GAlignmentPanel implements
         {
           if (im.getGraphics() != null)
           {
-            printUnwrapped(im.getGraphics(), aDimension.getWidth(),
-                    aDimension.getHeight(), 0);
+            printUnwrapped(aDimension.getWidth(), aDimension.getHeight(),
+                    0, im.getGraphics());
             im.writeImage();
           }
         }
+
       } catch (OutOfMemoryError err)
       {
         // Be noisy here.
@@ -1328,12 +1396,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
       }
     } finally
     {
-      if (alignFrame != null && !headless)
-      {
-        alignFrame.setProgressBar(
-                MessageManager.getString("status.export_complete"),
-                progress);
-      }
+
     }
   }
 
@@ -1400,7 +1463,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
   public void makePNGImageMap(File imgMapFile, String imageName)
   {
-    // /////ONLY WORKS WITH NONE WRAPPED ALIGNMENTS
+    // /////ONLY WORKS WITH NON WRAPPED ALIGNMENTS
     // ////////////////////////////////////////////
     int idWidth = getVisibleIdWidth(false);
     FontMetrics fm = getFontMetrics(av.getFont());
@@ -1414,7 +1477,6 @@ public class AlignmentPanel extends GAlignmentPanel implements
       {
         int s, sSize = av.getAlignment().getHeight(), res, alwidth = av
                 .getAlignment().getWidth(), g, gSize, f, fSize, sy;
-        StringBuffer text = new StringBuffer();
         PrintWriter out = new PrintWriter(new FileWriter(imgMapFile));
         out.println(jalview.io.HTMLOutput.getImageMapHTML());
         out.println("<img src=\"" + imageName
@@ -1430,7 +1492,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
           SequenceGroup[] groups = av.getAlignment().findAllGroups(seq);
           for (res = 0; res < alwidth; res++)
           {
-            text = new StringBuffer();
+            StringBuilder text = new StringBuilder();
             String triplet = null;
             if (av.getAlignment().isNucleotide())
             {
@@ -1454,18 +1516,20 @@ public class AlignmentPanel extends GAlignmentPanel implements
             {
               if (text.length() < 1)
               {
-                text.append("<area shape=\"rect\" coords=\""
-                        + (idWidth + res * av.getCharWidth()) + "," + sy
-                        + "," + (idWidth + (res + 1) * av.getCharWidth())
-                        + "," + (av.getCharHeight() + sy) + "\""
-                        + " onMouseOver=\"toolTip('" + alIndex + " "
-                        + triplet);
+                text.append("<area shape=\"rect\" coords=\"")
+                        .append((idWidth + res * av.getCharWidth()))
+                        .append(",").append(sy).append(",")
+                        .append((idWidth + (res + 1) * av.getCharWidth()))
+                        .append(",").append((av.getCharHeight() + sy))
+                        .append("\"").append(" onMouseOver=\"toolTip('")
+                        .append(alIndex).append(" ").append(triplet);
               }
 
               if (groups[g].getStartRes() < res
                       && groups[g].getEndRes() > res)
               {
-                text.append("<br><em>" + groups[g].getName() + "</em>");
+                text.append("<br><em>").append(groups[g].getName())
+                        .append("</em>");
               }
             }
 
@@ -1473,12 +1537,13 @@ public class AlignmentPanel extends GAlignmentPanel implements
             {
               if (text.length() < 1)
               {
-                text.append("<area shape=\"rect\" coords=\""
-                        + (idWidth + res * av.getCharWidth()) + "," + sy
-                        + "," + (idWidth + (res + 1) * av.getCharWidth())
-                        + "," + (av.getCharHeight() + sy) + "\""
-                        + " onMouseOver=\"toolTip('" + alIndex + " "
-                        + triplet);
+                text.append("<area shape=\"rect\" coords=\"")
+                        .append((idWidth + res * av.getCharWidth()))
+                        .append(",").append(sy).append(",")
+                        .append((idWidth + (res + 1) * av.getCharWidth()))
+                        .append(",").append((av.getCharHeight() + sy))
+                        .append("\"").append(" onMouseOver=\"toolTip('")
+                        .append(alIndex).append(" ").append(triplet);
               }
               fSize = features.length;
               for (f = 0; f < fSize; f++)
@@ -1487,15 +1552,15 @@ public class AlignmentPanel extends GAlignmentPanel implements
                 if ((features[f].getBegin() <= seq.findPosition(res))
                         && (features[f].getEnd() >= seq.findPosition(res)))
                 {
-                  if (features[f].getType().equals("disulfide bond"))
+                  if (features[f].isContactFeature())
                   {
                     if (features[f].getBegin() == seq.findPosition(res)
                             || features[f].getEnd() == seq
                                     .findPosition(res))
                     {
-                      text.append("<br>disulfide bond "
-                              + features[f].getBegin() + ":"
-                              + features[f].getEnd());
+                      text.append("<br>").append(features[f].getType())
+                              .append(" ").append(features[f].getBegin())
+                              .append(":").append(features[f].getEnd());
                     }
                   }
                   else
@@ -1506,13 +1571,13 @@ public class AlignmentPanel extends GAlignmentPanel implements
                             && !features[f].getType().equals(
                                     features[f].getDescription()))
                     {
-                      text.append(" " + features[f].getDescription());
+                      text.append(" ").append(features[f].getDescription());
                     }
 
                     if (features[f].getValue("status") != null)
                     {
-                      text.append(" (" + features[f].getValue("status")
-                              + ")");
+                      text.append(" (").append(features[f].getValue("status"))
+                              .append(")");
                     }
                   }
                 }
@@ -1587,8 +1652,18 @@ public class AlignmentPanel extends GAlignmentPanel implements
     PaintRefresher.RemoveComponent(getSeqPanel().seqCanvas);
     PaintRefresher.RemoveComponent(getIdPanel().getIdCanvas());
     PaintRefresher.RemoveComponent(this);
+
+    /*
+     * try to ensure references are nulled
+     */
+    if (annotationPanel != null)
+    {
+      annotationPanel.dispose();
+    }
+
     if (av != null)
     {
+      av.removePropertyChangeListener(propertyChangeListener);
       jalview.structure.StructureSelectionManager ssm = av
               .getStructureSelectionManager();
       ssm.removeStructureViewerListener(getSeqPanel(), null);
@@ -1596,7 +1671,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
       ssm.removeCommandListener(av);
       ssm.removeStructureViewerListener(getSeqPanel(), null);
       ssm.removeSelectionListener(getSeqPanel());
-      av.setAlignment(null);
+      av.dispose();
       av = null;
     }
     else