X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FSeqCanvas.java;h=6325e6136aecd54a39329628a236a580221259bc;hb=ad1a1b9167535b1f6e34d84f8d26f4c63f5d394f;hp=cf1375e0e6eff29a6b6b88b4fde32ccb376f4828;hpb=8ec36c3e36ff5beb0db07345babe8c8426d0426b;p=jalview.git diff --git a/src/jalview/gui/SeqCanvas.java b/src/jalview/gui/SeqCanvas.java index cf1375e..6325e61 100755 --- a/src/jalview/gui/SeqCanvas.java +++ b/src/jalview/gui/SeqCanvas.java @@ -25,13 +25,13 @@ import jalview.datamodel.HiddenColumns; import jalview.datamodel.SearchResultsI; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; +import jalview.datamodel.VisibleContigsIterator; import jalview.renderer.ScaleRenderer; import jalview.renderer.ScaleRenderer.ScaleMark; import jalview.util.Comparison; import jalview.viewmodel.ViewportListenerI; import jalview.viewmodel.ViewportRanges; -import java.awt.AlphaComposite; import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; @@ -39,12 +39,12 @@ import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; 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 @@ -52,7 +52,7 @@ import javax.swing.JComponent; * Wrapped mode, but not the scale above in Unwrapped mode. * */ -public class SeqCanvas extends JComponent implements ViewportListenerI +public class SeqCanvas extends JPanel implements ViewportListenerI { private static final String ZEROS = "0000000000"; @@ -87,7 +87,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. @@ -108,7 +109,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI public SequenceRenderer getSequenceRenderer() { - return seqRdr; + return seqRdr; } public FeatureRenderer getFeatureRenderer() @@ -194,12 +195,12 @@ 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(); - startX = hiddenColumns.adjustForHiddenColumns(startx); - endX = hiddenColumns.adjustForHiddenColumns(endx); + startX = hiddenColumns.visibleToAbsoluteColumn(startx); + endX = hiddenColumns.visibleToAbsoluteColumn(endx); } FontMetrics fm = getFontMetrics(av.getFont()); @@ -230,6 +231,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI } } + /* * white fill the space for the scale */ @@ -254,6 +256,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI g.drawString(valueAsString, xOffset, y); } } + } /** @@ -276,7 +279,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI */ public void fastPaint(int horizontal, int vertical) { - if (fastpainting || gg == null || img == null) + if (fastpainting || img == null) { return; } @@ -295,7 +298,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI int endSeq = ranges.getEndSeq(); int transX = 0; int transY = 0; - + + Graphics gg = img.getGraphics(); gg.copyArea(horizontal * charWidth, vertical * charHeight, img.getWidth(), img.getHeight(), -horizontal * charWidth, -vertical * charHeight); @@ -336,8 +340,12 @@ public class SeqCanvas extends JComponent implements ViewportListenerI gg.translate(transX, transY); drawPanel(gg, startRes, endRes, startSeq, endSeq, 0); gg.translate(-transX, -transY); - - repaint(); + 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. + av.getAlignPanel().repaint(); } finally { fastpainting = false; @@ -347,8 +355,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI @Override public void paintComponent(Graphics g) { - super.paintComponent(g); - + super.paintComponent(g); + int charHeight = av.getCharHeight(); int charWidth = av.getCharWidth(); @@ -360,34 +368,32 @@ public class SeqCanvas extends JComponent implements ViewportListenerI width -= (width % charWidth); height -= (height % charHeight); - // selectImage is the selection group outline image - BufferedImage selectImage = drawSelectionGroup( - ranges.getStartRes(), ranges.getEndRes(), - ranges.getStartSeq(), ranges.getEndSeq()); - + if ((img != null) && (fastPaint || (getVisibleRect().width != g.getClipBounds().width) || (getVisibleRect().height != g.getClipBounds().height))) { - BufferedImage lcimg = buildLocalImage(selectImage); - g.drawImage(lcimg, 0, 0, this); + g.drawImage(img, 0, 0, this); + + drawSelectionGroup((Graphics2D) g, ranges.getStartRes(), + ranges.getEndRes(), ranges.getStartSeq(), ranges.getEndSeq()); + fastPaint = false; } - else if ((width > 0) && (height > 0)) + else if (width > 0 && height > 0) { - // 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 any + * if we have no img or the size has changed, make a new one + */ if (img == null || width != img.getWidth() || height != img.getHeight()) { - img = setupImage(); - if (img == null) - { - return; - } - gg = (Graphics2D) img.getGraphics(); - gg.setFont(av.getFont()); + img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); } + + Graphics2D gg = (Graphics2D) img.getGraphics(); + gg.setFont(av.getFont()); if (av.antiAlias) { @@ -408,10 +414,11 @@ public class SeqCanvas extends JComponent implements ViewportListenerI ranges.getStartSeq(), ranges.getEndSeq(), 0); } - // lcimg is a local *copy* of img which we'll draw selectImage on top of - BufferedImage lcimg = buildLocalImage(selectImage); - g.drawImage(lcimg, 0, 0, this); + drawSelectionGroup(gg, ranges.getStartRes(), + ranges.getEndRes(), ranges.getStartSeq(), ranges.getEndSeq()); + g.drawImage(img, 0, 0, this); + gg.dispose(); } if (av.cursorMode) @@ -440,14 +447,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI { drawPanel(g1, startRes, endRes, startSeq, endSeq, 0); - BufferedImage selectImage = drawSelectionGroup(startRes, endRes, + drawSelectionGroup((Graphics2D) g1, startRes, endRes, startSeq, endSeq); - if (selectImage != null) - { - ((Graphics2D) g1).setComposite(AlphaComposite - .getInstance(AlphaComposite.SRC_OVER)); - g1.drawImage(selectImage, 0, 0, this); - } } /** @@ -465,99 +466,14 @@ public class SeqCanvas extends JComponent implements ViewportListenerI public void drawWrappedPanelForPrinting(Graphics g, int canvasWidth, int canvasHeight, int startRes) { - SequenceGroup group = av.getSelectionGroup(); - drawWrappedPanel(g, canvasWidth, canvasHeight, startRes); + SequenceGroup group = av.getSelectionGroup(); if (group != null) { - BufferedImage selectImage = null; - try - { - selectImage = new BufferedImage(canvasWidth, canvasHeight, - BufferedImage.TYPE_INT_ARGB); // ARGB so alpha compositing works - } catch (OutOfMemoryError er) - { - System.gc(); - System.err.println("Print image OutOfMemory Error.\n" + er); - new OOMWarning("Creating wrapped alignment image for printing", er); - } - if (selectImage != null) - { - Graphics2D g2 = selectImage.createGraphics(); - setupSelectionGroup(g2, selectImage); - drawWrappedSelection(g2, group, canvasWidth, canvasHeight, + drawWrappedSelection((Graphics2D) g, group, canvasWidth, canvasHeight, startRes); - - g2.setComposite( - AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); - g.drawImage(selectImage, 0, 0, this); - g2.dispose(); - } - } - } - - /* - * Make a local image by combining the cached image img - * with any selection - */ - private BufferedImage buildLocalImage(BufferedImage selectImage) - { - // clone the cached image - BufferedImage lcimg = new BufferedImage(img.getWidth(), img.getHeight(), - img.getType()); - Graphics2D g2d = lcimg.createGraphics(); - g2d.drawImage(img, 0, 0, null); - - // overlay selection group on lcimg - if (selectImage != null) - { - g2d.setComposite( - AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); - g2d.drawImage(selectImage, 0, 0, this); - } - - g2d.dispose(); - - return lcimg; - } - - /* - * Set up a buffered image of the correct height and size for the sequence canvas - */ - private BufferedImage setupImage() - { - BufferedImage lcimg = null; - - int charWidth = av.getCharWidth(); - int charHeight = av.getCharHeight(); - - int width = getWidth(); - int height = getHeight(); - - width -= (width % charWidth); - height -= (height % charHeight); - - if ((width < 1) || (height < 1)) - { - return null; } - - try - { - lcimg = new BufferedImage(width, height, - BufferedImage.TYPE_INT_ARGB); // ARGB so alpha compositing works - } catch (OutOfMemoryError er) - { - System.gc(); - System.err.println( - "Group image OutOfMemory Redraw Error.\n" + er); - new OOMWarning("Creating alignment image for display", er); - - return null; - } - - return lcimg; } /** @@ -644,8 +560,13 @@ public class SeqCanvas extends JComponent implements ViewportListenerI ViewportRanges ranges = av.getRanges(); ranges.setViewportStartAndWidth(startColumn, wrappedWidthInResidues); + // we need to call this again to make sure the startColumn + + // wrappedWidthInResidues values are used to calculate wrappedVisibleWidths + // correctly. + calculateWrappedGeometry(canvasWidth, canvasHeight); + /* - * draw one width at a time (including any scales or annotation shown), + * draw one width at a time (excluding any scales or annotation shown), * until we have run out of either alignment or vertical space available */ int ypos = wrappedSpaceAboveAlignment; @@ -696,7 +617,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI */ wrappedRepeatHeightPx = wrappedSpaceAboveAlignment; // add sequences - wrappedRepeatHeightPx += av.getRanges().getViewportHeight() + wrappedRepeatHeightPx += av.getAlignment().getHeight() * charHeight; // add annotations panel height if shown wrappedRepeatHeightPx += getAnnotationHeight(); @@ -760,28 +681,15 @@ 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 * scribble over an existing image) */ - gg.setColor(Color.white); - gg.fillRect(0, ypos, (endx - startColumn + 1) * charWidth, + g.setColor(Color.white); + g.fillRect(0, ypos, (endx - startColumn + 1) * charWidth, wrappedRepeatHeightPx); drawPanel(g, startColumn, endx, 0, av.getAlignment().getHeight() - 1, @@ -801,7 +709,6 @@ public class SeqCanvas extends JComponent implements ViewportListenerI startColumn, endx + 1); g.translate(0, -cHeight - ypos - 3); } - g.setClip(clip); g.translate(-xOffset, 0); } @@ -817,6 +724,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI int charWidth = av.getCharWidth(); g.setFont(av.getFont()); + g.setColor(Color.black); int ypos = wrappedSpaceAboveAlignment; @@ -838,6 +746,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); @@ -890,11 +799,14 @@ public class SeqCanvas extends JComponent implements ViewportListenerI int charWidth = av.getCharWidth(); g.setColor(Color.blue); + int res; HiddenColumns hidden = av.getAlignment().getHiddenColumns(); - List positions = hidden.findHiddenRegionPositions(); - for (int pos : positions) + + Iterator it = hidden.getStartRegionIterator(startColumn, + endColumn); + while (it.hasNext()) { - int res = pos - startColumn; + res = it.next() - startColumn; if (res < 0 || res > endColumn - startColumn + 1) { @@ -943,11 +855,15 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.hasHiddenColumns()) { maxwidth = av.getAlignment().getHiddenColumns() - .findColumnPosition(maxwidth); + .absoluteToVisibleColumn(maxwidth); } // chop the wrapped alignment extent up into panel-sized blocks and treat // each block as if it were a block from an unwrapped alignment + g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, + BasicStroke.JOIN_ROUND, 3f, new float[] + { 5f, 3f }, 0f)); + g.setColor(Color.RED); while ((ypos <= canvasHeight) && (startx < maxwidth)) { // set end value to be start + width, or maxwidth, whichever is smaller @@ -972,6 +888,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI // update horizontal offset startx += cWidth; } + g.setStroke(new BasicStroke()); } int getAnnotationHeight() @@ -1021,29 +938,23 @@ public class SeqCanvas extends JComponent implements ViewportListenerI else { int screenY = 0; - final int screenYMax = endRes - startRes; - int blockStart = startRes; - int blockEnd = endRes; + int blockStart; + int blockEnd; - for (int[] region : av.getAlignment().getHiddenColumns() - .getHiddenColumnsCopy()) - { - int hideStart = region[0]; - int hideEnd = region[1]; + HiddenColumns hidden = av.getAlignment().getHiddenColumns(); + VisibleContigsIterator regions = hidden + .getVisContigsIterator(startRes, endRes + 1, true); - if (hideStart <= blockStart) - { - blockStart += (hideEnd - hideStart) + 1; - continue; - } + while (regions.hasNext()) + { + int[] region = regions.next(); + blockEnd = region[1]; + blockStart = region[0]; /* * draw up to just before the next hidden region, or the end of * the visible region, whichever comes first */ - blockEnd = Math.min(hideStart - 1, blockStart + screenYMax - - screenY); - g1.translate(screenY * charWidth, 0); draw(g1, blockStart, blockEnd, startSeq, endSeq, yOffset); @@ -1052,7 +963,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI * draw the downline of the hidden column marker (ScalePanel draws the * triangle on top) if we reached it */ - if (av.getShowHiddenMarkers() && blockEnd == hideStart - 1) + if (av.getShowHiddenMarkers() + && (regions.hasNext() || regions.endsAtHidden())) { g1.setColor(Color.blue); @@ -1063,23 +975,6 @@ public class SeqCanvas extends JComponent implements ViewportListenerI g1.translate(-screenY * charWidth, 0); screenY += blockEnd - blockStart + 1; - blockStart = hideEnd + 1; - - if (screenY > screenYMax) - { - // already rendered last block - return; - } - } - - if (screenY <= screenYMax) - { - // remaining visible region to render - blockEnd = blockStart + screenYMax - screenY; - g1.translate(screenY * charWidth, 0); - draw(g1, blockStart, blockEnd, startSeq, endSeq, yOffset); - - g1.translate(-screenY * charWidth, 0); } } @@ -1137,16 +1032,16 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.hasSearchResults()) { SearchResultsI searchResults = av.getSearchResults(); - int[] visibleResults = searchResults.getResults(nextSeq, - startRes, endRes); + int[] visibleResults = searchResults.getResults(nextSeq, startRes, + endRes); if (visibleResults != null) { for (int r = 0; r < visibleResults.length; r += 2) { seqRdr.drawHighlightedText(nextSeq, visibleResults[r], - visibleResults[r + 1], (visibleResults[r] - startRes) - * charWidth, offset - + ((i - startSeq) * charHeight)); + visibleResults[r + 1], + (visibleResults[r] - startRes) * charWidth, + offset + ((i - startSeq) * charHeight)); } } } @@ -1160,14 +1055,21 @@ public class SeqCanvas extends JComponent implements ViewportListenerI } + /** + * Draws the outlines of any groups defined on the alignment (excluding the + * current selection group, if any) + * + * @param g1 + * @param startRes + * @param endRes + * @param startSeq + * @param endSeq + * @param offset + */ void drawGroupsBoundaries(Graphics g1, int startRes, int endRes, int startSeq, int endSeq, int offset) { Graphics2D g = (Graphics2D) g1; - // - // /////////////////////////////////// - // Now outline any areas if necessary - // /////////////////////////////////// SequenceGroup group = null; int groupIndex = -1; @@ -1180,58 +1082,44 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (group != null) { - g.setStroke(new BasicStroke()); - g.setColor(group.getOutlineColour()); - do { + g.setColor(group.getOutlineColour()); drawPartialGroupOutline(g, group, startRes, endRes, startSeq, endSeq, offset); groupIndex++; - - g.setStroke(new BasicStroke()); - if (groupIndex >= av.getAlignment().getGroups().size()) { break; } - group = av.getAlignment().getGroups().get(groupIndex); - } while (groupIndex < av.getAlignment().getGroups().size()); - } - } - - /* - * Draw the selection group as a separate image and overlay + /** + * Draws the outline of the current selection group (if any) + * + * @param g + * @param startRes + * @param endRes + * @param startSeq + * @param endSeq */ - private BufferedImage drawSelectionGroup(int startRes, int endRes, + private void drawSelectionGroup(Graphics2D g, int startRes, int endRes, int startSeq, int endSeq) { - // get a new image of the correct size - BufferedImage selectionImage = setupImage(); - - if (selectionImage == null) - { - return null; - } - SequenceGroup group = av.getSelectionGroup(); if (group == null) { - // nothing to draw - return null; + return; } - // set up drawing colour - Graphics2D g = (Graphics2D) selectionImage.getGraphics(); - - setupSelectionGroup(g, selectionImage); - + g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, + BasicStroke.JOIN_ROUND, 3f, new float[] + { 5f, 3f }, 0f)); + g.setColor(Color.RED); if (!av.getWrapAlignment()) { drawUnwrappedSelection(g, group, startRes, endRes, startSeq, endSeq, @@ -1242,9 +1130,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI drawWrappedSelection(g, group, getWidth(), getHeight(), av.getRanges().getStartRes()); } - - g.dispose(); - return selectionImage; + g.setStroke(new BasicStroke()); } /** @@ -1278,7 +1164,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI // convert the cursorX into a position on the visible alignment int cursor_xpos = av.getAlignment().getHiddenColumns() - .findColumnPosition(cursorX); + .absoluteToVisibleColumn(cursorX); if (av.getAlignment().getHiddenColumns().isVisible(cursorX)) { @@ -1335,33 +1221,23 @@ public class SeqCanvas extends JComponent implements ViewportListenerI } - /* - * Set up graphics for selection group - */ - private void setupSelectionGroup(Graphics2D g, - BufferedImage selectionImage) - { - // set background to transparent - g.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f)); - g.fillRect(0, 0, selectionImage.getWidth(), selectionImage.getHeight()); - - // set up foreground to draw red dashed line - g.setComposite(AlphaComposite.Src); - g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, - BasicStroke.JOIN_ROUND, 3f, new float[] - { 5f, 3f }, 0f)); - g.setColor(Color.RED); - } - - /* + /** * Draw a selection group over an unwrapped alignment - * @param g graphics object to draw with - * @param group selection group - * @param startRes start residue of area to draw - * @param endRes end residue of area to draw - * @param startSeq start sequence of area to draw - * @param endSeq end sequence of area to draw - * @param offset vertical offset (used when called from wrapped alignment code) + * + * @param g + * graphics object to draw with + * @param group + * selection group + * @param startRes + * start residue of area to draw + * @param endRes + * end residue of area to draw + * @param startSeq + * start sequence of area to draw + * @param endSeq + * end sequence of area to draw + * @param offset + * vertical offset (used when called from wrapped alignment code) */ private void drawUnwrappedSelection(Graphics2D g, SequenceGroup group, int startRes, int endRes, int startSeq, int endSeq, int offset) @@ -1377,22 +1253,17 @@ public class SeqCanvas extends JComponent implements ViewportListenerI { // package into blocks of visible columns int screenY = 0; - int blockStart = startRes; - int blockEnd = endRes; + int blockStart; + int blockEnd; - for (int[] region : av.getAlignment().getHiddenColumns() - .getHiddenColumnsCopy()) + HiddenColumns hidden = av.getAlignment().getHiddenColumns(); + VisibleContigsIterator regions = hidden + .getVisContigsIterator(startRes, endRes + 1, true); + while (regions.hasNext()) { - int hideStart = region[0]; - int hideEnd = region[1]; - - if (hideStart <= blockStart) - { - blockStart += (hideEnd - hideStart) + 1; - continue; - } - - blockEnd = hideStart - 1; + int[] region = regions.next(); + blockEnd = region[1]; + blockStart = region[0]; g.translate(screenY * charWidth, 0); drawPartialGroupOutline(g, group, @@ -1400,30 +1271,20 @@ public class SeqCanvas extends JComponent implements ViewportListenerI g.translate(-screenY * charWidth, 0); screenY += blockEnd - blockStart + 1; - blockStart = hideEnd + 1; - - if (screenY > (endRes - startRes)) - { - // already rendered last block - break; - } - } - - if (screenY <= (endRes - startRes)) - { - // remaining visible region to render - blockEnd = blockStart + (endRes - startRes) - screenY; - g.translate(screenY * charWidth, 0); - drawPartialGroupOutline(g, group, - blockStart, blockEnd, startSeq, endSeq, offset); - - g.translate(-screenY * charWidth, 0); } } } - /* - * Draw the selection group as a separate image and overlay + /** + * Draws part of a selection group outline + * + * @param g + * @param group + * @param startRes + * @param endRes + * @param startSeq + * @param endSeq + * @param verticalOffset */ private void drawPartialGroupOutline(Graphics2D g, SequenceGroup group, int startRes, int endRes, int startSeq, int endSeq, @@ -1580,20 +1441,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) { @@ -1602,7 +1485,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI boolean wrapped = av.getWrapAlignment(); try { - fastPaint = !noFastPaint; + fastPaint = doFastPaint; fastpainting = fastPaint; /* @@ -1659,7 +1542,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI */ protected boolean drawMappedPositions(SearchResultsI results) { - if (results == null) + if ((results == null) || (img == null)) // JAL-2784 check gg is not null { return false; } @@ -1681,9 +1564,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.hasHiddenColumns()) { firstVisibleColumn = alignment.getHiddenColumns() - .adjustForHiddenColumns(firstVisibleColumn); + .visibleToAbsoluteColumn(firstVisibleColumn); lastVisibleColumn = alignment.getHiddenColumns() - .adjustForHiddenColumns(lastVisibleColumn); + .visibleToAbsoluteColumn(lastVisibleColumn); } for (int seqNo = ranges.getStartSeq(); seqNo <= ranges @@ -1726,14 +1609,16 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.hasHiddenColumns()) { firstCol = alignment.getHiddenColumns() - .findColumnPosition(firstCol); - lastCol = alignment.getHiddenColumns().findColumnPosition(lastCol); + .absoluteToVisibleColumn(firstCol); + lastCol = alignment.getHiddenColumns().absoluteToVisibleColumn(lastCol); } 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; @@ -1783,7 +1668,7 @@ 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 @@ -1815,10 +1700,17 @@ public class SeqCanvas extends JComponent implements ViewportListenerI { fastPaint(scrollX, 0); } - // bizarrely, we only need to scroll on the x value here as fastpaint - // copies the full height of the image anyway. Passing in the y value - // causes nasty repaint artefacts, which only disappear on a full - // repaint. + } + else if (eventName.equals(ViewportRanges.STARTSEQ)) + { + // scroll + fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue()); + } + else if (eventName.equals(ViewportRanges.STARTRESANDSEQ)) + { + if (av.getWrapAlignment()) + { + fastPaintWrapped(scrollX); } } } @@ -1836,9 +1728,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI { ViewportRanges ranges = av.getRanges(); - // if (Math.abs(scrollX) > ranges.getViewportWidth()) - // JAL-2836, 2836 temporarily removed wrapped fastpaint for release 2.10.3 - if (true) + if (Math.abs(scrollX) > ranges.getViewportWidth()) { /* * shift of more than one view width is @@ -1849,7 +1739,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI return; } - if (fastpainting || gg == null) + if (fastpainting || img == null) { return; } @@ -1859,6 +1749,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI try { + + Graphics gg = img.getGraphics(); + calculateWrappedGeometry(getWidth(), getHeight()); /* @@ -1887,6 +1780,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI */ drawWrappedDecorators(gg, ranges.getStartRes()); + gg.dispose(); + repaint(); } finally { @@ -1910,6 +1805,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(); @@ -1936,6 +1833,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, @@ -1943,6 +1842,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI gg.translate(-xOffset, 0); drawWrappedWidth(gg, ypos, startRes, endRes, canvasHeight); + } /* @@ -1986,7 +1886,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 @@ -2002,6 +1903,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI { return; } + + Graphics gg = img.getGraphics(); + int charWidth = av.getCharWidth(); int canvasHeight = getHeight(); @@ -2068,11 +1972,11 @@ public class SeqCanvas extends JComponent implements ViewportListenerI * charWidth, heightToCopy, widthToCopy, -wrappedRepeatHeightPx); } - y += wrappedRepeatHeightPx; xpos += viewportWidth; } } + gg.dispose(); } @@ -2088,7 +1992,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI */ protected boolean drawMappedPositionsWrapped(SearchResultsI results) { - if (results == null) + if ((results == null) || (img == null)) // JAL-2784 check gg is not null { return false; } @@ -2116,13 +2020,16 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.hasHiddenColumns()) { firstVisibleColumn = alignment.getHiddenColumns() - .adjustForHiddenColumns(firstVisibleColumn); + .visibleToAbsoluteColumn(firstVisibleColumn); lastVisibleColumn = alignment.getHiddenColumns() - .adjustForHiddenColumns(lastVisibleColumn); + .visibleToAbsoluteColumn(lastVisibleColumn); } int gapHeight = charHeight * (av.getScaleAboveWrapped() ? 2 : 1); + + Graphics gg = img.getGraphics(); + for (int seqNo = ranges.getStartSeq(); seqNo <= ranges .getEndSeq(); seqNo++) { @@ -2157,7 +2064,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.hasHiddenColumns()) { displayColumn = alignment.getHiddenColumns() - .findColumnPosition(displayColumn); + .absoluteToVisibleColumn(displayColumn); } /* @@ -2193,6 +2100,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI } } + gg.dispose(); + return matchFound; }