*/
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;
import jalview.schemes.ResidueProperties;
import jalview.structure.StructureSelectionManager;
import jalview.util.Comparison;
+import jalview.util.ImageMaker;
import jalview.util.MessageManager;
import jalview.viewmodel.ViewportListenerI;
import jalview.viewmodel.ViewportRanges;
}
/**
- * 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)
if (av.getWrapAlignment())
{
- return printWrappedAlignment(pwidth, pheight, pi, pg);
+ return printWrappedAlignment(pwidth, pheight, pi, pg, true);
}
else
{
if (av.isShowAnnotation())
{
- pagesHigh += getAnnotationPanel().adjustPanelHeight() + 3;
+ pagesHigh += getAnnotationPanel().adjustPanelHeight()
+ + SeqCanvas.SEQS_ANNOTATION_GAP;
}
pagesHigh /= pageHeight;
{
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)
* 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;
* 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())
{
int resWidth = getSeqPanel().seqCanvas
.getWrappedCanvasWidth(pageWidth - idWidth);
+ av.getRanges().setViewportStartAndWidth(0, resWidth);
int totalHeight = cHeight * (maxwidth / resWidth + 1);
/*
* 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)
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)
{
return idwidth.intValue() + 4;
}
- void makeAlignmentImage(jalview.util.ImageMaker.TYPE type, File file)
+ /**
+ * Generates an image of the alignment panel of the specified type. If
+ * {@code type} is not null, the image is written to the file, otherwise the
+ * user is prompted to specify the output file before writing to it.
+ *
+ * @param type
+ * @param file
+ * @param forSplitFrame
+ */
+ void makeAlignmentImage(ImageMaker.TYPE type, File file,
+ boolean forSplitFrame)
{
- int boarderBottomOffset = 5;
+ int borderBottomOffset = 5;
long pSessionId = System.currentTimeMillis();
headless = (System.getProperty("java.awt.headless") != null
&& System.getProperty("java.awt.headless").equals("true"));
{ 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 boolean autoIdWidth = Cache.getDefault("FIGURE_AUTOIDWIDTH",
+ false);
+ final Integer fixedIdWidth = Cache
+ .getIntegerProperty("FIGURE_FIXEDIDWIDTH");
+
try
{
- AlignmentDimension aDimension = getAlignmentDimension();
- 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 complement = null;
+ AlignmentDimension dim1 = getAlignmentDimension();
+ AlignmentDimension dim2 = new AlignmentDimension(0, 0);
+
+ if (forSplitFrame)
{
- jalview.util.ImageMaker im;
- final String imageAction, imageTitle;
- if (type == jalview.util.ImageMaker.TYPE.PNG)
- {
- imageAction = "Create PNG image from alignment";
- imageTitle = null;
- }
- else if (type == jalview.util.ImageMaker.TYPE.EPS)
+ complement = ((AlignViewport) av.getCodingComplement())
+ .getAlignPanel();
+ dim2 = complement.getAlignmentDimension();
+ if (autoIdWidth && av.isScaleProteinAsCdna())
{
- imageAction = "Create EPS file from alignment";
- imageTitle = alignFrame.getTitle();
- }
- else
- {
- imageAction = "Create SVG file from alignment";
- imageTitle = alignFrame.getTitle();
+ 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 dialogTitle = MessageManager
+ .formatMessage("label.make_alignment_image", type.getName());
+ String imageTitle = type == PNG ? null : alignFrame.getTitle();
+
+ ImageMaker im = new ImageMaker(this, type, dialogTitle,
+ graphicsWidth, graphicsHeight, file,
+ imageTitle, alignFrame, pSessionId, headless);
+ Graphics graphics = im.getGraphics();
+ if (graphics == null)
+ {
+ return;
+ }
+ graphics.setColor(Color.white);
+ graphics.fillRect(0, 0, graphicsWidth, graphicsHeight);
+ if (av.getWrapAlignment())
+ {
+ printWrappedAlignment(dim1.width, dim1.height + borderBottomOffset,
+ 0, graphics, false);
+ }
+ else
+ {
+ printUnwrapped(dim1.width, dim1.height, 0, graphics, graphics);
+ }
- im = new jalview.util.ImageMaker(this, type, imageAction,
- aDimension.getWidth(),
- aDimension.getHeight() + boarderBottomOffset, file,
- imageTitle, alignFrame, pSessionId, headless);
- Graphics graphics = im.getGraphics();
- if (av.getWrapAlignment())
+ if (forSplitFrame)
+ {
+ /*
+ * append coding complement image
+ */
+ // to debug location of next write to Graphics:
+ // graphics.drawString("Hello world", 0, 0);
+ if (av.getCodingComplement().getWrapAlignment())
{
- if (graphics != null)
- {
- printWrappedAlignment(aDimension.getWidth(),
- aDimension.getHeight() + boarderBottomOffset, 0,
- graphics);
- im.writeImage();
- }
+ complement.printWrappedAlignment(dim2.width,
+ dim2.height + borderBottomOffset, 0, graphics, false);
}
else
{
- if (graphics != null)
- {
- printUnwrapped(aDimension.getWidth(), aDimension.getHeight(), 0,
- graphics, graphics);
- im.writeImage();
- }
+ complement.printUnwrapped(dim2.width, dim2.height, 0, graphics,
+ graphics);
}
-
- } catch (OutOfMemoryError err)
- {
- // Be noisy here.
- System.out.println("########################\n" + "OUT OF MEMORY "
- + file + "\n" + "########################");
- new OOMWarning("Creating Image for " + file, err);
- // System.out.println("Create IMAGE: " + err);
- } catch (Exception ex)
- {
- ex.printStackTrace();
}
+
+ im.writeImage();
+ } catch (OutOfMemoryError err)
+ {
+ // Be noisy here.
+ System.out.println("########################\n" + "OUT OF MEMORY "
+ + file + "\n" + "########################");
+ new OOMWarning("Creating Image for " + file, err);
+ // System.out.println("Create IMAGE: " + err);
+ } catch (Exception ex)
+ {
+ ex.printStackTrace();
} finally
{
-
+ /*
+ * restore preference settings in case they were fudged
+ */
+ Cache.setProperty("FIGURE_AUTOIDWIDTH",
+ String.valueOf(autoIdWidth));
+ Cache.setProperty("FIGURE_FIXEDIDWIDTH",
+ String.valueOf(fixedIdWidth));
}
}
+ /**
+ * Computes and answers the width and height of the alignment in pixels,
+ * including
+ * <ul>
+ * <li>sequence ids</li>
+ * <li>scale above, left or right if shown</li>
+ * <li>sequence rows, plus one spacer line</li>
+ * <li>annotations, if shown</li>
+ * </ul>
+ * The alignment may be in wrapped or unwrapped mode.
+ * <ul>
+ *
+ * @return
+ */
public AlignmentDimension getAlignmentDimension()
{
int maxwidth = av.getAlignment().getVisibleWidth();
{
height += getAnnotationPanel().adjustPanelHeight() + 3;
}
- return new AlignmentDimension(width, height);
+ return new AlignmentDimension(width, height);
}
/**
- * DOCUMENT ME!
+ * Creates and writes an EPS image of the alignment, to the given file if
+ * specified, else after prompting for the output file
+ *
+ * @param epsFile
+ * @param forSplitFrame
*/
- public void makeEPS(File epsFile)
+ public void makeEPS(File epsFile, boolean forSplitFrame)
{
- makeAlignmentImage(jalview.util.ImageMaker.TYPE.EPS, epsFile);
+ makeAlignmentImage(EPS, epsFile, forSplitFrame);
}
/**
- * DOCUMENT ME!
+ * Creates and writes a PNG image of the alignment, to the given file if
+ * specified, else after prompting for the output file
+ *
+ * @param pngFile
+ * @param forSplitFrame
*/
- public void makePNG(File pngFile)
+ public void makePNG(File pngFile, boolean forSplitFrame)
{
- makeAlignmentImage(jalview.util.ImageMaker.TYPE.PNG, pngFile);
+ makeAlignmentImage(PNG, pngFile, forSplitFrame);
}
- public void makeSVG(File svgFile)
+ /**
+ * Creates and writes an SVG image of the alignment, to the given file if
+ * specified, else after prompting for the output file
+ *
+ * @param svgFile
+ * @param forSplitFrame
+ */
+ public void makeSVG(File svgFile, boolean forSplitFrame)
{
- makeAlignmentImage(jalview.util.ImageMaker.TYPE.SVG, svgFile);
+ makeAlignmentImage(SVG, svgFile, forSplitFrame);
}
public void makePNGImageMap(File imgMapFile, String imageName)
}
+ /**
+ * Answers the height of the entire alignment in pixels, assuming it is in
+ * wrapped mode
+ *
+ * @return
+ */
int getWrappedHeight()
{
int seqPanelWidth = getSeqPanel().seqCanvas.getWidth();
int annotationHeight = 0;
if (av.isShowAnnotation())
{
+ hgap += SeqCanvas.SEQS_ANNOTATION_GAP;
annotationHeight = getAnnotationPanel().adjustPanelHeight();
}