JAL-2674 Removing most calls to getHiddenColumnsCopy
[jalview.git] / test / jalview / gui / AlignFrameTest.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.Assert.assertEquals;
24 import static org.testng.Assert.assertFalse;
25 import static org.testng.Assert.assertNotSame;
26 import static org.testng.Assert.assertSame;
27 import static org.testng.Assert.assertTrue;
28
29 import jalview.bin.Cache;
30 import jalview.bin.Jalview;
31 import jalview.datamodel.Alignment;
32 import jalview.datamodel.AlignmentI;
33 import jalview.datamodel.Sequence;
34 import jalview.datamodel.SequenceFeature;
35 import jalview.datamodel.SequenceGroup;
36 import jalview.datamodel.SequenceI;
37 import jalview.io.DataSourceType;
38 import jalview.io.FileLoader;
39 import jalview.io.Jalview2xmlTests;
40 import jalview.renderer.ResidueShaderI;
41 import jalview.schemes.BuriedColourScheme;
42 import jalview.schemes.HelixColourScheme;
43 import jalview.schemes.JalviewColourScheme;
44 import jalview.schemes.StrandColourScheme;
45 import jalview.schemes.TurnColourScheme;
46 import jalview.util.MessageManager;
47
48 import java.awt.Color;
49 import java.util.Iterator;
50
51 import org.testng.annotations.AfterMethod;
52 import org.testng.annotations.BeforeClass;
53 import org.testng.annotations.BeforeMethod;
54 import org.testng.annotations.Test;
55
56 public class AlignFrameTest
57 {
58   AlignFrame af;
59
60   @BeforeClass(alwaysRun = true)
61   public void setUpJvOptionPane()
62   {
63     JvOptionPane.setInteractiveMode(false);
64     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
65   }
66
67   @Test(groups = "Functional")
68   public void testHideFeatureColumns()
69   {
70     SequenceI seq1 = new Sequence("Seq1", "ABCDEFGHIJ");
71     SequenceI seq2 = new Sequence("Seq2", "ABCDEFGHIJ");
72     seq1.addSequenceFeature(new SequenceFeature("Metal", "", 1, 5,
73             Float.NaN, null));
74     seq2.addSequenceFeature(new SequenceFeature("Metal", "", 6, 10,
75             Float.NaN, null));
76     seq1.addSequenceFeature(new SequenceFeature("Turn", "", 2, 4,
77             Float.NaN, null));
78     seq2.addSequenceFeature(new SequenceFeature("Turn", "", 7, 9,
79             Float.NaN, null));
80     AlignmentI al = new Alignment(new SequenceI[] { seq1, seq2 });
81     AlignFrame alignFrame = new AlignFrame(al, al.getWidth(), al.getHeight());
82
83     /*
84      * hiding a feature not present does nothing
85      */
86     assertFalse(alignFrame.hideFeatureColumns("exon", true));
87     assertTrue(alignFrame.getViewport().getColumnSelection().isEmpty());
88     assertEquals(alignFrame.getViewport().getAlignment().getHiddenColumns()
89             .getNumberOfRegions(), 0);
90     assertFalse(alignFrame.hideFeatureColumns("exon", false));
91     assertTrue(alignFrame.getViewport().getColumnSelection().isEmpty());
92     assertEquals(alignFrame.getViewport().getAlignment().getHiddenColumns()
93             .getNumberOfRegions(), 0);
94
95     /*
96      * hiding a feature in all columns does nothing
97      */
98     assertFalse(alignFrame.hideFeatureColumns("Metal", true));
99     assertTrue(alignFrame.getViewport().getColumnSelection().isEmpty());
100     assertEquals(alignFrame.getViewport().getAlignment().getHiddenColumns()
101             .getNumberOfRegions(), 0);
102
103     /*
104      * hide a feature present in some columns
105      * sequence positions [2-4], [7-9] are column positions
106      * [1-3], [6-8] base zero
107      */
108     assertTrue(alignFrame.hideFeatureColumns("Turn", true));
109     Iterator<int[]> regions = alignFrame.getViewport().getAlignment()
110             .getHiddenColumns().iterator();
111     assertEquals(alignFrame.getViewport().getAlignment().getHiddenColumns()
112             .getNumberOfRegions(), 2);
113     int[] next = regions.next();
114     assertEquals(next[0], 1);
115     assertEquals(next[1], 3);
116     next = regions.next();
117     assertEquals(next[0], 6);
118     assertEquals(next[1], 8);
119   }
120
121   @BeforeClass(alwaysRun = true)
122   public static void setUpBeforeClass() throws Exception
123   {
124     /*
125      * use read-only test properties file
126      */
127     Cache.loadProperties("test/jalview/io/testProps.jvprops");
128     Jalview.main(new String[] { "-nonews" });
129   }
130
131   @AfterMethod(alwaysRun = true)
132   public void tearDown()
133   {
134     Desktop.instance.closeAll_actionPerformed(null);
135   }
136
137   /**
138    * configure (read-only) properties for test to ensure Consensus is computed
139    * for colour Above PID testing
140    */
141   @BeforeMethod(alwaysRun = true)
142   public void setUp()
143   {
144     Cache.loadProperties("test/jalview/io/testProps.jvprops");
145     Cache.applicationProperties.setProperty("SHOW_IDENTITY",
146             Boolean.TRUE.toString());
147     af = new FileLoader().LoadFileWaitTillLoaded("examples/uniref50.fa",
148             DataSourceType.FILE);
149
150     /*
151      * wait for Consensus thread to complete
152      */
153     synchronized (this)
154     {
155       while (af.getViewport().getConsensusSeq() == null)
156       {
157         try
158         {
159           wait(50);
160         } catch (InterruptedException e)
161         {
162         }
163       }
164     }
165   }
166
167   /**
168    * Test that changing background (alignment) colour scheme
169    * <ul>
170    * <li>with Apply Colour to All Groups not selected, does not change group
171    * colours</li>
172    * <li>with Apply Colour to All Groups selected, does change group colours</li>
173    * <li>in neither case, changes alignment or group colour thresholds (PID or
174    * Conservation)</li>
175    * </ul>
176    */
177   @Test(groups = "Functional")
178   public void testChangeColour_background_groupsAndThresholds()
179   {
180     AlignViewport av = af.getViewport();
181     AlignmentI al = av.getAlignment();
182
183     /*
184      * Colour alignment by Buried Index
185      */
186     af.applyToAllGroups_actionPerformed(false);
187     af.changeColour_actionPerformed(JalviewColourScheme.Buried.toString());
188     assertTrue(av.getGlobalColourScheme() instanceof BuriedColourScheme);
189     assertFalse(av.getResidueShading().conservationApplied());
190     assertEquals(av.getResidueShading().getThreshold(), 0);
191
192     /*
193      * Apply Conservation 20%
194      */
195     af.conservationMenuItem_actionPerformed(true);
196     SliderPanel sp = SliderPanel.getSliderPanel();
197     assertEquals(sp.getTitle(), MessageManager.formatMessage(
198             "label.conservation_colour_increment",
199             new String[] { "Background" }));
200     assertTrue(sp.isForConservation());
201     sp.valueChanged(20);
202     assertTrue(av.getResidueShading().conservationApplied());
203     assertEquals(av.getResidueShading().getConservationInc(), 20);
204
205     /*
206      * Apply PID threshold 10% (conservation still applies as well)
207      */
208     af.abovePIDThreshold_actionPerformed(true);
209     sp = SliderPanel.getSliderPanel();
210     assertFalse(sp.isForConservation());
211     assertEquals(sp.getTitle(), MessageManager.formatMessage(
212             "label.percentage_identity_threshold",
213             new String[] { "Background" }));
214     sp.valueChanged(10);
215     assertEquals(av.getResidueShading().getThreshold(), 10);
216     assertTrue(av.getResidueShading().conservationApplied());
217     assertEquals(av.getResidueShading().getConservationInc(), 20);
218
219     /*
220      * create a group with Strand colouring, 30% Conservation
221      * and 40% PID threshold
222      */
223     SequenceGroup sg = new SequenceGroup();
224     sg.addSequence(al.getSequenceAt(0), false);
225     sg.setStartRes(15);
226     sg.setEndRes(25);
227     av.setSelectionGroup(sg);
228
229     /*
230      * apply 30% Conservation to group
231      */
232     PopupMenu popupMenu = new PopupMenu(af.alignPanel, null, null);
233     popupMenu.changeColour_actionPerformed(JalviewColourScheme.Strand
234             .toString());
235     assertTrue(sg.getColourScheme() instanceof StrandColourScheme);
236     assertEquals(al.getGroups().size(), 1);
237     assertSame(al.getGroups().get(0), sg);
238     popupMenu.conservationMenuItem_actionPerformed(true);
239     sp = SliderPanel.getSliderPanel();
240     assertTrue(sp.isForConservation());
241     assertEquals(sp.getTitle(), MessageManager.formatMessage(
242             "label.conservation_colour_increment",
243             new String[] { sg.getName() }));
244     sp.valueChanged(30);
245     assertTrue(sg.getGroupColourScheme().conservationApplied());
246     assertEquals(sg.getGroupColourScheme().getConservationInc(), 30);
247
248     /*
249      * apply 40% PID threshold to group
250      */
251     popupMenu.abovePIDColour_actionPerformed(true);
252     sp = SliderPanel.getSliderPanel();
253     assertFalse(sp.isForConservation());
254     assertEquals(sp.getTitle(), MessageManager.formatMessage(
255             "label.percentage_identity_threshold",
256             new String[] { sg.getName() }));
257     sp.valueChanged(40);
258     assertEquals(sg.getGroupColourScheme().getThreshold(), 40);
259     // conservation threshold is unchanged:
260     assertTrue(sg.getGroupColourScheme().conservationApplied());
261     assertEquals(sg.getGroupColourScheme().getConservationInc(), 30);
262
263     /*
264      * change alignment colour - group colour, and all thresholds,
265      * should be unaffected
266      */
267     af.changeColour_actionPerformed(JalviewColourScheme.Turn.toString());
268     assertTrue(av.getGlobalColourScheme() instanceof TurnColourScheme);
269     assertTrue(av.getResidueShading().conservationApplied());
270     assertEquals(av.getResidueShading().getConservationInc(), 20);
271     assertEquals(av.getResidueShading().getThreshold(), 10);
272     assertTrue(sg.getColourScheme() instanceof StrandColourScheme);
273     assertTrue(sg.getGroupColourScheme().conservationApplied());
274     assertEquals(sg.getGroupColourScheme().getConservationInc(), 30);
275     assertEquals(sg.getGroupColourScheme().getThreshold(), 40);
276
277     /*
278      * Now change alignment colour with Apply Colour To All Groups
279      * - group colour should change, but not colour thresholds
280      */
281     af.applyToAllGroups_actionPerformed(true);
282     af.changeColour_actionPerformed(JalviewColourScheme.Helix.toString());
283     assertTrue(av.getGlobalColourScheme() instanceof HelixColourScheme);
284     assertTrue(av.getResidueShading().conservationApplied());
285     assertEquals(av.getResidueShading().getConservationInc(), 20);
286     assertEquals(av.getResidueShading().getThreshold(), 10);
287     assertTrue(sg.getColourScheme() instanceof HelixColourScheme);
288     assertTrue(sg.getGroupColourScheme().conservationApplied());
289     assertEquals(sg.getGroupColourScheme().getConservationInc(), 30);
290     assertEquals(sg.getGroupColourScheme().getThreshold(), 40);
291   }
292
293   /**
294    * Test residue colouring with various options
295    * <ol>
296    * <li>no PID or Conservation threshold</li>
297    * <li>colour by Conservation applied</li>
298    * <li>colour by Conservation removed</li>
299    * <li>colour above PID - various values</li>
300    * <li>colour above PID removed</li>
301    * <li>Above PID plus By Conservation combined</li>
302    * <li>remove Above PID to leave just By Conservation</li>
303    * <li>re-add Above PID</li>
304    * <li>remove By Conservation to leave just Above PID</li>
305    * <li>remove Above PID to leave original colours</li>
306    * </ol>
307    */
308   @Test(groups = "Functional")
309   public void testColourThresholdActions()
310   {
311     AlignViewport av = af.getViewport();
312     AlignmentI al = av.getAlignment();
313
314     /*
315      * Colour alignment by Helix Propensity, no thresholds
316      */
317     af.applyToAllGroups_actionPerformed(false);
318     af.changeColour_actionPerformed(JalviewColourScheme.Helix.toString());
319     assertTrue(av.getGlobalColourScheme() instanceof HelixColourScheme);
320     assertFalse(av.getResidueShading().conservationApplied());
321     assertEquals(av.getResidueShading().getThreshold(), 0);
322
323     /*
324      * inspect the colour of 
325      * FER_CAPAN.9(I), column 14 (14 base 0)
326      * FER_CAPAN.10(SER), column 16 (15 base 0)
327      */
328     SequenceI ferCapan = al.findName("FER_CAPAN");
329     ResidueShaderI rs = av.getResidueShading();
330     Color c = rs.findColour('I', 14, ferCapan);
331     Color i_original = new Color(138, 117, 138);
332     assertEquals(c, i_original);
333     c = rs.findColour('S', 15, ferCapan);
334     Color s_original = new Color(54, 201, 54);
335     assertEquals(c, s_original);
336
337     /*
338      * colour by conservation with increment 10
339      */
340     af.conservationMenuItem_actionPerformed(true);
341     SliderPanel sp = SliderPanel.getSliderPanel();
342     assertTrue(sp.isForConservation());
343     assertEquals(sp.getValue(), 30); // initial slider setting
344     sp.valueChanged(10);
345     assertSame(rs, av.getResidueShading());
346     c = rs.findColour('I', 14, ferCapan);
347     Color i_faded = new Color(196, 186, 196);
348     assertEquals(c, i_faded);
349     c = rs.findColour('S', 15, ferCapan);
350     Color s_faded = new Color(144, 225, 144);
351     assertEquals(c, s_faded);
352
353     /*
354      * deselect By Conservation - colour should revert
355      */
356     af.conservationMenuItem_actionPerformed(false);
357     c = rs.findColour('S', 15, ferCapan);
358     assertEquals(c, s_original);
359
360     /*
361      * now Above PID, threshold = 0%
362      * should be no change
363      */
364     af.abovePIDThreshold_actionPerformed(true);
365     sp = SliderPanel.getSliderPanel();
366     assertFalse(sp.isForConservation());
367     assertEquals(sp.getValue(), 0); // initial slider setting
368     c = rs.findColour('I', 14, ferCapan);
369     assertEquals(c, i_original);
370     c = rs.findColour('S', 15, ferCapan);
371     assertEquals(c, s_original);
372
373     /*
374      * Above PID, threshold = 1%
375      * 15.I becomes White because no match to consensus (V)
376      * 16.S remains coloured as matches 66.66% consensus
377      */
378     sp.valueChanged(1);
379     c = rs.findColour('I', 14, ferCapan);
380     assertEquals(c, Color.white);
381     c = rs.findColour('S', 15, ferCapan);
382     assertEquals(c, s_original);
383
384     /*
385      * threshold 66% - no further change yet...
386      */
387     sp.valueChanged(66);
388     c = rs.findColour('I', 14, ferCapan);
389     assertEquals(c, Color.white);
390     c = rs.findColour('S', 15, ferCapan);
391     assertEquals(c, s_original);
392
393     /*
394      * threshold 67% - now both residues are white
395      */
396     sp.valueChanged(67);
397     c = rs.findColour('I', 14, ferCapan);
398     assertEquals(c, Color.white);
399     c = rs.findColour('S', 15, ferCapan);
400     assertEquals(c, Color.white);
401
402     /*
403      * deselect Above PID - colours should revert
404      */
405     af.abovePIDThreshold_actionPerformed(false);
406     c = rs.findColour('I', 14, ferCapan);
407     assertEquals(c, i_original);
408     c = rs.findColour('S', 15, ferCapan);
409     assertEquals(c, s_original);
410
411     /*
412      * Now combine Above 50% PID and By Conservation 10%
413      * 15.I is White because no match to consensus (V)
414      * 16.S is coloured but faded
415      */
416     af.abovePIDThreshold_actionPerformed(true);
417     sp = SliderPanel.getSliderPanel();
418     assertFalse(sp.isForConservation());
419     sp.valueChanged(50);
420     af.conservationMenuItem_actionPerformed(true);
421     sp = SliderPanel.getSliderPanel();
422     assertTrue(sp.isForConservation());
423     sp.valueChanged(10);
424     c = rs.findColour('I', 14, ferCapan);
425     assertEquals(c, Color.white);
426     c = rs.findColour('S', 15, ferCapan);
427     assertEquals(c, s_faded);
428
429     /*
430      * turn off Above PID - should just leave Conservation fading as before 
431      */
432     af.abovePIDThreshold_actionPerformed(false);
433     c = rs.findColour('I', 14, ferCapan);
434     assertEquals(c, i_faded);
435     c = rs.findColour('S', 15, ferCapan);
436     assertEquals(c, s_faded);
437
438     /*
439      * Now add Above 50% PID to conservation colouring
440      * - should give the same as PID followed by conservation (above)
441      */
442     af.abovePIDThreshold_actionPerformed(true);
443     SliderPanel.getSliderPanel().valueChanged(50);
444     c = rs.findColour('I', 14, ferCapan);
445     assertEquals(c, Color.white);
446     c = rs.findColour('S', 15, ferCapan);
447     assertEquals(c, s_faded);
448
449     /*
450      * turn off By Conservation
451      * should leave I white, S original (unfaded) colour
452      */
453     af.conservationMenuItem_actionPerformed(false);
454     c = rs.findColour('I', 14, ferCapan);
455     assertEquals(c, Color.white);
456     c = rs.findColour('S', 15, ferCapan);
457     assertEquals(c, s_original);
458
459     /*
460      * finally turn off Above PID to leave original colours
461      */
462     af.abovePIDThreshold_actionPerformed(false);
463     c = rs.findColour('I', 14, ferCapan);
464     assertEquals(c, i_original);
465     c = rs.findColour('S', 15, ferCapan);
466     assertEquals(c, s_original);
467   }
468
469   /**
470    * Verify that making a New View transfers alignment and group colour schemes,
471    * including any thresholds, to the new view. Because New View is performed by
472    * saving and reloading a 'project' file, this is similar to verifying a
473    * project save and reload.
474    * 
475    * @see Jalview2xmlTests#testStoreAndRecoverColourThresholds()
476    */
477   @Test(groups = "Functional")
478   public void testNewView_colourThresholds()
479   {
480     AlignViewport av = af.getViewport();
481     AlignmentI al = av.getAlignment();
482
483     /*
484      * Colour alignment by Buried Index, Above 10% PID, By Conservation 20%
485      */
486     af.changeColour_actionPerformed(JalviewColourScheme.Buried.toString());
487     assertTrue(av.getGlobalColourScheme() instanceof BuriedColourScheme);
488     af.abovePIDThreshold_actionPerformed(true);
489     SliderPanel sp = SliderPanel.getSliderPanel();
490     assertFalse(sp.isForConservation());
491     sp.valueChanged(10);
492     af.conservationMenuItem_actionPerformed(true);
493     sp = SliderPanel.getSliderPanel();
494     assertTrue(sp.isForConservation());
495     sp.valueChanged(20);
496     ResidueShaderI rs = av.getResidueShading();
497     assertEquals(rs.getThreshold(), 10);
498     assertTrue(rs.conservationApplied());
499     assertEquals(rs.getConservationInc(), 20);
500
501     /*
502      * create a group with Strand colouring, 30% Conservation
503      * and 40% PID threshold
504      */
505     SequenceGroup sg = new SequenceGroup();
506     sg.addSequence(al.getSequenceAt(0), false);
507     sg.setStartRes(15);
508     sg.setEndRes(25);
509     av.setSelectionGroup(sg);
510     PopupMenu popupMenu = new PopupMenu(af.alignPanel, null, null);
511     popupMenu.changeColour_actionPerformed(JalviewColourScheme.Strand
512             .toString());
513     assertTrue(sg.getColourScheme() instanceof StrandColourScheme);
514     assertEquals(al.getGroups().size(), 1);
515     assertSame(al.getGroups().get(0), sg);
516     popupMenu.conservationMenuItem_actionPerformed(true);
517     sp = SliderPanel.getSliderPanel();
518     assertTrue(sp.isForConservation());
519     sp.valueChanged(30);
520     popupMenu.abovePIDColour_actionPerformed(true);
521     sp = SliderPanel.getSliderPanel();
522     assertFalse(sp.isForConservation());
523     sp.valueChanged(40);
524     rs = sg.getGroupColourScheme();
525     assertTrue(rs.conservationApplied());
526     assertEquals(rs.getConservationInc(), 30);
527     assertEquals(rs.getThreshold(), 40);
528
529     /*
530      * set slider panel focus to the background alignment
531      */
532     af.conservationMenuItem_actionPerformed(true);
533     sp = SliderPanel.getSliderPanel();
534     assertTrue(sp.isForConservation());
535     assertEquals(sp.getTitle(), MessageManager.formatMessage(
536             "label.conservation_colour_increment",
537             new String[] { "Background" }));
538
539     /*
540      * make a new View, verify alignment and group colour schemes
541      */
542     af.newView_actionPerformed(null);
543     assertEquals(af.alignPanel.getViewName(), "View 1");
544     AlignViewport av2 = af.getViewport();
545     assertNotSame(av, av2);
546     assertSame(av2, af.alignPanel.av);
547     rs = av2.getResidueShading();
548     assertNotSame(av.getResidueShading(), rs);
549     assertEquals(rs.getThreshold(), 10);
550     assertTrue(rs.conservationApplied(), rs.toString());
551     assertEquals(rs.getConservationInc(), 20);
552     assertEquals(av2.getAlignment().getGroups().size(), 1);
553     sg = av2.getAlignment().getGroups().get(0);
554     rs = sg.getGroupColourScheme();
555     assertTrue(rs.conservationApplied());
556     assertEquals(rs.getConservationInc(), 30);
557     assertEquals(rs.getThreshold(), 40);
558
559     /*
560      * check the Conservation SliderPanel (still open) is linked to 
561      * and updates the new view (JAL-2385)
562      */
563     sp = SliderPanel.getSliderPanel();
564     assertTrue(sp.isForConservation());
565     assertEquals(sp.getTitle(), MessageManager.formatMessage(
566             "label.conservation_colour_increment",
567             new String[] { "View 1" }));
568     sp.valueChanged(22);
569     assertEquals(av2.getResidueShading().getConservationInc(), 22);
570   }
571 }