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