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