import jalview.api.AlignViewportI;
import jalview.api.AlignmentViewPanel;
import jalview.bin.Cache;
+import jalview.bin.Jalview;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SearchResultsI;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
+import jalview.gui.ImageExporter.ImageWriterI;
import jalview.io.HTMLOutput;
import jalview.jbgui.GAlignmentPanel;
import jalview.math.AlignmentDimension;
import jalview.schemes.ResidueProperties;
import jalview.structure.StructureSelectionManager;
import jalview.util.Comparison;
+import jalview.util.ImageMaker;
import jalview.util.MessageManager;
-import jalview.util.Platform;
import jalview.viewmodel.ViewportListenerI;
import jalview.viewmodel.ViewportRanges;
* @author $author$
* @version $Revision: 1.161 $
*/
+@SuppressWarnings("serial")
public class AlignmentPanel extends GAlignmentPanel implements
AdjustmentListener, Printable, AlignmentViewPanel, ViewportListenerI
{
private IdPanel idPanel;
- private boolean headless;
-
IdwidthAdjuster idwidthAdjuster;
- /** DOCUMENT ME!! */
public AlignFrame alignFrame;
private ScalePanel scalePanel;
*/
public AlignmentPanel(AlignFrame af, final AlignViewport av)
{
+// setBackground(Color.white); // BH 2019
alignFrame = af;
this.av = av;
setSeqPanel(new SeqPanel(av, this));
new Dimension(10, av.getCharHeight() + fm.getDescent()));
idwidthAdjuster.invalidate();
scalePanelHolder.invalidate();
- getIdPanel().getIdCanvas().gg = null;
+ // BH 2018 getIdPanel().getIdCanvas().gg = null;
getSeqPanel().seqCanvas.img = null;
getAnnotationPanel().adjustPanelHeight();
}
/**
- * Highlight the given results on the alignment.
+ * Highlight the given results on the alignment
*
*/
public void highlightSearchResults(SearchResultsI results)
{
- boolean scrolled = scrollToPosition(results, 0, true, false);
+ boolean scrolled = scrollToPosition(results, 0, false);
- boolean noFastPaint = scrolled && av.getWrapAlignment();
+ boolean fastPaint = !(scrolled && av.getWrapAlignment());
- getSeqPanel().seqCanvas.highlightSearchResults(results, noFastPaint);
+ getSeqPanel().seqCanvas.highlightSearchResults(results, fastPaint);
}
/**
* (if any)
*
* @param searchResults
- * @param redrawOverview
* @return
*/
- public boolean scrollToPosition(SearchResultsI searchResults,
- boolean redrawOverview)
+ public boolean scrollToPosition(SearchResultsI searchResults)
{
- return scrollToPosition(searchResults, 0, redrawOverview, false);
+ return scrollToPosition(searchResults, 0, false);
}
/**
* @param verticalOffset
* if greater than zero, allows scrolling to a position below the
* first displayed sequence
- * @param redrawOverview
- * - when set, the overview will be recalculated (takes longer)
* @param centre
* if true, try to centre the search results horizontally in the view
* @return
*/
protected boolean scrollToPosition(SearchResultsI results,
- int verticalOffset, boolean redrawOverview, boolean centre)
+ int verticalOffset, boolean centre)
{
int startv, endv, starts, ends;
ViewportRanges ranges = av.getRanges();
scrollNeeded = ranges.scrollToWrappedVisible(start);
}
- paintAlignment(redrawOverview, false);
+ paintAlignment(false, false);
return scrollNeeded;
}
addNotify();
// TODO: many places call this method and also paintAlignment with various
// different settings. this means multiple redraws are triggered...
- paintAlignment(true, false);
+ paintAlignment(true, av.needToUpdateStructureViews());
}
/**
*/
protected void validateAnnotationDimensions(boolean adjustPanelHeight)
{
- int annotationHeight = getAnnotationPanel().adjustPanelHeight();
-
- if (adjustPanelHeight)
- {
- int rowHeight = av.getCharHeight();
- int alignmentHeight = rowHeight * av.getAlignment().getHeight();
+ // BH 2018.04.18 comment: addNotify() is not appropriate here. We
+ // are not changing ancestors, and keyboard action listeners do
+ // not need to be reset. addNotify() is a very expensive operation,
+ // requiring a full re-layout of all parents and children.
+ // Note in JComponent:
+ // This method is called by the toolkit internally and should
+ // not be called directly by programs.
+ // I note that addNotify() is called in several areas of Jalview.
- /*
- * Estimate available height in the AlignFrame for alignment +
- * annotations. Deduct an estimate for title bar, menu bar, scale panel,
- * hscroll, status bar, insets.
- */
- int stuff = Platform.isAMac() ? 120 : 140;
- int availableHeight = alignFrame.getHeight() - stuff;
+ int annotationHeight = getAnnotationPanel().adjustPanelHeight();
+ annotationHeight = getAnnotationPanel()
+ .adjustForAlignFrame(adjustPanelHeight, annotationHeight);
- /*
- * If not enough vertical space, maximize annotation height while keeping
- * at least two rows of alignment visible
- */
- if (annotationHeight + alignmentHeight > availableHeight)
- {
- annotationHeight = Math.min(annotationHeight,
- availableHeight - 2 * rowHeight);
- }
- }
- else
- {
- // maintain same window layout whilst updating sliders
- annotationHeight = annotationScroller.getSize().height;
- }
hscroll.addNotify();
-
annotationScroller.setPreferredSize(
new Dimension(annotationScroller.getWidth(), annotationHeight));
Dimension e = idPanel.getSize();
alabels.setSize(new Dimension(e.width, annotationHeight));
+
annotationSpaceFillerHolder.setPreferredSize(new Dimension(
annotationSpaceFillerHolder.getWidth(), annotationHeight));
annotationScroller.validate();
{
annotationScroller.setVisible(true);
annotationSpaceFillerHolder.setVisible(true);
+ validateAnnotationDimensions(false);
}
int canvasWidth = getSeqPanel().seqCanvas.getWidth();
}
else
{
- int width = av.getAlignment().getWidth();
+ int width = av.getAlignment().getVisibleWidth();
int height = av.getAlignment().getHeight();
- if (av.hasHiddenColumns())
- {
- // reset the width to exclude hidden columns
- width = av.getAlignment().getHiddenColumns()
- .absoluteToVisibleColumn(width);
- }
-
hextent = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth();
vextent = getSeqPanel().seqCanvas.getHeight() / av.getCharHeight();
*/
ViewportRanges ranges = av.getRanges();
setScrollValues(ranges.getStartRes(), ranges.getStartSeq());
+ super.paintComponent(g);
}
/**
final int totalSeq = (pageHeight - scaleHeight) / charHeight - 1;
- final int alignmentWidth = av.getAlignment().getWidth();
- final int pagesWide = (alignmentWidth / totalRes) + 1;
+ final int alignmentWidth = av.getAlignment().getVisibleWidth();
+ int pagesWide = (alignmentWidth / totalRes) + 1;
final int startRes = (pageIndex % pagesWide) * totalRes;
final int endRes = Math.min(startRes + totalRes - 1,
int idWidth = getVisibleIdWidth(false);
- int maxwidth = av.getAlignment().getWidth();
- if (av.hasHiddenColumns())
- {
- maxwidth = av.getAlignment().getHiddenColumns()
- .absoluteToVisibleColumn(maxwidth) - 1;
- }
+ int maxwidth = av.getAlignment().getVisibleWidth();
int resWidth = getSeqPanel().seqCanvas
.getWrappedCanvasWidth(pageWidth - idWidth);
g.setFont(av.getFont());
g.setColor(Color.black);
+ /*
+ * 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)
+ */
g.translate(0, -pageNumber * pageHeight);
g.setClip(0, pageNumber * pageHeight, pageWidth, pageHeight);
return idwidth.intValue() + 4;
}
- void makeAlignmentImage(jalview.util.ImageMaker.TYPE type, File file)
+ /**
+ * Builds an image of the alignment of the specified type (EPS/PNG/SVG) and
+ * writes it to the specified file
+ *
+ * @param type
+ * @param file
+ */
+ void makeAlignmentImage(ImageMaker.TYPE type, File file)
{
- 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)
- {
- if (file != null)
- {
- alignFrame.setProgressBar(MessageManager
- .formatMessage("status.saving_file", new Object[]
- { type.getLabel() }), pSessionId);
- }
- }
- try
+ final int borderBottomOffset = 5;
+
+ AlignmentDimension aDimension = getAlignmentDimension();
+ // todo use a lambda function in place of callback here?
+ ImageWriterI writer = new ImageWriterI()
{
- AlignmentDimension aDimension = getAlignmentDimension();
- try
+ @Override
+ public void exportImage(Graphics graphics) throws Exception
{
- 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)
- {
- imageAction = "Create EPS file from alignment";
- imageTitle = alignFrame.getTitle();
- }
- else
- {
- imageAction = "Create SVG file from alignment";
- imageTitle = alignFrame.getTitle();
- }
-
- 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 (graphics != null)
- {
- printWrappedAlignment(aDimension.getWidth(),
- aDimension.getHeight() + boarderBottomOffset, 0,
- graphics);
- im.writeImage();
- }
+ printWrappedAlignment(aDimension.getWidth(),
+ aDimension.getHeight() + borderBottomOffset, 0, graphics);
}
else
{
- if (graphics != null)
- {
- printUnwrapped(aDimension.getWidth(), aDimension.getHeight(), 0,
- graphics, graphics);
- im.writeImage();
- }
+ printUnwrapped(aDimension.getWidth(), aDimension.getHeight(), 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();
}
- } finally
- {
+ };
- }
+ String fileTitle = alignFrame.getTitle();
+ ImageExporter exporter = new ImageExporter(writer, alignFrame, type,
+ fileTitle);
+ int imageWidth = aDimension.getWidth();
+ int imageHeight = aDimension.getHeight() + borderBottomOffset;
+ String of = MessageManager.getString("label.alignment");
+ exporter.doExport(file, this, imageWidth, imageHeight, of);
}
+ /**
+ * Calculates and returns a suitable width and height (in pixels) for an
+ * exported image
+ *
+ * @return
+ */
public AlignmentDimension getAlignmentDimension()
{
- int maxwidth = av.getAlignment().getWidth();
- if (av.hasHiddenColumns())
- {
- maxwidth = av.getAlignment().getHiddenColumns()
- .absoluteToVisibleColumn(maxwidth);
- }
+ int maxwidth = av.getAlignment().getVisibleWidth();
int height = ((av.getAlignment().getHeight() + 1) * av.getCharHeight())
+ getScalePanel().getHeight();
if (av.getWrapAlignment())
{
height = getWrappedHeight();
- if (headless)
+ if (Jalview.isHeadlessMode())
{
// need to obtain default alignment width and then add in any
// additional allowance for id margin
}
- /**
- * DOCUMENT ME!
- */
- public void makeEPS(File epsFile)
- {
- makeAlignmentImage(jalview.util.ImageMaker.TYPE.EPS, epsFile);
- }
-
- /**
- * DOCUMENT ME!
- */
- public void makePNG(File pngFile)
- {
- makeAlignmentImage(jalview.util.ImageMaker.TYPE.PNG, pngFile);
- }
-
- public void makeSVG(File svgFile)
- {
- makeAlignmentImage(jalview.util.ImageMaker.TYPE.SVG, svgFile);
- }
-
public void makePNGImageMap(File imgMapFile, String imageName)
{
// /////ONLY WORKS WITH NON WRAPPED ALIGNMENTS
{
int seqPanelWidth = getSeqPanel().seqCanvas.getWidth();
- if (System.getProperty("java.awt.headless") != null
- && System.getProperty("java.awt.headless").equals("true"))
+ if (Jalview.isHeadlessMode())
{
seqPanelWidth = alignFrame.getWidth() - getVisibleIdWidth()
- vscroll.getPreferredSize().width
@Override
public String getViewName()
{
- return av.viewName;
+ return av.getViewName();
}
/**
*/
protected void scrollToCentre(SearchResultsI sr, int verticalOffset)
{
- scrollToPosition(sr, verticalOffset, true, true);
+ scrollToPosition(sr, verticalOffset, true);
}
/**
{
return calculationDialog;
}
+
}