Merge branch 'features/JAL-2379pcaMemory' into develop
[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", 6, 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   }
338
339   /**
340    * Test result of selecting an annotation type, with 'Hide for all sequences'.
341    * 
342    * We expect all annotations of that type to be set hidden. Other annotations
343    * should be left visible.
344    */
345   @Test(groups = { "Functional" })
346   public void testSelectType_hideForAll()
347   {
348     selectSequences(1, 2);
349     testee = new AnnotationChooser(parentPanel);
350     final Checkbox hideCheckbox = (Checkbox) getComponent(testee, 1, 0, 1);
351     setSelected(hideCheckbox, true);
352
353     final Checkbox allSequencesCheckbox = (Checkbox) getComponent(testee,
354             1, 1, 0);
355     setSelected(allSequencesCheckbox, true);
356
357     AlignmentAnnotation[] anns = parentPanel.getAlignment()
358             .getAlignmentAnnotation();
359
360     assertTrue(anns[5].visible); // JMol for seq3
361     assertTrue(anns[7].visible); // JMol for seq1
362
363     setSelected(getTypeCheckbox("JMol"), true);
364     assertTrue(anns[0].visible); // Conservation
365     assertTrue(anns[1].visible); // Quality
366     assertTrue(anns[2].visible); // Consensus
367     assertTrue(anns[3].visible); // IUPred for seq0
368     assertTrue(anns[4].visible); // Beauty
369     assertFalse(anns[5].visible); // JMol for seq3 - not selected but hidden
370     assertTrue(anns[6].visible); // IUPRED for seq2
371     assertFalse(anns[7].visible); // JMol for seq1 - selected and hidden
372   }
373
374   /**
375    * Test result of selecting an annotation type, with 'Hide for selected
376    * sequences'.
377    * 
378    * We expect the annotations of that type, linked to the sequence group, to be
379    * set hidden. Other annotations should be left visible.
380    */
381   @Test(groups = { "Functional" })
382   public void testSelectType_hideForSelected()
383   {
384     selectSequences(1, 2);
385     testee = new AnnotationChooser(parentPanel);
386     final Checkbox hideCheckbox = (Checkbox) getComponent(testee, 1, 0, 1);
387     setSelected(hideCheckbox, true);
388
389     /*
390      * Don't set the 'selected sequences' radio button since this would trigger
391      * an update, including unselected sequences / annotation types
392      */
393     // setSelected(getSelectedSequencesCheckbox());
394
395     AlignmentAnnotation[] anns = parentPanel.getAlignment()
396             .getAlignmentAnnotation();
397
398     assertTrue(anns[7].visible); // JMol for seq1
399
400     setSelected(getTypeCheckbox("JMol"), true);
401     assertTrue(anns[0].visible); // Conservation
402     assertTrue(anns[1].visible); // Quality
403     assertTrue(anns[2].visible); // Consensus
404     assertTrue(anns[3].visible); // IUPred for seq0
405     assertTrue(anns[4].visible); // Beauty
406     assertTrue(anns[5].visible); // JMol for seq3 not in selection group
407     assertTrue(anns[6].visible); // IUPRED for seq2
408     assertFalse(anns[7].visible); // JMol for seq1 in selection group
409   }
410
411   /**
412    * Test result of deselecting an annotation type, with 'Hide for all
413    * sequences'.
414    * 
415    * We expect all annotations of that type to be set visible. Other annotations
416    * should be left unchanged.
417    */
418   @Test(groups = { "Functional" })
419   public void testDeselectType_hideForAll()
420   {
421     selectSequences(1, 2);
422     testee = new AnnotationChooser(parentPanel);
423
424     final Checkbox hideCheckbox = (Checkbox) getComponent(testee, 1, 0, 1);
425     setSelected(hideCheckbox, true);
426
427     final Checkbox allSequencesCheckbox = (Checkbox) getComponent(testee,
428             1, 1, 0);
429     setSelected(allSequencesCheckbox, true);
430
431     AlignmentAnnotation[] anns = parentPanel.getAlignment()
432             .getAlignmentAnnotation();
433
434     final Checkbox typeCheckbox = getTypeCheckbox("JMol");
435
436     // select JMol - all hidden
437     setSelected(typeCheckbox, true);
438     assertFalse(anns[5].visible); // JMol for seq3
439     assertFalse(anns[7].visible); // JMol for seq1
440
441     // deselect JMol - all unhidden
442     setSelected(typeCheckbox, false);
443     assertTrue(anns[0].visible); // Conservation
444     assertTrue(anns[1].visible); // Quality
445     assertTrue(anns[2].visible); // Consensus
446     assertTrue(anns[3].visible); // IUPred for seq0
447     assertTrue(anns[4].visible); // Beauty
448     assertTrue(anns[5].visible); // JMol for seq3
449     assertTrue(anns[6].visible); // IUPRED for seq2
450     assertTrue(anns[7].visible); // JMol for seq1
451   }
452
453   /**
454    * Test result of deselecting an annotation type, with 'Hide for selected
455    * sequences'.
456    * 
457    * We expect the annotations of that type, linked to the sequence group, to be
458    * set visible. Other annotations should be left unchanged.
459    */
460   @Test(groups = { "Functional" })
461   public void testDeselectType_hideForSelected()
462   {
463     selectSequences(1, 2);
464     testee = new AnnotationChooser(parentPanel);
465     final Checkbox hideCheckbox = (Checkbox) getComponent(testee, 1, 0, 1);
466     setSelected(hideCheckbox, true);
467
468     /*
469      * Don't set the 'selected sequences' radio button since this would trigger
470      * an update, including unselected sequences / annotation types
471      */
472     // setSelected(getSelectedSequencesCheckbox());
473
474     setSelected(getTypeCheckbox("JMol"), true);
475     setSelected(getTypeCheckbox("JMol"), false);
476
477     AlignmentAnnotation[] anns = parentPanel.getAlignment()
478             .getAlignmentAnnotation();
479     assertTrue(anns[0].visible); // Conservation
480     assertTrue(anns[1].visible); // Quality
481     assertTrue(anns[2].visible); // Consensus
482     assertTrue(anns[3].visible); // IUPred for seq0
483     assertTrue(anns[4].visible); // Beauty
484     assertTrue(anns[5].visible); // JMol for seq3 not in selection group
485     assertTrue(anns[6].visible); // IUPRED for seq2
486     assertTrue(anns[7].visible); // JMol for seq1 in selection group
487   }
488
489   /**
490    * Test result of selecting an annotation type, with 'Show for all sequences'.
491    * 
492    * We expect all annotations of that type to be set visible. Other annotations
493    * should be left unchanged
494    */
495   @Test(groups = { "Functional" })
496   public void testSelectType_showForAll()
497   {
498     selectSequences(1, 2);
499     testee = new AnnotationChooser(parentPanel);
500     final Checkbox showCheckbox = (Checkbox) getComponent(testee, 1, 0, 0);
501     final Checkbox hideCheckbox = (Checkbox) getComponent(testee, 1, 0, 1);
502
503     final Checkbox allSequencesCheckbox = (Checkbox) getComponent(testee,
504             1, 1, 0);
505
506     AlignmentAnnotation[] anns = parentPanel.getAlignment()
507             .getAlignmentAnnotation();
508
509     // hide all JMol annotations
510     setSelected(allSequencesCheckbox, true);
511     setSelected(hideCheckbox, true);
512     setSelected(getTypeCheckbox("JMol"), true);
513     assertFalse(anns[5].visible); // JMol for seq3
514     assertFalse(anns[7].visible); // JMol for seq1
515     // ...now show them...
516     setSelected(showCheckbox, true);
517     assertTrue(anns[0].visible); // Conservation
518     assertTrue(anns[1].visible); // Quality
519     assertTrue(anns[2].visible); // Consensus
520     assertTrue(anns[3].visible); // IUPred for seq0
521     assertTrue(anns[4].visible); // Beauty
522     assertTrue(anns[5].visible); // JMol for seq3
523     assertTrue(anns[6].visible); // IUPRED for seq2
524     assertTrue(anns[7].visible); // JMol for seq1
525   }
526
527   /**
528    * Test result of selecting an annotation type, with 'Show for selected
529    * sequences'.
530    * 
531    * We expect all annotations of that type, linked to the sequence group, to be
532    * set visible. Other annotations should be left unchanged
533    */
534   @Test(groups = { "Functional" })
535   public void testSelectType_showForSelected()
536   {
537     // sequences 1 and 2 have annotations IUPred and Jmol
538     selectSequences(1, 2);
539     testee = new AnnotationChooser(parentPanel);
540     final Checkbox showCheckbox = (Checkbox) getComponent(testee, 1, 0, 0);
541     final Checkbox hideCheckbox = (Checkbox) getComponent(testee, 1, 0, 1);
542
543     final Checkbox selectedSequencesCheckbox = (Checkbox) getComponent(
544             testee, 1, 1, 1);
545
546     AlignmentAnnotation[] anns = parentPanel.getAlignment()
547             .getAlignmentAnnotation();
548
549     // hide all JMol annotations in the selection region (== annotation 7)
550     setSelected(selectedSequencesCheckbox, true);
551     setSelected(hideCheckbox, true);
552     setSelected(getTypeCheckbox("JMol"), true);
553
554     assertTrue(anns[5].visible); // JMol for seq3
555     assertFalse(anns[7].visible); // JMol for seq1
556     // ...now show them...
557     setSelected(showCheckbox, true);
558
559     assertTrue(anns[0].visible); // Conservation
560     assertTrue(anns[1].visible); // Quality
561     assertTrue(anns[2].visible); // Consensus
562     assertTrue(anns[3].visible); // IUPred for seq0
563     assertTrue(anns[4].visible); // Beauty
564     assertTrue(anns[5].visible); // JMol for seq3
565     assertTrue(anns[6].visible); // IUPRED for seq2
566     assertTrue(anns[7].visible); // JMol for seq1
567   }
568
569   /**
570    * Test result of deselecting an annotation type, with 'Show for all
571    * sequences'.
572    * 
573    * We expect all annotations of that type to be set hidden. Other annotations
574    * should be left unchanged.
575    */
576   @Test(groups = { "Functional" })
577   public void testDeselectType_showForAll()
578   {
579     selectSequences(1, 2);
580     testee = new AnnotationChooser(parentPanel);
581
582     final Checkbox showCheckbox = (Checkbox) getComponent(testee, 1, 0, 0);
583     setSelected(showCheckbox, true);
584
585     final Checkbox allSequencesCheckbox = (Checkbox) getComponent(testee,
586             1, 1, 0);
587     setSelected(allSequencesCheckbox, true);
588
589     AlignmentAnnotation[] anns = parentPanel.getAlignment()
590             .getAlignmentAnnotation();
591
592     final Checkbox typeCheckbox = getTypeCheckbox("JMol");
593     // select JMol - all shown
594     setSelected(typeCheckbox, true);
595     assertTrue(anns[5].visible); // JMol for seq3
596     assertTrue(anns[7].visible); // JMol for seq1
597
598     // deselect JMol - all hidden
599     setSelected(typeCheckbox, false);
600     assertTrue(anns[0].visible); // Conservation
601     assertTrue(anns[1].visible); // Quality
602     assertTrue(anns[2].visible); // Consensus
603     assertTrue(anns[3].visible); // IUPred for seq0
604     assertTrue(anns[4].visible); // Beauty
605     assertFalse(anns[5].visible); // JMol for seq3
606     assertTrue(anns[6].visible); // IUPRED for seq2
607     assertFalse(anns[7].visible); // JMol for seq1
608   }
609
610   /**
611    * Test result of deselecting an annotation type, with 'Show for selected
612    * sequences'.
613    * 
614    * We expect the annotations of that type, linked to the sequence group, to be
615    * set hidden. Other annotations should be left unchanged.
616    */
617   @Test(groups = { "Functional" })
618   public void testDeselectType_showForSelected()
619   {
620     selectSequences(1, 2);
621     testee = new AnnotationChooser(parentPanel);
622     final Checkbox showCheckbox = (Checkbox) getComponent(testee, 1, 0, 0);
623     setSelected(showCheckbox, true);
624
625     /*
626      * Don't set the 'selected sequences' radio button since this would trigger
627      * an update, including unselected sequences / annotation types
628      */
629     // setSelected(getSelectedSequencesCheckbox());
630
631     AlignmentAnnotation[] anns = parentPanel.getAlignment()
632             .getAlignmentAnnotation();
633
634     // select JMol - should remain visible
635     setSelected(getTypeCheckbox("JMol"), true);
636     assertTrue(anns[5].visible); // JMol for seq3
637     assertTrue(anns[7].visible); // JMol for seq1
638
639     // deselect JMol - should be hidden for selected sequences only
640     setSelected(getTypeCheckbox("JMol"), false);
641     assertTrue(anns[0].visible); // Conservation
642     assertTrue(anns[1].visible); // Quality
643     assertTrue(anns[2].visible); // Consensus
644     assertTrue(anns[3].visible); // IUPred for seq0
645     assertTrue(anns[4].visible); // Beauty
646     assertTrue(anns[5].visible); // JMol for seq3 not in selection group
647     assertTrue(anns[6].visible); // IUPRED for seq2
648     assertFalse(anns[7].visible); // JMol for seq1 in selection group
649   }
650
651   /**
652    * Helper method to drill down to a sub-component in a Container hierarchy.
653    * 
654    * @param cont
655    * @param i
656    * @param j
657    * @param k
658    * @return
659    */
660   public static Component getComponent(Container cont, int... positions)
661   {
662     Component comp = cont;
663     for (int i : positions)
664     {
665       comp = ((Container) comp).getComponent(i);
666     }
667     return comp;
668   }
669
670   /**
671    * Helper method to set or unset a checkbox and fire its action listener.
672    * 
673    * @param cb
674    * @param select
675    */
676   protected void setSelected(Checkbox cb, boolean select)
677   {
678     // TODO refactor to a test utility class
679     cb.setState(select);
680     // have to manually fire the action listener
681     cb.getItemListeners()[0].itemStateChanged(new ItemEvent(cb,
682             ItemEvent.ITEM_STATE_CHANGED, cb, select ? ItemEvent.SELECTED
683                     : ItemEvent.DESELECTED));
684   }
685
686   /**
687    * Helper method to drill down to the 'Annotation type' checkbox with given
688    * label.
689    * 
690    * @return
691    */
692   private Checkbox getTypeCheckbox(String forLabel)
693   {
694     Component[] cbs = ((JPanel) testee.getComponent(0)).getComponents();
695     for (Component comp : cbs)
696     {
697       final Checkbox cb = (Checkbox) comp;
698       if (cb.getLabel().equals(forLabel))
699       {
700         return cb;
701       }
702     }
703     return null;
704   }
705
706   /**
707    * Test isInActionScope for the case where the scope is selected sequences.
708    * Test cases include sequences in the selection group, and others not in the
709    * group.
710    */
711   @Test(groups = { "Functional" })
712   public void testIsInActionScope_selectedScope()
713   {
714     // sequences 1 and 2 have annotations 4 and 3 respectively
715     selectSequences(1, 2);
716     testee = new AnnotationChooser(parentPanel);
717
718     final Checkbox selectedSequencesCheckbox = (Checkbox) getComponent(
719             testee, 1, 1, 1);
720     setSelected(selectedSequencesCheckbox, true);
721
722     AlignmentAnnotation[] anns = parentPanel.getAlignment()
723             .getAlignmentAnnotation();
724     // remember 3 annotations to skip (Conservation/Quality/Consensus)
725     assertFalse(testee.isInActionScope(anns[3]));
726     assertFalse(testee.isInActionScope(anns[4]));
727     assertFalse(testee.isInActionScope(anns[5]));
728     assertTrue(testee.isInActionScope(anns[6]));
729     assertTrue(testee.isInActionScope(anns[7]));
730   }
731
732   /**
733    * Test isInActionScope for the case where the scope is unselected sequences.
734    * Test cases include sequences in the selection group, and others not in the
735    * group.
736    */
737   @Test(groups = { "Functional" })
738   public void testIsInActionScope_unselectedScope()
739   {
740     // sequences 1 and 2 have annotations 4 and 3 respectively
741     selectSequences(1, 2);
742     testee = new AnnotationChooser(parentPanel);
743
744     final Checkbox unselectedSequencesCheckbox = (Checkbox) getComponent(
745             testee, 1, 1, 2);
746     setSelected(unselectedSequencesCheckbox, true);
747
748     AlignmentAnnotation[] anns = parentPanel.getAlignment()
749             .getAlignmentAnnotation();
750     // remember 3 annotations to skip (Conservation/Quality/Consensus)
751     assertTrue(testee.isInActionScope(anns[3]));
752     assertTrue(testee.isInActionScope(anns[4]));
753     assertTrue(testee.isInActionScope(anns[5]));
754     assertFalse(testee.isInActionScope(anns[6]));
755     assertFalse(testee.isInActionScope(anns[7]));
756   }
757
758   /**
759    * Test that the reset method restores previous visibility flags.
760    */
761   @Test(groups = { "Functional" })
762   public void testResetOriginalState()
763   {
764     testee = new AnnotationChooser(parentPanel);
765
766     AlignmentAnnotation[] anns = parentPanel.getAlignment()
767             .getAlignmentAnnotation();
768     // all start visible
769     for (int i = 0; i < anns.length; i++)
770     {
771       assertTrue(i + "'th sequence not visible", anns[i].visible);
772     }
773
774     /*
775      * check options to hide JMol and IUPRED annotations for all sequences
776      */
777     final Checkbox hideCheckbox = (Checkbox) getComponent(testee, 1, 0, 1);
778     setSelected(hideCheckbox, true);
779
780     final Checkbox allSequencesCheckbox = (Checkbox) getComponent(testee,
781             1, 1, 0);
782     setSelected(allSequencesCheckbox, true);
783
784     setSelected(getTypeCheckbox("JMol"), true);
785     setSelected(getTypeCheckbox("IUPRED"), true);
786
787     assertTrue(anns[0].visible); // Conservation
788     assertTrue(anns[1].visible); // Quality
789     assertTrue(anns[2].visible); // Consensus
790     assertFalse(anns[3].visible); // IUPRED
791     assertTrue(anns[4].visible); // Beauty (not seq-related)
792     assertFalse(anns[5].visible); // JMol
793     assertFalse(anns[6].visible); // IUPRED
794     assertFalse(anns[7].visible); // JMol
795
796     // reset - should all be visible
797     testee.resetOriginalState();
798     for (int i = 0; i < anns.length; i++)
799     {
800       assertTrue(i + "'th sequence not visible", anns[i].visible);
801     }
802   }
803 }