+
+ nextSequence(ignoreHidden);
+ return false;
+ }
+
+ /**
+ * Adds the match held in the <code>searchPattern</code> Regex to the
+ * <code>searchResults</code>, unless it is a subregion of the last match
+ * recorded. <code>residueIndex</code> is advanced to the position after the
+ * start of the matched region, ready for the next search. Answers true if a
+ * match was added, else false.
+ * <p>
+ * Matches that lie entirely within hidden regions of the alignment are not
+ * added.
+ *
+ * @param searchPattern
+ * @param ignoreHidden
+ * @return
+ */
+ protected boolean recordMatch(Regex searchPattern, boolean ignoreHidden)
+ {
+ SequenceI seq = viewport.getAlignment().getSequenceAt(sequenceIndex);
+
+ /*
+ * convert start/end of the match to sequence coordinates
+ */
+ int offset = searchPattern.matchedFrom();
+ int matchStartPosition = this.searchedSequenceStartPosition + offset;
+ int matchEndPosition = matchStartPosition
+ + searchPattern.charsMatched() - 1;
+
+ /*
+ * update residueIndex to next position after the start of the match
+ * (findIndex returns a value base 1, columnIndex is held base 0)
+ */
+ residueIndex = searchPattern.matchedFrom()+1;
+
+ /*
+ * return false if the match is entirely in a hidden region
+ */
+ if (allHidden(seq, matchStartPosition, matchEndPosition))
+ {
+ return false;
+ }
+
+ /*
+ * check that this match is not a subset of the previous one (JAL-2302)
+ */
+ List<SearchResultMatchI> matches = searchResults.getResults();
+ SearchResultMatchI lastMatch = matches.isEmpty() ? null
+ : matches.get(matches.size() - 1);
+
+ if (lastMatch == null || !lastMatch.contains(seq, matchStartPosition,
+ matchEndPosition))
+ {
+ addMatch(seq, matchStartPosition, matchEndPosition, ignoreHidden);
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Adds one match to the stored list. If hidden residues are being skipped, then
+ * the match may need to be split into contiguous positions of the sequence (so
+ * it does not include skipped residues).
+ *
+ * @param seq
+ * @param matchStartPosition
+ * @param matchEndPosition
+ * @param ignoreHidden
+ */
+ private void addMatch(SequenceI seq, int matchStartPosition,
+ int matchEndPosition, boolean ignoreHidden)
+ {
+ if (!ignoreHidden)
+ {
+ /*
+ * simple case
+ */
+ searchResults.addResult(seq, matchStartPosition, matchEndPosition);
+ return;
+ }
+
+ /*
+ * get start-end contiguous ranges in underlying sequence
+ */
+ int[] truePositions = searchedSequenceMap
+ .locateInFrom(matchStartPosition, matchEndPosition);
+ searchResults.addResult(seq, truePositions);
+ }
+
+ /**
+ * Returns true if all residues are hidden, else false
+ *
+ * @param seq
+ * @param fromPos
+ * @param toPos
+ * @return
+ */
+ private boolean allHidden(SequenceI seq, int fromPos, int toPos)
+ {
+ if (!viewport.hasHiddenColumns())
+ {
+ return false;
+ }
+ for (int res = fromPos; res <= toPos; res++)
+ {
+ if (isVisible(seq, res))
+ {
+ return false;
+ }
+ }
+ return true;