JAL-3364 align split frame sequence panels with wrapped view scale left
[jalview.git] / src / jalview / gui / AlignmentPanel.java
index 4ec71c5..716c237 100644 (file)
  */
 package jalview.gui;
 
+import static jalview.util.ImageMaker.TYPE.EPS;
+import static jalview.util.ImageMaker.TYPE.PNG;
+import static jalview.util.ImageMaker.TYPE.SVG;
+
 import jalview.analysis.AnnotationSorter;
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
@@ -561,9 +565,6 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
   /**
    * update alignment layout for viewport settings
-   * 
-   * @param wrap
-   *          DOCUMENT ME!
    */
   public void updateLayout()
   {
@@ -610,6 +611,13 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
     idSpaceFillerPanel1.setVisible(!wrap);
 
+    AlignViewportI complement = av.getCodingComplement();
+    if (complement != null)
+    {
+      SplitFrame splitFrame = (SplitFrame) alignFrame
+              .getSplitViewContainer();
+      splitFrame.adjustLayout();
+    }
     repaint();
   }
 
@@ -872,19 +880,18 @@ public class AlignmentPanel extends GAlignmentPanel implements
   }
 
   /**
-   * DOCUMENT ME!
+   * Provides the implementation of Printable.print
    * 
    * @param pg
-   *          DOCUMENT ME!
+   *             DOCUMENT ME!
    * @param pf
-   *          DOCUMENT ME!
+   *             DOCUMENT ME!
    * @param pi
-   *          DOCUMENT ME!
+   *             DOCUMENT ME!
    * 
    * @return DOCUMENT ME!
    * 
    * @throws PrinterException
-   *           DOCUMENT ME!
    */
   @Override
   public int print(Graphics pg, PageFormat pf, int pi)
@@ -897,7 +904,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
     if (av.getWrapAlignment())
     {
-      return printWrappedAlignment(pwidth, pheight, pi, pg);
+      return printWrappedAlignment(pwidth, pheight, pi, pg, true);
     }
     else
     {
@@ -967,7 +974,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
     if (av.isShowAnnotation())
     {
-      pagesHigh += getAnnotationPanel().adjustPanelHeight() + 3;
+      pagesHigh += getAnnotationPanel().adjustPanelHeight()
+              + SeqCanvas.SEQS_ANNOTATION_GAP;
     }
 
     pagesHigh /= pageHeight;
@@ -976,7 +984,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
     {
       return Printable.NO_SUCH_PAGE;
     }
-    final int alignmentDrawnHeight = (endSeq - startSeq) * charHeight + 3;
+    final int alignmentDrawnHeight = (endSeq - startSeq + 1) * charHeight;
 
     /*
      * draw the Scale at horizontal offset, then reset to top left (0, 0)
@@ -1017,19 +1025,33 @@ public class AlignmentPanel extends GAlignmentPanel implements
        * then reset to (0, scale height)
        */
       int offset = getAlabels().getScrollOffset();
+      int yShift = alignmentDrawnHeight + SeqCanvas.SEQS_ANNOTATION_GAP;
       idGraphics.translate(0, -offset);
-      idGraphics.translate(0, alignmentDrawnHeight);
+      idGraphics.translate(0, yShift);
       getAlabels().drawComponent(idGraphics, idWidth);
-      idGraphics.translate(0, -alignmentDrawnHeight);
+      idGraphics.translate(0, -yShift);
 
       /*
        * draw the annotations starting at 
        * (idOffset, alignmentHeight) from (0, scaleHeight)
        */
       alignmentGraphics.translate(alignmentGraphicsOffset,
-              alignmentDrawnHeight);
+              yShift);
       getAnnotationPanel().renderer.drawComponent(getAnnotationPanel(), av,
               alignmentGraphics, -1, startRes, endRes + 1);
+
+      /*
+       * reset to left margin below annotation
+       */
+      int justDrawn = getAnnotationPanel().renderer.getLastDrawnHeight();
+      alignmentGraphics.translate(-alignmentGraphicsOffset, justDrawn);
+    }
+    else
+    {
+      /*
+       * shift graphics to position after drawn sequences
+       */
+      alignmentGraphics.translate(0, alignmentDrawnHeight);
     }
 
     return Printable.PAGE_EXISTS;
@@ -1039,20 +1061,28 @@ public class AlignmentPanel extends GAlignmentPanel implements
    * Prints one page of an alignment in wrapped mode. Returns
    * Printable.PAGE_EXISTS (0) if a page was drawn, or Printable.NO_SUCH_PAGE if
    * no page could be drawn (page number out of range).
+   * <p>
+   * The method is to write the whole alignment, but set a clip region such that
+   * only the specified page is written. This allows specified page(s) to be
+   * printed from the print dialog. The whole image may be written simply by
+   * making the page size match the image size. In this case, parameter
+   * {@code clipToPage} should be set to {@code false}, so that more output (for
+   * example the second panel of a split frame) can be written if wanted.
    * 
    * @param pageWidth
    * @param pageHeight
    * @param pageNumber
-   *          (0, 1, ...)
+   *                     (0, 1, ...)
    * @param g
+   * @param clipToPage
    * 
    * @return
-   * 
-   * @throws PrinterException
    */
   public int printWrappedAlignment(int pageWidth, int pageHeight, int pageNumber,
-          Graphics g) throws PrinterException
+          Graphics g, boolean clipToPage)
   {
+    getSeqPanel().seqCanvas.calculateWrappedGeometry(getWidth(),
+            getHeight());
     int annotationHeight = 0;
     if (av.isShowAnnotation())
     {
@@ -1074,6 +1104,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
     int resWidth = getSeqPanel().seqCanvas
             .getWrappedCanvasWidth(pageWidth - idWidth);
+    av.getRanges().setViewportStartAndWidth(0, resWidth);
 
     int totalHeight = cHeight * (maxwidth / resWidth + 1);
 
@@ -1085,12 +1116,15 @@ public class AlignmentPanel extends GAlignmentPanel implements
     /*
      * method: print the whole wrapped alignment, but with a clip region that
      * is restricted to the requested page; this supports selective print of 
-     * single  pages or ranges, (at the cost of some repeated processing in 
-     * the 'normal' case, when all pages are printed)
+     * single pages or ranges, (at the cost of repeated processing in the 
+     * 'normal' case, when all pages are printed)
      */
     g.translate(0, -pageNumber * pageHeight);
 
-    g.setClip(0, pageNumber * pageHeight, pageWidth, pageHeight);
+    if (clipToPage)
+    {
+      g.setClip(0, pageNumber * pageHeight, pageWidth, pageHeight);
+    }
 
     /*
      * draw sequence ids and annotation labels (if shown)
@@ -1099,9 +1133,9 @@ public class AlignmentPanel extends GAlignmentPanel implements
     idCanvas.drawIdsWrapped((Graphics2D) g, av, 0, totalHeight);
 
     g.translate(idWidth, 0);
-
     getSeqPanel().seqCanvas.drawWrappedPanelForPrinting(g, pageWidth - idWidth,
             totalHeight, 0);
+    g.translate(-idWidth, 0);
 
     if ((pageNumber * pageHeight) < totalHeight)
     {
@@ -1175,44 +1209,52 @@ public class AlignmentPanel extends GAlignmentPanel implements
                 { type.getLabel() }), pSessionId);
       }
     }
+
+    /*
+    * cache preferences in case we need to fudge them for export of
+    * split frame with 'protein scaled to codons' and 'auto id width'
+    */
+
+    final String autoIdWidth = Cache.getProperty("FIGURE_AUTOIDWIDTH");
+    final Integer fixedIdWidth = Cache
+            .getIntegerProperty("FIGURE_FIXEDIDWIDTH");
+
     try
     {
       /*
        * if exporting a split frame image, the graphics object has 
        * width: maximum of the top and bottom image widths
        * height: sum of the top and bottom image heights
+       * if 'protein scaled to codons' and 'auto id width', fudge
+       * to a fixed width (and restore preferences afterwards)
        */
-      AlignmentPanel comp = null;
+      AlignmentPanel complement = null;
       AlignmentDimension dim1 = getAlignmentDimension();
       AlignmentDimension dim2 = new AlignmentDimension(0, 0);
+
       if (forSplitFrame)
       {
-        comp = ((AlignViewport) av.getCodingComplement())
+        complement = ((AlignViewport) av.getCodingComplement())
                 .getAlignPanel();
-        dim2 = comp.getAlignmentDimension();
+        dim2 = complement.getAlignmentDimension();
+        if (Boolean.valueOf(autoIdWidth) && av.isScaleProteinAsCdna())
+        {
+          int w1 = this.getVisibleIdWidth(false);
+          int w2 = complement.getVisibleIdWidth(false);
+          Cache.setProperty("FIGURE_AUTOIDWIDTH", Boolean.FALSE.toString());
+          Cache.setProperty("FIGURE_FIXEDIDWIDTH",
+                  String.valueOf(Math.max(w1, w2)));
+        }
       }
       final int graphicsHeight = dim1.height + dim2.height
               + borderBottomOffset;
       final int graphicsWidth = Math.max(dim1.width, dim2.width);
 
-      final String imageAction, imageTitle;
-      if (type == ImageMaker.TYPE.PNG)
-      {
-        imageAction = "Create PNG image from alignment";
-        imageTitle = null;
-      }
-      else if (type == ImageMaker.TYPE.EPS)
-      {
-        imageAction = "Create EPS file from alignment";
-        imageTitle = alignFrame.getTitle();
-      }
-      else
-      {
-        imageAction = "Create SVG file from alignment";
-        imageTitle = alignFrame.getTitle();
-      }
+      final String dialogTitle = MessageManager
+              .formatMessage("label.make_alignment_image", type.getName());
+      String imageTitle = type == PNG ? null : alignFrame.getTitle();
 
-      ImageMaker im = new ImageMaker(this, type, imageAction,
+      ImageMaker im = new ImageMaker(this, type, dialogTitle,
               graphicsWidth, graphicsHeight, file,
               imageTitle, alignFrame, pSessionId, headless);
       Graphics graphics = im.getGraphics();
@@ -1225,7 +1267,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
       if (av.getWrapAlignment())
       {
         printWrappedAlignment(dim1.width, dim1.height + borderBottomOffset,
-                0, graphics);
+                0, graphics, false);
       }
       else
       {
@@ -1237,15 +1279,16 @@ public class AlignmentPanel extends GAlignmentPanel implements
         /*
          * append coding complement image
          */
-        graphics.translate(0, dim1.height);
+        // to debug location of next write to Graphics:
+        // graphics.drawString("Hello world", 0, 0);
         if (av.getCodingComplement().getWrapAlignment())
         {
-          comp.printWrappedAlignment(dim2.width,
-                  dim2.height + borderBottomOffset, 0, graphics);
+          complement.printWrappedAlignment(dim2.width,
+                  dim2.height + borderBottomOffset, 0, graphics, false);
         }
         else
         {
-          comp.printUnwrapped(dim2.width, dim2.height, 0, graphics,
+          complement.printUnwrapped(dim2.width, dim2.height, 0, graphics,
                   graphics);
         }
       }
@@ -1261,6 +1304,28 @@ public class AlignmentPanel extends GAlignmentPanel implements
     } catch (Exception ex)
     {
       ex.printStackTrace();
+    } finally
+    {
+      /*
+       * restore preference settings in case they were fudged
+       */
+      if (autoIdWidth == null)
+      {
+        Cache.removeProperty("FIGURE_AUTOIDWIDTH");
+      }
+      else
+      {
+        Cache.setProperty("FIGURE_AUTOIDWIDTH", autoIdWidth);
+      }
+      if (fixedIdWidth == null)
+      {
+        Cache.removeProperty("FIGURE_FIXEDIDWIDTH");
+      }
+      else
+      {
+        Cache.setProperty("FIGURE_FIXEDIDWIDTH",
+                String.valueOf(fixedIdWidth));
+      }
     }
   }
 
@@ -1270,7 +1335,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
    * <ul>
    * <li>sequence ids</li>
    * <li>scale above, left or right if shown</li>
-   * <li>sequences</li>
+   * <li>sequence rows, plus one spacer line</li>
    * <li>annotations, if shown</li>
    * </ul>
    * The alignment may be in wrapped or unwrapped mode.
@@ -1322,7 +1387,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
    */
   public void makeEPS(File epsFile, boolean forSplitFrame)
   {
-    makeAlignmentImage(ImageMaker.TYPE.EPS, epsFile, forSplitFrame);
+    makeAlignmentImage(EPS, epsFile, forSplitFrame);
   }
 
   /**
@@ -1334,7 +1399,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
    */
   public void makePNG(File pngFile, boolean forSplitFrame)
   {
-    makeAlignmentImage(ImageMaker.TYPE.PNG, pngFile, forSplitFrame);
+    makeAlignmentImage(PNG, pngFile, forSplitFrame);
   }
 
   /**
@@ -1346,7 +1411,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
    */
   public void makeSVG(File svgFile, boolean forSplitFrame)
   {
-    makeAlignmentImage(ImageMaker.TYPE.SVG, svgFile, forSplitFrame);
+    makeAlignmentImage(SVG, svgFile, forSplitFrame);
   }
 
   public void makePNGImageMap(File imgMapFile, String imageName)
@@ -1478,6 +1543,12 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
   }
 
+  /**
+   * Answers the height of the entire alignment in pixels, assuming it is in
+   * wrapped mode
+   * 
+   * @return
+   */
   int getWrappedHeight()
   {
     int seqPanelWidth = getSeqPanel().seqCanvas.getWidth();
@@ -1502,6 +1573,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
     int annotationHeight = 0;
     if (av.isShowAnnotation())
     {
+      hgap += SeqCanvas.SEQS_ANNOTATION_GAP;
       annotationHeight = getAnnotationPanel().adjustPanelHeight();
     }