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