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