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