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