X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FAlignmentPanel.java;h=0a128c8333c722f578c156cf8bf53907ff0f7a96;hb=86fd4dbafd6175d651fe569c0861de10029cc7b8;hp=9e9f1c1313dee9e0839d09146ccb44cc262f1380;hpb=838e4f91d4a53dd315640dbc9ff6ef7a815ee576;p=jalview.git diff --git a/src/jalview/gui/AlignmentPanel.java b/src/jalview/gui/AlignmentPanel.java index 9e9f1c1..0a128c8 100644 --- a/src/jalview/gui/AlignmentPanel.java +++ b/src/jalview/gui/AlignmentPanel.java @@ -1,6 +1,6 @@ /* - * Jalview - A Sequence Alignment Editor and Viewer (Version 2.9.0b1) - * Copyright (C) 2015 The Jalview Authors + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors * * This file is part of Jalview. * @@ -25,7 +25,7 @@ import jalview.api.AlignViewportI; import jalview.api.AlignmentViewPanel; import jalview.bin.Cache; import jalview.datamodel.AlignmentI; -import jalview.datamodel.SearchResults; +import jalview.datamodel.SearchResultsI; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; @@ -35,6 +35,8 @@ import jalview.schemes.ResidueProperties; import jalview.structure.StructureSelectionManager; import jalview.util.MessageManager; import jalview.util.Platform; +import jalview.viewmodel.ViewportListenerI; +import jalview.viewmodel.ViewportRanges; import java.awt.BorderLayout; import java.awt.Color; @@ -65,10 +67,13 @@ import javax.swing.SwingUtilities; * @version $Revision: 1.161 $ */ public class AlignmentPanel extends GAlignmentPanel implements - AdjustmentListener, Printable, AlignmentViewPanel + AdjustmentListener, Printable, AlignmentViewPanel, + ViewportListenerI { public AlignViewport av; + ViewportRanges vpRanges; + OverviewPanel overviewPanel; private SeqPanel seqPanel; @@ -91,9 +96,9 @@ public class AlignmentPanel extends GAlignmentPanel implements // this value is set false when selection area being dragged boolean fastPaint = true; - int hextent = 0; + private int hextent = 0; - int vextent = 0; + private int vextent = 0; /* * Flag set while scrolling to follow complementary cDNA/protein scroll. When @@ -101,6 +106,8 @@ public class AlignmentPanel extends GAlignmentPanel implements */ private boolean dontScrollComplement; + private PropertyChangeListener propertyChangeListener; + /** * Creates a new AlignmentPanel object. * @@ -111,6 +118,7 @@ public class AlignmentPanel extends GAlignmentPanel implements { alignFrame = af; this.av = av; + vpRanges = av.getRanges(); setSeqPanel(new SeqPanel(av, this)); setIdPanel(new IdPanel(av, this)); @@ -135,8 +143,9 @@ public class AlignmentPanel extends GAlignmentPanel implements vscroll.addAdjustmentListener(this); final AlignmentPanel ap = this; - av.addPropertyChangeListener(new PropertyChangeListener() + propertyChangeListener = new PropertyChangeListener() { + @Override public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals("alignment")) @@ -145,7 +154,10 @@ public class AlignmentPanel extends GAlignmentPanel implements alignmentChanged(); } } - }); + }; + av.addPropertyChangeListener(propertyChangeListener); + + av.getRanges().addPropertyChangeListener(this); fontChanged(); adjustAnnotationHeight(); updateLayout(); @@ -293,7 +305,7 @@ public class AlignmentPanel extends GAlignmentPanel implements * Highlight the given results on the alignment. * */ - public void highlightSearchResults(SearchResults results) + public void highlightSearchResults(SearchResultsI results) { scrollToPosition(results); getSeqPanel().seqCanvas.highlightSearchResults(results); @@ -305,7 +317,7 @@ public class AlignmentPanel extends GAlignmentPanel implements * * @param results */ - public boolean scrollToPosition(SearchResults results) + public boolean scrollToPosition(SearchResultsI results) { return scrollToPosition(results, 0, true, false); } @@ -318,7 +330,7 @@ public class AlignmentPanel extends GAlignmentPanel implements * @param redrawOverview * @return */ - public boolean scrollToPosition(SearchResults searchResults, + public boolean scrollToPosition(SearchResultsI searchResults, boolean redrawOverview) { return scrollToPosition(searchResults, 0, redrawOverview, false); @@ -338,7 +350,7 @@ public class AlignmentPanel extends GAlignmentPanel implements * if true, try to centre the search results horizontally in the view * @return false if results were not found */ - public boolean scrollToPosition(SearchResults results, + public boolean scrollToPosition(SearchResultsI results, int verticalOffset, boolean redrawOverview, boolean centre) { int startv, endv, starts, ends; @@ -373,7 +385,7 @@ public class AlignmentPanel extends GAlignmentPanel implements */ if (centre) { - int offset = (av.getEndRes() - av.getStartRes() + 1) / 2 - 1; + int offset = (vpRanges.getEndRes() - vpRanges.getStartRes() + 1) / 2 - 1; start = Math.max(start - offset, 0); end = end + offset - 1; } @@ -409,7 +421,7 @@ public class AlignmentPanel extends GAlignmentPanel implements // + av.getStartSeq() + ", ends=" + av.getEndSeq()); if (!av.getWrapAlignment()) { - if ((startv = av.getStartRes()) >= start) + if ((startv = vpRanges.getStartRes()) >= start) { /* * Scroll left to make start of search results visible @@ -417,7 +429,7 @@ public class AlignmentPanel extends GAlignmentPanel implements // setScrollValues(start - 1, seqIndex); // plus one residue setScrollValues(start, seqIndex); } - else if ((endv = av.getEndRes()) <= end) + else if ((endv = vpRanges.getEndRes()) <= end) { /* * Scroll right to make end of search results visible @@ -425,19 +437,20 @@ public class AlignmentPanel extends GAlignmentPanel implements // setScrollValues(startv + 1 + end - endv, seqIndex); // plus one setScrollValues(startv + end - endv, seqIndex); } - else if ((starts = av.getStartSeq()) > seqIndex) + else if ((starts = vpRanges.getStartSeq()) > seqIndex) { /* * Scroll up to make start of search results visible */ - setScrollValues(av.getStartRes(), seqIndex); + setScrollValues(vpRanges.getStartRes(), seqIndex); } - else if ((ends = av.getEndSeq()) <= seqIndex) + else if ((ends = vpRanges.getEndSeq()) <= seqIndex) { /* * Scroll down to make end of search results visible */ - setScrollValues(av.getStartRes(), starts + seqIndex - ends + 1); + setScrollValues(vpRanges.getStartRes(), starts + seqIndex - ends + + 1); } /* * Else results are already visible - no need to scroll @@ -460,10 +473,10 @@ public class AlignmentPanel extends GAlignmentPanel implements { int cwidth = getSeqPanel().seqCanvas .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth()); - if (res < av.getStartRes() || res >= (av.getStartRes() + cwidth)) + if (res < vpRanges.getStartRes() + || res >= (vpRanges.getStartRes() + cwidth)) { vscroll.setValue((res / cwidth)); - av.startRes = vscroll.getValue() * cwidth; } } @@ -509,6 +522,7 @@ public class AlignmentPanel extends GAlignmentPanel implements * automatically adjust annotation panel height for new annotation whilst * ensuring the alignment is still visible. */ + @Override public void adjustAnnotationHeight() { // TODO: display vertical annotation scrollbar if necessary @@ -586,7 +600,7 @@ public class AlignmentPanel extends GAlignmentPanel implements fontChanged(); setAnnotationVisible(av.isShowAnnotation()); boolean wrap = av.getWrapAlignment(); - av.startSeq = 0; + vpRanges.setStartSeq(0); scalePanelHolder.setVisible(!wrap); hscroll.setVisible(!wrap); idwidthAdjuster.setVisible(!wrap); @@ -683,64 +697,64 @@ public class AlignmentPanel extends GAlignmentPanel implements */ public void setScrollValues(int x, int y) { - // System.err.println("Scroll " + this.av.viewName + " to " + x + "," + y); if (av == null || av.getAlignment() == null) { return; } - int width = av.getAlignment().getWidth(); - int height = av.getAlignment().getHeight(); - if (av.hasHiddenColumns()) + if (av.getWrapAlignment()) { - width = av.getColumnSelection().findColumnPosition(width); + setScrollingForWrappedPanel(x); } + else + { - av.setEndRes((x + (getSeqPanel().seqCanvas.getWidth() / av - .getCharWidth())) - 1); + int width = av.getAlignment().getWidth(); + int height = av.getAlignment().getHeight(); - hextent = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth(); - vextent = getSeqPanel().seqCanvas.getHeight() / av.getCharHeight(); + if (av.hasHiddenColumns()) + { + // reset the width to exclude hidden columns + width = av.getColumnSelection().findColumnPosition(width); + } - if (hextent > width) - { - hextent = width; - } + hextent = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth(); + vextent = getSeqPanel().seqCanvas.getHeight() / av.getCharHeight(); - if (vextent > height) - { - vextent = height; - } + if (hextent > width) + { + hextent = width; + } - if ((hextent + x) > width) - { - x = width - hextent; - } + if (vextent > height) + { + vextent = height; + } - if ((vextent + y) > height) - { - y = height - vextent; - } + if ((hextent + x) > width) + { + x = width - hextent; + } - if (y < 0) - { - y = 0; - } + if ((vextent + y) > height) + { + y = height - vextent; + } - if (x < 0) - { - x = 0; - } + if (y < 0) + { + y = 0; + } - /* - * each scroll adjustment triggers adjustmentValueChanged, which resets the - * 'do not scroll complement' flag; ensure it is the same for both - * operations - */ - boolean flag = isDontScrollComplement(); - hscroll.setValues(x, hextent, 0, width); - setDontScrollComplement(flag); - vscroll.setValues(y, vextent, 0, height); + if (x < 0) + { + x = 0; + } + + // update the scroll values + hscroll.setValues(x, hextent, 0, width); + vscroll.setValues(y, vextent, 0, height); + } } /** @@ -749,31 +763,34 @@ public class AlignmentPanel extends GAlignmentPanel implements * @param evt * DOCUMENT ME! */ + @Override public void adjustmentValueChanged(AdjustmentEvent evt) { - int oldX = av.getStartRes(); - int oldY = av.getStartSeq(); - - if (evt.getSource() == hscroll) - { - int x = hscroll.getValue(); - av.setStartRes(x); - av.setEndRes((x + (getSeqPanel().seqCanvas.getWidth() / av - .getCharWidth())) - 1); - } + int oldX = vpRanges.getStartRes(); + int oldY = vpRanges.getStartSeq(); - if (evt.getSource() == vscroll) + if (av.getWrapAlignment()) { - int offy = vscroll.getValue(); - - if (av.getWrapAlignment()) + if (evt.getSource() == hscroll) { - if (offy > -1) + return; // no horizontal scroll when wrapped + } + else if (evt.getSource() == vscroll) + { + int offy = vscroll.getValue(); + int rowSize = getSeqPanel().seqCanvas + .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth()); + + // if we're scrolling to the position we're already at, stop + // this prevents infinite recursion of events when the scroll/viewport + // ranges values are the same + if (offy * rowSize == oldX) { - int rowSize = getSeqPanel().seqCanvas - .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth()); - av.setStartRes(offy * rowSize); - av.setEndRes((offy + 1) * rowSize); + return; + } + else if (offy > -1) + { + vpRanges.setStartEndRes(offy * rowSize, (offy + 1) * rowSize); } else { @@ -782,69 +799,56 @@ public class AlignmentPanel extends GAlignmentPanel implements // as preference setting SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { - setScrollValues(av.getStartRes(), av.getStartSeq()); + setScrollValues(vpRanges.getStartRes(), + vpRanges.getStartSeq()); } }); } } - else - { - av.setStartSeq(offy); - av.setEndSeq(offy - + (getSeqPanel().seqCanvas.getHeight() / av.getCharHeight())); - } - } - - if (overviewPanel != null) - { - overviewPanel.setBoxPosition(); - } - - int scrollX = av.startRes - oldX; - int scrollY = av.startSeq - oldY; - - if (av.getWrapAlignment() || !fastPaint) - { repaint(); } else { - // Make sure we're not trying to draw a panel - // larger than the visible window - if (scrollX > av.endRes - av.startRes) - { - scrollX = av.endRes - av.startRes; - } - else if (scrollX < av.startRes - av.endRes) + // horizontal scroll + if (evt.getSource() == hscroll) { - scrollX = av.startRes - av.endRes; - } + int x = hscroll.getValue(); - if (scrollX != 0 || scrollY != 0) + // if we're scrolling to the position we're already at, stop + // this prevents infinite recursion of events when the scroll/viewport + // ranges values are the same + if (x == oldX) + { + return; + } + vpRanges.setStartEndRes(x, + (x + (getSeqPanel().seqCanvas.getWidth() / av + .getCharWidth())) - 1); + } + else if (evt.getSource() == vscroll) { - getIdPanel().getIdCanvas().fastPaint(scrollY); - getSeqPanel().seqCanvas.fastPaint(scrollX, scrollY); - getScalePanel().repaint(); + int offy = vscroll.getValue(); - if (av.isShowAnnotation() && scrollX != 0) + // if we're scrolling to the position we're already at, stop + // this prevents infinite recursion of events when the scroll/viewport + // ranges values are the same + if (offy == oldY) { - getAnnotationPanel().fastPaint(scrollX); + return; } + vpRanges.setStartEndSeq( + offy, + offy + + (getSeqPanel().seqCanvas.getHeight() / av + .getCharHeight()) - 1); + } + if (!fastPaint) + { + repaint(); } - } - /* - * If there is one, scroll the (Protein/cDNA) complementary alignment to - * match, unless we are ourselves doing that. - */ - if (isDontScrollComplement()) - { - setDontScrollComplement(false); - } - else - { - av.scrollComplementaryAlignment(); } } @@ -852,6 +856,7 @@ public class AlignmentPanel extends GAlignmentPanel implements * Repaint the alignment including the annotations and overview panels (if * shown). */ + @Override public void paintAlignment(boolean updateOverview) { final AnnotationSorter sorter = new AnnotationSorter(getAlignment(), @@ -878,6 +883,7 @@ public class AlignmentPanel extends GAlignmentPanel implements * @param g * DOCUMENT ME! */ + @Override public void paintComponent(Graphics g) { invalidate(); @@ -888,36 +894,38 @@ public class AlignmentPanel extends GAlignmentPanel implements validate(); /* - * set scroll bar positions; first suppress this being 'followed' in any - * complementary split pane + * set scroll bar positions */ - setDontScrollComplement(true); + setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq()); + } - if (av.getWrapAlignment()) + /* + * Set vertical scroll bar parameters for wrapped panel + * @param res + * the residue to scroll to + */ + private void setScrollingForWrappedPanel(int res) + { + // get the width of the alignment in residues + int maxwidth = av.getAlignment().getWidth(); + if (av.hasHiddenColumns()) { - int maxwidth = av.getAlignment().getWidth(); - - if (av.hasHiddenColumns()) - { - maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1; - } - - int canvasWidth = getSeqPanel().seqCanvas - .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth()); - if (canvasWidth > 0) - { - int max = maxwidth - / getSeqPanel().seqCanvas - .getWrappedCanvasWidth(getSeqPanel().seqCanvas - .getWidth()) + 1; - vscroll.setMaximum(max); - vscroll.setUnitIncrement(1); - vscroll.setVisibleAmount(1); - } + maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1; } - else + + // get the width of the canvas in residues + int canvasWidth = getSeqPanel().seqCanvas + .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth()); + if (canvasWidth > 0) { - setScrollValues(av.getStartRes(), av.getStartSeq()); + // position we want to scroll to is number of canvasWidth's to get there + int current = res / canvasWidth; + + // max scroll position: add one because extent is 1 and scrollbar value + // can only be set to at most max - extent + int max = maxwidth / canvasWidth + 1; + vscroll.setUnitIncrement(1); + vscroll.setValues(current, 1, 0, max); } } @@ -936,6 +944,7 @@ public class AlignmentPanel extends GAlignmentPanel implements * @throws PrinterException * DOCUMENT ME! */ + @Override public int print(Graphics pg, PageFormat pf, int pi) throws PrinterException { @@ -946,11 +955,11 @@ public class AlignmentPanel extends GAlignmentPanel implements if (av.getWrapAlignment()) { - return printWrappedAlignment(pg, pwidth, pheight, pi); + return printWrappedAlignment(pwidth, pheight, pi, pg); } else { - return printUnwrapped(pg, pwidth, pheight, pi); + return printUnwrapped(pwidth, pheight, pi, pg, pg); } } @@ -971,84 +980,103 @@ public class AlignmentPanel extends GAlignmentPanel implements * @throws PrinterException * DOCUMENT ME! */ - public int printUnwrapped(Graphics pg, int pwidth, int pheight, int pi) + /** + * Draws the alignment image, including sequence ids, sequences, and + * annotation labels and annotations if shown, on either one or two Graphics + * context. + * + * @param pageWidth + * @param pageHeight + * @param pi + * @param idGraphics + * the graphics context for sequence ids and annotation labels + * @param alignmentGraphics + * the graphics context for sequences and annotations (may or may not + * be the same context as idGraphics) + * @return + * @throws PrinterException + */ + public int printUnwrapped(int pageWidth, int pageHeight, int pi, + Graphics idGraphics, Graphics alignmentGraphics) throws PrinterException { - int idWidth = getVisibleIdWidth(false); - FontMetrics fm = getFontMetrics(av.getFont()); - int scaleHeight = av.getCharHeight() + fm.getDescent(); - - pg.setColor(Color.white); - pg.fillRect(0, 0, pwidth, pheight); - pg.setFont(av.getFont()); + final int idWidth = getVisibleIdWidth(false); - // ////////////////////////////////// - // / How many sequences and residues can we fit on a printable page? - int totalRes = (pwidth - idWidth) / av.getCharWidth(); + /* + * Get the horizontal offset to where we draw the sequences. + * This is idWidth if using a single Graphics context, else zero. + */ + final int alignmentGraphicsOffset = idGraphics != alignmentGraphics ? 0 : idWidth; - int totalSeq = (pheight - scaleHeight) / av.getCharHeight() - 1; + FontMetrics fm = getFontMetrics(av.getFont()); + int charHeight = av.getCharHeight(); + int scaleHeight = charHeight + fm.getDescent(); - int pagesWide = (av.getAlignment().getWidth() / totalRes) + 1; + idGraphics.setColor(Color.white); + idGraphics.fillRect(0, 0, pageWidth, pageHeight); + idGraphics.setFont(av.getFont()); - // /////////////////////////// - // / Only print these sequences and residues on this page - int startRes; + /* + * How many sequences and residues can we fit on a printable page? + */ + int totalRes = (pageWidth - idWidth) / av.getCharWidth(); - // /////////////////////////// - // / Only print these sequences and residues on this page - int endRes; + int totalSeq = (pageHeight - scaleHeight) / charHeight - 1; - // /////////////////////////// - // / Only print these sequences and residues on this page - int startSeq; + int alignmentWidth = av.getAlignment().getWidth(); + int pagesWide = (alignmentWidth / totalRes) + 1; - // /////////////////////////// - // / Only print these sequences and residues on this page - int endSeq; - startRes = (pi % pagesWide) * totalRes; - endRes = (startRes + totalRes) - 1; + final int startRes = (pi % pagesWide) * totalRes; + int endRes = (startRes + totalRes) - 1; - if (endRes > (av.getAlignment().getWidth() - 1)) + if (endRes > (alignmentWidth - 1)) { - endRes = av.getAlignment().getWidth() - 1; + endRes = alignmentWidth - 1; } - startSeq = (pi / pagesWide) * totalSeq; - endSeq = startSeq + totalSeq; + final int startSeq = (pi / pagesWide) * totalSeq; + int endSeq = startSeq + totalSeq; - if (endSeq > av.getAlignment().getHeight()) + int alignmentHeight = av.getAlignment().getHeight(); + if (endSeq > alignmentHeight) { - endSeq = av.getAlignment().getHeight(); + endSeq = alignmentHeight; } - int pagesHigh = ((av.getAlignment().getHeight() / totalSeq) + 1) - * pheight; + int pagesHigh = ((alignmentHeight / totalSeq) + 1) + * pageHeight; if (av.isShowAnnotation()) { pagesHigh += getAnnotationPanel().adjustPanelHeight() + 3; } - pagesHigh /= pheight; + pagesHigh /= pageHeight; if (pi >= (pagesWide * pagesHigh)) { return Printable.NO_SUCH_PAGE; } + final int alignmentDrawnHeight = (endSeq - startSeq) * charHeight + + 3; - // draw Scale - pg.translate(idWidth, 0); - getScalePanel().drawScale(pg, startRes, endRes, pwidth - idWidth, - scaleHeight); - pg.translate(-idWidth, scaleHeight); + /* + * draw the Scale at horizontal offset, then reset to top left (0, 0) + */ + alignmentGraphics.translate(alignmentGraphicsOffset, 0); + getScalePanel().drawScale(alignmentGraphics, startRes, endRes, + pageWidth - idWidth, scaleHeight); + alignmentGraphics.translate(-alignmentGraphicsOffset, 0); - // ////////////// - // Draw the ids + /* + * Draw the sequence ids, offset for scale height, + * then reset to top left (0, 0) + */ + idGraphics.translate(0, scaleHeight); + idGraphics.setFont(getIdPanel().getIdCanvas().getIdfont()); Color currentColor = null; Color currentTextColor = null; - pg.setFont(getIdPanel().getIdCanvas().getIdfont()); - SequenceI seq; for (int i = startSeq; i < endSeq; i++) { @@ -1056,6 +1084,9 @@ public class AlignmentPanel extends GAlignmentPanel implements if ((av.getSelectionGroup() != null) && av.getSelectionGroup().getSequences(null).contains(seq)) { + /* + * gray out ids of sequences in selection group (if any) + */ currentColor = Color.gray; currentTextColor = Color.black; } @@ -1065,45 +1096,58 @@ public class AlignmentPanel extends GAlignmentPanel implements currentTextColor = Color.black; } - pg.setColor(currentColor); - pg.fillRect(0, (i - startSeq) * av.getCharHeight(), idWidth, - av.getCharHeight()); + idGraphics.setColor(currentColor); + idGraphics.fillRect(0, (i - startSeq) * charHeight, idWidth, + charHeight); - pg.setColor(currentTextColor); + idGraphics.setColor(currentTextColor); int xPos = 0; + String displayId = seq.getDisplayId(av.getShowJVSuffix()); if (av.isRightAlignIds()) { - fm = pg.getFontMetrics(); + fm = idGraphics.getFontMetrics(); xPos = idWidth - - fm.stringWidth(seq.getDisplayId(av.getShowJVSuffix())) + - fm.stringWidth(displayId) - 4; } - pg.drawString(seq.getDisplayId(av.getShowJVSuffix()), xPos, - (((i - startSeq) * av.getCharHeight()) + av.getCharHeight()) - - (av.getCharHeight() / 5)); + idGraphics.drawString(displayId, xPos, + (((i - startSeq) * charHeight) + charHeight) + - (charHeight / 5)); } + idGraphics.setFont(av.getFont()); + idGraphics.translate(0, -scaleHeight); - pg.setFont(av.getFont()); + /* + * draw the sequences, offset for scale height, and id width (if using a + * single graphics context), then reset to (0, scale height) + */ + alignmentGraphics.translate(alignmentGraphicsOffset, scaleHeight); + getSeqPanel().seqCanvas.drawPanel(alignmentGraphics, startRes, endRes, + startSeq, endSeq, 0); + alignmentGraphics.translate(-alignmentGraphicsOffset, 0); - // draw main sequence panel - pg.translate(idWidth, 0); - getSeqPanel().seqCanvas.drawPanel(pg, startRes, endRes, startSeq, - endSeq, 0); - - if (av.isShowAnnotation() && (endSeq == av.getAlignment().getHeight())) - { - // draw annotation - need to offset for current scroll position - int offset = -getAlabels().getScrollOffset(); - pg.translate(0, offset); - pg.translate(-idWidth - 3, (endSeq - startSeq) * av.getCharHeight() - + 3); - getAlabels().drawComponent(pg, idWidth); - pg.translate(idWidth + 3, 0); + if (av.isShowAnnotation() && (endSeq == alignmentHeight)) + { + /* + * draw annotation labels; drawComponent() translates by + * getScrollOffset(), so compensate for that first; + * then reset to (0, scale height) + */ + int offset = getAlabels().getScrollOffset(); + idGraphics.translate(0, -offset); + idGraphics.translate(0, alignmentDrawnHeight); + getAlabels().drawComponent(idGraphics, idWidth); + idGraphics.translate(0, -alignmentDrawnHeight); + + /* + * draw the annotations starting at + * (idOffset, alignmentHeight) from (0, scaleHeight) + */ + alignmentGraphics.translate(alignmentGraphicsOffset, alignmentDrawnHeight); getAnnotationPanel().renderer.drawComponent(getAnnotationPanel(), av, - pg, -1, startRes, endRes + 1); - pg.translate(0, -offset); + alignmentGraphics, -1, startRes, endRes + 1); } return Printable.PAGE_EXISTS; @@ -1126,8 +1170,8 @@ public class AlignmentPanel extends GAlignmentPanel implements * @throws PrinterException * DOCUMENT ME! */ - public int printWrappedAlignment(Graphics pg, int pwidth, int pheight, - int pi) throws PrinterException + public int printWrappedAlignment(int pwidth, int pheight, int pi, + Graphics pg) throws PrinterException { int annotationHeight = 0; AnnotationLabels labels = null; @@ -1254,22 +1298,26 @@ public class AlignmentPanel extends GAlignmentPanel implements if (onscreen || (idwidth = Cache.getIntegerProperty("FIGURE_FIXEDIDWIDTH")) == null) { - return (getIdPanel().getWidth() > 0 ? getIdPanel().getWidth() - : calculateIdWidth().width + 4); + int w = getIdPanel().getWidth(); + return (w > 0 ? w : calculateIdWidth().width + 4); } return idwidth.intValue() + 4; } void makeAlignmentImage(jalview.util.ImageMaker.TYPE type, File file) { - long progress = System.currentTimeMillis(); + 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) { - alignFrame.setProgressBar(MessageManager.formatMessage( - "status.saving_file", new Object[] { type.getLabel() }), - progress); + if (file != null) + { + alignFrame.setProgressBar(MessageManager.formatMessage( + "status.saving_file", new Object[] { type.getLabel() }), + pSessionId); + } } try { @@ -1295,26 +1343,30 @@ public class AlignmentPanel extends GAlignmentPanel implements } im = new jalview.util.ImageMaker(this, type, imageAction, - aDimension.getWidth(), aDimension.getHeight(), file, - imageTitle); + aDimension.getWidth(), aDimension.getHeight() + + boarderBottomOffset, file, imageTitle, + alignFrame, pSessionId, headless); + Graphics graphics = im.getGraphics(); if (av.getWrapAlignment()) { - if (im.getGraphics() != null) + if (graphics != null) { - printWrappedAlignment(im.getGraphics(), aDimension.getWidth(), - aDimension.getHeight(), 0); + printWrappedAlignment(aDimension.getWidth(), + aDimension.getHeight() + boarderBottomOffset, 0, + graphics); im.writeImage(); } } else { - if (im.getGraphics() != null) + if (graphics != null) { - printUnwrapped(im.getGraphics(), aDimension.getWidth(), - aDimension.getHeight(), 0); + printUnwrapped(aDimension.getWidth(), aDimension.getHeight(), + 0, graphics, graphics); im.writeImage(); } } + } catch (OutOfMemoryError err) { // Be noisy here. @@ -1328,12 +1380,7 @@ public class AlignmentPanel extends GAlignmentPanel implements } } finally { - if (alignFrame != null && !headless) - { - alignFrame.setProgressBar( - MessageManager.getString("status.export_complete"), - progress); - } + } } @@ -1400,7 +1447,7 @@ public class AlignmentPanel extends GAlignmentPanel implements public void makePNGImageMap(File imgMapFile, String imageName) { - // /////ONLY WORKS WITH NONE WRAPPED ALIGNMENTS + // /////ONLY WORKS WITH NON WRAPPED ALIGNMENTS // //////////////////////////////////////////// int idWidth = getVisibleIdWidth(false); FontMetrics fm = getFontMetrics(av.getFont()); @@ -1414,7 +1461,6 @@ public class AlignmentPanel extends GAlignmentPanel implements { int s, sSize = av.getAlignment().getHeight(), res, alwidth = av .getAlignment().getWidth(), g, gSize, f, fSize, sy; - StringBuffer text = new StringBuffer(); PrintWriter out = new PrintWriter(new FileWriter(imgMapFile)); out.println(jalview.io.HTMLOutput.getImageMapHTML()); out.println(" res) { - text.append("
" + groups[g].getName() + ""); + text.append("
").append(groups[g].getName()) + .append(""); } } @@ -1473,12 +1521,13 @@ public class AlignmentPanel extends GAlignmentPanel implements { if (text.length() < 1) { - text.append("= seq.findPosition(res))) { - if (features[f].getType().equals("disulfide bond")) + if (features[f].isContactFeature()) { if (features[f].getBegin() == seq.findPosition(res) || features[f].getEnd() == seq .findPosition(res)) { - text.append("
disulfide bond " - + features[f].getBegin() + ":" - + features[f].getEnd()); + text.append("
").append(features[f].getType()) + .append(" ").append(features[f].getBegin()) + .append(":").append(features[f].getEnd()); } } else @@ -1506,13 +1555,13 @@ public class AlignmentPanel extends GAlignmentPanel implements && !features[f].getType().equals( features[f].getDescription())) { - text.append(" " + features[f].getDescription()); + text.append(" ").append(features[f].getDescription()); } if (features[f].getValue("status") != null) { - text.append(" (" + features[f].getValue("status") - + ")"); + text.append(" (").append(features[f].getValue("status")) + .append(")"); } } } @@ -1587,8 +1636,18 @@ public class AlignmentPanel extends GAlignmentPanel implements PaintRefresher.RemoveComponent(getSeqPanel().seqCanvas); PaintRefresher.RemoveComponent(getIdPanel().getIdCanvas()); PaintRefresher.RemoveComponent(this); + + /* + * try to ensure references are nulled + */ + if (annotationPanel != null) + { + annotationPanel.dispose(); + } + if (av != null) { + av.removePropertyChangeListener(propertyChangeListener); jalview.structure.StructureSelectionManager ssm = av .getStructureSelectionManager(); ssm.removeStructureViewerListener(getSeqPanel(), null); @@ -1596,7 +1655,7 @@ public class AlignmentPanel extends GAlignmentPanel implements ssm.removeCommandListener(av); ssm.removeStructureViewerListener(getSeqPanel(), null); ssm.removeSelectionListener(getSeqPanel()); - av.setAlignment(null); + av.dispose(); av = null; } else @@ -1767,14 +1826,14 @@ public class AlignmentPanel extends GAlignmentPanel implements * @param verticalOffset * the number of visible sequences to show above the mapped region */ - public void scrollToCentre(SearchResults sr, int verticalOffset) + public void scrollToCentre(SearchResultsI sr, int verticalOffset) { /* * To avoid jumpy vertical scrolling (if some sequences are gapped or not * mapped), we can make the scroll-to location a sequence above the one * actually mapped. */ - SequenceI mappedTo = sr.getResultSequence(0); + SequenceI mappedTo = sr.getResults().get(0).getSequence(); List seqs = av.getAlignment().getSequences(); /* @@ -1815,4 +1874,43 @@ public class AlignmentPanel extends GAlignmentPanel implements { return this.dontScrollComplement; } + + /** + * Redraw sensibly. + * + * @adjustHeight if true, try to recalculate panel height for visible + * annotations + */ + protected void refresh(boolean adjustHeight) + { + validateAnnotationDimensions(adjustHeight); + addNotify(); + if (adjustHeight) + { + // sort, repaint, update overview + paintAlignment(true); + } + else + { + // lightweight repaint + repaint(); + } + } + + @Override + /** + * Property change event fired when a change is made to the viewport ranges + * object associated with this alignment panel's viewport + */ + public void propertyChange(PropertyChangeEvent evt) + { + // update this panel's scroll values based on the new viewport ranges values + int x = vpRanges.getStartRes(); + int y = vpRanges.getStartSeq(); + setScrollValues(x, y); + + // now update any complementary alignment (its viewport ranges object + // is different so does not get automatically updated) + av.scrollComplementaryAlignment(); + } }