Merge branch 'develop' of https://source.jalview.org/git/jalview into develop
authortcofoegbu <tcnofoegbu@dundee.ac.uk>
Tue, 28 Jun 2016 14:28:28 +0000 (15:28 +0100)
committertcofoegbu <tcnofoegbu@dundee.ac.uk>
Tue, 28 Jun 2016 14:28:28 +0000 (15:28 +0100)
src/jalview/appletgui/APopupMenu.java
src/jalview/datamodel/HiddenSequences.java
src/jalview/gui/Jalview2XML.java
src/jalview/gui/PopupMenu.java
src/jalview/viewmodel/AlignmentViewport.java
test/jalview/datamodel/HiddenSequencesTest.java [new file with mode: 0644]
test/jalview/io/Jalview2xmlTests.java

index 748954a..948c8e5 100644 (file)
@@ -537,6 +537,7 @@ public class APopupMenu extends java.awt.PopupMenu implements
     MenuItem item = new MenuItem(label);
     item.addActionListener(new java.awt.event.ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
         ap.alignFrame.showURL(url, target);
@@ -545,6 +546,7 @@ public class APopupMenu extends java.awt.PopupMenu implements
     linkMenu.add(item);
   }
 
+  @Override
   public void itemStateChanged(ItemEvent evt)
   {
     if (evt.getSource() == abovePIDColour)
@@ -569,6 +571,7 @@ public class APopupMenu extends java.awt.PopupMenu implements
     }
   }
 
+  @Override
   public void actionPerformed(ActionEvent evt)
   {
     Object source = evt.getSource();
@@ -1299,35 +1302,7 @@ public class APopupMenu extends java.awt.PopupMenu implements
 
   void hideSequences(boolean representGroup)
   {
-    SequenceGroup sg = ap.av.getSelectionGroup();
-    if (sg == null || sg.getSize() < 1)
-    {
-      ap.av.hideSequence(new SequenceI[] { seq });
-      return;
-    }
-
-    ap.av.setSelectionGroup(null);
-
-    if (representGroup)
-    {
-      ap.av.hideRepSequences(seq, sg);
-
-      return;
-    }
-
-    int gsize = sg.getSize();
-    SequenceI[] hseqs;
-
-    hseqs = new SequenceI[gsize];
-
-    int index = 0;
-    for (int i = 0; i < gsize; i++)
-    {
-      hseqs[index++] = sg.getSequenceAt(i);
-    }
-
-    ap.av.hideSequence(hseqs);
-    ap.av.sendSelection();
+    ap.av.hideSequences(seq, representGroup);
   }
 
   /**
index db4c858..8ca3c5a 100755 (executable)
@@ -33,11 +33,21 @@ public class HiddenSequences
 
   AlignmentI alignment;
 
+  /**
+   * Constructor given a reference to an alignment (with no hidden sequences)
+   * 
+   * @param al
+   */
   public HiddenSequences(AlignmentI al)
   {
     alignment = al;
   }
 
+  /**
+   * Answers the number of hidden sequences
+   * 
+   * @return
+   */
   public int getSize()
   {
     if (hiddenSequences == null)
@@ -45,9 +55,9 @@ public class HiddenSequences
       return 0;
     }
     int count = 0;
-    for (int i = 0; i < hiddenSequences.length; i++)
+    for (SequenceI seq : hiddenSequences)
     {
-      if (hiddenSequences[i] != null)
+      if (seq != null)
       {
         count++;
       }
@@ -56,15 +66,23 @@ public class HiddenSequences
     return count;
   }
 
+  /**
+   * Answers the length of the longest hidden sequence
+   * 
+   * @return
+   */
   public int getWidth()
   {
+    if (hiddenSequences == null)
+    {
+      return 0;
+    }
     int width = 0;
-    for (int i = 0; i < hiddenSequences.length; i++)
+    for (SequenceI seq : hiddenSequences)
     {
-      if (hiddenSequences[i] != null
-              && hiddenSequences[i].getLength() > width)
+      if (seq != null && seq.getLength() > width)
       {
-        width = hiddenSequences[i].getLength();
+        width = seq.getLength();
       }
     }
 
@@ -72,7 +90,7 @@ public class HiddenSequences
   }
 
   /**
-   * Call this method if sequences are removed from the main alignment
+   * Call this method after a sequence is removed from the main alignment
    */
   public void adjustHeightSequenceDeleted(int seqIndex)
   {
@@ -108,8 +126,7 @@ public class HiddenSequences
   }
 
   /**
-   * Call this method if sequences are added to or removed from the main
-   * alignment
+   * Call this method after a sequence is added to the main alignment
    */
   public void adjustHeightSequenceAdded()
   {
@@ -125,6 +142,11 @@ public class HiddenSequences
     hiddenSequences = tmp;
   }
 
+  /**
+   * Mark the specified sequence as hidden
+   * 
+   * @param sequence
+   */
   public void hideSequence(SequenceI sequence)
   {
     if (hiddenSequences == null)
@@ -163,6 +185,17 @@ public class HiddenSequences
     return revealedSeqs;
   }
 
+  /**
+   * Reveals (unhides) consecutive hidden sequences just above the given
+   * alignment index. The revealed sequences are selected (including their
+   * visible representative sequence if there was one and 'reveal' is being
+   * performed on it).
+   * 
+   * @param alignmentIndex
+   * @param hiddenRepSequences
+   *          a map of representative sequences to the sequences they represent
+   * @return
+   */
   public List<SequenceI> showSequence(int alignmentIndex,
           Map<SequenceI, SequenceCollectionI> hiddenRepSequences)
   {
@@ -203,20 +236,22 @@ public class HiddenSequences
                     + " has been deleted whilst hidden");
           }
         }
-
       }
     }
-
     return revealedSeqs;
   }
 
   public SequenceI getHiddenSequence(int alignmentIndex)
   {
-    return hiddenSequences[alignmentIndex];
+    return hiddenSequences == null ? null : hiddenSequences[alignmentIndex];
   }
 
   public int findIndexWithoutHiddenSeqs(int alignmentIndex)
   {
+    if (hiddenSequences == null)
+    {
+      return alignmentIndex;
+    }
     int index = 0;
     int hiddenSeqs = 0;
     if (hiddenSequences.length <= alignmentIndex)
@@ -232,13 +267,16 @@ public class HiddenSequences
       }
       index++;
     }
-    ;
 
     return (alignmentIndex - hiddenSeqs);
   }
 
   public int adjustForHiddenSeqs(int alignmentIndex)
   {
+    if (hiddenSequences == null)
+    {
+      return alignmentIndex;
+    }
     int index = 0;
     int hSize = hiddenSequences.length;
     while (index <= alignmentIndex && index < hSize)
@@ -262,20 +300,28 @@ public class HiddenSequences
    */
   public AlignmentI getFullAlignment()
   {
-    int isize = hiddenSequences.length;
-    SequenceI[] seq = new Sequence[isize];
-
-    int index = 0;
-    for (int i = 0; i < hiddenSequences.length; i++)
+    SequenceI[] seq;
+    if (hiddenSequences == null)
     {
-      if (hiddenSequences[i] != null)
-      {
-        seq[i] = hiddenSequences[i];
-      }
-      else
+      seq = alignment.getSequencesArray();
+    }
+    else
+    {
+      int isize = hiddenSequences.length;
+      seq = new Sequence[isize];
+
+      int index = 0;
+      for (int i = 0; i < hiddenSequences.length; i++)
       {
-        seq[i] = alignment.getSequenceAt(index);
-        index++;
+        if (hiddenSequences[i] != null)
+        {
+          seq[i] = hiddenSequences[i];
+        }
+        else
+        {
+          seq[i] = alignment.getSequenceAt(index);
+          index++;
+        }
       }
     }
     Alignment fAlignmt = new Alignment(seq);
index eeb4214..01e60d4 100644 (file)
@@ -680,9 +680,8 @@ public class Jalview2XML
     Set<String> calcIdSet = new HashSet<String>();
 
     // SAVE SEQUENCES
-    for (int i = 0; i < rjal.getHeight(); i++)
+    for (final SequenceI jds : rjal.getSequences())
     {
-      final SequenceI jds = rjal.getSequenceAt(i);
       final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds
               : jds.getDatasetSequence();
       String id = seqHash(jds);
@@ -725,15 +724,15 @@ public class Jalview2XML
           jseq.setHidden(av.getAlignment().getHiddenSequences()
                   .isHidden(jds));
 
-          if (av.isHiddenRepSequence(rjal.getSequenceAt(i)))
+          if (av.isHiddenRepSequence(jds))
           {
             jalview.datamodel.SequenceI[] reps = av
-                    .getRepresentedSequences(rjal.getSequenceAt(i))
+                    .getRepresentedSequences(jds)
                     .getSequencesInOrder(rjal);
 
             for (int h = 0; h < reps.length; h++)
             {
-              if (reps[h] != rjal.getSequenceAt(i))
+              if (reps[h] != jds)
               {
                 jseq.addHiddenSequences(rjal.findIndex(reps[h]));
               }
@@ -743,7 +742,7 @@ public class Jalview2XML
         // mark sequence as reference - if it is the reference for this view
         if (jal.hasSeqrep())
         {
-          jseq.setViewreference(rjal.getSequenceAt(i) == jal.getSeqrep());
+          jseq.setViewreference(jds == jal.getSeqrep());
         }
       }
 
index e64d43f..497f3ba 100644 (file)
@@ -2270,28 +2270,7 @@ public class PopupMenu extends JPopupMenu
 
   void hideSequences(boolean representGroup)
   {
-    SequenceGroup sg = ap.av.getSelectionGroup();
-    if (sg == null || sg.getSize() < 1)
-    {
-      ap.av.hideSequence(new SequenceI[] { sequence });
-      return;
-    }
-
-    ap.av.setSelectionGroup(null);
-
-    if (representGroup)
-    {
-      ap.av.hideRepSequences(sequence, sg);
-
-      return;
-    }
-
-    int gsize = sg.getSize();
-    SequenceI[] hseqs = sg.getSequences().toArray(new SequenceI[gsize]);
-
-    ap.av.hideSequence(hseqs);
-    // refresh(); TODO: ? needed ?
-    ap.av.sendSelection();
+    ap.av.hideSequences(sequence, representGroup);
   }
 
   public void copy_actionPerformed()
index 91ee3c1..eab4aa5 100644 (file)
@@ -1413,6 +1413,39 @@ public abstract class AlignmentViewport implements AlignViewportI,
   }
 
   /**
+   * 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)
+  {
+    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();
+  }
+
+  /**
    * Set visibility for any annotations for the given sequence.
    * 
    * @param sequenceI
diff --git a/test/jalview/datamodel/HiddenSequencesTest.java b/test/jalview/datamodel/HiddenSequencesTest.java
new file mode 100644 (file)
index 0000000..8b50a8b
--- /dev/null
@@ -0,0 +1,378 @@
+package jalview.datamodel;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertNotNull;
+import static org.testng.AssertJUnit.assertNotSame;
+import static org.testng.AssertJUnit.assertNull;
+import static org.testng.AssertJUnit.assertSame;
+import static org.testng.AssertJUnit.assertTrue;
+import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
+
+import jalview.gui.AlignViewport;
+
+import java.util.List;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+@Test(singleThreaded = true)
+public class HiddenSequencesTest
+{
+  static int SEQ_COUNT = 10;
+
+  SequenceI[] seqs;
+  
+  /**
+   * Set up an alignment of 10 sequences
+   */
+  @BeforeTest(alwaysRun = true)
+  public void setUp()
+  {
+    seqs = new SequenceI[SEQ_COUNT];
+    for (int i = 0; i < SEQ_COUNT; i++)
+    {
+      // sequence lengths are 1, 2, ... 10
+      seqs[i] = new Sequence("Seq" + i, "abcdefghijk".substring(0, i + 1));
+    }
+  }
+
+  /**
+   * Test the method that converts sequence alignment index to what it would be
+   * if all sequences were unhidden
+   */
+  @Test(groups = "Functional")
+  public void testAdjustForHiddenSeqs()
+  {
+    AlignmentI al = new Alignment(seqs);
+    HiddenSequences hs = al.getHiddenSequences();
+    for (int i = 0; i < SEQ_COUNT; i++)
+    {
+      assertEquals(i, hs.adjustForHiddenSeqs(i));
+    }
+
+    // hide seq1 and seq5 and seq6
+    hs.hideSequence(seqs[1]);
+    hs.hideSequence(seqs[5]);
+    hs.hideSequence(seqs[6]);
+
+    /*
+     * alignment is now seq0/2/3/4/7/8/9
+     */
+    assertEquals(7, al.getHeight());
+    assertEquals(0, hs.adjustForHiddenSeqs(0));
+    assertEquals(2, hs.adjustForHiddenSeqs(1));
+    assertEquals(3, hs.adjustForHiddenSeqs(2));
+    assertEquals(4, hs.adjustForHiddenSeqs(3));
+    assertEquals(7, hs.adjustForHiddenSeqs(4));
+    assertEquals(8, hs.adjustForHiddenSeqs(5));
+    assertEquals(9, hs.adjustForHiddenSeqs(6));
+  }
+
+  /**
+   * Test the method that increments the internal array size if a sequence is
+   * added to the alignment (ugh this should not be exposed to the light of day)
+   */
+  @Test(groups = "Functional")
+  public void testAdjustHeightSequenceAdded()
+  {
+    AlignmentI al = new Alignment(seqs);
+    assertEquals(SEQ_COUNT, al.getHeight());
+
+    HiddenSequences hs = al.getHiddenSequences();
+    // initially does nothing
+    hs.adjustHeightSequenceAdded();
+    assertNull(hs.hiddenSequences);
+
+    // hide one sequence
+    hs.hideSequence(seqs[3]);
+    assertEquals(1, hs.getSize());
+    assertEquals(SEQ_COUNT - 1, al.getHeight());
+    assertEquals(SEQ_COUNT, hs.hiddenSequences.length);
+
+    /*
+     * add a sequence to the alignment
+     * - the safe way to call hs.adjustHeightSequenceAdded!
+     * (implementation depends on alignment height having
+     * been already updated for the added sequence)
+     */
+    al.addSequence(new Sequence("a", "b"));
+    assertEquals(1, hs.getSize());
+    assertEquals(SEQ_COUNT, al.getHeight());
+    assertEquals(SEQ_COUNT + 1, hs.hiddenSequences.length);
+  }
+
+  /**
+   * Test the method that decrements the internal array size if a sequence is
+   * deleted from the alignment (ugh this should not be exposed to the light of
+   * day)
+   */
+  @Test(groups = "Functional")
+  public void testAdjustHeightSequenceDeleted()
+  {
+    AlignmentI al = new Alignment(seqs);
+    assertEquals(SEQ_COUNT, al.getHeight());
+
+    HiddenSequences hs = al.getHiddenSequences();
+    // initially does nothing
+    hs.adjustHeightSequenceAdded();
+    assertNull(hs.hiddenSequences);
+
+    // hide two sequences
+    hs.hideSequence(seqs[3]);
+    hs.hideSequence(seqs[5]);
+    assertEquals(2, hs.getSize());
+    assertTrue(hs.isHidden(seqs[3]));
+    assertTrue(hs.isHidden(seqs[5]));
+    assertEquals(SEQ_COUNT - 2, al.getHeight());
+    assertEquals(SEQ_COUNT, hs.hiddenSequences.length);
+
+    /*
+     * delete a visible sequence from the alignment
+     * - the safe way to call hs.adjustHeightSequenceDeleted!
+     * (implementation depends on alignment height having
+     * been already updated for the removed sequence)
+     */
+    al.deleteSequence(seqs[2]);
+    assertEquals(2, hs.getSize());
+    // the visible alignment is unchanged:
+    assertEquals(SEQ_COUNT - 3, al.getHeight());
+    // sequences array size has decremented:
+    assertEquals(SEQ_COUNT - 1, hs.hiddenSequences.length);
+  }
+
+  /**
+   * Test the method that converts a 'full alignment' sequence index into the
+   * equivalent in the alignment with sequences hidden
+   */
+  @Test(groups = "Functional")
+  public void testFindIndexWithoutHiddenSeqs()
+  {
+    AlignmentI al = new Alignment(seqs);
+    HiddenSequences hs = al.getHiddenSequences();
+    for (int i = 0; i < SEQ_COUNT; i++)
+    {
+      assertEquals(i, hs.findIndexWithoutHiddenSeqs(i));
+    }
+
+    // hide seq1 and seq5 and seq6
+    hs.hideSequence(seqs[1]);
+    hs.hideSequence(seqs[5]);
+    hs.hideSequence(seqs[6]);
+
+    /*
+     * alignment is now seq0/2/3/4/7/8/9
+     */
+    assertEquals(7, al.getHeight());
+    assertEquals(0, hs.findIndexWithoutHiddenSeqs(0));
+    assertEquals(0, hs.findIndexWithoutHiddenSeqs(1));
+    assertEquals(1, hs.findIndexWithoutHiddenSeqs(2));
+    assertEquals(2, hs.findIndexWithoutHiddenSeqs(3));
+    assertEquals(3, hs.findIndexWithoutHiddenSeqs(4));
+    assertEquals(3, hs.findIndexWithoutHiddenSeqs(5));
+    assertEquals(3, hs.findIndexWithoutHiddenSeqs(6));
+    assertEquals(4, hs.findIndexWithoutHiddenSeqs(7));
+    assertEquals(5, hs.findIndexWithoutHiddenSeqs(8));
+    assertEquals(6, hs.findIndexWithoutHiddenSeqs(9));
+  }
+
+  /**
+   * Test the method that reconstructs (sort of) the full alignment including
+   * hidden sequences
+   */
+  @Test(groups = "Functional")
+  public void testGetFullAlignment()
+  {
+    AlignmentI al = new Alignment(seqs);
+    assertArrayEquals(seqs, al.getSequencesArray());
+    al.setProperty("a", "b");
+    al.addAnnotation(new AlignmentAnnotation("ann", "label", 12f));
+    al.setSeqrep(seqs[4]);
+    SequenceGroup sg = new SequenceGroup();
+    sg.addSequence(seqs[8], false);
+    al.addGroup(sg);
+    ((Alignment) al).hasRNAStructure = true;
+
+    HiddenSequences hs = al.getHiddenSequences();
+    AlignmentI al2 = hs.getFullAlignment();
+    // new alignment but with original sequences
+    assertNotSame(al, al2);
+    assertArrayEquals(al.getSequencesArray(), al2.getSequencesArray());
+
+    hs.hideSequence(seqs[4]);
+    hs.hideSequence(seqs[9]);
+    al2 = hs.getFullAlignment();
+    assertNotSame(al, al2);
+    assertArrayEquals(seqs, al2.getSequencesArray());
+    assertNotNull(al2.getProperties());
+    assertSame(al.getProperties(), al2.getProperties());
+    assertNotNull(al2.getAlignmentAnnotation());
+    assertSame(al.getAlignmentAnnotation(), al2.getAlignmentAnnotation());
+    assertSame(seqs[4], al2.getSeqrep());
+    assertNotNull(al2.getGroups());
+    assertSame(al.getGroups(), al2.getGroups());
+    assertTrue(al2.hasRNAStructure());
+  }
+
+  /**
+   * Test the method that returns the hidden sequence at a given index in the
+   * full alignment
+   * 
+   * @return either the sequence (if hidden) or null (if not hidden)
+   */
+  @Test(groups = "Functional")
+  public void testGetHiddenSequence()
+  {
+    AlignmentI al = new Alignment(seqs);
+    HiddenSequences hs = al.getHiddenSequences();
+    assertNull(hs.getHiddenSequence(0));
+    hs.hideSequence(seqs[3]);
+    assertSame(seqs[3], hs.getHiddenSequence(3));
+    assertNull(hs.getHiddenSequence(2));
+    assertNull(hs.getHiddenSequence(4));
+  }
+
+  @Test(groups = "Functional")
+  public void testGetSize()
+  {
+  }
+
+  @Test(groups = "Functional")
+  public void testGetWidth()
+  {
+    AlignmentI al = new Alignment(seqs);
+    HiddenSequences hs = al.getHiddenSequences();
+    assertEquals(0, hs.getWidth());
+    hs.hideSequence(seqs[6]);
+    hs.hideSequence(seqs[8]);
+    assertEquals(9, hs.getWidth());
+  }
+
+  /**
+   * Test the method that adds a sequence to the hidden sequences and deletes it
+   * from the alignment, and its converse
+   */
+  @Test(groups = "Functional")
+  public void testHideShowSequence()
+  {
+    AlignmentI al = new Alignment(seqs);
+    assertTrue(al.getSequences().contains(seqs[1]));
+    HiddenSequences hs = al.getHiddenSequences();
+    assertEquals(0, hs.getSize());
+    assertEquals(10, al.getHeight());
+
+    /*
+     * hide the second sequence in the alignment
+     */
+    hs.hideSequence(seqs[1]);
+    assertFalse(hs.isHidden(seqs[0]));
+    assertTrue(hs.isHidden(seqs[1]));
+    assertFalse(al.getSequences().contains(seqs[1]));
+    assertEquals(1, hs.getSize());
+    assertEquals(9, al.getHeight());
+    assertSame(seqs[2], al.getSequenceAt(1));
+
+    /*
+     * hide what is now the second sequence in the alignment
+     */
+    hs.hideSequence(seqs[2]);
+    assertFalse(hs.isHidden(seqs[0]));
+    assertTrue(hs.isHidden(seqs[1]));
+    assertTrue(hs.isHidden(seqs[2]));
+    assertFalse(al.getSequences().contains(seqs[1]));
+    assertFalse(al.getSequences().contains(seqs[2]));
+    assertEquals(2, hs.getSize());
+    assertEquals(8, al.getHeight());
+
+    /*
+     * perform 'reveal' on what is now the second sequence in the alignment
+     * this should unhide the two sequences that precede it
+     */
+    List<SequenceI> revealed = hs.showSequence(1, null);
+    assertEquals(2, revealed.size());
+    assertTrue(revealed.contains(seqs[1]));
+    assertTrue(revealed.contains(seqs[2]));
+    assertEquals(0, hs.getSize());
+    assertEquals(10, al.getHeight());
+  }
+
+  @Test(groups = "Functional")
+  public void testIsHidden()
+  {
+    AlignmentI al = new Alignment(seqs);
+    HiddenSequences hs = al.getHiddenSequences();
+    hs.hideSequence(seqs[7]);
+    hs.hideSequence(seqs[4]);
+    assertTrue(hs.isHidden(seqs[4]));
+    assertFalse(hs.isHidden(seqs[5]));
+    assertFalse(hs.isHidden(seqs[6]));
+    assertTrue(hs.isHidden(seqs[7]));
+    assertFalse(hs.isHidden(null));
+    assertFalse(hs.isHidden(new Sequence("", "")));
+  }
+
+  /**
+   * Test hiding and unhiding a group with a representative sequence. The
+   * representative should be left visible when the group is hidden, and
+   * included in the selected group when it is unhidden.
+   */
+  @Test(groups = "Functional")
+  public void testHideShowSequence_withHiddenRepSequence()
+  {
+    AlignmentI al = new Alignment(seqs);
+
+    /*
+     * represent seqs 2-4 with seq3
+     * this hides seq2 and seq4 but not seq3
+     */
+    AlignViewport av = new AlignViewport(al);
+    SequenceGroup sg = new SequenceGroup();
+    sg.addSequence(seqs[1], false);
+    sg.addSequence(seqs[2], false);
+    sg.addSequence(seqs[3], false);
+    av.setSelectionGroup(sg);
+
+    /*
+     * hiding group with reference sequence is done via AlignViewport
+     */
+    av.hideSequences(seqs[2], true);
+    HiddenSequences hs = al.getHiddenSequences();
+    assertEquals(2, hs.getSize());
+    assertTrue(hs.isHidden(seqs[1]));
+    assertFalse(hs.isHidden(seqs[2]));
+    assertTrue(hs.isHidden(seqs[3]));
+
+    /*
+     * should now be no sequences selected in the alignment
+     */
+    assertNull(av.getSelectionGroup());
+
+    /*
+     * visible alignment is now seq0/2/4/5/6/7/8/9
+     * 'reveal sequences' at the representative sequence (index = 1)
+     * this should unhide the one above i.e. seq1
+     * and return a selection list including seq2
+     * 
+     * note have to call via AlignViewport to get the expected
+     * resulting sequence selection
+     */
+    av.showSequence(1);
+
+    /*
+     * only seq3 is now hidden
+     */
+    assertEquals(1, hs.getSize());
+    assertTrue(hs.isHidden(seqs[3]));
+    assertEquals(SEQ_COUNT - 1, al.getHeight());
+    sg = av.getSelectionGroup();
+
+    /*
+     * unhidden and representative sequence selected
+     * (this behaviour may change! JAL-2133)
+     */
+    assertEquals(2, sg.getSize());
+    assertTrue(sg.getSequences().contains(seqs[1]));
+    assertTrue(sg.getSequences().contains(seqs[2]));
+    assertFalse(sg.getSequences().contains(seqs[3]));
+  }
+}
index 00d4ee0..a77e10a 100644 (file)
  */
 package jalview.io;
 
+import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
 import static org.testng.AssertJUnit.assertTrue;
 
+import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.api.ViewStyleI;
 import jalview.bin.Cache;
 import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.HiddenSequences;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
@@ -34,9 +38,12 @@ import jalview.gui.Desktop;
 import jalview.gui.Jalview2XML;
 import jalview.schemes.AnnotationColourGradient;
 import jalview.schemes.ColourSchemeI;
+import jalview.viewmodel.AlignmentViewport;
 
 import java.io.File;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import org.testng.Assert;
@@ -66,10 +73,9 @@ public class Jalview2xmlTests
   public static void tearDownAfterClass() throws Exception
   {
     jalview.gui.Desktop.instance.closeAll_actionPerformed(null);
-
   }
 
-  public int countDsAnn(jalview.viewmodel.AlignmentViewport avp)
+  int countDsAnn(jalview.viewmodel.AlignmentViewport avp)
   {
     int numdsann = 0;
     for (SequenceI sq : avp.getAlignment().getDataset().getSequences())
@@ -361,7 +367,7 @@ public class Jalview2xmlTests
    * 
    * @throws Exception
    */
-  @Test(groups = { "Functional" }, enabled = false)
+  @Test(groups = { "Functional" }, enabled = true)
   public void testStoreAndRecoverExpandedviews() throws Exception
   {
     AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
@@ -417,7 +423,8 @@ public class Jalview2xmlTests
   }
 
   /**
-   * based on above test store and recovery of expanded views.
+   * Test save and reload of a project with a different representative sequence
+   * in each view.
    * 
    * @throws Exception
    */
@@ -425,36 +432,69 @@ public class Jalview2xmlTests
   public void testStoreAndRecoverReferenceSeqSettings() throws Exception
   {
     Desktop.instance.closeAll_actionPerformed(null);
-    String afid = "";
-    {
-      AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
-              "examples/exampleFile_2_7.jar", FormatAdapter.FILE);
-      assertTrue("Didn't read in the example file correctly.", af != null);
-      afid = af.getViewport().getSequenceSetId();
-    }
-    Map<String, SequenceI> refs = new HashMap<String, SequenceI>();
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+            "examples/exampleFile_2_7.jar", FormatAdapter.FILE);
+    assertTrue("Didn't read in the example file correctly.", af != null);
+    String afid = af.getViewport().getSequenceSetId();
+
+    /*
+     * remember representative and hidden sequences marked 
+     * on each panel
+     */
+    Map<String, SequenceI> refseqs = new HashMap<String, SequenceI>();
+    Map<String, List<String>> hiddenSeqNames = new HashMap<String, List<String>>();
+
+    /*
+     * mark sequence 2, 3, 4.. in panels 1, 2, 3...
+     * as reference sequence for itself and the preceding sequence
+     */
     int n = 1;
     for (AlignmentViewPanel ap : Desktop.getAlignmentPanels(afid))
     {
-      // mark representative
-      SequenceI rep = ap.getAlignment().getSequenceAt(
-              n++ % ap.getAlignment().getHeight());
-      refs.put(ap.getViewName(), rep);
+      AlignViewportI av = ap.getAlignViewport();
+      AlignmentI alignment = ap.getAlignment();
+      int repIndex = n % alignment.getHeight();
+      SequenceI rep = alignment.getSequenceAt(repIndex);
+      refseqs.put(ap.getViewName(), rep);
+      List<String> hiddenNames = new ArrayList<String>();
+      hiddenSeqNames.put(ap.getViewName(), hiddenNames);
+
+      /*
+       * hide rep sequence and the one before it
+       */
+      SequenceI seqToHide = alignment.getSequenceAt(repIndex);
+      SequenceGroup sg = new SequenceGroup();
+      sg.addSequence(seqToHide, false);
+      SequenceI precedingSeq = alignment.getSequenceAt(repIndex - 1);
+      sg.addSequence(precedingSeq, false);
+      av.setSelectionGroup(sg);
+      ((AlignmentViewport) av).hideSequences(seqToHide, true);
+
+      /*
+       * record names of hidden sequences
+       */
+      HiddenSequences hs = alignment.getHiddenSequences();
+      for (SequenceI seq : hs.hiddenSequences)
+      {
+        if (seq != null)
+        {
+          hiddenNames.add(seq.getName());
+        }
+      }
       // code from mark/unmark sequence as reference in jalview.gui.PopupMenu
-      // todo refactor the to an alignment view controller
-      ap.getAlignViewport().setDisplayReferenceSeq(true);
-      ap.getAlignViewport().setColourByReferenceSeq(true);
-      ap.getAlignViewport().getAlignment().setSeqrep(rep);
+      // todo refactor this to an alignment view controller
+      av.setDisplayReferenceSeq(true);
+      av.setColourByReferenceSeq(true);
+      av.getAlignment().setSeqrep(rep);
+
+      n++;
     }
     File tfile = File.createTempFile("testStoreAndRecoverReferenceSeq",
             ".jvp");
     try
     {
       new Jalview2XML(false).saveState(tfile);
-    } catch (Error e)
-    {
-      Assert.fail("Didn't save the expanded view state", e);
-    } catch (Exception e)
+    } catch (Throwable e)
     {
       Assert.fail("Didn't save the expanded view state", e);
     }
@@ -463,28 +503,39 @@ public class Jalview2xmlTests
     {
       Assert.assertEquals(Desktop.getAlignFrames().length, 0);
     }
-    {
-      AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
+
+    af = new FileLoader().LoadFileWaitTillLoaded(
             tfile.getAbsolutePath(), FormatAdapter.FILE);
-      afid = af.getViewport().getSequenceSetId();
-    }
+    afid = af.getViewport().getSequenceSetId();
+
     for (AlignmentViewPanel ap : Desktop.getAlignmentPanels(afid))
     {
       // check representative
-      SequenceI rep = ap.getAlignment().getSeqrep();
+      AlignmentI alignment = ap.getAlignment();
+      SequenceI rep = alignment.getSeqrep();
       Assert.assertNotNull(rep,
               "Couldn't restore sequence representative from project");
       // can't use a strong equals here, because by definition, the sequence IDs
       // will be different.
       // could set vamsas session save/restore flag to preserve IDs across
       // load/saves.
-      Assert.assertEquals(refs.get(ap.getViewName()).toString(),
+      Assert.assertEquals(refseqs.get(ap.getViewName()).toString(),
               rep.toString(),
               "Representative wasn't the same when recovered.");
       Assert.assertTrue(ap.getAlignViewport().isDisplayReferenceSeq(),
               "Display reference sequence view setting not set.");
       Assert.assertTrue(ap.getAlignViewport().isColourByReferenceSeq(),
               "Colour By Reference Seq view setting not set.");
+
+      /*
+       * verify hidden sequences in restored panel
+       */
+      List<String> hidden = hiddenSeqNames.get(ap.getViewName());
+      HiddenSequences hs = alignment.getHiddenSequences();
+      assertEquals(
+              "wrong number of restored hidden sequences in "
+                      + ap.getViewName(),
+              hidden.size(), hs.getSize());
     }
   }