X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FAlignmentPanel.java;h=aa28a8c9f11d5ea4261bccc602e284297e3b5758;hb=03bc8848382795bda548083f0bc3202dfe6a9b8b;hp=61b4565d3aead8986c85da4855c640338f648235;hpb=fab0afc9e1e7a5ca460f0cbd48545536f989a435;p=jalview.git diff --git a/src/jalview/gui/AlignmentPanel.java b/src/jalview/gui/AlignmentPanel.java index 61b4565..aa28a8c 100644 --- a/src/jalview/gui/AlignmentPanel.java +++ b/src/jalview/gui/AlignmentPanel.java @@ -20,29 +20,6 @@ */ package jalview.gui; -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.viewmodel.ViewportListenerI; -import jalview.viewmodel.ViewportRanges; - import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; @@ -67,15 +44,47 @@ import java.util.List; import javax.swing.SwingUtilities; +import jalview.analysis.AnnotationSorter; +import jalview.api.AlignViewportI; +import jalview.api.AlignmentViewPanel; +import jalview.bin.Cache; +import jalview.bin.Console; +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.io.exceptions.ImageOutputException; +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.imagemaker.BitmapImageSizing; +import jalview.viewmodel.ViewportListenerI; +import jalview.viewmodel.ViewportRanges; + /** * DOCUMENT ME! * * @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; @@ -116,6 +125,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)); @@ -222,19 +232,21 @@ public class AlignmentPanel extends GAlignmentPanel implements // to prevent drawing old image FontMetrics fm = getFontMetrics(av.getFont()); + // update the flag controlling whether the grid is too small to render the + // font + av.validCharWidth = fm.charWidth('M') <= av.getCharWidth(); + scalePanelHolder.setPreferredSize( new Dimension(10, av.getCharHeight() + fm.getDescent())); idSpaceFillerPanel1.setPreferredSize( 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); @@ -242,20 +254,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); } @@ -265,6 +281,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; } @@ -277,7 +303,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(); @@ -287,19 +313,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++; } @@ -313,27 +333,25 @@ 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 fastPaint = !(scrolled && av.getWrapAlignment()); @@ -345,13 +363,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); } /** @@ -364,14 +380,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(); @@ -464,8 +478,7 @@ public class AlignmentPanel extends GAlignmentPanel implements /* * Scroll down to make end of search results visible */ - setScrollValues(ranges.getStartRes(), starts + seqIndex - ends - + 1); + setScrollValues(ranges.getStartRes(), starts + seqIndex - ends + 1); } /* * Else results are already visible - no need to scroll @@ -477,7 +490,7 @@ public class AlignmentPanel extends GAlignmentPanel implements scrollNeeded = ranges.scrollToWrappedVisible(start); } - paintAlignment(redrawOverview, false); + paintAlignment(false, false); return scrollNeeded; } @@ -536,7 +549,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()); } /** @@ -545,6 +558,15 @@ public class AlignmentPanel extends GAlignmentPanel implements */ protected void validateAnnotationDimensions(boolean adjustPanelHeight) { + // 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. + int annotationHeight = getAnnotationPanel().adjustPanelHeight(); annotationHeight = getAnnotationPanel() .adjustForAlignFrame(adjustPanelHeight, annotationHeight); @@ -641,16 +663,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(); @@ -796,7 +811,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( + Console.warn( "Unexpected path through code: Wrapped jar file opened with wrap alignment set in preferences"); // scroll to start of panel @@ -835,12 +850,6 @@ public class AlignmentPanel extends GAlignmentPanel implements } } - /** - * DOCUMENT ME! - * - * @param g - * DOCUMENT ME! - */ @Override public void paintComponent(Graphics g) { @@ -858,6 +867,7 @@ public class AlignmentPanel extends GAlignmentPanel implements */ ViewportRanges ranges = av.getRanges(); setScrollValues(ranges.getStartRes(), ranges.getStartSeq()); + super.paintComponent(g); } /** @@ -962,8 +972,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, @@ -1015,8 +1025,8 @@ public class AlignmentPanel extends GAlignmentPanel implements * single graphics context), then reset to (0, scale height) */ alignmentGraphics.translate(alignmentGraphicsOffset, scaleHeight); - getSeqPanel().seqCanvas.drawPanelForPrinting(alignmentGraphics, startRes, - endRes, startSeq, endSeq - 1); + getSeqPanel().seqCanvas.drawPanelForPrinting(alignmentGraphics, + startRes, endRes, startSeq, endSeq - 1); alignmentGraphics.translate(-alignmentGraphicsOffset, 0); if (av.isShowAnnotation() && (endSeq == alignmentHeight)) @@ -1038,6 +1048,7 @@ public class AlignmentPanel extends GAlignmentPanel implements */ alignmentGraphics.translate(alignmentGraphicsOffset, alignmentDrawnHeight); + updateLayout(); getAnnotationPanel().renderer.drawComponent(getAnnotationPanel(), av, alignmentGraphics, -1, startRes, endRes + 1); } @@ -1060,9 +1071,11 @@ public class AlignmentPanel extends GAlignmentPanel implements * * @throws PrinterException */ - public int printWrappedAlignment(int pageWidth, int pageHeight, int pageNumber, - Graphics g) throws PrinterException + public int printWrappedAlignment(int pageWidth, int pageHeight, + int pageNumber, Graphics g) throws PrinterException { + getSeqPanel().seqCanvas.calculateWrappedGeometry(getWidth(), + getHeight()); int annotationHeight = 0; if (av.isShowAnnotation()) { @@ -1080,15 +1093,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); @@ -1100,8 +1109,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); @@ -1115,8 +1124,8 @@ public class AlignmentPanel extends GAlignmentPanel implements g.translate(idWidth, 0); - getSeqPanel().seqCanvas.drawWrappedPanelForPrinting(g, pageWidth - idWidth, - totalHeight, 0); + getSeqPanel().seqCanvas.drawWrappedPanelForPrinting(g, + pageWidth - idWidth, totalHeight, 0); if ((pageNumber * pageHeight) < totalHeight) { @@ -1148,21 +1157,29 @@ 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(ImageMaker.TYPE type, File file, String renderer) + throws ImageOutputException + { + makeAlignmentImage(type, file, renderer, + BitmapImageSizing.nullBitmapImageSizing()); } /** @@ -1171,8 +1188,11 @@ public class AlignmentPanel extends GAlignmentPanel implements * * @param type * @param file + * @param textrenderer + * @param bitmapscale */ - void makeAlignmentImage(ImageMaker.TYPE type, File file) + void makeAlignmentImage(ImageMaker.TYPE type, File file, String renderer, + BitmapImageSizing userBis) throws ImageOutputException { final int borderBottomOffset = 5; @@ -1202,7 +1222,8 @@ public class AlignmentPanel extends GAlignmentPanel implements int imageWidth = aDimension.getWidth(); int imageHeight = aDimension.getHeight() + borderBottomOffset; String of = MessageManager.getString("label.alignment"); - exporter.doExport(file, this, imageWidth, imageHeight, of); + exporter.doExport(file, this, imageWidth, imageHeight, of, renderer, + userBis); } /** @@ -1213,12 +1234,7 @@ public class AlignmentPanel extends GAlignmentPanel implements */ 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(); @@ -1252,6 +1268,7 @@ public class AlignmentPanel extends GAlignmentPanel implements } public void makePNGImageMap(File imgMapFile, String imageName) + throws ImageOutputException { // /////ONLY WORKS WITH NON WRAPPED ALIGNMENTS // //////////////////////////////////////////// @@ -1285,13 +1302,13 @@ public class AlignmentPanel extends GAlignmentPanel implements String triplet = null; if (av.getAlignment().isNucleotide()) { - triplet = ResidueProperties.nucleotideName.get(seq - .getCharAt(column) + ""); + triplet = ResidueProperties.nucleotideName + .get(seq.getCharAt(column) + ""); } else { - triplet = ResidueProperties.aa2Triplet.get(seq.getCharAt(column) - + ""); + triplet = ResidueProperties.aa2Triplet + .get(seq.getCharAt(column) + ""); } if (triplet == null) @@ -1308,7 +1325,8 @@ public class AlignmentPanel extends GAlignmentPanel implements text.append(" features = seq.findFeatures(column, column); + List features = seq.findFeatures(column, + column); for (SequenceFeature sf : features) { if (sf.isContactFeature()) @@ -1374,12 +1393,19 @@ public class AlignmentPanel extends GAlignmentPanel implements } catch (Exception ex) { - ex.printStackTrace(); + throw new ImageOutputException( + "couldn't write ImageMap due to unexpected error", ex); } } // /////////END OF IMAGE MAP } + /** + * Answers the height of the entire alignment in pixels, assuming it is in + * wrapped mode + * + * @return + */ int getWrappedHeight() { int seqPanelWidth = getSeqPanel().seqCanvas.getWidth(); @@ -1404,6 +1430,7 @@ public class AlignmentPanel extends GAlignmentPanel implements int annotationHeight = 0; if (av.isShowAnnotation()) { + hgap += SeqCanvas.SEQS_ANNOTATION_GAP; annotationHeight = getAnnotationPanel().adjustPanelHeight(); } @@ -1458,9 +1485,9 @@ public class AlignmentPanel extends GAlignmentPanel implements } else { - if (Cache.log.isDebugEnabled()) + if (Console.isDebugEnabled()) { - Cache.log.warn("Closing alignment panel which is already closed."); + Console.warn("Closing alignment panel which is already closed."); } } } @@ -1535,13 +1562,17 @@ 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() { @@ -1643,7 +1674,7 @@ public class AlignmentPanel extends GAlignmentPanel implements */ protected void scrollToCentre(SearchResultsI sr, int verticalOffset) { - scrollToPosition(sr, verticalOffset, true, true); + scrollToPosition(sr, verticalOffset, true); } /** @@ -1730,4 +1761,43 @@ public class AlignmentPanel extends GAlignmentPanel implements { return calculationDialog; } + + /** + * Constructs and sets the title for the Overview window (if there is one), + * including the align frame's title, and view name (if applicable). Returns + * the title, or null if this panel has no Overview window open. + * + * @param alignFrame + * @return + */ + public String setOverviewTitle(AlignFrame alignFrame) + { + if (this.overviewPanel == null) + { + return null; + } + String overviewTitle = MessageManager + .formatMessage("label.overview_params", new Object[] + { alignFrame.getTitle() }); + String viewName = getViewName(); + if (viewName != null) + { + overviewTitle += (" " + viewName); + } + overviewPanel.setTitle(overviewTitle); + return overviewTitle; + } + + /** + * If this alignment panel has an Overview panel open, closes it + */ + public void closeOverviewPanel() + { + if (overviewPanel != null) + { + overviewPanel.close(); + overviewPanel = null; + } + } + }