X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FAlignmentPanel.java;h=065872fbd43182094b94b2526804c33f0d0ef9a4;hb=a1984b1c8c273ed33c7ce9283039f4027dcae2de;hp=c46a2ab5ace978502ce70b7fa4dfacf2760e078c;hpb=ddae5cd17183675eb4a1cb7ad49048193caaf1a0;p=jalview.git diff --git a/src/jalview/gui/AlignmentPanel.java b/src/jalview/gui/AlignmentPanel.java index c46a2ab..065872f 100644 --- a/src/jalview/gui/AlignmentPanel.java +++ b/src/jalview/gui/AlignmentPanel.java @@ -24,20 +24,22 @@ import jalview.analysis.AnnotationSorter; 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; @@ -71,9 +73,15 @@ import javax.swing.SwingUtilities; * @author $author$ * @version $Revision: 1.161 $ */ +@SuppressWarnings("serial") public class AlignmentPanel extends GAlignmentPanel implements AdjustmentListener, Printable, AlignmentViewPanel, ViewportListenerI { + /* + * spare space in pixels between sequence id and alignment panel + */ + private static final int ID_WIDTH_PADDING = 4; + public AlignViewport av; OverviewPanel overviewPanel; @@ -82,11 +90,8 @@ public class AlignmentPanel extends GAlignmentPanel implements private IdPanel idPanel; - private boolean headless; - IdwidthAdjuster idwidthAdjuster; - /** DOCUMENT ME!! */ public AlignFrame alignFrame; private ScalePanel scalePanel; @@ -117,6 +122,7 @@ public class AlignmentPanel extends GAlignmentPanel implements */ public AlignmentPanel(AlignFrame af, final AlignViewport av) { +// setBackground(Color.white); // BH 2019 alignFrame = af; this.av = av; setSeqPanel(new SeqPanel(av, this)); @@ -229,13 +235,11 @@ public class AlignmentPanel extends GAlignmentPanel implements 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(); Dimension d = calculateIdWidth(); - - d.setSize(d.width + 4, d.height); getIdPanel().getIdCanvas().setPreferredSize(d); hscrollFillerPanel.setPreferredSize(d); @@ -243,20 +247,24 @@ public class AlignmentPanel extends GAlignmentPanel implements } /** - * Calculate the width of the alignment labels based on the displayed names - * and any bounds on label width set in preferences. + * Calculates the width of the alignment labels based on the displayed names + * and any bounds on label width set in preferences. The calculated width is + * also set as a property of the viewport. * * @return Dimension giving the maximum width of the alignment label panel * that should be used. */ public Dimension calculateIdWidth() { + int oldWidth = av.getIdWidth(); + // calculate sensible default width when no preference is available Dimension r = null; if (av.getIdWidth() < 0) { int afwidth = (alignFrame != null ? alignFrame.getWidth() : 300); - int maxwidth = Math.max(20, Math.min(afwidth - 200, 2 * afwidth / 3)); + int idWidth = Math.min(afwidth - 200, 2 * afwidth / 3); + int maxwidth = Math.max(IdwidthAdjuster.MIN_ID_WIDTH, idWidth); r = calculateIdWidth(maxwidth); av.setIdWidth(r.width); } @@ -266,6 +274,16 @@ public class AlignmentPanel extends GAlignmentPanel implements r.width = av.getIdWidth(); r.height = 0; } + + /* + * fudge: if desired width has changed, update layout + * (see also paintComponent - updates layout on a repaint) + */ + if (r.width != oldWidth) + { + idPanelHolder.setPreferredSize(r); + validate(); + } return r; } @@ -278,7 +296,7 @@ public class AlignmentPanel extends GAlignmentPanel implements * @return Dimension giving the maximum width of the alignment label panel * that should be used. */ - public Dimension calculateIdWidth(int maxwidth) + protected Dimension calculateIdWidth(int maxwidth) { Container c = new Container(); @@ -288,19 +306,13 @@ public class AlignmentPanel extends GAlignmentPanel implements AlignmentI al = av.getAlignment(); int i = 0; int idWidth = 0; - String id; while ((i < al.getHeight()) && (al.getSequenceAt(i) != null)) { SequenceI s = al.getSequenceAt(i); - - id = s.getDisplayId(av.getShowJVSuffix()); - - if (fm.stringWidth(id) > idWidth) - { - idWidth = fm.stringWidth(id); - } - + String id = s.getDisplayId(av.getShowJVSuffix()); + int stringWidth = fm.stringWidth(id); + idWidth = Math.max(idWidth, stringWidth); i++; } @@ -314,31 +326,29 @@ public class AlignmentPanel extends GAlignmentPanel implements while (i < al.getAlignmentAnnotation().length) { String label = al.getAlignmentAnnotation()[i].label; - - if (fm.stringWidth(label) > idWidth) - { - idWidth = fm.stringWidth(label); - } - + int stringWidth = fm.stringWidth(label); + idWidth = Math.max(idWidth, stringWidth); i++; } } - return new Dimension( - maxwidth < 0 ? idWidth : Math.min(maxwidth, idWidth), 12); + int w = maxwidth < 0 ? idWidth : Math.min(maxwidth, idWidth); + w += ID_WIDTH_PADDING; + + return new Dimension(w, 12); } /** - * 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); } /** @@ -346,13 +356,11 @@ public class AlignmentPanel extends GAlignmentPanel implements * (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); } /** @@ -365,14 +373,12 @@ public class AlignmentPanel extends GAlignmentPanel implements * @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(); @@ -478,7 +484,7 @@ public class AlignmentPanel extends GAlignmentPanel implements scrollNeeded = ranges.scrollToWrappedVisible(start); } - paintAlignment(redrawOverview, false); + paintAlignment(false, false); return scrollNeeded; } @@ -537,7 +543,7 @@ public class AlignmentPanel extends GAlignmentPanel implements 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()); } /** @@ -546,44 +552,27 @@ public class AlignmentPanel extends GAlignmentPanel implements */ 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(); @@ -616,6 +605,7 @@ public class AlignmentPanel extends GAlignmentPanel implements { annotationScroller.setVisible(true); annotationSpaceFillerHolder.setVisible(true); + validateAnnotationDimensions(false); } int canvasWidth = getSeqPanel().seqCanvas.getWidth(); @@ -668,16 +658,9 @@ public class AlignmentPanel extends GAlignmentPanel implements } 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(); @@ -823,7 +806,7 @@ public class AlignmentPanel extends GAlignmentPanel implements // could not be validated and it is not clear if it is now being // called. Log warning here in case it is called and unforeseen // problems occur - Cache.log.warn( + Cache.warn( "Unexpected path through code: Wrapped jar file opened with wrap alignment set in preferences"); // scroll to start of panel @@ -862,12 +845,6 @@ public class AlignmentPanel extends GAlignmentPanel implements } } - /** - * DOCUMENT ME! - * - * @param g - * DOCUMENT ME! - */ @Override public void paintComponent(Graphics g) { @@ -885,6 +862,7 @@ public class AlignmentPanel extends GAlignmentPanel implements */ ViewportRanges ranges = av.getRanges(); setScrollValues(ranges.getStartRes(), ranges.getStartSeq()); + super.paintComponent(g); } /** @@ -989,8 +967,8 @@ public class AlignmentPanel extends GAlignmentPanel implements 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, @@ -1090,6 +1068,8 @@ public class AlignmentPanel extends GAlignmentPanel implements public int printWrappedAlignment(int pageWidth, int pageHeight, int pageNumber, Graphics g) throws PrinterException { + getSeqPanel().seqCanvas.calculateWrappedGeometry(getWidth(), + getHeight()); int annotationHeight = 0; if (av.isShowAnnotation()) { @@ -1107,15 +1087,11 @@ public class AlignmentPanel extends GAlignmentPanel implements 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); + av.getRanges().setViewportStartAndWidth(0, resWidth); int totalHeight = cHeight * (maxwidth / resWidth + 1); @@ -1127,8 +1103,8 @@ 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); @@ -1175,111 +1151,73 @@ public class AlignmentPanel extends GAlignmentPanel implements * be returned * @return */ - public int getVisibleIdWidth(boolean onscreen) + protected int getVisibleIdWidth(boolean onscreen) { // see if rendering offscreen - check preferences and calc width accordingly if (!onscreen && Cache.getDefault("FIGURE_AUTOIDWIDTH", false)) { - return calculateIdWidth(-1).width + 4; + return calculateIdWidth(-1).width; } - Integer idwidth = null; - if (onscreen || (idwidth = Cache - .getIntegerProperty("FIGURE_FIXEDIDWIDTH")) == null) + Integer idwidth = onscreen ? null + : Cache.getIntegerProperty("FIGURE_FIXEDIDWIDTH"); + if (idwidth != null) { - int w = getIdPanel().getWidth(); - return (w > 0 ? w : calculateIdWidth().width + 4); + return idwidth.intValue() + ID_WIDTH_PADDING; } - return idwidth.intValue() + 4; + + int w = getIdPanel().getWidth(); + return (w > 0 ? w : calculateIdWidth().width); } - 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(); @@ -1288,7 +1226,7 @@ public class AlignmentPanel extends GAlignmentPanel implements 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 @@ -1312,27 +1250,6 @@ public class AlignmentPanel extends GAlignmentPanel implements } - /** - * 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 @@ -1462,6 +1379,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(); @@ -1486,6 +1409,7 @@ public class AlignmentPanel extends GAlignmentPanel implements int annotationHeight = 0; if (av.isShowAnnotation()) { + hgap += SeqCanvas.SEQS_ANNOTATION_GAP; annotationHeight = getAnnotationPanel().adjustPanelHeight(); } @@ -1540,9 +1464,9 @@ public class AlignmentPanel extends GAlignmentPanel implements } else { - if (Cache.log.isDebugEnabled()) + if (Cache.isDebugEnabled()) { - Cache.log.warn("Closing alignment panel which is already closed."); + Cache.warn("Closing alignment panel which is already closed."); } } } @@ -1594,7 +1518,7 @@ public class AlignmentPanel extends GAlignmentPanel implements @Override public String getViewName() { - return av.viewName; + return av.getViewName(); } /** @@ -1617,13 +1541,16 @@ public class AlignmentPanel extends GAlignmentPanel implements } catch (Exception ex) { } - if (b) { - alignFrame.setDisplayedView(this); + setAlignFrameView(); } } - + public void setAlignFrameView() + { + alignFrame.setDisplayedView(this); + } + @Override public StructureSelectionManager getStructureSelectionManager() { @@ -1725,7 +1652,7 @@ public class AlignmentPanel extends GAlignmentPanel implements */ protected void scrollToCentre(SearchResultsI sr, int verticalOffset) { - scrollToPosition(sr, verticalOffset, true, true); + scrollToPosition(sr, verticalOffset, true); } /** @@ -1812,4 +1739,5 @@ public class AlignmentPanel extends GAlignmentPanel implements { return calculationDialog; } + }