X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FSeqCanvas.java;h=d1046f85927e1bd96d6c495e87d0032740b77f18;hb=c0b77a767e71bffd8f55704f9a64f943f559e4f6;hp=b3fcc542f3c0f6f7d2fc3899b172bf0fe3b551b3;hpb=87e1ada6a62777b415f14b0444fdcc63336c8f73;p=jalview.git diff --git a/src/jalview/gui/SeqCanvas.java b/src/jalview/gui/SeqCanvas.java index b3fcc54..d1046f8 100755 --- a/src/jalview/gui/SeqCanvas.java +++ b/src/jalview/gui/SeqCanvas.java @@ -38,14 +38,14 @@ import java.awt.Color; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.Rectangle; import java.awt.RenderingHints; -import java.awt.Shape; import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; import java.util.Iterator; import java.util.List; -import javax.swing.JComponent; +import javax.swing.JPanel; /** * The Swing component on which the alignment sequences, and annotations (if @@ -53,7 +53,8 @@ import javax.swing.JComponent; * Wrapped mode, but not the scale above in Unwrapped mode. * */ -public class SeqCanvas extends JComponent implements ViewportListenerI +@SuppressWarnings("serial") +public class SeqCanvas extends JPanel implements ViewportListenerI { /* * pixels gap between sequences and annotations when in wrapped mode @@ -93,7 +94,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI private int wrappedVisibleWidths; // number of wrapped widths displayed - private Graphics2D gg; + // Don't do this! Graphics handles are supposed to be transient + //private Graphics2D gg; /** * Creates a new SeqCanvas object. @@ -114,7 +116,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI public SequenceRenderer getSequenceRenderer() { - return seqRdr; + return seqRdr; } public FeatureRenderer getFeatureRenderer() @@ -200,7 +202,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI int yPos = ypos + charHeight; int startX = startx; int endX = endx; - + if (av.hasHiddenColumns()) { HiddenColumns hiddenColumns = av.getAlignment().getHiddenColumns(); @@ -236,6 +238,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI } } + /* * white fill the space for the scale */ @@ -260,6 +263,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI g.drawString(valueAsString, xOffset, y); } } + } /** @@ -273,6 +277,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI *
  • scrolling by trackpad, middle mouse button, or other device
  • *
  • by moving the box in the Overview window
  • *
  • programmatically to make a highlighted position visible
  • + *
  • pasting a block of sequences
  • * * * @param horizontal @@ -282,18 +287,22 @@ public class SeqCanvas extends JComponent implements ViewportListenerI */ public void fastPaint(int horizontal, int vertical) { - if (fastpainting || gg == null || img == null) + // System.err.println("< 0) // scrollbar pulled right, image to the left { @@ -339,13 +344,27 @@ public class SeqCanvas extends JComponent implements ViewportListenerI } } + + // System.err.println(">>> FastPaint to " + transX + " " + transY + " " + // + horizontal + " " + vertical + " " + startRes + " " + endRes + // + " " + startSeq + " " + endSeq); + + Graphics gg = img.getGraphics(); + gg.copyArea(horizontal * charWidth, vertical * charHeight, + img.getWidth(), img.getHeight(), -horizontal * charWidth, + -vertical * charHeight); + + /** @j2sNative xxi = this.img */ + gg.translate(transX, transY); drawPanel(gg, startRes, endRes, startSeq, endSeq, 0); gg.translate(-transX, -transY); + gg.dispose(); // Call repaint on alignment panel so that repaints from other alignment // panel components can be aggregated. Otherwise performance of the // overview window and others may be adversely affected. + // System.out.println("SeqCanvas fastPaint() repaint() request..."); av.getAlignPanel().repaint(); } finally { @@ -356,73 +375,89 @@ public class SeqCanvas extends JComponent implements ViewportListenerI @Override public void paintComponent(Graphics g) { - super.paintComponent(g); - int charHeight = av.getCharHeight(); int charWidth = av.getCharWidth(); - - ViewportRanges ranges = av.getRanges(); - + int width = getWidth(); int height = getHeight(); - + width -= (width % charWidth); height -= (height % charHeight); - - if ((img != null) && (fastPaint - || (getVisibleRect().width != g.getClipBounds().width) - || (getVisibleRect().height != g.getClipBounds().height))) - { - g.drawImage(img, 0, 0, this); - drawSelectionGroup((Graphics2D) g, ranges.getStartRes(), - ranges.getEndRes(), ranges.getStartSeq(), ranges.getEndSeq()); + // BH 2019 can't possibly fastPaint if width and height are 0 + if (width == 0 || height == 0) + { + return; + } + ViewportRanges ranges = av.getRanges(); + int startRes = ranges.getStartRes(); + int startSeq = ranges.getStartSeq(); + int endRes = ranges.getEndRes(); + int endSeq = ranges.getEndSeq(); + + // System.err.println(">>SeqCanvas paintComponent " + fastPaint + "\n" + // + getVisibleRect() + "\n" + g.getClipBounds()); + // System.err.println(">>>>>>>>>>>>>>>>SeqCanvas paintComponent " + // + startRes + " " + endRes + " " + startSeq + " " + endSeq); + Rectangle vis, clip; + if (img != null + && (fastPaint + || (vis = getVisibleRect()).width != (clip = g + .getClipBounds()).width + || vis.height != clip.height)) + { + g.drawImage(img, 0, 0, this); + // System.err.println(">>>>>>>>>>>>>>>>SeqCanvas paintComponent FAST"); + drawSelectionGroup((Graphics2D) g, startRes, endRes, startSeq, + endSeq); fastPaint = false; + //System.out.println("SeqCanvas fast paint"); } - else if (width > 0 && height > 0) + else { + + System.out.println("SeqCanvas full paint"); /* - * img is a cached version of the last view we drew, if any - * if we have no img or the size has changed, make a new one + * img is a cached version of the last view we drew. + * If we have no img or the size has changed, make a new one */ if (img == null || width != img.getWidth() || height != img.getHeight()) { img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); - gg = (Graphics2D) img.getGraphics(); - gg.setFont(av.getFont()); } - + + Graphics2D gg = (Graphics2D) img.getGraphics(); + gg.setFont(av.getFont()); + if (av.antiAlias) { gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); } - + gg.setColor(Color.white); gg.fillRect(0, 0, img.getWidth(), img.getHeight()); - + if (av.getWrapAlignment()) { - drawWrappedPanel(gg, getWidth(), getHeight(), ranges.getStartRes()); + drawWrappedPanel(gg, width, height, ranges.getStartRes()); } else { - drawPanel(gg, ranges.getStartRes(), ranges.getEndRes(), - ranges.getStartSeq(), ranges.getEndSeq(), 0); + drawPanel(gg, startRes, endRes, startSeq, endSeq, 0); } - drawSelectionGroup(gg, ranges.getStartRes(), - ranges.getEndRes(), ranges.getStartSeq(), ranges.getEndSeq()); + drawSelectionGroup(gg, startRes, endRes, startSeq, endSeq); g.drawImage(img, 0, 0, this); + gg.dispose(); } if (av.cursorMode) { - drawCursor(g, ranges.getStartRes(), ranges.getEndRes(), - ranges.getStartSeq(), ranges.getEndSeq()); + drawCursor(g, startRes, endRes, startSeq, endSeq); } } @@ -688,21 +723,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI int xOffset = labelWidthWest + ((startColumn - ranges.getStartRes()) % viewportWidth) * charWidth; - g.translate(xOffset, 0); - - // When printing we have an extra clipped region, - // the Printable page which we need to account for here - Shape clip = g.getClip(); - if (clip == null) - { - g.setClip(0, 0, viewportWidth * charWidth, canvasHeight); - } - else - { - g.setClip(0, (int) clip.getBounds().getY(), - viewportWidth * charWidth, (int) clip.getBounds().getHeight()); - } + g.translate(xOffset, 0); /* * white fill the region to be drawn (so incremental fast paint doesn't @@ -730,7 +752,6 @@ public class SeqCanvas extends JComponent implements ViewportListenerI startColumn, endx + 1); g.translate(0, -yShift); } - g.setClip(clip); g.translate(-xOffset, 0); } @@ -746,6 +767,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI int charWidth = av.getCharWidth(); g.setFont(av.getFont()); + g.setColor(Color.black); int ypos = wrappedSpaceAboveAlignment; @@ -767,6 +789,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.getScaleRightWrapped()) { int x = labelWidthWest + viewportWidth * charWidth; + g.translate(x, 0); drawVerticalScale(g, startCol, endColumn, ypos, false); g.translate(-x, 0); @@ -1099,23 +1122,17 @@ public class SeqCanvas extends JComponent implements ViewportListenerI do { g.setColor(group.getOutlineColour()); - drawPartialGroupOutline(g, group, startRes, endRes, startSeq, endSeq, offset); groupIndex++; - if (groupIndex >= av.getAlignment().getGroups().size()) { break; } - group = av.getAlignment().getGroups().get(groupIndex); - } while (groupIndex < av.getAlignment().getGroups().size()); - } - } /** @@ -1461,20 +1478,42 @@ public class SeqCanvas extends JComponent implements ViewportListenerI * Highlights search results in the visible region by rendering as white text * on a black background. Any previous highlighting is removed. Answers true * if any highlight was left on the visible alignment (so status bar should be + * set to match), else false. This method does _not_ set the 'fastPaint' flag, + * so allows the next repaint to update the whole display. + * + * @param results + * @return + */ + public boolean highlightSearchResults(SearchResultsI results) + { + return highlightSearchResults(results, false); + + } + + /** + * Highlights search results in the visible region by rendering as white text + * on a black background. Any previous highlighting is removed. Answers true + * if any highlight was left on the visible alignment (so status bar should be * set to match), else false. *

    - * Currently fastPaint is not implemented for wrapped alignments. If a wrapped - * alignment had to be scrolled to show the highlighted region, then it should - * be fully redrawn, otherwise a fast paint can be performed. This argument - * could be removed if fast paint of scrolled wrapped alignment is coded in - * future (JAL-2609). + * Optionally, set the 'fastPaint' flag for a faster redraw if only the + * highlighted regions are modified. This speeds up highlighting across linked + * alignments. + *

    + * Currently fastPaint is not implemented for scrolled wrapped alignments. If + * a wrapped alignment had to be scrolled to show the highlighted region, then + * it should be fully redrawn, otherwise a fast paint can be performed. This + * argument could be removed if fast paint of scrolled wrapped alignment is + * coded in future (JAL-2609). * * @param results - * @param noFastPaint + * @param doFastPaint + * if true, sets a flag so the next repaint only redraws the modified + * image * @return */ public boolean highlightSearchResults(SearchResultsI results, - boolean noFastPaint) + boolean doFastPaint) { if (fastpainting) { @@ -1483,7 +1522,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI boolean wrapped = av.getWrapAlignment(); try { - fastPaint = !noFastPaint; + fastPaint = doFastPaint; fastpainting = fastPaint; /* @@ -1540,7 +1579,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI */ protected boolean drawMappedPositions(SearchResultsI results) { - if ((results == null) || (gg == null)) // JAL-2784 check gg is not null + if ((results == null) || (img == null)) // JAL-2784 check gg is not null { return false; } @@ -1612,9 +1651,11 @@ public class SeqCanvas extends JComponent implements ViewportListenerI } int transX = (firstCol - ranges.getStartRes()) * av.getCharWidth(); int transY = (firstSeq - ranges.getStartSeq()) * av.getCharHeight(); + Graphics gg = img.getGraphics(); gg.translate(transX, transY); drawPanel(gg, firstCol, lastCol, firstSeq, lastSeq, 0); gg.translate(-transX, -transY); + gg.dispose(); } return matchFound; @@ -1624,7 +1665,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI public void propertyChange(PropertyChangeEvent evt) { String eventName = evt.getPropertyName(); - + // System.err.println(">>SeqCanvas propertyChange " + eventName); if (eventName.equals(SequenceGroup.SEQ_GROUP_CHANGED)) { fastPaint = true; @@ -1634,6 +1675,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI else if (eventName.equals(ViewportRanges.MOVE_VIEWPORT)) { fastPaint = false; + // System.err.println("!!!! fastPaint false from MOVE_VIEWPORT"); repaint(); return; } @@ -1665,37 +1707,37 @@ public class SeqCanvas extends JComponent implements ViewportListenerI scrollX = -range; } } - // Both scrolling and resizing change viewport ranges: scrolling changes - // both start and end points, but resize only changes end values. - // Here we only want to fastpaint on a scroll, with resize using a normal - // paint, so scroll events are identified as changes to the horizontal or - // vertical start value. - if (eventName.equals(ViewportRanges.STARTRES)) + // Both scrolling and resizing change viewport ranges: scrolling changes + // both start and end points, but resize only changes end values. + // Here we only want to fastpaint on a scroll, with resize using a normal + // paint, so scroll events are identified as changes to the horizontal or + // vertical start value. + if (eventName.equals(ViewportRanges.STARTRES)) + { + if (av.getWrapAlignment()) { - if (av.getWrapAlignment()) - { - fastPaintWrapped(scrollX); - } - else - { - fastPaint(scrollX, 0); - } + fastPaintWrapped(scrollX); } - else if (eventName.equals(ViewportRanges.STARTSEQ)) + else { - // scroll - fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue()); + fastPaint(scrollX, 0); } - else if (eventName.equals(ViewportRanges.STARTRESANDSEQ)) + } + else if (eventName.equals(ViewportRanges.STARTSEQ)) + { + // scroll + fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue()); + } + else if (eventName.equals(ViewportRanges.STARTRESANDSEQ)) + { + if (av.getWrapAlignment()) { - if (av.getWrapAlignment()) - { - fastPaintWrapped(scrollX); - } - else - { - fastPaint(scrollX, 0); - } + fastPaintWrapped(scrollX); + } + else + { + fastPaint(scrollX, 0); + } } else if (eventName.equals(ViewportRanges.STARTSEQ)) { @@ -1735,7 +1777,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI return; } - if (fastpainting || gg == null) + if (fastpainting || img == null) { return; } @@ -1745,6 +1787,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI try { + + Graphics gg = img.getGraphics(); + calculateWrappedGeometry(getWidth(), getHeight()); /* @@ -1773,6 +1818,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI */ drawWrappedDecorators(gg, ranges.getStartRes()); + gg.dispose(); + repaint(); } finally { @@ -1796,6 +1843,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI return; } + Graphics gg = img.getGraphics(); + ViewportRanges ranges = av.getRanges(); int viewportWidth = ranges.getViewportWidth(); int charWidth = av.getCharWidth(); @@ -1822,6 +1871,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI /* * white fill first to erase annotations */ + + gg.translate(xOffset, 0); gg.setColor(Color.white); gg.fillRect(labelWidthWest, ypos, @@ -1829,6 +1880,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI gg.translate(-xOffset, 0); drawWrappedWidth(gg, ypos, startRes, endRes, canvasHeight); + } /* @@ -1872,7 +1924,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI gg.setColor(Color.white); gg.fillRect(0, canvasHeight - heightBelow, getWidth(), heightBelow); } - } + gg.dispose(); + } /** * Shifts the visible alignment by the specified number of columns - left if @@ -1888,6 +1941,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI { return; } + + Graphics gg = img.getGraphics(); + int charWidth = av.getCharWidth(); int canvasHeight = getHeight(); @@ -1961,11 +2017,11 @@ public class SeqCanvas extends JComponent implements ViewportListenerI * charWidth, heightToCopy, widthToCopy, -wrappedRepeatHeightPx); } - y += wrappedRepeatHeightPx; xpos += viewportWidth; } } + gg.dispose(); } @@ -1981,7 +2037,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI */ protected boolean drawMappedPositionsWrapped(SearchResultsI results) { - if ((results == null) || (gg == null)) // JAL-2784 check gg is not null + if ((results == null) || (img == null)) // JAL-2784 check gg is not null { return false; } @@ -2016,6 +2072,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI int gapHeight = charHeight * (av.getScaleAboveWrapped() ? 2 : 1); + + Graphics gg = img.getGraphics(); + for (int seqNo = ranges.getStartSeq(); seqNo <= ranges .getEndSeq(); seqNo++) { @@ -2086,6 +2145,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI } } + gg.dispose(); + return matchFound; } @@ -2098,4 +2159,19 @@ public class SeqCanvas extends JComponent implements ViewportListenerI { return labelWidthWest; } + + /** + * Ensure that a full paint is done next, for whatever reason. This was + * necessary for JavaScript; apparently in Java the timing is just right on + * multiple threads (EventQueue-0, Consensus, Conservation) that we can get + * away with one fast paint before the others, but this ensures that in the + * end we get a full paint. Problem arose in relation to copy/paste, where the + * paste was not finalized with a full paint. + * + * @author hansonr 2019.04.17 + */ + public void clearFastPaint() + { + fastPaint = false; + } }