Merge branch 'develop' into Jalview-JS/develop
[jalview.git] / test / jalview / gui / AlignmentPanelTest.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.assertNotEquals;
25
26 import java.awt.Dimension;
27 import java.awt.Font;
28 import java.awt.FontMetrics;
29 import java.lang.reflect.InvocationTargetException;
30
31 import javax.swing.SwingUtilities;
32
33 import org.testng.annotations.BeforeMethod;
34 import org.testng.annotations.Test;
35
36 import jalview.api.AlignViewportI;
37 import jalview.bin.Cache;
38 import jalview.bin.Jalview;
39 import jalview.datamodel.AlignmentAnnotation;
40 import jalview.datamodel.SequenceI;
41 import jalview.io.DataSourceType;
42 import jalview.io.FileLoader;
43 import jalview.viewmodel.ViewportRanges;
44
45 public class AlignmentPanelTest
46 {
47   AlignFrame af;
48
49   @BeforeMethod(alwaysRun = true)
50   public void setUp() throws InvocationTargetException, InterruptedException
51   {
52     Jalview.main(new String[] { "-nonews", "-props",
53         "test/jalview/testProps.jvprops" });
54
55     Cache.applicationProperties.setProperty("SHOW_IDENTITY",
56             Boolean.TRUE.toString());
57     af = new FileLoader().LoadFileWaitTillLoaded("examples/uniref50.fa",
58             DataSourceType.FILE);
59     
60     /*
61      * ensure the panel has been repainted and so ViewportRanges set
62      */
63     SwingUtilities.invokeAndWait(new Runnable() {
64                 @Override
65                 public void run() {
66                     af.repaint();
67                 }});
68
69     /*
70      * wait for Consensus thread to complete
71      */
72     synchronized (this)
73     {
74       while (af.getViewport().getConsensusSeq() == null)
75       {
76         try
77         {
78           wait(50);
79         } catch (InterruptedException e)
80         {
81         }
82       }
83     }
84   }
85
86   /**
87    * Test side effect that end residue is set correctly by setScrollValues, with
88    * or without hidden columns
89    */
90   @Test(groups = "Functional")
91   public void testSetScrollValues()
92   {
93     ViewportRanges ranges = af.getViewport().getRanges();
94     af.alignPanel.setScrollValues(0, 0);
95
96     int oldres = ranges.getEndRes();
97     af.alignPanel.setScrollValues(-1, 5);
98
99     // setting -ve x value does not change residue
100     assertEquals(ranges.getEndRes(), oldres);
101
102     af.alignPanel.setScrollValues(0, 5);
103
104     // setting 0 as x value does not change residue
105     assertEquals(ranges.getEndRes(), oldres);
106
107     af.alignPanel.setScrollValues(5, 5);
108     // setting x value to 5 extends endRes by 5 residues
109     assertEquals(ranges.getEndRes(), oldres + 5);
110
111     // scroll to position after hidden columns sets endres to oldres (width) +
112     // position
113     int scrollpos = 60;
114     af.getViewport().hideColumns(30, 50);
115     af.alignPanel.setScrollValues(scrollpos, 5);
116     assertEquals(ranges.getEndRes(), oldres + scrollpos);
117
118     // scroll to position within hidden columns, still sets endres to oldres +
119     // position
120     // not sure if this is actually correct behaviour but this is what Jalview
121     // currently does
122     scrollpos = 40;
123     af.getViewport().showAllHiddenColumns();
124     af.getViewport().hideColumns(30, 50);
125     af.alignPanel.setScrollValues(scrollpos, 5);
126     assertEquals(ranges.getEndRes(), oldres + scrollpos);
127
128     // scroll to position within <width> distance of the end of the alignment
129     // endRes should be set to width of alignment - 1
130     scrollpos = 130;
131     af.getViewport().showAllHiddenColumns();
132     af.alignPanel.setScrollValues(scrollpos, 5);
133     assertEquals(ranges.getEndRes(), af.getViewport()
134             .getAlignment().getWidth() - 1);
135
136     // now hide some columns, and scroll to position within <width>
137     // distance of the end of the alignment
138     // endRes should be set to width of alignment - 1 - the number of hidden
139     // columns
140     af.getViewport().hideColumns(30, 50);
141     af.alignPanel.setScrollValues(scrollpos, 5);
142     assertEquals(ranges.getEndRes(), af.getViewport()
143             .getAlignment().getWidth() - 1 - 21); // 21 is the number of hidden
144                                                   // columns
145   }
146
147   /**
148    * Test that update layout reverts to original (unwrapped) values for endRes
149    * when switching from wrapped back to unwrapped mode (JAL-2739)
150    */
151   @Test(groups = "Functional")
152   public void testUpdateLayout_endRes()
153   {
154     // get details of original alignment dimensions
155     ViewportRanges ranges = af.getViewport().getRanges();
156     int endres = ranges.getEndRes();
157
158     // wrap
159     af.alignPanel.getAlignViewport().setWrapAlignment(true);
160     af.alignPanel.updateLayout();
161
162     // endRes has changed
163     assertNotEquals(ranges.getEndRes(), endres);
164
165     // unwrap
166     af.alignPanel.getAlignViewport().setWrapAlignment(false);
167     af.alignPanel.updateLayout();
168
169     // endRes back to original value
170     assertEquals(ranges.getEndRes(), endres);
171   }
172
173   /**
174    * Test the variant of calculateIdWidth that only recomputes the width if it is
175    * not already saved in the viewport (initial value is -1)
176    */
177   @Test(groups = "Functional")
178   public void testCalculateIdWidth_noArgs()
179   {
180     AlignViewportI av = af.alignPanel.getAlignViewport();
181     av.setShowJVSuffix(true);
182     av.setFont(new Font("Courier", Font.PLAIN, 15), true);
183
184     av.setIdWidth(0);
185     Dimension d = af.alignPanel.calculateIdWidth();
186     assertEquals(d.width, 0);
187     assertEquals(d.height, 0);
188
189     av.setIdWidth(99);
190     d = af.alignPanel.calculateIdWidth();
191     assertEquals(d.width, 99);
192     assertEquals(d.height, 0);
193
194     /*
195      * note 4 pixels padding are added to the longest sequence name width
196      */
197     av.setIdWidth(-1); // force recalculation
198     d = af.alignPanel.calculateIdWidth();
199     assertEquals(d.width, 166); // 4 + pixel width of "Q93Z60_ARATH/1-118"
200     assertEquals(d.height, 12);
201     assertEquals(d.width, av.getIdWidth());
202   }
203
204   /**
205    * Test the variant of calculateIdWidth that computes the longest of any
206    * sequence name or annotation label width
207    */
208   @Test(groups = "Functional")
209   public void testCalculateIdWidth_withMaxWidth()
210   {
211     AlignViewportI av = af.alignPanel.getAlignViewport();
212     av.setShowJVSuffix(true);
213     av.setFont(new Font("Courier", Font.PLAIN, 15), true);
214     av.setShowAnnotation(false);
215     av.setIdWidth(18);
216
217     /*
218      * note 4 pixels 'padding' are added to the longest seq name/annotation label
219      */
220     Dimension d = af.alignPanel.calculateIdWidth(2000);
221     assertEquals(d.width, 166); // 4 + pixel width of "Q93Z60_ARATH/1-118"
222     assertEquals(d.height, 12); // fixed value (not used?)
223     assertEquals(av.getIdWidth(), 18); // not changed by this method
224
225     /*
226      * make the longest sequence name longer
227      */
228     SequenceI seq = af.viewport.getAlignment()
229             .findSequenceMatch("Q93Z60_ARATH")[0];
230     seq.setName(seq.getName() + "MMMMM");
231     d = af.alignPanel.calculateIdWidth(2000);
232     assertEquals(d.width, 211); // 4 + pixel width of "Q93Z60_ARATHMMMMM/1-118"
233     assertEquals(d.height, 12);
234     assertEquals(av.getIdWidth(), 18); // unchanged
235
236     /*
237      * make the longest annotation name even longer
238      * note this is checked even if annotations are not shown
239      */
240     AlignmentAnnotation aa = av.getAlignment().getAlignmentAnnotation()[0];
241     aa.label = "THIS IS A VERY LONG LABEL INDEED";
242     FontMetrics fmfor = af.alignPanel
243             .getFontMetrics(af.alignPanel.getAlabels().getFont());
244     // Assumption ID_WIDTH_PADDING == 4
245     int expwidth = 4 + fmfor.stringWidth(aa.label);
246     d = af.alignPanel.calculateIdWidth(2000);
247     assertEquals(d.width, expwidth); // 228 == ID_WIDTH_PADDING + pixel width of "THIS IS A VERY LONG LABEL INDEED"
248     assertEquals(d.height, 12);
249
250     /*
251      * override with maxwidth
252      * note the 4 pixels padding is added to this value
253      */
254     d = af.alignPanel.calculateIdWidth(213);
255     assertEquals(d.width, 217);
256     assertEquals(d.height, 12);
257   }
258
259   @Test(groups = { "Functional", "Not-bamboo" })
260   public void testGetVisibleWidth()
261   {
262     /*
263      * width for onscreen rendering is IDPanel width
264      */
265     int w = af.alignPanel.getVisibleIdWidth(true);
266     assertEquals(w, af.alignPanel.getIdPanel().getWidth());
267     assertEquals(w, 115);
268
269     /*
270      * width for offscreen rendering is the same
271      * if no fixed id width is specified in preferences
272      */
273     Cache.setProperty("FIGURE_AUTOIDWIDTH", Boolean.FALSE.toString());
274     Cache.removeProperty("FIGURE_FIXEDIDWIDTH");
275     assertEquals(w, af.alignPanel.getVisibleIdWidth(false));
276
277     /*
278      * preference for fixed id width - note 4 pixels padding is added
279      */
280     Cache.setProperty("FIGURE_FIXEDIDWIDTH", "120");
281     assertEquals(124, af.alignPanel.getVisibleIdWidth(false));
282
283     /*
284      * preference for auto id width overrides fixed width
285      */
286     Cache.setProperty("FIGURE_AUTOIDWIDTH", Boolean.TRUE.toString());
287     assertEquals(115, af.alignPanel.getVisibleIdWidth(false));
288   }
289 }