JAL-3210 Improvements to eclipse detection. New src tree and SwingJS updated from...
[jalview.git] / src / jalview / datamodel / ColumnSelection.java
index 4d69fa4..3ccaab8 100644 (file)
@@ -20,7 +20,6 @@
  */
 package jalview.datamodel;
 
-import jalview.util.ShiftList;
 import jalview.viewmodel.annotationfilter.AnnotationFilterParameter;
 import jalview.viewmodel.annotationfilter.AnnotationFilterParameter.SearchableAnnotationField;
 
@@ -28,6 +27,7 @@ import java.util.ArrayList;
 import java.util.BitSet;
 import java.util.Collections;
 import java.util.List;
+import java.util.regex.PatternSyntaxException;
 
 /**
  * Data class holding the selected columns and hidden column ranges for a view.
@@ -60,7 +60,7 @@ public class ColumnSelection
      */
     IntList()
     {
-      order = new ArrayList<Integer>();
+      order = new ArrayList<>();
       _uorder = Collections.unmodifiableList(order);
       selected = new BitSet();
     }
@@ -231,7 +231,7 @@ public class ColumnSelection
      */
     List<int[]> getRanges()
     {
-      List<int[]> rlist = new ArrayList<int[]>();
+      List<int[]> rlist = new ArrayList<>();
       if (selected.isEmpty())
       {
         return rlist;
@@ -264,9 +264,7 @@ public class ColumnSelection
     }
   }
 
-  IntList selection = new IntList();
-
-  HiddenColumns hiddenColumns = new HiddenColumns();
+  private IntList selection = new IntList();
 
   /**
    * Add a column to the selection
@@ -391,93 +389,6 @@ public class ColumnSelection
     return selection.getMinColumn();
   }
 
-  /**
-   * propagate shift in alignment columns to column selection
-   * 
-   * @param start
-   *          beginning of edit
-   * @param left
-   *          shift in edit (+ve for removal, or -ve for inserts)
-   */
-  /*  public List<int[]> compensateForEdit(int start, int change)
-    {
-      selection.compensateForEdits(start, change);
-      return hiddenColumns.compensateForEdit(start, change, this);
-    }
-  */
-  /**
-   * propagate shift in alignment columns to column selection special version of
-   * compensateForEdit - allowing for edits within hidden regions
-   * 
-   * @param start
-   *          beginning of edit
-   * @param left
-   *          shift in edit (+ve for removal, or -ve for inserts)
-   */
-  private void compensateForDelEdits(int start, int change)
-  {
-    selection.compensateForEdits(start, change);
-    hiddenColumns.compensateForDelEdits(start, change);
-  }
-
-  /**
-   * Adjust hidden column boundaries based on a series of column additions or
-   * deletions in visible regions.
-   * 
-   * @param shiftrecord
-   * @return
-   */
-  private ShiftList compensateForEdits(ShiftList shiftrecord)
-  {
-    if (shiftrecord != null)
-    {
-      final List<int[]> shifts = shiftrecord.getShifts();
-      if (shifts != null && shifts.size() > 0)
-      {
-        int shifted = 0;
-        for (int i = 0, j = shifts.size(); i < j; i++)
-        {
-          int[] sh = shifts.get(i);
-          compensateForDelEdits(shifted + sh[0], sh[1]);
-          shifted -= sh[1];
-        }
-      }
-      return shiftrecord.getInverse();
-    }
-    return null;
-  }
-
-
-  /**
-   * remove any hiddenColumns or selected columns and shift remaining based on a
-   * series of position, range deletions.
-   * 
-   * @param deletions
-   */
-  private void pruneDeletions(ShiftList deletions)
-  {
-    if (deletions != null)
-    {
-      final List<int[]> shifts = deletions.getShifts();
-      if (shifts != null && shifts.size() > 0)
-      {
-        hiddenColumns.pruneDeletions(shifts);
-
-        if (selection != null && selection.size() > 0)
-        {
-          selection.pruneColumnList(shifts);
-          if (selection != null && selection.size() == 0)
-          {
-            selection = null;
-          }
-        }
-        // and shift the rest.
-        this.compensateForEdits(deletions);
-      }
-    }
-  }
-
-
   public void hideSelectedColumns(AlignmentI al)
   {
     synchronized (selection)
@@ -491,7 +402,6 @@ public class ColumnSelection
 
   }
 
-
   /**
    * Hides the specified column and any adjacent selected columns
    * 
@@ -534,10 +444,6 @@ public class ColumnSelection
     hidden.hideColumns(min, max);
   }
 
-
-
-
-
   /**
    * Copy constructor
    * 
@@ -558,11 +464,6 @@ public class ColumnSelection
   {
   }
 
-
-
-
-
-
   /**
    * Invert the column selection from first to end-1. leaves hiddenColumns
    * untouched (and unselected)
@@ -572,7 +473,7 @@ public class ColumnSelection
    */
   public void invertColumnSelection(int first, int width, AlignmentI al)
   {
-    boolean hasHidden = al.getHiddenColumns().hasHidden();
+    boolean hasHidden = al.getHiddenColumns().hasHiddenColumns();
     for (int i = first; i < width; i++)
     {
       if (contains(i))
@@ -590,191 +491,35 @@ public class ColumnSelection
   }
 
   /**
-   * add in any unselected columns from the given column selection, excluding
-   * any that are hidden.
+   * set the selected columns to the given column selection, excluding any
+   * columns that are hidden.
    * 
    * @param colsel
    */
-  public void addElementsFrom(ColumnSelection colsel)
-  {
-    if (colsel != null && !colsel.isEmpty())
-    {
-      for (Integer col : colsel.getSelected())
-      {
-        if (hiddenColumns != null
-                && hiddenColumns.isVisible(col.intValue()))
-        {
-          selection.add(col);
-        }
-      }
-    }
-  }
-
-  /**
-   * set the selected columns the given column selection, excluding any columns
-   * that are hidden.
-   * 
-   * @param colsel
-   */
-  public void setElementsFrom(ColumnSelection colsel)
+  public void setElementsFrom(ColumnSelection colsel,
+          HiddenColumns hiddenColumns)
   {
     selection = new IntList();
     if (colsel.selection != null && colsel.selection.size() > 0)
     {
-      if (hiddenColumns.hasHidden())
+      if (hiddenColumns.hasHiddenColumns())
       {
         // only select visible columns in this columns selection
-        addElementsFrom(colsel);
-      }
-      else
-      {
-        // add everything regardless
         for (Integer col : colsel.getSelected())
         {
-          addElement(col);
-        }
-      }
-    }
-  }
-
-  /**
-   * Add gaps into the sequences aligned to profileseq under the given
-   * AlignmentView
-   * 
-   * @param profileseq
-   * @param al
-   *          - alignment to have gaps inserted into it
-   * @param input
-   *          - alignment view where sequence corresponding to profileseq is
-   *          first entry
-   * @return new Column selection for new alignment view, with insertions into
-   *         profileseq marked as hidden.
-   */
-  public static ColumnSelection propagateInsertions(SequenceI profileseq,
-          AlignmentI al, AlignmentView input)
-  {
-    int profsqpos = 0;
-
-    // return propagateInsertions(profileseq, al, )
-    char gc = al.getGapCharacter();
-    Object[] alandcolsel = input.getAlignmentAndHiddenColumns(gc);
-    ColumnSelection nview = (ColumnSelection) alandcolsel[1];
-    SequenceI origseq = ((SequenceI[]) alandcolsel[0])[profsqpos];
-    nview.propagateInsertions(profileseq, al, origseq);
-    return nview;
-  }
-
-  /**
-   * 
-   * @param profileseq
-   *          - sequence in al which corresponds to origseq
-   * @param al
-   *          - alignment which is to have gaps inserted into it
-   * @param origseq
-   *          - sequence corresponding to profileseq which defines gap map for
-   *          modifying al
-   */
-  private void propagateInsertions(SequenceI profileseq, AlignmentI al,
-          SequenceI origseq)
-  {
-    char gc = al.getGapCharacter();
-    // recover mapping between sequence's non-gap positions and positions
-    // mapping to view.
-    pruneDeletions(ShiftList.parseMap(origseq.gapMap()));
-    int[] viscontigs = hiddenColumns.getVisibleContigs(0,
-            profileseq.getLength());
-    int spos = 0;
-    int offset = 0;
-
-    // add profile to visible contigs
-    for (int v = 0; v < viscontigs.length; v += 2)
-    {
-      if (viscontigs[v] > spos)
-      {
-        StringBuffer sb = new StringBuffer();
-        for (int s = 0, ns = viscontigs[v] - spos; s < ns; s++)
-        {
-          sb.append(gc);
-        }
-        for (int s = 0, ns = al.getHeight(); s < ns; s++)
-        {
-          SequenceI sqobj = al.getSequenceAt(s);
-          if (sqobj != profileseq)
+          if (hiddenColumns != null
+                  && hiddenColumns.isVisible(col.intValue()))
           {
-            String sq = al.getSequenceAt(s).getSequenceAsString();
-            if (sq.length() <= spos + offset)
-            {
-              // pad sequence
-              int diff = spos + offset - sq.length() - 1;
-              if (diff > 0)
-              {
-                // pad gaps
-                sq = sq + sb;
-                while ((diff = spos + offset - sq.length() - 1) > 0)
-                {
-                  // sq = sq
-                  // + ((diff >= sb.length()) ? sb.toString() : sb
-                  // .substring(0, diff));
-                  if (diff >= sb.length())
-                  {
-                    sq += sb.toString();
-                  }
-                  else
-                  {
-                    char[] buf = new char[diff];
-                    sb.getChars(0, diff, buf, 0);
-                    sq += buf.toString();
-                  }
-                }
-              }
-              sq += sb.toString();
-            }
-            else
-            {
-              al.getSequenceAt(s).setSequence(
-                      sq.substring(0, spos + offset) + sb.toString()
-                              + sq.substring(spos + offset));
-            }
+            selection.add(col);
           }
         }
-        // offset+=sb.length();
-      }
-      spos = viscontigs[v + 1] + 1;
-    }
-    if ((offset + spos) < profileseq.getLength())
-    {
-      // pad the final region with gaps.
-      StringBuffer sb = new StringBuffer();
-      for (int s = 0, ns = profileseq.getLength() - spos - offset; s < ns; s++)
-      {
-        sb.append(gc);
       }
-      for (int s = 0, ns = al.getHeight(); s < ns; s++)
+      else
       {
-        SequenceI sqobj = al.getSequenceAt(s);
-        if (sqobj == profileseq)
-        {
-          continue;
-        }
-        String sq = sqobj.getSequenceAsString();
-        // pad sequence
-        int diff = origseq.getLength() - sq.length();
-        while (diff > 0)
+        // add everything regardless
+        for (Integer col : colsel.getSelected())
         {
-          // sq = sq
-          // + ((diff >= sb.length()) ? sb.toString() : sb
-          // .substring(0, diff));
-          if (diff >= sb.length())
-          {
-            sq += sb.toString();
-          }
-          else
-          {
-            char[] buf = new char[diff];
-            sb.getChars(0, diff, buf, 0);
-            sq += buf.toString();
-          }
-          diff = origseq.getLength() - sq.length();
+          addElement(col);
         }
       }
     }
@@ -789,103 +534,118 @@ public class ColumnSelection
     return (selection != null && selection.size() > 0);
   }
 
-
-
-  public boolean filterAnnotations(Annotation[] annotations,
+  /**
+   * Selects columns where the given annotation matches the provided filter
+   * condition(s). Any existing column selections are first cleared. Answers the
+   * number of columns added.
+   * 
+   * @param annotations
+   * @param filterParams
+   * @return
+   */
+  public int filterAnnotations(Annotation[] annotations,
           AnnotationFilterParameter filterParams)
   {
     // JBPNote - this method needs to be refactored to become independent of
     // viewmodel package
-    hiddenColumns.revealAllHiddenColumns(this);
     this.clear();
-    int count = 0;
+    int addedCount = 0;
+    int column = 0;
     do
     {
-      if (annotations[count] != null)
+      Annotation ann = annotations[column];
+      if (ann != null)
       {
-
-        boolean itemMatched = false;
-
-        if (filterParams.getThresholdType() == AnnotationFilterParameter.ThresholdType.ABOVE_THRESHOLD
-                && annotations[count].value >= filterParams
-                        .getThresholdValue())
+        boolean matched = false;
+
+        /*
+         * filter may have multiple conditions - 
+         * these are or'd until a match is found
+         */
+        if (filterParams
+                .getThresholdType() == AnnotationFilterParameter.ThresholdType.ABOVE_THRESHOLD
+                && ann.value > filterParams.getThresholdValue())
         {
-          itemMatched = true;
+          matched = true;
         }
-        if (filterParams.getThresholdType() == AnnotationFilterParameter.ThresholdType.BELOW_THRESHOLD
-                && annotations[count].value <= filterParams
-                        .getThresholdValue())
+
+        if (!matched && filterParams
+                .getThresholdType() == AnnotationFilterParameter.ThresholdType.BELOW_THRESHOLD
+                && ann.value < filterParams.getThresholdValue())
         {
-          itemMatched = true;
+          matched = true;
         }
 
-        if (filterParams.isFilterAlphaHelix()
-                && annotations[count].secondaryStructure == 'H')
+        if (!matched && filterParams.isFilterAlphaHelix()
+                && ann.secondaryStructure == 'H')
         {
-          itemMatched = true;
+          matched = true;
         }
 
-        if (filterParams.isFilterBetaSheet()
-                && annotations[count].secondaryStructure == 'E')
+        if (!matched && filterParams.isFilterBetaSheet()
+                && ann.secondaryStructure == 'E')
         {
-          itemMatched = true;
+          matched = true;
         }
 
-        if (filterParams.isFilterTurn()
-                && annotations[count].secondaryStructure == 'S')
+        if (!matched && filterParams.isFilterTurn()
+                && ann.secondaryStructure == 'S')
         {
-          itemMatched = true;
+          matched = true;
         }
 
         String regexSearchString = filterParams.getRegexString();
-        if (regexSearchString != null
-                && !filterParams.getRegexSearchFields().isEmpty())
+        if (!matched && regexSearchString != null)
         {
           List<SearchableAnnotationField> fields = filterParams
                   .getRegexSearchFields();
-          try
-          {
-            if (fields.contains(SearchableAnnotationField.DISPLAY_STRING)
-                    && annotations[count].displayCharacter
-                            .matches(regexSearchString))
-            {
-              itemMatched = true;
-            }
-          } catch (java.util.regex.PatternSyntaxException pse)
+          for (SearchableAnnotationField field : fields)
           {
-            if (annotations[count].displayCharacter
-                    .equals(regexSearchString))
+            String compareTo = field == SearchableAnnotationField.DISPLAY_STRING
+                    ? ann.displayCharacter // match 'Label'
+                    : ann.description; // and/or 'Description'
+            if (compareTo != null)
             {
-              itemMatched = true;
+              try
+              {
+                if (compareTo.matches(regexSearchString))
+                {
+                  matched = true;
+                }
+              } catch (PatternSyntaxException pse)
+              {
+                if (compareTo.equals(regexSearchString))
+                {
+                  matched = true;
+                }
+              }
+              if (matched)
+              {
+                break;
+              }
             }
           }
-          if (fields.contains(SearchableAnnotationField.DESCRIPTION)
-                  && annotations[count].description != null
-                  && annotations[count].description
-                          .matches(regexSearchString))
-          {
-            itemMatched = true;
-          }
         }
 
-        if (itemMatched)
+        if (matched)
         {
-          this.addElement(count);
+          this.addElement(column);
+          addedCount++;
         }
       }
-      count++;
-    } while (count < annotations.length);
-    return false;
+      column++;
+    } while (column < annotations.length);
+
+    return addedCount;
   }
 
   /**
-   * Returns a hashCode built from selected columns and hidden column ranges
+   * Returns a hashCode built from selected columns ranges
    */
   @Override
   public int hashCode()
   {
-    int hashCode = selection.hashCode();
-    return hiddenColumns.hashCode(hashCode);
+    return selection.hashCode();
   }
 
   /**
@@ -916,7 +676,7 @@ public class ColumnSelection
       return false;
     }
 
-    return this.hiddenColumns.equals(that.hiddenColumns);
+    return true;
   }
 
   /**
@@ -938,8 +698,8 @@ public class ColumnSelection
    * 
    * @return
    */
-  public boolean markColumns(BitSet markedColumns, int startCol,
-          int endCol, boolean invert, boolean extendCurrent, boolean toggle)
+  public boolean markColumns(BitSet markedColumns, int startCol, int endCol,
+          boolean invert, boolean extendCurrent, boolean toggle)
   {
     boolean changed = false;
     if (!extendCurrent && !toggle)