Merge branch 'develop' into trialMerge
[jalview.git] / test / jalview / gui / AnnotationChooserTest.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.gui;
22
23 import static org.testng.AssertJUnit.assertEquals;
24 import static org.testng.AssertJUnit.assertFalse;
25 import static org.testng.AssertJUnit.assertTrue;
26
27 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
28 import jalview.bin.Cache;
29 import jalview.datamodel.AlignmentAnnotation;
30 import jalview.datamodel.AlignmentI;
31 import jalview.datamodel.Annotation;
32 import jalview.datamodel.SequenceGroup;
33 import jalview.datamodel.SequenceI;
34 import jalview.io.DataSourceType;
35 import jalview.io.FileFormat;
36 import jalview.io.FormatAdapter;
37 import jalview.util.MessageManager;
38
39 import java.awt.BorderLayout;
40 import java.awt.Checkbox;
41 import java.awt.Component;
42 import java.awt.Container;
43 import java.awt.FlowLayout;
44 import java.awt.event.ItemEvent;
45 import java.io.IOException;
46 import java.util.List;
47
48 import javax.swing.JButton;
49 import javax.swing.JPanel;
50
51 import org.testng.annotations.BeforeMethod;
52 import org.testng.annotations.Test;
53
54 /**
55  * Unit tests for AnnotationChooser
56  * 
57  * @author gmcarstairs
58  *
59  */
60 public class AnnotationChooserTest
61 {
62   // 4 sequences x 13 positions
63   final static String TEST_DATA = ">FER_CAPAA Ferredoxin\n"
64           + "TIETHKEAELVG-\n"
65           + ">FER_CAPAN Ferredoxin, chloroplast precursor\n"
66           + "TIETHKEAELVG-\n"
67           + ">FER1_SOLLC Ferredoxin-1, chloroplast precursor\n"
68           + "TIETHKEEELTA-\n" + ">Q93XJ9_SOLTU Ferredoxin I precursor\n"
69           + "TIETHKEEELTA-\n";
70
71   AnnotationChooser testee;
72
73   AlignmentPanel parentPanel;
74
75   AlignFrame af;
76
77   @BeforeMethod(alwaysRun = true)
78   public void setUp() throws IOException
79   {
80     Cache.loadProperties("test/jalview/io/testProps.jvprops");
81     // pin down annotation sort order for test
82     Cache.applicationProperties.setProperty(Preferences.SORT_ANNOTATIONS,
83             SequenceAnnotationOrder.NONE.name());
84     final String TRUE = Boolean.TRUE.toString();
85     Cache.applicationProperties.setProperty(
86             Preferences.SHOW_AUTOCALC_ABOVE, TRUE);
87     Cache.applicationProperties.setProperty("SHOW_QUALITY", TRUE);
88     Cache.applicationProperties.setProperty("SHOW_CONSERVATION", TRUE);
89     Cache.applicationProperties.setProperty("SHOW_IDENTITY", TRUE);
90
91     AlignmentI al = new FormatAdapter().readFile(TEST_DATA,
92             DataSourceType.PASTE, FileFormat.Fasta);
93     af = new AlignFrame(al, 700, 500);
94     parentPanel = new AlignmentPanel(af, af.getViewport());
95     addAnnotations();
96   }
97
98   /**
99    * Add 4 annotations, 3 of them sequence-specific.
100    * 
101    * <PRE>
102    * ann1 - for sequence 0 - label 'IUPRED' 
103    * ann2 - not sequence related - label 'Beauty' 
104    * ann3 - for sequence 3 - label 'JMol'
105    * ann4 - for sequence 2 - label 'IUPRED'
106    * ann5 - for sequence 1 - label 'JMol'
107    */
108   private void addAnnotations()
109   {
110     Annotation an = new Annotation(2f);
111     Annotation[] anns = new Annotation[] { an, an, an };
112     AlignmentAnnotation ann0 = new AlignmentAnnotation("IUPRED", "", anns);
113     AlignmentAnnotation ann1 = new AlignmentAnnotation("Beauty", "", anns);
114     AlignmentAnnotation ann2 = new AlignmentAnnotation("JMol", "", anns);
115     AlignmentAnnotation ann3 = new AlignmentAnnotation("IUPRED", "", anns);
116     AlignmentAnnotation ann4 = new AlignmentAnnotation("JMol", "", anns);
117     SequenceI[] seqs = parentPanel.getAlignment().getSequencesArray();
118     ann0.setSequenceRef(seqs[0]);
119     ann2.setSequenceRef(seqs[3]);
120     ann3.setSequenceRef(seqs[2]);
121     ann4.setSequenceRef(seqs[1]);
122     parentPanel.getAlignment().addAnnotation(ann0);
123     parentPanel.getAlignment().addAnnotation(ann1);
124     parentPanel.getAlignment().addAnnotation(ann2);
125     parentPanel.getAlignment().addAnnotation(ann3);
126     parentPanel.getAlignment().addAnnotation(ann4);
127   }
128
129   /**
130    * Test creation of panel with OK and Cancel buttons
131    */
132   @Test(groups = { "Functional" })
133   public void testBuildActionButtonsPanel()
134   {
135     testee = new AnnotationChooser(parentPanel);
136     JPanel jp = testee.buildActionButtonsPanel();
137     assertTrue("Wrong layout", jp.getLayout() instanceof FlowLayout);
138
139     Component[] comps = jp.getComponents();
140     assertEquals("Not 2 action buttons", 2, comps.length);
141
142     final Component jb1 = comps[0];
143     final Component jb2 = comps[1];
144
145     assertEquals("Not 'OK' button", MessageManager.getString("action.ok"),
146             ((JButton) jb1).getText());
147     assertEquals("Wrong button font", JvSwingUtils.getLabelFont(),
148             jb1.getFont());
149
150     assertEquals("Not 'Cancel' button",
151             MessageManager.getString("action.cancel"),
152             ((JButton) jb2).getText());
153     assertEquals("Wrong button font", JvSwingUtils.getLabelFont(),
154             jb2.getFont());
155   }
156
157   /**
158    * Test 'Apply to' has 3 radio buttons enabled, 'Selected Sequences' selected,
159    * when there is a current selection group.
160    */
161   @Test(groups = { "Functional" })
162   public void testBuildApplyToOptionsPanel_withSelectionGroup()
163   {
164     selectSequences(0, 2, 3);
165     testee = new AnnotationChooser(parentPanel);
166
167     JPanel jp = testee.buildApplyToOptionsPanel();
168     Component[] comps = jp.getComponents();
169     assertEquals("Not 3 radio buttons", 3, comps.length);
170
171     final Checkbox cb1 = (Checkbox) comps[0];
172     final Checkbox cb2 = (Checkbox) comps[1];
173     final Checkbox cb3 = (Checkbox) comps[2];
174
175     assertTrue("Not enabled", cb1.isEnabled());
176     assertTrue("Not enabled", cb2.isEnabled());
177     assertTrue("Not enabled", cb3.isEnabled());
178     assertEquals("Option not selected", cb2, cb2.getCheckboxGroup()
179             .getSelectedCheckbox());
180
181     // check state variables match checkbox selection
182     assertTrue(testee.isApplyToSelectedSequences());
183     assertFalse(testee.isApplyToUnselectedSequences());
184   }
185
186   /**
187    * Add a sequence group to the alignment with the specified sequences (base 0)
188    * in it
189    * 
190    * @param i
191    * @param more
192    */
193   private void selectSequences(int... selected)
194   {
195     SequenceI[] seqs = parentPanel.getAlignment().getSequencesArray();
196     SequenceGroup sg = new SequenceGroup();
197     for (int i : selected)
198     {
199       sg.addSequence(seqs[i], false);
200     }
201     parentPanel.av.setSelectionGroup(sg);
202   }
203
204   /**
205    * Test 'Apply to' has 1 radio button enabled, 'All Sequences' selected, when
206    * there is no current selection group.
207    */
208   @Test(groups = { "Functional" })
209   public void testBuildApplyToOptionsPanel_noSelectionGroup()
210   {
211     testee = new AnnotationChooser(parentPanel);
212     JPanel jp = testee.buildApplyToOptionsPanel();
213     verifyApplyToOptionsPanel_noSelectionGroup(jp);
214   }
215
216   protected void verifyApplyToOptionsPanel_noSelectionGroup(JPanel jp)
217   {
218     assertTrue("Wrong layout", jp.getLayout() instanceof FlowLayout);
219     Component[] comps = jp.getComponents();
220     assertEquals("Not 3 radio buttons", 3, comps.length);
221
222     final Checkbox cb1 = (Checkbox) comps[0];
223     final Checkbox cb2 = (Checkbox) comps[1];
224     final Checkbox cb3 = (Checkbox) comps[2];
225
226     assertTrue("Not enabled", cb1.isEnabled());
227     assertFalse("Enabled", cb2.isEnabled());
228     assertFalse("Enabled", cb3.isEnabled());
229     assertEquals("Not selected", cb1, cb1.getCheckboxGroup()
230             .getSelectedCheckbox());
231
232     // check state variables match checkbox selection
233     assertTrue(testee.isApplyToSelectedSequences());
234     assertTrue(testee.isApplyToUnselectedSequences());
235
236     assertEquals("Wrong text",
237             MessageManager.getString("label.all_sequences"), cb1.getLabel());
238     assertEquals("Wrong text",
239             MessageManager.getString("label.selected_sequences"),
240             cb2.getLabel());
241     assertEquals("Wrong text",
242             MessageManager.getString("label.except_selected_sequences"),
243             cb3.getLabel());
244   }
245
246   /**
247    * Test Show and Hide radio buttons created, with Hide initially selected.
248    */
249   @Test(groups = { "Functional" })
250   public void testBuildShowHidePanel()
251   {
252     testee = new AnnotationChooser(parentPanel);
253     JPanel jp = testee.buildShowHidePanel();
254     verifyShowHidePanel(jp);
255
256   }
257
258   protected void verifyShowHidePanel(JPanel jp)
259   {
260     assertTrue("Wrong layout", jp.getLayout() instanceof FlowLayout);
261     Component[] comps = jp.getComponents();
262     assertEquals("Not 2 radio buttons", 2, comps.length);
263
264     final Checkbox cb1 = (Checkbox) comps[0];
265     final Checkbox cb2 = (Checkbox) comps[1];
266
267     assertTrue("Show not enabled", cb1.isEnabled());
268     assertTrue("Hide not enabled", cb2.isEnabled());
269
270     // Hide (button 2) selected; note this may change to none (null)
271     assertEquals("Not selected", cb2, cb2.getCheckboxGroup()
272             .getSelectedCheckbox());
273
274     assertTrue("Show is flagged", !testee.isShowSelected());
275
276     assertEquals("Wrong text",
277             MessageManager.getString("label.show_selected_annotations"),
278             cb1.getLabel());
279     assertEquals("Wrong text",
280             MessageManager.getString("label.hide_selected_annotations"),
281             cb2.getLabel());
282   }
283
284   /**
285    * Test construction of panel containing two sub-panels
286    */
287   @Test(groups = { "Functional" })
288   public void testBuildShowHideOptionsPanel()
289   {
290     testee = new AnnotationChooser(parentPanel);
291     JPanel jp = testee.buildShowHideOptionsPanel();
292     assertTrue("Wrong layout", jp.getLayout() instanceof BorderLayout);
293     Component[] comps = jp.getComponents();
294     assertEquals("Not 2 sub-panels", 2, comps.length);
295
296     verifyShowHidePanel((JPanel) comps[0]);
297     verifyApplyToOptionsPanel_noSelectionGroup((JPanel) comps[1]);
298   }
299
300   /**
301    * Test that annotation types are (uniquely) identified.
302    * 
303    */
304   @Test(groups = { "Functional" })
305   public void testGetAnnotationTypes()
306   {
307     selectSequences(1);
308     testee = new AnnotationChooser(parentPanel);
309     // selection group should make no difference to the result
310     // as all annotation types for the alignment are considered
311
312     List<String> types = AnnotationChooser.getAnnotationTypes(
313             parentPanel.getAlignment(), true);
314     assertEquals("Not two annotation types", 2, types.size());
315     assertTrue("IUPRED missing", types.contains("IUPRED"));
316     assertTrue("JMol missing", types.contains("JMol"));
317
318     types = AnnotationChooser.getAnnotationTypes(
319             parentPanel.getAlignment(), false);
320     assertEquals("Not six annotation types", 6, types.size());
321     assertTrue("IUPRED missing", types.contains("IUPRED"));
322     assertTrue("JMol missing", types.contains("JMol"));
323     assertTrue("Beauty missing", types.contains("Beauty"));
324     // These are added by viewmodel.AlignViewport.initAutoAnnotation():
325     assertTrue("Consensus missing", types.contains("Consensus"));
326     assertTrue("Quality missing", types.contains("Quality"));
327     assertTrue("Conservation missing", types.contains("Conservation"));
328   }
329
330   /**
331    * Test result of selecting an annotation type, with 'Hide for all sequences'.
332    * 
333    * We expect all annotations of that type to be set hidden. Other annotations
334    * should be left visible.
335    */
336   @Test(groups = { "Functional" })
337   public void testSelectType_hideForAll()
338   {
339     selectSequences(1, 2);
340     testee = new AnnotationChooser(parentPanel);
341     final Checkbox hideCheckbox = (Checkbox) getComponent(testee, 1, 0, 1);
342     setSelected(hideCheckbox, true);
343
344     final Checkbox allSequencesCheckbox = (Checkbox) getComponent(testee,
345             1, 1, 0);
346     setSelected(allSequencesCheckbox, true);
347
348     AlignmentAnnotation[] anns = parentPanel.getAlignment()
349             .getAlignmentAnnotation();
350
351     assertTrue(anns[5].visible); // JMol for seq3
352     assertTrue(anns[7].visible); // JMol for seq1
353
354     setSelected(getTypeCheckbox("JMol"), true);
355     assertTrue(anns[0].visible); // Conservation
356     assertTrue(anns[1].visible); // Quality
357     assertTrue(anns[2].visible); // Consensus
358     assertTrue(anns[3].visible); // IUPred for seq0
359     assertTrue(anns[4].visible); // Beauty
360     assertFalse(anns[5].visible); // JMol for seq3 - not selected but hidden
361     assertTrue(anns[6].visible); // IUPRED for seq2
362     assertFalse(anns[7].visible); // JMol for seq1 - selected and hidden
363   }
364
365   /**
366    * Test result of selecting an annotation type, with 'Hide for selected
367    * sequences'.
368    * 
369    * We expect the annotations of that type, linked to the sequence group, to be
370    * set hidden. Other annotations should be left visible.
371    */
372   @Test(groups = { "Functional" })
373   public void testSelectType_hideForSelected()
374   {
375     selectSequences(1, 2);
376     testee = new AnnotationChooser(parentPanel);
377     final Checkbox hideCheckbox = (Checkbox) getComponent(testee, 1, 0, 1);
378     setSelected(hideCheckbox, true);
379
380     /*
381      * Don't set the 'selected sequences' radio button since this would trigger
382      * an update, including unselected sequences / annotation types
383      */
384     // setSelected(getSelectedSequencesCheckbox());
385
386     AlignmentAnnotation[] anns = parentPanel.getAlignment()
387             .getAlignmentAnnotation();
388
389     assertTrue(anns[7].visible); // JMol for seq1
390
391     setSelected(getTypeCheckbox("JMol"), true);
392     assertTrue(anns[0].visible); // Conservation
393     assertTrue(anns[1].visible); // Quality
394     assertTrue(anns[2].visible); // Consensus
395     assertTrue(anns[3].visible); // IUPred for seq0
396     assertTrue(anns[4].visible); // Beauty
397     assertTrue(anns[5].visible); // JMol for seq3 not in selection group
398     assertTrue(anns[6].visible); // IUPRED for seq2
399     assertFalse(anns[7].visible); // JMol for seq1 in selection group
400   }
401
402   /**
403    * Test result of deselecting an annotation type, with 'Hide for all
404    * sequences'.
405    * 
406    * We expect all annotations of that type to be set visible. Other annotations
407    * should be left unchanged.
408    */
409   @Test(groups = { "Functional" })
410   public void testDeselectType_hideForAll()
411   {
412     selectSequences(1, 2);
413     testee = new AnnotationChooser(parentPanel);
414
415     final Checkbox hideCheckbox = (Checkbox) getComponent(testee, 1, 0, 1);
416     setSelected(hideCheckbox, true);
417
418     final Checkbox allSequencesCheckbox = (Checkbox) getComponent(testee,
419             1, 1, 0);
420     setSelected(allSequencesCheckbox, true);
421
422     AlignmentAnnotation[] anns = parentPanel.getAlignment()
423             .getAlignmentAnnotation();
424
425     final Checkbox typeCheckbox = getTypeCheckbox("JMol");
426
427     // select JMol - all hidden
428     setSelected(typeCheckbox, true);
429     assertFalse(anns[5].visible); // JMol for seq3
430     assertFalse(anns[7].visible); // JMol for seq1
431
432     // deselect JMol - all unhidden
433     setSelected(typeCheckbox, false);
434     assertTrue(anns[0].visible); // Conservation
435     assertTrue(anns[1].visible); // Quality
436     assertTrue(anns[2].visible); // Consensus
437     assertTrue(anns[3].visible); // IUPred for seq0
438     assertTrue(anns[4].visible); // Beauty
439     assertTrue(anns[5].visible); // JMol for seq3
440     assertTrue(anns[6].visible); // IUPRED for seq2
441     assertTrue(anns[7].visible); // JMol for seq1
442   }
443
444   /**
445    * Test result of deselecting an annotation type, with 'Hide for selected
446    * sequences'.
447    * 
448    * We expect the annotations of that type, linked to the sequence group, to be
449    * set visible. Other annotations should be left unchanged.
450    */
451   @Test(groups = { "Functional" })
452   public void testDeselectType_hideForSelected()
453   {
454     selectSequences(1, 2);
455     testee = new AnnotationChooser(parentPanel);
456     final Checkbox hideCheckbox = (Checkbox) getComponent(testee, 1, 0, 1);
457     setSelected(hideCheckbox, true);
458
459     /*
460      * Don't set the 'selected sequences' radio button since this would trigger
461      * an update, including unselected sequences / annotation types
462      */
463     // setSelected(getSelectedSequencesCheckbox());
464
465     setSelected(getTypeCheckbox("JMol"), true);
466     setSelected(getTypeCheckbox("JMol"), false);
467
468     AlignmentAnnotation[] anns = parentPanel.getAlignment()
469             .getAlignmentAnnotation();
470     assertTrue(anns[0].visible); // Conservation
471     assertTrue(anns[1].visible); // Quality
472     assertTrue(anns[2].visible); // Consensus
473     assertTrue(anns[3].visible); // IUPred for seq0
474     assertTrue(anns[4].visible); // Beauty
475     assertTrue(anns[5].visible); // JMol for seq3 not in selection group
476     assertTrue(anns[6].visible); // IUPRED for seq2
477     assertTrue(anns[7].visible); // JMol for seq1 in selection group
478   }
479
480   /**
481    * Test result of selecting an annotation type, with 'Show for all sequences'.
482    * 
483    * We expect all annotations of that type to be set visible. Other annotations
484    * should be left unchanged
485    */
486   @Test(groups = { "Functional" })
487   public void testSelectType_showForAll()
488   {
489     selectSequences(1, 2);
490     testee = new AnnotationChooser(parentPanel);
491     final Checkbox showCheckbox = (Checkbox) getComponent(testee, 1, 0, 0);
492     final Checkbox hideCheckbox = (Checkbox) getComponent(testee, 1, 0, 1);
493
494     final Checkbox allSequencesCheckbox = (Checkbox) getComponent(testee,
495             1, 1, 0);
496
497     AlignmentAnnotation[] anns = parentPanel.getAlignment()
498             .getAlignmentAnnotation();
499
500     // hide all JMol annotations
501     setSelected(allSequencesCheckbox, true);
502     setSelected(hideCheckbox, true);
503     setSelected(getTypeCheckbox("JMol"), true);
504     assertFalse(anns[5].visible); // JMol for seq3
505     assertFalse(anns[7].visible); // JMol for seq1
506     // ...now show them...
507     setSelected(showCheckbox, true);
508     assertTrue(anns[0].visible); // Conservation
509     assertTrue(anns[1].visible); // Quality
510     assertTrue(anns[2].visible); // Consensus
511     assertTrue(anns[3].visible); // IUPred for seq0
512     assertTrue(anns[4].visible); // Beauty
513     assertTrue(anns[5].visible); // JMol for seq3
514     assertTrue(anns[6].visible); // IUPRED for seq2
515     assertTrue(anns[7].visible); // JMol for seq1
516   }
517
518   /**
519    * Test result of selecting an annotation type, with 'Show for selected
520    * sequences'.
521    * 
522    * We expect all annotations of that type, linked to the sequence group, to be
523    * set visible. Other annotations should be left unchanged
524    */
525   @Test(groups = { "Functional" })
526   public void testSelectType_showForSelected()
527   {
528     // sequences 1 and 2 have annotations IUPred and Jmol
529     selectSequences(1, 2);
530     testee = new AnnotationChooser(parentPanel);
531     final Checkbox showCheckbox = (Checkbox) getComponent(testee, 1, 0, 0);
532     final Checkbox hideCheckbox = (Checkbox) getComponent(testee, 1, 0, 1);
533
534     final Checkbox selectedSequencesCheckbox = (Checkbox) getComponent(
535             testee, 1, 1, 1);
536
537     AlignmentAnnotation[] anns = parentPanel.getAlignment()
538             .getAlignmentAnnotation();
539
540     // hide all JMol annotations in the selection region (== annotation 7)
541     setSelected(selectedSequencesCheckbox, true);
542     setSelected(hideCheckbox, true);
543     setSelected(getTypeCheckbox("JMol"), true);
544
545     assertTrue(anns[5].visible); // JMol for seq3
546     assertFalse(anns[7].visible); // JMol for seq1
547     // ...now show them...
548     setSelected(showCheckbox, true);
549
550     assertTrue(anns[0].visible); // Conservation
551     assertTrue(anns[1].visible); // Quality
552     assertTrue(anns[2].visible); // Consensus
553     assertTrue(anns[3].visible); // IUPred for seq0
554     assertTrue(anns[4].visible); // Beauty
555     assertTrue(anns[5].visible); // JMol for seq3
556     assertTrue(anns[6].visible); // IUPRED for seq2
557     assertTrue(anns[7].visible); // JMol for seq1
558   }
559
560   /**
561    * Test result of deselecting an annotation type, with 'Show for all
562    * sequences'.
563    * 
564    * We expect all annotations of that type to be set hidden. Other annotations
565    * should be left unchanged.
566    */
567   @Test(groups = { "Functional" })
568   public void testDeselectType_showForAll()
569   {
570     selectSequences(1, 2);
571     testee = new AnnotationChooser(parentPanel);
572
573     final Checkbox showCheckbox = (Checkbox) getComponent(testee, 1, 0, 0);
574     setSelected(showCheckbox, true);
575
576     final Checkbox allSequencesCheckbox = (Checkbox) getComponent(testee,
577             1, 1, 0);
578     setSelected(allSequencesCheckbox, true);
579
580     AlignmentAnnotation[] anns = parentPanel.getAlignment()
581             .getAlignmentAnnotation();
582
583     final Checkbox typeCheckbox = getTypeCheckbox("JMol");
584     // select JMol - all shown
585     setSelected(typeCheckbox, true);
586     assertTrue(anns[5].visible); // JMol for seq3
587     assertTrue(anns[7].visible); // JMol for seq1
588
589     // deselect JMol - all hidden
590     setSelected(typeCheckbox, false);
591     assertTrue(anns[0].visible); // Conservation
592     assertTrue(anns[1].visible); // Quality
593     assertTrue(anns[2].visible); // Consensus
594     assertTrue(anns[3].visible); // IUPred for seq0
595     assertTrue(anns[4].visible); // Beauty
596     assertFalse(anns[5].visible); // JMol for seq3
597     assertTrue(anns[6].visible); // IUPRED for seq2
598     assertFalse(anns[7].visible); // JMol for seq1
599   }
600
601   /**
602    * Test result of deselecting an annotation type, with 'Show for selected
603    * sequences'.
604    * 
605    * We expect the annotations of that type, linked to the sequence group, to be
606    * set hidden. Other annotations should be left unchanged.
607    */
608   @Test(groups = { "Functional" })
609   public void testDeselectType_showForSelected()
610   {
611     selectSequences(1, 2);
612     testee = new AnnotationChooser(parentPanel);
613     final Checkbox showCheckbox = (Checkbox) getComponent(testee, 1, 0, 0);
614     setSelected(showCheckbox, true);
615
616     /*
617      * Don't set the 'selected sequences' radio button since this would trigger
618      * an update, including unselected sequences / annotation types
619      */
620     // setSelected(getSelectedSequencesCheckbox());
621
622     AlignmentAnnotation[] anns = parentPanel.getAlignment()
623             .getAlignmentAnnotation();
624
625     // select JMol - should remain visible
626     setSelected(getTypeCheckbox("JMol"), true);
627     assertTrue(anns[5].visible); // JMol for seq3
628     assertTrue(anns[7].visible); // JMol for seq1
629
630     // deselect JMol - should be hidden for selected sequences only
631     setSelected(getTypeCheckbox("JMol"), false);
632     assertTrue(anns[0].visible); // Conservation
633     assertTrue(anns[1].visible); // Quality
634     assertTrue(anns[2].visible); // Consensus
635     assertTrue(anns[3].visible); // IUPred for seq0
636     assertTrue(anns[4].visible); // Beauty
637     assertTrue(anns[5].visible); // JMol for seq3 not in selection group
638     assertTrue(anns[6].visible); // IUPRED for seq2
639     assertFalse(anns[7].visible); // JMol for seq1 in selection group
640   }
641
642   /**
643    * Helper method to drill down to a sub-component in a Container hierarchy.
644    * 
645    * @param cont
646    * @param i
647    * @param j
648    * @param k
649    * @return
650    */
651   public static Component getComponent(Container cont, int... positions)
652   {
653     Component comp = cont;
654     for (int i : positions)
655     {
656       comp = ((Container) comp).getComponent(i);
657     }
658     return comp;
659   }
660
661   /**
662    * Helper method to set or unset a checkbox and fire its action listener.
663    * 
664    * @param cb
665    * @param select
666    */
667   protected void setSelected(Checkbox cb, boolean select)
668   {
669     // TODO refactor to a test utility class
670     cb.setState(select);
671     // have to manually fire the action listener
672     cb.getItemListeners()[0].itemStateChanged(new ItemEvent(cb,
673             ItemEvent.ITEM_STATE_CHANGED, cb, select ? ItemEvent.SELECTED
674                     : ItemEvent.DESELECTED));
675   }
676
677   /**
678    * Helper method to drill down to the 'Annotation type' checkbox with given
679    * label.
680    * 
681    * @return
682    */
683   private Checkbox getTypeCheckbox(String forLabel)
684   {
685     Component[] cbs = ((JPanel) testee.getComponent(0)).getComponents();
686     for (Component comp : cbs)
687     {
688       final Checkbox cb = (Checkbox) comp;
689       if (cb.getLabel().equals(forLabel))
690       {
691         return cb;
692       }
693     }
694     return null;
695   }
696
697   /**
698    * Test isInActionScope for the case where the scope is selected sequences.
699    * Test cases include sequences in the selection group, and others not in the
700    * group.
701    */
702   @Test(groups = { "Functional" })
703   public void testIsInActionScope_selectedScope()
704   {
705     // sequences 1 and 2 have annotations 4 and 3 respectively
706     selectSequences(1, 2);
707     testee = new AnnotationChooser(parentPanel);
708
709     final Checkbox selectedSequencesCheckbox = (Checkbox) getComponent(
710             testee, 1, 1, 1);
711     setSelected(selectedSequencesCheckbox, true);
712
713     AlignmentAnnotation[] anns = parentPanel.getAlignment()
714             .getAlignmentAnnotation();
715     // remember 3 annotations to skip (Conservation/Quality/Consensus)
716     assertFalse(testee.isInActionScope(anns[3]));
717     assertFalse(testee.isInActionScope(anns[4]));
718     assertFalse(testee.isInActionScope(anns[5]));
719     assertTrue(testee.isInActionScope(anns[6]));
720     assertTrue(testee.isInActionScope(anns[7]));
721   }
722
723   /**
724    * Test isInActionScope for the case where the scope is unselected sequences.
725    * Test cases include sequences in the selection group, and others not in the
726    * group.
727    */
728   @Test(groups = { "Functional" })
729   public void testIsInActionScope_unselectedScope()
730   {
731     // sequences 1 and 2 have annotations 4 and 3 respectively
732     selectSequences(1, 2);
733     testee = new AnnotationChooser(parentPanel);
734
735     final Checkbox unselectedSequencesCheckbox = (Checkbox) getComponent(
736             testee, 1, 1, 2);
737     setSelected(unselectedSequencesCheckbox, true);
738
739     AlignmentAnnotation[] anns = parentPanel.getAlignment()
740             .getAlignmentAnnotation();
741     // remember 3 annotations to skip (Conservation/Quality/Consensus)
742     assertTrue(testee.isInActionScope(anns[3]));
743     assertTrue(testee.isInActionScope(anns[4]));
744     assertTrue(testee.isInActionScope(anns[5]));
745     assertFalse(testee.isInActionScope(anns[6]));
746     assertFalse(testee.isInActionScope(anns[7]));
747   }
748
749   /**
750    * Test that the reset method restores previous visibility flags.
751    */
752   @Test(groups = { "Functional" })
753   public void testResetOriginalState()
754   {
755     testee = new AnnotationChooser(parentPanel);
756
757     AlignmentAnnotation[] anns = parentPanel.getAlignment()
758             .getAlignmentAnnotation();
759     // all start visible
760     for (int i = 0; i < anns.length; i++)
761     {
762       assertTrue(i + "'th sequence not visible", anns[i].visible);
763     }
764
765     /*
766      * check options to hide JMol and IUPRED annotations for all sequences
767      */
768     final Checkbox hideCheckbox = (Checkbox) getComponent(testee, 1, 0, 1);
769     setSelected(hideCheckbox, true);
770
771     final Checkbox allSequencesCheckbox = (Checkbox) getComponent(testee,
772             1, 1, 0);
773     setSelected(allSequencesCheckbox, true);
774
775     setSelected(getTypeCheckbox("JMol"), true);
776     setSelected(getTypeCheckbox("IUPRED"), true);
777
778     assertTrue(anns[0].visible); // Conservation
779     assertTrue(anns[1].visible); // Quality
780     assertTrue(anns[2].visible); // Consensus
781     assertFalse(anns[3].visible); // IUPRED
782     assertTrue(anns[4].visible); // Beauty (not seq-related)
783     assertFalse(anns[5].visible); // JMol
784     assertFalse(anns[6].visible); // IUPRED
785     assertFalse(anns[7].visible); // JMol
786
787     // reset - should all be visible
788     testee.resetOriginalState();
789     for (int i = 0; i < anns.length; i++)
790     {
791       assertTrue(i + "'th sequence not visible", anns[i].visible);
792     }
793   }
794 }