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