+ /*
+ * if highlights were either removed or added, repaint
+ */
+ if (redrawn)
+ {
+ 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
+ public void propertyChange(PropertyChangeEvent evt)
+ {
+ if (!av.getWrapAlignment())
+ {
+ if (evt.getPropertyName().equals("startres")
+ || evt.getPropertyName().equals("endres"))
+ {
+ // Make sure we're not trying to draw a panel
+ // larger than the visible window
+ ViewportRanges vpRanges = av.getRanges();
+ int scrollX = (int) evt.getNewValue() - (int) evt.getOldValue();
+ if (scrollX > vpRanges.getEndRes() - vpRanges.getStartRes())
+ {
+ scrollX = vpRanges.getEndRes() - vpRanges.getStartRes();
+ }
+ else if (scrollX < vpRanges.getStartRes() - vpRanges.getEndRes())
+ {
+ scrollX = vpRanges.getStartRes() - vpRanges.getEndRes();
+ }
+ fastPaint(scrollX, 0);
+ }
+ else if (evt.getPropertyName().equals("startseq")
+ || evt.getPropertyName().equals("endseq"))
+ {
+ fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue());
+ }
+ }
+ }
+
+ /**
+ * Redraws any positions in the search results in the visible region. Any
+ * highlights are drawn depending on the search results set on the Viewport,
+ * not the results parameter. This allows this method to be called to either
+ * clear highlighting (passing the previous search results), or set new
+ * highlighting.
+ *
+ * @param results
+ * @return
+ */
+ protected boolean drawWrappedMappedPositions(SearchResultsI results)
+ {
+ if (results == null)
+ {
+ return false;
+ }
+
+ boolean matchFound = false;
+
+ /*
+ * Viewport ranges are set for the 'row' of the wrapped alignment
+ * the cursor is in, not the whole visible region; really we want
+ * the latter; +-6 a temporary fudge for codons wrapping across lines
+ */
+ ViewportRanges ranges = av.getRanges();
+ int firstVisibleColumn = ranges.getStartRes() - 6;
+ int lastVisibleColumn = ranges.getEndRes() + 6;
+ AlignmentI alignment = av.getAlignment();
+ if (av.hasHiddenColumns())
+ {
+ firstVisibleColumn = alignment.getHiddenColumns()
+ .adjustForHiddenColumns(firstVisibleColumn);
+ lastVisibleColumn = alignment.getHiddenColumns()
+ .adjustForHiddenColumns(lastVisibleColumn);
+ }
+
+ /*
+ * find width of alignment in residues, and height of alignment,
+ * so we can calculate where to render each matched position
+ */
+ int wrappedWidth = av.getWrappedWidth();
+ int wrappedHeight = av.getAlignment().getHeight() * av.getCharHeight();
+ int gapHeight = av.getCharHeight()
+ * (av.getScaleAboveWrapped() ? 2 : 1);
+ wrappedHeight += gapHeight;
+ wrappedHeight += getAnnotationHeight();
+
+ 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
+ */
+ firstMatchedColumn = Math.max(firstMatchedColumn,
+ firstVisibleColumn);
+ lastMatchedColumn = Math.min(lastMatchedColumn,
+ lastVisibleColumn);
+
+ /*
+ * draw each mapped position separately (as contiguous positions may
+ * wrap across lines)
+ */
+ for (int mappedPos = firstMatchedColumn; mappedPos <= lastMatchedColumn; mappedPos++)
+ {
+ int displayColumn = mappedPos;
+ if (av.hasHiddenColumns())
+ {
+ displayColumn = alignment.getHiddenColumns()
+ .findColumnPosition(displayColumn);
+ }
+
+ /*
+ * transX: offset from left edge of canvas to residue position
+ */
+ int transX = labelWidthWest
+ + ((displayColumn - ranges.getStartRes()) % wrappedWidth)
+ * av.getCharWidth();
+
+ /*
+ * transY: offset from top edge of canvas to residue position
+ */
+ int transY = gapHeight;
+ transY += (displayColumn / wrappedWidth) * wrappedHeight;
+ transY += (seqNo - ranges.getStartSeq()) * av.getCharHeight();
+
+ /*
+ * yOffset is from graphics origin to start of visible region
+ */
+ int yOffset = 0;// (displayColumn / wrappedWidth) * wrappedHeight;
+ if (transY < getHeight())
+ {
+ matchFound = true;
+ gg.translate(transX, transY);
+ drawPanel(gg, displayColumn, displayColumn, seqNo, seqNo,
+ yOffset);
+ gg.translate(-transX, -transY);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return matchFound;