JAL-2418 source formatting
[jalview.git] / src / jalview / analysis / Finder.java
index 5280467..191f6e8 100644 (file)
@@ -1,33 +1,82 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
 package jalview.analysis;
 
-import java.util.*;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SearchResultMatchI;
+import jalview.datamodel.SearchResults;
+import jalview.datamodel.SearchResultsI;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+import jalview.util.Comparison;
 
-import jalview.datamodel.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Vector;
+
+import com.stevesoft.pat.Regex;
 
 public class Finder
 {
   /**
    * Implements the search algorithms for the Find dialog box.
    */
-  SearchResults searchResults;
+  SearchResultsI searchResults;
+
   AlignmentI alignment;
-  jalview.datamodel.SequenceGroup selection = null;
-  Vector idMatch = null;
+
+  SequenceGroup selection = null;
+
+  Vector<SequenceI> idMatch = null;
+
   boolean caseSensitive = false;
+
+  private boolean includeDescription = false;
+
   boolean findAll = false;
-  com.stevesoft.pat.Regex regex = null;
+
+  Regex regex = null;
+
   /**
-   * hold's last-searched position between calles to find(false)
+   * holds last-searched position between calls to find(false)
    */
-  int seqIndex = 0, resIndex = 0;
+  int seqIndex = 0, resIndex = -1;
+
   public Finder(AlignmentI alignment, SequenceGroup selection)
   {
     this.alignment = alignment;
     this.selection = selection;
   }
 
+  /**
+   * restart search at given sequence and residue on alignment and (optionally)
+   * contained in selection
+   * 
+   * @param alignment
+   * @param selectionGroup
+   * @param seqIndex
+   * @param resIndex
+   */
   public Finder(AlignmentI alignment, SequenceGroup selectionGroup,
-                int seqIndex, int resIndex)
+          int seqIndex, int resIndex)
   {
     this(alignment, selectionGroup);
     this.seqIndex = seqIndex;
@@ -41,80 +90,108 @@ public class Finder
     {
       searchString = searchString.toUpperCase();
     }
-    regex = new com.stevesoft.pat.Regex(searchString);
+    regex = new Regex(searchString);
+    regex.setIgnoreCase(!caseSensitive);
     searchResults = new SearchResults();
-    idMatch = new Vector();
-    Sequence seq;
+    idMatch = new Vector<SequenceI>();
     String item = null;
     boolean found = false;
-
-    ////// is the searchString a residue number?
-    try
-    {
-      int res = Integer.parseInt(searchString);
-      found = true;
-      if (selection == null || selection.getSize() < 1)
-      {
-        seq = (Sequence) alignment.getSequenceAt(0);
-      }
-      else
-      {
-        seq = (Sequence) (selection.getSequenceAt(0));
-      }
-
-      searchResults.addResult(seq, res, res);
-      hasResults = true;
-    }
-    catch (NumberFormatException ex)
-    {
-    }
-
-    ///////////////////////////////////////////////
-
     int end = alignment.getHeight();
 
+    // /////////////////////////////////////////////
+
     if (selection != null)
     {
-      if ( (selection.getSize() < 1) ||
-          ( (selection.getEndRes() - selection.getStartRes()) < 2))
+      if ((selection.getSize() < 1)
+              || ((selection.getEndRes() - selection.getStartRes()) < 2))
       {
         selection = null;
       }
     }
+    SearchResultMatchI lastm = null;
 
     while (!found && (seqIndex < end))
     {
-      seq = (Sequence) alignment.getSequenceAt(seqIndex);
+      SequenceI seq = alignment.getSequenceAt(seqIndex);
 
-      if ( (selection != null) && !selection.getSequences(null).contains(seq))
+      if ((selection != null && selection.getSize() > 0)
+              && !selection.getSequences(null).contains(seq))
       {
         seqIndex++;
-        resIndex = 0;
+        resIndex = -1;
 
         continue;
       }
+      if (resIndex < 0)
+      {
+        resIndex = 0;
+        // test for one off matches - sequence position and sequence ID
+        // //// is the searchString a residue number?
+        try
+        {
+          int res = Integer.parseInt(searchString);
+          // possibly a residue number - check if valid for seq
+          if (seq.getEnd() >= res)
+          {
+            searchResults.addResult(seq, res, res);
+            hasResults = true;
+            // resIndex=seq.getLength();
+            // seqIndex++;
+            if (!findAll)
+            {
+              found = true;
+              break;
+            }
+          }
+        } catch (NumberFormatException ex)
+        {
+        }
 
+        if (regex.search(seq.getName()) && !idMatch.contains(seq))
+        {
+          idMatch.addElement(seq);
+          hasResults = true;
+          if (!findAll)
+          {
+            // stop and return the match
+            found = true;
+            break;
+          }
+        }
+
+        if (isIncludeDescription() && seq.getDescription() != null
+                && regex.search(seq.getDescription())
+                && !idMatch.contains(seq))
+        {
+          idMatch.addElement(seq);
+          hasResults = true;
+          if (!findAll)
+          {
+            // stop and return the match
+            found = true;
+            break;
+          }
+        }
+      }
       item = seq.getSequenceAsString();
-      if(!caseSensitive)
-        item = item.toUpperCase();
 
-      if ( (selection != null) &&
-          (selection.getEndRes() < alignment.getWidth() - 1))
+      if ((selection != null)
+              && (selection.getEndRes() < alignment.getWidth() - 1))
       {
         item = item.substring(0, selection.getEndRes() + 1);
       }
 
-      ///Shall we ignore gaps???? - JBPNote: Add Flag for forcing this or not
-      StringBuffer noGapsSB = new StringBuffer();
+      // /Shall we ignore gaps???? - JBPNote: Add Flag for forcing this or not
+      StringBuilder noGapsSB = new StringBuilder();
       int insertCount = 0;
-      Vector spaces = new Vector();
+      List<Integer> spaces = new ArrayList<Integer>();
 
       for (int j = 0; j < item.length(); j++)
       {
-        if (!jalview.util.Comparison.isGap(item.charAt(j)))
+        if (!Comparison.isGap(item.charAt(j)))
         {
           noGapsSB.append(item.charAt(j));
-          spaces.addElement(new Integer(insertCount));
+          spaces.add(Integer.valueOf(insertCount));
         }
         else
         {
@@ -123,7 +200,6 @@ public class Finder
       }
 
       String noGaps = noGapsSB.toString();
-
       for (int r = resIndex; r < noGaps.length(); r++)
       {
 
@@ -131,24 +207,22 @@ public class Finder
         {
           resIndex = regex.matchedFrom();
 
-          if ( (selection != null) &&
-              ( (resIndex +
-                 Integer.parseInt(spaces.elementAt(resIndex).toString())) <
-               selection.getStartRes()))
+          if ((selection != null && selection.getSize() > 0) && (resIndex
+                  + spaces.get(resIndex) < selection.getStartRes()))
           {
             continue;
           }
-
-          int sres = seq.findPosition(resIndex +
-                                      Integer.parseInt(spaces.elementAt(
-              resIndex)
-              .toString()));
-          int eres = seq.findPosition(regex.matchedTo() - 1 +
-                                      Integer.parseInt(spaces.elementAt(regex.
-              matchedTo() -
-              1).toString()));
-
-          searchResults.addResult(seq, sres, eres);
+          // if invalid string used, then regex has no matched to/from
+          int sres = seq.findPosition(resIndex + spaces.get(resIndex));
+          int eres = seq.findPosition(regex.matchedTo() - 1
+                  + (spaces.get(regex.matchedTo() - 1)));
+          // only add result if not contained in previous result
+          if (lastm == null || (lastm.getSequence() != seq
+                  || (!(lastm.getStart() <= sres
+                          && lastm.getEnd() >= eres))))
+          {
+            lastm = searchResults.addResult(seq, sres, eres);
+          }
           hasResults = true;
           if (!findAll)
           {
@@ -170,18 +244,16 @@ public class Finder
       if (!found)
       {
         seqIndex++;
-        resIndex = 0;
+        resIndex = -1;
       }
     }
 
-    for (int id = 0; id < alignment.getHeight(); id++)
-    {
-      if (regex.search(alignment.getSequenceAt(id).getName()))
-      {
-        idMatch.addElement(alignment.getSequenceAt(id));
-        hasResults = true;
-      }
-    }
+    /**
+     * We now search the Id string in the main search loop. for (int id = 0; id
+     * < alignment.getHeight(); id++) { if
+     * (regex.search(alignment.getSequenceAt(id).getName())) {
+     * idMatch.addElement(alignment.getSequenceAt(id)); hasResults = true; } }
+     */
     return hasResults;
   }
 
@@ -194,7 +266,8 @@ public class Finder
   }
 
   /**
-   * @param alignment the alignment to set
+   * @param alignment
+   *          the alignment to set
    */
   public void setAlignment(AlignmentI alignment)
   {
@@ -210,7 +283,8 @@ public class Finder
   }
 
   /**
-   * @param caseSensitive the caseSensitive to set
+   * @param caseSensitive
+   *          the caseSensitive to set
    */
   public void setCaseSensitive(boolean caseSensitive)
   {
@@ -226,7 +300,8 @@ public class Finder
   }
 
   /**
-   * @param findAll the findAll to set
+   * @param findAll
+   *          the findAll to set
    */
   public void setFindAll(boolean findAll)
   {
@@ -242,7 +317,8 @@ public class Finder
   }
 
   /**
-   * @param selection the selection to set
+   * @param selection
+   *          the selection to set
    */
   public void setSelection(jalview.datamodel.SequenceGroup selection)
   {
@@ -250,9 +326,12 @@ public class Finder
   }
 
   /**
-   * @return the idMatch
+   * Returns the (possibly empty) list of matching sequences (when search
+   * includes searching sequence names)
+   * 
+   * @return
    */
-  public Vector getIdMatch()
+  public Vector<SequenceI> getIdMatch()
   {
     return idMatch;
   }
@@ -268,7 +347,7 @@ public class Finder
   /**
    * @return the searchResults
    */
-  public SearchResults getSearchResults()
+  public SearchResultsI getSearchResults()
   {
     return searchResults;
   }
@@ -282,7 +361,8 @@ public class Finder
   }
 
   /**
-   * @param resIndex the resIndex to set
+   * @param resIndex
+   *          the resIndex to set
    */
   public void setResIndex(int resIndex)
   {
@@ -298,10 +378,21 @@ public class Finder
   }
 
   /**
-   * @param seqIndex the seqIndex to set
+   * @param seqIndex
+   *          the seqIndex to set
    */
   public void setSeqIndex(int seqIndex)
   {
     this.seqIndex = seqIndex;
   }
+
+  public boolean isIncludeDescription()
+  {
+    return includeDescription;
+  }
+
+  public void setIncludeDescription(boolean includeDescription)
+  {
+    this.includeDescription = includeDescription;
+  }
 }