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