X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fanalysis%2FFinder.java;h=3ee5be47ef01f542cb6e277cd6dd6cf73c8b372e;hb=970956e40635fd5a86d46e399532abda64ccdf92;hp=de57d691e3bed8679d4cb186b9462cec570a5687;hpb=3ba65b98445f192453664357a1df25128fe07c84;p=jalview.git diff --git a/src/jalview/analysis/Finder.java b/src/jalview/analysis/Finder.java index de57d69..3ee5be4 100644 --- a/src/jalview/analysis/Finder.java +++ b/src/jalview/analysis/Finder.java @@ -20,7 +20,10 @@ */ package jalview.analysis; +import jalview.api.AlignViewportI; +import jalview.api.FinderI; import jalview.datamodel.AlignmentI; +import jalview.datamodel.Range; import jalview.datamodel.SearchResultMatchI; import jalview.datamodel.SearchResults; import jalview.datamodel.SearchResultsI; @@ -28,6 +31,7 @@ import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; import jalview.datamodel.VisibleContigsIterator; import jalview.util.Comparison; +import jalview.util.Platform; import java.util.List; import java.util.Vector; @@ -37,7 +41,7 @@ import com.stevesoft.pat.Regex; /** * Implements the search algorithm for the Find dialog */ -public class Finder +public class Finder implements FinderI { /* * matched residue locations @@ -47,32 +51,12 @@ public class Finder /* * sequences matched by id or description */ - private Vector idMatch; + private Vector idMatches; /* - * the alignment to search over + * the viewport to search over */ - private AlignmentI alignment; - - /* - * (optional) selection to restrict search to - */ - private SequenceGroup selection; - - /* - * set true for case-sensitive search (default is false) - */ - private boolean caseSensitive; - - /* - * set true to search sequence description (default is false) - */ - private boolean includeDescription; - - /* - * set true to return all matches (default is next match only) - */ - private boolean findAll; + private AlignViewportI viewport; /* * sequence index in alignment to search from @@ -82,75 +66,90 @@ public class Finder /* * column position in sequence to search from, base 0 * - absolute column number including any hidden columns - * (position of last match for a repeat search) + * (position after start of last match for a repeat search) */ private int columnIndex; /** - * Constructor to start searching an alignment, optionally restricting results - * to a selection + * Constructor for searching a viewport * - * @param al - * @param sel + * @param av */ - public Finder(AlignmentI al, SequenceGroup sel) + public Finder(AlignViewportI av) { - this(al, sel, 0, -1); + this.viewport = av; + this.sequenceIndex = 0; + this.columnIndex = -1; } - /** - * Constructor to resume search at given sequence and residue on alignment and - * (optionally) restricted to a selection - * - * @param al - * @param sel - * @param seqindex - * @param colindex - */ - public Finder(AlignmentI al, SequenceGroup sel, int seqindex, - int colindex) + @Override + public void findAll(String theSearchString, boolean matchCase, + boolean searchDescription) { - this.alignment = al; - this.selection = sel; - this.sequenceIndex = seqindex; - this.columnIndex = colindex; + /* + * search from the start + */ + sequenceIndex = 0; + columnIndex = -1; + + doFind(theSearchString, matchCase, searchDescription, true); + + /* + * reset to start for next search + */ + sequenceIndex = 0; + columnIndex = -1; } - /** - * Performs a find for the given search string. By default the next match is - * found, but if setFindAll(true) has been called, then all matches are found. - * Sequences matched by id or description can be retrieved by getIdMatch(), - * and matched residue patterns by getSearchResults(). - * - * @param theSearchString - * @return - */ - public void find(String theSearchString) + @Override + public void findNext(String theSearchString, boolean matchCase, + boolean searchDescription) { - if (findAll) + doFind(theSearchString, matchCase, searchDescription, false); + + if (searchResults.isEmpty() && idMatches.isEmpty()) { + /* + * search failed - reset to start for next search + */ sequenceIndex = 0; columnIndex = -1; } + } - String searchString = caseSensitive ? theSearchString + /** + * Performs a 'find next' or 'find all' + * + * @param theSearchString + * @param matchCase + * @param searchDescription + * @param findAll + */ + protected void doFind(String theSearchString, boolean matchCase, + boolean searchDescription, boolean findAll) + { + String searchString = matchCase ? theSearchString : theSearchString.toUpperCase(); - Regex searchPattern = new Regex(searchString); - searchPattern.setIgnoreCase(!caseSensitive); + Regex searchPattern = Platform.newRegex(searchString, null); + searchPattern.setIgnoreCase(!matchCase); + searchResults = new SearchResults(); - idMatch = new Vector<>(); + idMatches = new Vector<>(); + SequenceGroup selection = viewport.getSelectionGroup(); if (selection != null && selection.getSize() < 1) { selection = null; // ? ignore column-only selection } + AlignmentI alignment = viewport.getAlignment(); int end = alignment.getHeight(); while (sequenceIndex < end) { SequenceI seq = alignment.getSequenceAt(sequenceIndex); - boolean found = findNext(seq, searchString, searchPattern); + boolean found = findNextMatch(seq, searchString, searchPattern, + searchDescription); if (found && !findAll) { return; @@ -164,17 +163,57 @@ public class Finder } /** - * Answers the start-end column range of the visible region starting at or - * after the given column. if there are no hidden columns, this just returns - * the remaining width of the alignment. Answers null if there are no visible - * columns at or after column. + * Answers the start-end column range of the visible region of + * sequence starting at or after the given column. + * If there are no hidden columns, this just returns the remaining width of + * the sequence. The range is restricted to the current selection + * if there is one. Answers null if there are no visible columns at or after + * column. */ - protected int[] getNextVisibleRegion(int column) + protected Range getNextVisibleSequenceRegion(SequenceI sequence, + int column) { + int seqColStart = column; + int seqColEnd = sequence.getLength() - 1; + + /* + * restrict search to (next) visible column region, + * in case there are hidden columns + */ + AlignmentI alignment = viewport.getAlignment(); VisibleContigsIterator visibleRegions = alignment.getHiddenColumns() .getVisContigsIterator(column, alignment.getWidth(), false); - return visibleRegions.hasNext() ? visibleRegions.next() : null; + int[] visible = visibleRegions.hasNext() ? visibleRegions.next() : null; + if (visible == null) + { + columnIndex = seqColEnd + 1; + return null; + } + seqColStart = Math.max(seqColStart, visible[0]); + seqColEnd = Math.min(seqColEnd, visible[1]); + + /* + * restrict search to selected region if there is one + */ + SequenceGroup selection = viewport.getSelectionGroup(); + if (selection != null) + { + int selectionStart = selection.getStartRes(); + int selectionEnd = selection.getEndRes(); + if (selectionStart > seqColEnd || selectionEnd < seqColStart) + { + /* + * sequence region doesn't overlap selection region + */ + columnIndex = seqColEnd + 1; + return null; + } + seqColStart = Math.max(seqColStart, selectionStart); + seqColEnd = Math.min(seqColEnd, selectionEnd); + } + + return new Range(seqColStart, seqColEnd); } /** @@ -186,11 +225,13 @@ public class Finder * @param seq * @param searchString * @param searchPattern + * @param matchDescription * @return */ - protected boolean findNext(SequenceI seq, String searchString, - Regex searchPattern) + protected boolean findNextMatch(SequenceI seq, String searchString, + Regex searchPattern, boolean matchDescription) { + SequenceGroup selection = viewport.getSelectionGroup(); if (selection != null && !selection.contains(seq)) { /* @@ -205,7 +246,8 @@ public class Finder * at start of sequence; try find by residue number, in sequence id, * or (optionally) in sequence description */ - if (doNonMotifSearches(seq, searchString, searchPattern)) + if (doNonMotifSearches(seq, searchString, searchPattern, + matchDescription)) { return true; } @@ -237,55 +279,17 @@ public class Finder */ protected boolean searchNextVisibleRegion(SequenceI seq, Regex searchPattern) { - /* - * sequence columns to search (working in absolute column - * positions, base 0, including any hidden columns) - */ - int seqColStart = columnIndex; - int seqColEnd = seq.getLength() - 1; - - /* - * restrict search to (next) visible column region, - * in case there are hidden columns - */ - int[] visible = getNextVisibleRegion(columnIndex); - if (visible != null) - { - seqColStart = Math.max(seqColStart, visible[0]); - seqColEnd = Math.min(seqColEnd, visible[1]); - } - else + Range visible = getNextVisibleSequenceRegion(seq, columnIndex); + if (visible == null) { - columnIndex = seqColEnd + 1; return false; } - - /* - * restrict search to selected region if there is one - */ - if (selection != null) - { - int selectionStart = selection.getStartRes(); - int selectionEnd = selection.getEndRes(); - if (selectionStart > seqColEnd || selectionEnd < seqColStart) - { - /* - * sequence region doesn't overlap selection region - - * no match, advance to next visible region - */ - columnIndex = seqColEnd + 1; - return false; - } - seqColStart = Math.max(seqColStart, selectionStart); - seqColEnd = Math.min(seqColEnd, selectionEnd); - } - - String seqString = seq.getSequenceAsString(seqColStart, seqColEnd + 1); + String seqString = seq.getSequenceAsString(visible.start, visible.end + 1); String noGaps = AlignSeq.extractGaps(Comparison.GapChars, seqString); if (searchPattern.search(noGaps)) { - int sequenceStartPosition = seq.findPosition(seqColStart); + int sequenceStartPosition = seq.findPosition(visible.start); recordMatch(seq, searchPattern, sequenceStartPosition); return true; } @@ -295,7 +299,7 @@ public class Finder * no match - advance columnIndex past this visible region * so the next visible region (if any) is searched next */ - columnIndex = seqColEnd + 1; + columnIndex = visible.end + 1; } return false; @@ -359,10 +363,11 @@ public class Finder * @param seq * @param searchString * @param searchPattern + * @param includeDescription * @return */ protected boolean doNonMotifSearches(SequenceI seq, String searchString, - Regex searchPattern) + Regex searchPattern, boolean includeDescription) { /* * position sequence search to start of sequence @@ -396,9 +401,9 @@ public class Finder protected boolean searchSequenceDescription(SequenceI seq, Regex searchPattern) { String desc = seq.getDescription(); - if (desc != null && searchPattern.search(desc) && !idMatch.contains(seq)) + if (desc != null && searchPattern.search(desc) && !idMatches.contains(seq)) { - idMatch.addElement(seq); + idMatches.addElement(seq); return true; } return false; @@ -415,9 +420,9 @@ public class Finder */ protected boolean searchSequenceName(SequenceI seq, Regex searchPattern) { - if (searchPattern.search(seq.getName()) && !idMatch.contains(seq)) + if (searchPattern.search(seq.getName()) && !idMatches.contains(seq)) { - idMatch.addElement(seq); + idMatches.addElement(seq); return true; } return false; @@ -444,79 +449,21 @@ public class Finder return false; } - /** - * Sets whether the search is case sensitive (default is no) - * - * @param value - */ - public void setCaseSensitive(boolean value) - { - this.caseSensitive = value; - } - - /** - * Sets whether search returns all matches. Default is to return the next - * match only. - * - * @param value - */ - public void setFindAll(boolean value) - { - this.findAll = value; - } - - /** - * Returns the (possibly empty) list of sequences matched on sequence name or - * description - * - * @return + /* (non-Javadoc) + * @see jalview.analysis.FinderI#getIdMatch() */ - public Vector getIdMatch() + @Override + public Vector getIdMatches() { - return idMatch; + return idMatches; } - /** - * Answers the search results (possibly empty) from the last search - * - * @return + /* (non-Javadoc) + * @see jalview.analysis.FinderI#getSearchResults() */ + @Override public SearchResultsI getSearchResults() { return searchResults; } - - /** - * Answers the absolute column position (base 0, including any hidden columns) - * of the start of the last sequence motif (residue pattern) match found. A - * 'Find next' will search from the next position. - * - * @return - */ - public int getColumnIndex() - { - return columnIndex; - } - - /** - * Answers the offset in the alignment (0..) of the sequence in which the last - * match was found (if any) - * - * @return - */ - public int getSequenceIndex() - { - return sequenceIndex; - } - - /** - * Sets whether search also searches in sequence description text (default is - * no) - * - * @param value - */ - public void setIncludeDescription(boolean value) - { - this.includeDescription = value; - } }