JAL-1989 added hashCode and equals, renamed field to avoid name conflict
[jalview.git] / src / jalview / datamodel / ColumnSelection.java
index c232781..74c58b7 100644 (file)
@@ -32,10 +32,14 @@ import java.util.List;
 import java.util.Vector;
 
 /**
- * NOTE: Columns are zero based.
+ * Data class holding the selected columns and hidden column ranges for a view.
+ * Ranges are base 1.
  */
 public class ColumnSelection
 {
+  /**
+   * A class to hold an efficient representation of selected columns
+   */
   private class IntList
   {
     /*
@@ -205,9 +209,26 @@ public class ColumnSelection
       }
       return rlist;
     }
+
+    @Override
+    public int hashCode()
+    {
+      // TODO Auto-generated method stub
+      return selected.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+      if (obj instanceof IntList)
+      {
+        return ((IntList) obj).selected.equals(selected);
+      }
+      return false;
+    }
   }
 
-  IntList selected = new IntList();
+  IntList selection = new IntList();
 
   /*
    * list of hidden column [start, end] ranges; the list is maintained in
@@ -223,7 +244,7 @@ public class ColumnSelection
    */
   public void addElement(int col)
   {
-    selected.add(col);
+    selection.add(col);
   }
 
   /**
@@ -231,7 +252,7 @@ public class ColumnSelection
    */
   public void clear()
   {
-    selected.clear();
+    selection.clear();
   }
 
   /**
@@ -242,7 +263,7 @@ public class ColumnSelection
    */
   public void removeElement(int col)
   {
-    selected.remove(col);
+    selection.remove(col);
   }
 
   /**
@@ -259,9 +280,9 @@ public class ColumnSelection
     for (int i = start; i < end; i++)
     {
       colInt = new Integer(i);
-      if (selected.contains(colInt))
+      if (selection.contains(colInt))
       {
-        selected.remove(colInt);
+        selection.remove(colInt);
       }
     }
   }
@@ -273,7 +294,7 @@ public class ColumnSelection
    */
   public List<Integer> getSelected()
   {
-    return selected.getList();
+    return selection.getList();
   }
 
   /**
@@ -282,7 +303,7 @@ public class ColumnSelection
    */
   public List<int[]> getSelectedRanges()
   {
-    return selected.getRanges();
+    return selection.getRanges();
   }
 
   /**
@@ -294,7 +315,7 @@ public class ColumnSelection
    */
   public boolean contains(int col)
   {
-    return (col > -1) ? selected.isSelected(col) : false;
+    return (col > -1) ? selection.isSelected(col) : false;
   }
 
   /**
@@ -302,7 +323,7 @@ public class ColumnSelection
    */
   public boolean isEmpty()
   {
-    return selected == null || selected.isEmpty();
+    return selection == null || selection.isEmpty();
   }
 
   /**
@@ -312,11 +333,11 @@ public class ColumnSelection
    */
   public int getMax()
   {
-    if (selected.isEmpty())
+    if (selection.isEmpty())
     {
       return -1;
     }
-    return selected.getMaxColumn();
+    return selection.getMaxColumn();
   }
 
   /**
@@ -326,11 +347,11 @@ public class ColumnSelection
    */
   public int getMin()
   {
-    if (selected.isEmpty())
+    if (selection.isEmpty())
     {
       return 1000000000;
     }
-    return selected.getMinColumn();
+    return selection.getMinColumn();
   }
 
   /**
@@ -344,7 +365,7 @@ public class ColumnSelection
   public List<int[]> compensateForEdit(int start, int change)
   {
     List<int[]> deletedHiddenColumns = null;
-    selected.compensateForEdits(start, change);
+    selection.compensateForEdits(start, change);
 
     if (hiddenColumns != null)
     {
@@ -394,7 +415,7 @@ public class ColumnSelection
   private void compensateForDelEdits(int start, int change)
   {
 
-    selected.compensateForEdits(start, change);
+    selection.compensateForEdits(start, change);
 
     if (hiddenColumns != null)
     {
@@ -571,12 +592,12 @@ public class ColumnSelection
             hiddenColumns = null;
           }
         }
-        if (selected != null && selected.size() > 0)
+        if (selection != null && selection.size() > 0)
         {
-          selected.pruneColumnList(shifts);
-          if (selected != null && selected.size() == 0)
+          selection.pruneColumnList(shifts);
+          if (selection != null && selection.size() == 0)
           {
-            selected = null;
+            selection = null;
           }
         }
         // and shift the rest.
@@ -600,7 +621,7 @@ public class ColumnSelection
    * Return absolute column index for a visible column index
    * 
    * @param column
-   *          int column index in alignment view
+   *          int column index in alignment view (count from zero)
    * @return alignment column index for column
    */
   public int adjustForHiddenColumns(int column)
@@ -743,13 +764,13 @@ public class ColumnSelection
 
   public void hideSelectedColumns()
   {
-    synchronized (selected)
+    synchronized (selection)
     {
-      for (int[] selregions : selected.getRanges())
+      for (int[] selregions : selection.getRanges())
       {
         hideColumns(selregions[0], selregions[1]);
       }
-      selected.clear();
+      selection.clear();
     }
 
   }
@@ -927,12 +948,12 @@ public class ColumnSelection
   {
     if (copy != null)
     {
-      if (copy.selected != null)
+      if (copy.selection != null)
       {
-        selected = new IntList();
-        for (int i = 0, j = copy.selected.size(); i < j; i++)
+        selection = new IntList();
+        for (int i = 0, j = copy.selection.size(); i < j; i++)
         {
-          selected.add(copy.selected.elementAt(i));
+          selection.add(copy.selection.elementAt(i));
         }
       }
       if (copy.hiddenColumns != null)
@@ -1082,21 +1103,22 @@ public class ColumnSelection
   /**
    * Locate the first and last position visible for this sequence. if seq isn't
    * visible then return the position of the left and right of the hidden
-   * boundary region
+   * boundary region, and the corresponding alignment column indices for the
+   * extent of the sequence
    * 
    * @param seq
-   * @return int[] { visible start, visible end, first seqpos, last seqpos }
+   * @return int[] { visible start, visible end, first seqpos, last seqpos,
+   *         alignment index for seq start, alignment index for seq end }
    */
   public int[] locateVisibleBoundsOfSequence(SequenceI seq)
   {
     int fpos=seq.getStart(),lpos= seq.getEnd();
     int start = 0;
-    int end = seq.getLength();
     
     if (hiddenColumns == null || hiddenColumns.size() == 0)
     {
-      return new int[] { seq.findIndex(fpos), seq.findIndex(lpos), fpos,
-          lpos };
+      int ifpos = seq.findIndex(fpos) - 1, ilpos = seq.findIndex(lpos) - 1;
+      return new int[] { ifpos, ilpos, fpos, lpos, ifpos, ilpos };
     }
 
     // Simply walk along the sequence whilst watching for hidden column
@@ -1104,19 +1126,26 @@ public class ColumnSelection
     List<int[]> regions = getHiddenColumns();
     int spos = fpos, lastvispos = -1, rcount = 0, hideStart = seq
             .getLength(), hideEnd = -1;
-    int visPrev = 0, visNext = 0, base = 0;
+    int visPrev = 0, visNext = 0, firstP = -1, lastP = -1;
     boolean foundStart = false;
     for (int p = 0, pLen = seq.getLength(); spos <= seq.getEnd()
             && p < pLen; p++)
     {
       if (!Comparison.isGap(seq.getCharAt(p)))
       {
+        // keep track of first/last column
+        // containing sequence data regardless of visibility
+        if (firstP == -1)
+        {
+          firstP = p;
+        }
+        lastP = p;
         // update hidden region start/end
         while (hideEnd < p && rcount < regions.size())
         {
           int[] region = regions.get(rcount++);
-          visNext += region[1] + 1 - region[0];
-          visPrev = visNext-1;
+          visPrev = visNext;
+          visNext += region[0] - visPrev;
           hideStart = region[0];
           hideEnd = region[1];
         }
@@ -1143,10 +1172,10 @@ public class ColumnSelection
     if (foundStart)
     {
       return new int[] { findColumnPosition(start),
-          findColumnPosition(lastvispos), fpos, lpos };
+          findColumnPosition(lastvispos), fpos, lpos, firstP, lastP };
     }
     // otherwise, sequence was completely hidden
-    return new int[] { visPrev, visNext, 0, 0 };
+    return new int[] { visPrev, visNext, 0, 0, firstP, lastP };
   }
 
   /**
@@ -1299,7 +1328,7 @@ public class ColumnSelection
       {
         if (hiddenColumns != null && isVisible(col.intValue()))
         {
-          selected.add(col);
+          selection.add(col);
         }
       }
     }
@@ -1313,8 +1342,8 @@ public class ColumnSelection
    */
   public void setElementsFrom(ColumnSelection colsel)
   {
-    selected = new IntList();
-    if (colsel.selected != null && colsel.selected.size() > 0)
+    selection = new IntList();
+    if (colsel.selection != null && colsel.selection.size() > 0)
     {
       if (hiddenColumns != null && hiddenColumns.size() > 0)
       {
@@ -1481,7 +1510,7 @@ public class ColumnSelection
    */
   public boolean hasSelectedColumns()
   {
-    return (selected != null && selected.size() > 0);
+    return (selection != null && selection.size() > 0);
   }
 
   /**
@@ -1604,4 +1633,32 @@ public class ColumnSelection
     return false;
   }
 
+  /**
+   * Returns a hashCode built from selected columns and hidden column ranges
+   */
+  @Override
+  public int hashCode()
+  {
+    int hashCode = selection.hashCode();
+    if (hiddenColumns != null)
+    {
+      for (int[] hidden : hiddenColumns)
+      {
+        hashCode = 31 * hashCode + hidden[0];
+        hashCode = 31 * hashCode + hidden[1];
+      }
+    }
+    return hashCode;
+  }
+
+  @Override
+  public boolean equals(Object obj)
+  {
+    if (obj instanceof ColumnSelection)
+    {
+      return hashCode() == obj.hashCode();
+    }
+    return false;
+  }
+
 }