*/
public class SeqCanvas extends JComponent implements ViewportListenerI
{
+ private static String ZEROS = "0000000000";
+
final FeatureRenderer fr;
- final SequenceRenderer sr;
+ final SequenceRenderer seqRdr;
BufferedImage img;
inGroup = false;
}
+ }
+ }
- groupIndex++;
+ if (inGroup)
+ {
+ sy = verticalOffset + ((i - startSeq) * charHeight);
+ if (sx >= 0 && sx < visWidth)
+ {
+ g.drawLine(sx, oldY, sx, sy);
+ }
- g.setStroke(new BasicStroke());
+ if (sx + xwidth < visWidth)
+ {
+ g.drawLine(sx + xwidth, oldY, sx + xwidth, sy);
+ }
- if (groupIndex >= av.getAlignment().getGroups().size())
- {
- break;
- }
+ if (sx < 0)
+ {
+ xwidth += sx;
+ sx = 0;
+ }
- group = av.getAlignment().getGroups().get(groupIndex);
+ if (sx + xwidth > visWidth)
+ {
+ xwidth = visWidth;
+ }
+ else if (sx + xwidth >= (endRes - startRes + 1) * charWidth)
+ {
+ xwidth = (endRes - startRes + 1) * charWidth;
+ }
- } while (groupIndex < av.getAlignment().getGroups().size());
+ if (top != -1)
+ {
+ g.drawLine(sx, top, sx + xwidth, top);
+ top = -1;
+ }
- }
+ if (bottom != -1)
+ {
+ g.drawLine(sx, bottom - 1, sx + xwidth, bottom - 1);
+ bottom = -1;
+ }
+ inGroup = false;
+ }
}
-
+
/**
- * DOCUMENT ME!
+ * 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.
+ * <p>
+ * 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).
*
* @param results
- * DOCUMENT ME!
+ * @param noFastPaint
+ * @return
*/
- public void highlightSearchResults(SearchResultsI results)
+ public boolean highlightSearchResults(SearchResultsI results,
+ boolean noFastPaint)
{
- img = null;
+ if (fastpainting)
+ {
+ return false;
+ }
+ boolean wrapped = av.getWrapAlignment();
+
+ try
+ {
+ fastPaint = !noFastPaint;
+ fastpainting = fastPaint;
+
+ updateViewport();
+
+ /*
+ * to avoid redrawing the whole visible region, we instead
+ * redraw just the minimal regions to remove previous highlights
+ * and add new ones
+ */
+ SearchResultsI previous = av.getSearchResults();
+ av.setSearchResults(results);
+ boolean redrawn = false;
+ boolean drawn = false;
+ if (wrapped)
+ {
+ redrawn = drawMappedPositionsWrapped(previous);
+ drawn = drawMappedPositionsWrapped(results);
+ redrawn |= drawn;
+ }
+ else
+ {
+ redrawn = drawMappedPositions(previous);
+ drawn = drawMappedPositions(results);
+ redrawn |= drawn;
+ }
- av.setSearchResults(results);
+ /*
+ * if highlights were either removed or added, repaint
+ */
+ if (redrawn)
+ {
+ repaint();
+ }
- repaint();
+ /*
+ * return true only if highlights were added
+ */
+ return drawn;
+
+ } finally
+ {
+ fastpainting = false;
+ }
+ }
+
+ /**
+ * Redraws the minimal rectangle in the visible region (if any) that includes
+ * mapped positions of the given search results. Whether or not positions are
+ * highlighted depends on the SearchResults set on the Viewport. This allows
+ * this method to be called to either clear or set highlighting. Answers true
+ * if any positions were drawn (in which case a repaint is still required),
+ * else false.
+ *
+ * @param results
+ * @return
+ */
+ protected boolean drawMappedPositions(SearchResultsI results)
+ {
+ if (results == null)
+ {
+ return false;
+ }
+
+ /*
+ * calculate the minimal rectangle to redraw that
+ * includes both new and existing search results
+ */
+ int firstSeq = Integer.MAX_VALUE;
+ int lastSeq = -1;
+ int firstCol = Integer.MAX_VALUE;
+ int lastCol = -1;
+ boolean matchFound = false;
+
+ ViewportRanges ranges = av.getRanges();
+ int firstVisibleColumn = ranges.getStartRes();
+ int lastVisibleColumn = ranges.getEndRes();
+ AlignmentI alignment = av.getAlignment();
+ if (av.hasHiddenColumns())
+ {
+ firstVisibleColumn = alignment.getHiddenColumns()
+ .adjustForHiddenColumns(firstVisibleColumn);
+ lastVisibleColumn = alignment.getHiddenColumns()
+ .adjustForHiddenColumns(lastVisibleColumn);
+ }
+
+ for (int seqNo = ranges.getStartSeq(); seqNo <= ranges
+ .getEndSeq(); seqNo++)
+ {
+ SequenceI seq = alignment.getSequenceAt(seqNo);
+
+ int[] visibleResults = results.getResults(seq, firstVisibleColumn,
+ lastVisibleColumn);
+ if (visibleResults != null)
+ {
+ for (int i = 0; i < visibleResults.length - 1; i += 2)
+ {
+ int firstMatchedColumn = visibleResults[i];
+ int lastMatchedColumn = visibleResults[i + 1];
+ if (firstMatchedColumn <= lastVisibleColumn
+ && lastMatchedColumn >= firstVisibleColumn)
+ {
+ /*
+ * found a search results match in the visible region -
+ * remember the first and last sequence matched, and the first
+ * and last visible columns in the matched positions
+ */
+ matchFound = true;
+ firstSeq = Math.min(firstSeq, seqNo);
+ lastSeq = Math.max(lastSeq, seqNo);
+ firstMatchedColumn = Math.max(firstMatchedColumn,
+ firstVisibleColumn);
+ lastMatchedColumn = Math.min(lastMatchedColumn,
+ lastVisibleColumn);
+ firstCol = Math.min(firstCol, firstMatchedColumn);
+ lastCol = Math.max(lastCol, lastMatchedColumn);
+ }
+ }
+ }
+ }
+
+ if (matchFound)
+ {
+ if (av.hasHiddenColumns())
+ {
+ firstCol = alignment.getHiddenColumns()
+ .findColumnPosition(firstCol);
+ lastCol = alignment.getHiddenColumns().findColumnPosition(lastCol);
+ }
+ int transX = (firstCol - ranges.getStartRes()) * av.getCharWidth();
+ int transY = (firstSeq - ranges.getStartSeq()) * av.getCharHeight();
+ gg.translate(transX, transY);
+ drawPanel(gg, firstCol, lastCol, firstSeq, lastSeq, 0);
+ gg.translate(-transX, -transY);
+ }
+
+ return matchFound;
}
@Override