added copy consensus sequence to consensus annotation popup menu
[jalview.git] / src / jalview / datamodel / ColumnSelection.java
index 4f4a510..2d22231 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Jalview - A Sequence Alignment Editor and Viewer
- * Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
+ * Copyright (C) 2006 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -18,6 +18,8 @@
  */
 package jalview.datamodel;
 
+import jalview.util.ShiftList;
+
 import java.util.*;
 
 /**
@@ -168,10 +170,10 @@ public class ColumnSelection
 
 
     /**
-     * DOCUMENT ME!
+     * propagate shift in alignment columns to column selection
      *
-     * @param start DOCUMENT ME!
-     * @param change DOCUMENT ME!
+     * @param start beginning of edit
+     * @param left shift in edit (+ve for removal, or -ve for inserts)
      */
     public void compensateForEdit(int start, int change)
     {
@@ -202,7 +204,180 @@ public class ColumnSelection
           }
         }
     }
+    /**
+     * 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)
+    {
+        for (int i = 0; i < size(); i++)
+        {
+            int temp = columnAt(i);
 
+            if (temp >= start)
+            {
+                selected.setElementAt(new Integer(temp - change), i);
+            }
+        }
+
+        if(hiddenColumns!=null)
+        {
+          for(int i=0; i<hiddenColumns.size(); i++)
+          {
+            int[] region = (int[]) hiddenColumns.elementAt(i);
+            if(region[0] >= start)
+            {
+              region[0] -= change;
+            }
+            if (region[1]>= start) {
+              region[1] -=change;
+            }
+            if (region[1]<region[0]) {
+              hiddenColumns.removeElementAt(i--);
+            }
+
+            if(region[0]<0)
+              region[0] = 0;
+            if(region[1] <0)
+             region[1] = 0;
+          }
+        }
+    }
+    /**
+     * Adjust hidden column boundaries based on a series of column
+     * additions or deletions in visible regions.
+     * @param shiftrecord
+     * @return
+     */
+    public ShiftList compensateForEdits(ShiftList shiftrecord) {
+      if (shiftrecord!=null) {
+        Vector shifts = shiftrecord.shifts;
+        if (shifts!=null && shifts.size()>0) {
+          int shifted=0;
+          for (int i=0,j=shifts.size(); i<j; i++) {
+            int[] sh = (int[]) shifts.elementAt(i);
+            //compensateForEdit(shifted+sh[0], sh[1]);
+            compensateForDelEdits(shifted+sh[0], sh[1]);
+            shifted-=sh[1];
+          }
+        }
+        return shiftrecord.getInverse();
+      }
+      return null;
+    }
+    /**
+     * removes intersection of position,length ranges in deletions
+     * from the start,end regions marked in intervals.
+     * @param deletions
+     * @param intervals
+     * @return
+     */
+    private boolean pruneIntervalVector(Vector deletions, Vector intervals) {
+      boolean pruned=false;
+      int i=0,j=intervals.size()-1, s=0, t=deletions.size()-1;
+      int hr[]=(int[]) intervals.elementAt(i);
+      int sr[]=(int[]) deletions.elementAt(s);
+      while (i<=j && s<=t) {
+        boolean trailinghn=hr[1]>=sr[0];
+        if (!trailinghn) {
+          if (i<j)
+            hr=(int[]) intervals.elementAt(++i);
+          else
+            i++;
+          continue;
+        }
+        int endshift=sr[0]+sr[1]; // deletion ranges - -ve means an insert
+        if (endshift<hr[0] || endshift<sr[0]) { // leadinghc disjoint or not a deletion
+          if (s<t)
+            sr=(int[]) deletions.elementAt(++s);
+          else
+            s++;
+          continue;
+        }
+        boolean leadinghn=hr[0]>=sr[0];
+        boolean leadinghc=hr[0]<endshift;
+        boolean trailinghc=hr[1]<endshift;
+        if (leadinghn) {
+          if (trailinghc) {// deleted hidden region.
+            intervals.removeElementAt(i);
+            pruned=true;
+            j--;
+            if (i<=j)
+              hr=(int[]) intervals.elementAt(i);
+            continue;
+          }
+          if (leadinghc) {
+            hr[0]=endshift; // clip c terminal region
+            leadinghn=!leadinghn;
+            pruned=true;
+          }
+        }
+        if (!leadinghn) {
+          if (trailinghc) {
+            if (trailinghn) {
+              hr[1]=sr[0]-1;
+              pruned=true;
+            }
+          } else {
+            // sr contained in hr
+            if (s<t)
+              sr=(int[]) deletions.elementAt(++s);
+            else
+              s++;
+            continue;
+          }
+        }
+      }
+      return pruned; // true if any interval was removed or modified by operations.
+    }
+    private boolean pruneColumnList(Vector deletion, Vector list) {
+      int s=0,t=deletion.size();
+      int[] sr=(int[])list.elementAt(s++);
+      boolean pruned=false;
+      int i=0, j=list.size();
+      while (i<j && s<=t) {
+        int c=((Integer)list.elementAt(i++)).intValue();
+        if (sr[0]<=c) {
+          if (sr[1]+sr[0]>=c) { // sr[1] -ve means inseriton.
+            list.removeElementAt(--i);
+            j--;
+          } else {
+            if (s<t)
+              sr = (int[])deletion.elementAt(s);
+            s++;
+          }
+        }
+      }
+      return pruned;
+    }
+    /**
+     * remove any hiddenColumns or selected columns and shift remaining
+     * based on a series of position, range deletions.
+     * @param deletions
+     */
+    public void pruneDeletions(ShiftList deletions) {
+      if (deletions!=null) {
+        Vector shifts=deletions.shifts;
+        if (shifts!=null && shifts.size()>0) {
+          // delete any intervals intersecting.
+          if (hiddenColumns!=null) {
+            pruneIntervalVector(shifts, hiddenColumns);
+            if (hiddenColumns!=null && hiddenColumns.size()==0) {
+              hiddenColumns=null;
+            }
+          }
+          if (selected!=null && selected.size()>0) {
+            pruneColumnList(shifts, selected);
+            if (selected!=null && selected.size()==0)
+              selected=null;
+          }
+          // and shift the rest.
+          this.compensateForEdits(deletions);
+        }
+      }
+    }
     /**
      * This Method is used to return all the HiddenColumn regions
      * less than the given index.
@@ -435,7 +610,7 @@ public class ColumnSelection
         int [] region = (int[])hiddenColumns.elementAt(i);
         if( res == region[0])
         {
-          for (int j = region[0]; j < region[1]; j++)
+          for (int j = region[0]; j < region[1]+1; j++)
           {
             addElement(j);
           }
@@ -460,5 +635,94 @@ public class ColumnSelection
       }
       return true;
     }
+    /**
+     * Copy constructor
+     * @param copy
+     */
+    public ColumnSelection(ColumnSelection copy) {
+      if (copy!=null) {
+        if (copy.selected!=null) {
+          selected = new Vector();
+          for (int i=0,j=copy.selected.size(); i<j; i++) {
+            selected.setElementAt( ((Integer) copy.selected.elementAt(i)), i);
+          }
+        }
+        if (copy.hiddenColumns!=null) {
+          hiddenColumns=new Vector();
+          for (int i=0,j=copy.hiddenColumns.size(); i<j; i++) {
+            int[] rh,cp;
+            rh = (int[])copy.hiddenColumns.elementAt(i);
+            if (rh!=null) {
+              cp = new int[rh.length];
+              System.arraycopy(rh, 0, cp, 0, rh.length);
+              hiddenColumns.setElementAt(cp, i);
+            }
+          }
+        }
+      }
+    }
+
+  /**
+   * ColumnSelection
+   */
+  public ColumnSelection()
+  {
+  }
+
+  public String[] getVisibleSequenceStrings(int start, int end, SequenceI[] seqs) {
+    int i,iSize=seqs.length;
+    String selection[] = new String[iSize];
+    if (hiddenColumns!=null && hiddenColumns.size()>0)
+      {
+      for (i=0; i<iSize; i++) {
+        StringBuffer visibleSeq = new StringBuffer();
+        Vector regions = getHiddenColumns();
+
+        int blockStart = start, blockEnd=end;
+        int [] region;
+           int hideStart, hideEnd;
+
+           for (int j = 0; j < regions.size(); j++)
+           {
+             region = (int[]) regions.elementAt(j);
+             hideStart = region[0];
+             hideEnd = region[1];
+
+             if(hideStart < start)
+             {
+               continue;
+             }
+
+             blockStart = Math.min(blockStart, hideEnd+1);
+             blockEnd = Math.min(blockEnd, hideStart);
+
+             if(blockStart>blockEnd)
+             {
+                break;
+             }
 
+
+             visibleSeq.append(seqs[i].getSequence(blockStart, blockEnd));
+
+             blockStart = hideEnd+1;
+             blockEnd = end;
+           }
+
+           if(end>blockStart)
+             visibleSeq.append(seqs[i].getSequence(blockStart, end));
+
+           selection[i] = visibleSeq.toString();
+        }
+      }
+      else
+      {
+        for(i=0; i<iSize; i++)
+        {
+        selection[i] = seqs[i].getSequence(start, end);
+        }
+      }
+      
+    return selection;
+    }
+  
 }