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