JAL-2388 Preliminary refactor check-in, does not compile
[jalview.git] / src / jalview / viewmodel / ViewportPositionProps.java
index 1bb49af..4f67cc6 100644 (file)
 package jalview.viewmodel;
 
 import jalview.api.ViewStyleI;
+import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.SequenceCollectionI;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
 
 /**
  * Supplies and updates viewport properties relating to position such as: start
@@ -54,6 +64,14 @@ public class ViewportPositionProps extends ViewportProperties
   // viewstyle
   private ViewStyleI viewstyle;
 
+  // hidden column data
+  protected ColumnSelection colSel = new ColumnSelection();
+
+  private long colselhash = -1;
+
+  // hidden sequence data
+  private Map<SequenceI, SequenceCollectionI> hiddenRepSequences;
+
   /**
    * Constructor
    * @param alignment TODO
@@ -209,7 +227,6 @@ public class ViewportPositionProps extends ViewportProperties
   public int convertPixelsToResidues(int x)
   {
     return Math.round((float) x / viewstyle.getCharWidth());
-    // return (int) ((float) x / viewstyle.getCharWidth());
   }
 
   /**
@@ -222,7 +239,6 @@ public class ViewportPositionProps extends ViewportProperties
   public int convertPixelsToSequences(int y)
   {
     return Math.round((float) y / viewstyle.getCharHeight());
-    // return (int) ((float) y / viewstyle.getCharHeight());
   }
   
   /**
@@ -248,4 +264,389 @@ public class ViewportPositionProps extends ViewportProperties
   {
     return (r * viewstyle.getCharWidth());
   }
+
+  public void setHiddenColumns(ColumnSelection colsel)
+  {
+    this.colSel = colsel;
+  }
+
+  public ColumnSelection getColumnSelection()
+  {
+    return colSel;
+  }
+
+  public void setColumnSelection(ColumnSelection colSel)
+  {
+    this.colSel = colSel;
+    if (colSel != null)
+    {
+      // updateHiddenColumns(); - does nothing
+    }
+    isColSelChanged(true);
+  }
+
+  public boolean hasHiddenColumns()
+  {
+    return colSel != null && colSel.hasHiddenColumns();
+  }
+
+  /**
+   * checks current colsel against record of last hash value, and optionally
+   * updates record.
+   * 
+   * @param b
+   *          update the record of last hash value
+   * @return true if colsel changed since last call (when b is true)
+   */
+  public boolean isColSelChanged(boolean b)
+  {
+    int hc = (colSel == null || colSel.isEmpty()) ? -1 : colSel.hashCode();
+    if (hc != -1 && hc != colselhash)
+    {
+      if (b)
+      {
+        colselhash = hc;
+      }
+      return true;
+    }
+    return false;
+  }
+
+  public void hideColumns(int start, int end)
+  {
+    if (start == end)
+    {
+      colSel.hideColumns(start);
+    }
+    else
+    {
+      colSel.hideColumns(start, end);
+    }
+    isColSelChanged(true);
+  }
+
+  public void showColumn(int col)
+  {
+    colSel.revealHiddenColumns(col);
+    isColSelChanged(true);
+  }
+
+  public void showAllHiddenColumns()
+  {
+    colSel.revealAllHiddenColumns();
+    isColSelChanged(true);
+  }
+
+  public void invertColumnSelection()
+  {
+    colSel.invertColumnSelection(0, al.getWidth());
+  }
+
+  public List<int[]> getVisibleRegionBoundaries(int min, int max)
+  {
+    ArrayList<int[]> regions = new ArrayList<int[]>();
+    int start = min;
+    int end = max;
+
+    do
+    {
+      if (hasHiddenColumns())
+      {
+        if (start == 0)
+        {
+          start = colSel.adjustForHiddenColumns(start);
+        }
+
+        end = colSel.getHiddenBoundaryRight(start);
+        if (start == end)
+        {
+          end = max;
+        }
+        if (end > max)
+        {
+          end = max;
+        }
+      }
+
+      regions.add(new int[] { start, end });
+
+      if (hasHiddenColumns())
+      {
+        start = colSel.adjustForHiddenColumns(end);
+        start = colSel.getHiddenBoundaryLeft(start) + 1;
+      }
+    } while (end < max);
+
+    int[][] startEnd = new int[regions.size()][2];
+
+    return regions;
+  }
+
+  /**
+   * synthesize a column selection if none exists so it covers the given
+   * selection group. if wholewidth is false, no column selection is made if the
+   * selection group covers the whole alignment width.
+   * 
+   * @param sg
+   * @param wholewidth
+   */
+  public void expandColSelection(SequenceGroup sg, boolean wholewidth)
+  {
+    int sgs, sge;
+    if (sg != null && (sgs = sg.getStartRes()) >= 0
+            && sg.getStartRes() <= (sge = sg.getEndRes()))
+    {
+      if (!wholewidth && al.getWidth() == (1 + sge - sgs))
+      {
+        // do nothing
+        return;
+      }
+      if (colSel == null)
+      {
+        colSel = new ColumnSelection();
+      }
+      for (int cspos = sg.getStartRes(); cspos <= sg.getEndRes(); cspos++)
+      {
+        colSel.addElement(cspos);
+      }
+    }
+  }
+
+  public List<AlignmentAnnotation> getVisibleAlignmentAnnotation(
+          boolean selectedOnly, SequenceGroup selectionGroup)
+  {
+    ArrayList<AlignmentAnnotation> ala = new ArrayList<AlignmentAnnotation>();
+    AlignmentAnnotation[] aa;
+    if ((aa = al.getAlignmentAnnotation()) != null)
+    {
+      for (AlignmentAnnotation annot : aa)
+      {
+        AlignmentAnnotation clone = new AlignmentAnnotation(annot);
+        if (selectedOnly && selectionGroup != null)
+        {
+          colSel.makeVisibleAnnotation(selectionGroup.getStartRes(),
+                  selectionGroup.getEndRes(), clone);
+        }
+        else
+        {
+          colSel.makeVisibleAnnotation(clone);
+        }
+        ala.add(clone);
+      }
+    }
+    return ala;
+  }
+
+  public String[] getVisibleSequenceStrings(int start, int end,
+          SequenceI[] seqs)
+  {
+    return colSel.getVisibleSequenceStrings(start, end, seqs);
+  }
+
+  /**
+   * Set visibility for any annotations for the given sequence.
+   * 
+   * @param sequenceI
+   */
+  protected void setSequenceAnnotationsVisible(SequenceI sequenceI,
+          boolean visible)
+  {
+    AlignmentAnnotation[] anns = al.getAlignmentAnnotation();
+    if (anns != null)
+    {
+      for (AlignmentAnnotation ann : anns)
+      {
+        if (ann.sequenceRef == sequenceI)
+        {
+          ann.visible = visible;
+        }
+      }
+    }
+  }
+
+  public void setHiddenRepSequences(
+          Map<SequenceI, SequenceCollectionI> hiddenRepSequences)
+  {
+    this.hiddenRepSequences = hiddenRepSequences;
+  }
+
+  public Map<SequenceI, SequenceCollectionI> getHiddenRepSequences()
+  {
+    return hiddenRepSequences;
+  }
+
+  // common hide/show seq stuff
+  public SequenceGroup showAllHiddenSeqs(SequenceGroup selectionGroup)
+  {
+    if (al.getHiddenSequences().getSize() > 0)
+    {
+      if (selectionGroup == null)
+      {
+        selectionGroup = new SequenceGroup();
+        selectionGroup.setEndRes(al.getWidth() - 1);
+      }
+      List<SequenceI> tmp = al.getHiddenSequences().showAll(
+              hiddenRepSequences);
+      for (SequenceI seq : tmp)
+      {
+        selectionGroup.addSequence(seq, false);
+        setSequenceAnnotationsVisible(seq, true);
+      }
+
+      hiddenRepSequences = null;
+
+      firePropertyChange("alignment", null, al.getSequences());
+      // used to set hasHiddenRows/hiddenRepSequences here, after the property
+      // changed event
+      sendSelection();
+    }
+  }
+
+  public void showSequence(int index, SequenceGroup selectionGroup)
+  {
+    List<SequenceI> tmp = al.getHiddenSequences().showSequence(index,
+            hiddenRepSequences);
+    if (tmp.size() > 0)
+    {
+      if (selectionGroup == null)
+      {
+        selectionGroup = new SequenceGroup();
+        selectionGroup.setEndRes(al.getWidth() - 1);
+      }
+
+      for (SequenceI seq : tmp)
+      {
+        selectionGroup.addSequence(seq, false);
+        setSequenceAnnotationsVisible(seq, true);
+      }
+      firePropertyChange("alignment", null, al.getSequences());
+      sendSelection();
+    }
+  }
+
+  public void hideAllSelectedSeqs(SequenceGroup selectionGroup)
+  {
+    if (selectionGroup == null || selectionGroup.getSize() < 1)
+    {
+      return;
+    }
+
+    SequenceI[] seqs = selectionGroup.getSequencesInOrder(al);
+
+    hideSequence(seqs);
+
+    setSelectionGroup(null);
+  }
+
+  public void hideSequence(SequenceI[] seq)
+  {
+    if (seq != null)
+    {
+      for (int i = 0; i < seq.length; i++)
+      {
+        al.getHiddenSequences().hideSequence(seq[i]);
+        setSequenceAnnotationsVisible(seq[i], false);
+      }
+      firePropertyChange("alignment", null, al.getSequences());
+    }
+  }
+
+  /**
+   * Hides the specified sequence, or the sequences it represents
+   * 
+   * @param sequence
+   *          the sequence to hide, or keep as representative
+   * @param representGroup
+   *          if true, hide the current selection group except for the
+   *          representative sequence
+   */
+  public void hideSequences(SequenceI sequence, boolean representGroup,
+          SequenceGroup selectionGroup)
+  {
+    if (selectionGroup == null || selectionGroup.getSize() < 1)
+    {
+      hideSequence(new SequenceI[] { sequence });
+      return;
+    }
+
+    if (representGroup)
+    {
+      hideRepSequences(sequence, selectionGroup);
+      setSelectionGroup(null);
+      return;
+    }
+
+    int gsize = selectionGroup.getSize();
+    SequenceI[] hseqs = selectionGroup.getSequences().toArray(
+            new SequenceI[gsize]);
+
+    hideSequence(hseqs);
+    setSelectionGroup(null);
+    sendSelection();
+  }
+
+  public void hideRepSequences(SequenceI repSequence, SequenceGroup sg)
+  {
+    int sSize = sg.getSize();
+    if (sSize < 2)
+    {
+      return;
+    }
+
+    if (hiddenRepSequences == null)
+    {
+      hiddenRepSequences = new Hashtable<SequenceI, SequenceCollectionI>();
+    }
+
+    hiddenRepSequences.put(repSequence, sg);
+
+    // Hide all sequences except the repSequence
+    SequenceI[] seqs = new SequenceI[sSize - 1];
+    int index = 0;
+    for (int i = 0; i < sSize; i++)
+    {
+      if (sg.getSequenceAt(i) != repSequence)
+      {
+        if (index == sSize - 1)
+        {
+          return;
+        }
+
+        seqs[index++] = sg.getSequenceAt(i);
+      }
+    }
+    sg.setSeqrep(repSequence); // note: not done in 2.7applet
+    sg.setHidereps(true); // note: not done in 2.7applet
+    hideSequence(seqs);
+
+  }
+
+  /**
+   * 
+   * @param seq
+   * @return true if there are sequences represented by this sequence that are
+   *         currently hidden
+   */
+  public boolean isHiddenRepSequence(SequenceI seq)
+  {
+    return (hiddenRepSequences != null && hiddenRepSequences
+            .containsKey(seq));
+  }
+
+  /**
+   * 
+   * @param seq
+   * @return null or a sequence group containing the sequences that seq
+   *         represents
+   */
+  public SequenceGroup getRepresentedSequences(SequenceI seq)
+  {
+    return (SequenceGroup) (hiddenRepSequences == null ? null
+            : hiddenRepSequences.get(seq));
+  }
+
+  public int adjustForHiddenSeqs(int alignmentIndex)
+  {
+    return al.getHiddenSequences().adjustForHiddenSeqs(alignmentIndex);
+  }
 }