d01eaa3cb614f68370af030809ee41e4f3339d79
[jalview.git] / test / jalview / viewmodel / OverviewDimensionsTest.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.viewmodel;
22
23 import static org.testng.Assert.assertEquals;
24 import static org.testng.Assert.assertTrue;
25
26 import jalview.bin.Cache;
27 import jalview.bin.Jalview;
28 import jalview.datamodel.Alignment;
29 import jalview.datamodel.Sequence;
30 import jalview.datamodel.SequenceI;
31 import jalview.gui.AlignFrame;
32 import jalview.gui.AlignViewport;
33 import jalview.io.DataSourceType;
34 import jalview.io.FileLoader;
35
36 import org.testng.annotations.AfterClass;
37 import org.testng.annotations.BeforeMethod;
38 import org.testng.annotations.Test;
39
40 public class OverviewDimensionsTest {
41
42   boolean showConservationSetting;
43
44   SequenceI seq1 = new Sequence(
45           "Seq1",
46           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
47
48   SequenceI seq2 = new Sequence(
49           "Seq2",
50           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
51
52   SequenceI seq3 = new Sequence(
53           "Seq3",
54           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
55
56   SequenceI seq4 = new Sequence(
57           "Seq4",
58           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
59
60   SequenceI seq5 = new Sequence(
61           "Seq5",
62           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
63
64   SequenceI seq6 = new Sequence(
65           "Seq6",
66           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
67
68   SequenceI seq7 = new Sequence(
69           "Seq7",
70           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
71
72   SequenceI seq8 = new Sequence(
73           "Seq8",
74           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
75
76   SequenceI seq9 = new Sequence(
77           "Seq9",
78           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
79
80   SequenceI seq10 = new Sequence(
81           "Seq10",
82           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
83
84   SequenceI seq11 = new Sequence(
85           "Seq11",
86           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
87
88   SequenceI seq12 = new Sequence(
89           "Seq12",
90           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
91
92   SequenceI seq13 = new Sequence(
93           "Seq13",
94           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
95
96   SequenceI seq14 = new Sequence(
97           "Seq14",
98           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
99
100   SequenceI seq15 = new Sequence(
101           "Seq15",
102           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
103
104   SequenceI seq16 = new Sequence(
105           "Seq16",
106           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
107
108   SequenceI seq17 = new Sequence(
109           "Seq17",
110           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
111
112   SequenceI seq18 = new Sequence(
113           "Seq18",
114           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
115
116   SequenceI seq19 = new Sequence(
117           "Seq19",
118           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
119
120   SequenceI seq20 = new Sequence(
121           "Seq20",
122           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
123
124   SequenceI seq21 = new Sequence(
125           "Seq21",
126           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
127
128   SequenceI seq22 = new Sequence(
129           "Seq22",
130           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"
131                   + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"
132                   + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"
133                   + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"
134                   + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
135
136   SequenceI seq23 = new Sequence(
137           "Seq23",
138           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
139
140   AlignFrame af;
141
142   @BeforeMethod(alwaysRun = true)
143   public void setUp()
144   {
145     Jalview.main(new String[] { "-nonews", "-props",
146         "test/jalview/testProps.jvprops" });
147
148     Cache.applicationProperties.setProperty("SHOW_IDENTITY",
149             Boolean.TRUE.toString());
150     af = new FileLoader().LoadFileWaitTillLoaded(
151             "examples/testdata/bigal.fa",
152             DataSourceType.FILE);
153
154     /*
155      * wait for Consensus thread to complete
156      */
157     synchronized (this)
158     {
159       while (af.getViewport().getConsensusSeq() == null)
160       {
161         try
162         {
163           wait(50);
164         } catch (InterruptedException e)
165         {
166         }
167       }
168     }
169     // get cached setting for showConservation
170     // reset it in AfterClass!
171     showConservationSetting = Cache.getDefault("SHOW_CONSERVATION", true);
172   }
173
174
175   @AfterClass(alwaysRun = true)
176   public void tearDown()
177   {
178     Cache.applicationProperties.setProperty("SHOW_CONSERVATION",
179             Boolean.toString(showConservationSetting));
180   }
181
182   /**
183    * Test that the OverviewDimensions constructor sets width and height
184    * correctly
185    */
186   @Test(groups = { "Functional" })
187   public void testConstructor()
188   {
189     SequenceI seqa = new Sequence("Seq1", "ABC");
190     SequenceI seqb = new Sequence("Seq2", "ABC");
191     SequenceI seqc = new Sequence("Seq3", "ABC");
192     SequenceI seqd = new Sequence("Seq4", "ABC");
193     SequenceI seqe = new Sequence("Seq5",
194             "ABCABCABCABCABCABCABCABCBACBACBACBAC");
195
196     int defaultGraphHeight = 20;
197     int maxWidth = 400;
198     int minWidth = 120;
199     int maxSeqHeight = 300;
200     int minSeqHeight = 40;
201
202     Cache.applicationProperties.setProperty("SHOW_CONSERVATION",
203             Boolean.toString(true));
204
205     // test for alignment with width > height
206     SequenceI[] seqs1 = new SequenceI[] { seqa, seqb };
207     Alignment al1 = new Alignment(seqs1);
208     al1.setDataset(null);
209     AlignViewport av1 = new AlignViewport(al1);
210
211     OverviewDimensions od = new OverviewDimensions(av1);
212     int scaledHeight = 266;
213     assertEquals(od.getGraphHeight(), defaultGraphHeight);
214     assertEquals(od.getSequencesHeight(), scaledHeight);
215     assertEquals(od.getWidth(), maxWidth);
216     assertEquals(od.getHeight(), scaledHeight + defaultGraphHeight);
217
218     // test for alignment with width < height
219     SequenceI[] seqs2 = new SequenceI[] { seqa, seqb, seqc, seqd };
220     Alignment al2 = new Alignment(seqs2);
221     al2.setDataset(null);
222     AlignViewport av2 = new AlignViewport(al2);
223
224     od = new OverviewDimensions(av2);
225     int scaledWidth = 300;
226     assertEquals(od.getGraphHeight(), defaultGraphHeight);
227     assertEquals(od.getSequencesHeight(), maxSeqHeight);
228     assertEquals(od.getWidth(), scaledWidth);
229     assertEquals(od.getHeight(), scaledWidth + defaultGraphHeight);
230
231     // test for alignment with width > height and sequence height scaled below
232     // min value
233     SequenceI[] seqs3 = new SequenceI[] { seqe };
234     Alignment al3 = new Alignment(seqs3);
235     al3.setDataset(null);
236     AlignViewport av3 = new AlignViewport(al3);
237
238     od = new OverviewDimensions(av3);
239     assertEquals(od.getGraphHeight(), defaultGraphHeight);
240     assertEquals(od.getSequencesHeight(), minSeqHeight);
241     assertEquals(od.getWidth(), maxWidth);
242     assertEquals(od.getHeight(), minSeqHeight + defaultGraphHeight);
243
244     // test for alignment with width < height and width scaled below min value
245     SequenceI[] seqs4 = new SequenceI[] { seqa, seqb, seqc, seqd, seqa,
246         seqb, seqc, seqd, seqa, seqb, seqc, seqd, seqa, seqb, seqc, seqd };
247     Alignment al4 = new Alignment(seqs4);
248     al4.setDataset(null);
249     AlignViewport av4 = new AlignViewport(al4);
250
251     od = new OverviewDimensions(av4);
252     assertEquals(od.getGraphHeight(), defaultGraphHeight);
253     assertEquals(od.getSequencesHeight(), maxSeqHeight);
254     assertEquals(od.getWidth(), minWidth);
255     assertEquals(od.getHeight(), maxSeqHeight + defaultGraphHeight);
256
257     // test for alignment where no conservation annotation is shown
258     Cache.applicationProperties.setProperty("SHOW_CONSERVATION",
259             Boolean.toString(false));
260
261     Alignment al5 = new Alignment(seqs4);
262     al5.setDataset(null);
263     AlignViewport av5 = new AlignViewport(al5);
264
265     od = new OverviewDimensions(av5);
266     assertEquals(od.getGraphHeight(), 0);
267     assertEquals(od.getSequencesHeight(), maxSeqHeight);
268     assertEquals(od.getWidth(), minWidth);
269     assertEquals(od.getHeight(), maxSeqHeight);
270   }
271
272   /**
273    * Test that validation after mouse adjustments to boxX and boxY sets box
274    * dimensions and scroll values correctly, when there are no hidden rows or
275    * columns.
276    * 
277    * The current implementation uses multiple transformations between coordinate
278    * systems which often involve casting to int, which causes values to be
279    * truncated. As a result we can lose accuracy. The tests below use
280    * approximate test values where appropriate.
281    */
282   @Test(groups = { "Functional" })
283   public void testSetBoxFromMouseClick()
284   {
285     AlignViewport av = af.getViewport();
286     OverviewDimensions od = new OverviewDimensions(av);
287
288     // Initial box sizing - default path through code
289     od.setBoxPosition();
290     float scalew = (float) od.getWidth()
291             / (av.getAlignment().getWidth() * av.getCharWidth());
292     float scaleh = (float) od.getSequencesHeight()
293             / (av.getAlignment().getHeight() * av.getCharHeight());
294     int boxWidth = (int) ((av.getEndRes() - av.getStartRes() + 1)
295             * av.getCharWidth() * scalew);
296     int boxHeight = (int) ((av.getEndSeq() - av.getStartSeq())
297             * av.getCharHeight() * scaleh);
298
299     od.checkValid();
300     assertEquals(od.getBoxX(), 0);
301     assertEquals(od.getBoxY(), 0);
302     assertEquals(od.getBoxWidth(), boxWidth);
303     assertEquals(od.getScrollCol(), 0);
304     assertEquals(od.getScrollRow(), 0);
305
306     // negative boxX value reset to 0
307     mouseClick(od, -5, 10);
308     assertEquals(od.getBoxX(), 0);
309     assertEquals(od.getBoxWidth(), boxWidth);
310     assertEquals(od.getBoxHeight(), boxHeight);
311     assertEquals(od.getScrollRow(),
312             (int) (10 / scaleh / av.getCharHeight()));
313     assertEquals(od.getScrollCol(), 0);
314
315     // negative boxY value reset to 0
316     mouseClick(od, 6, -2);
317     assertEquals(od.getBoxY(), 0);
318     assertEquals(od.getBoxWidth(), boxWidth);
319     assertEquals(od.getBoxHeight(), boxHeight);
320     assertEquals(od.getScrollCol(), (int) (6 / scalew / av.getCharWidth()));
321     assertEquals(od.getScrollRow(), 0);
322
323     // overly large boxX value reset to width-boxWidth
324     mouseClick(od, 100, 6);
325     assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth(), 1.5);
326     assertEquals(od.getBoxY(), 6, 1.5);
327     assertEquals(od.getBoxWidth(), boxWidth);
328     assertEquals(od.getBoxHeight(), boxHeight);
329     assertEquals(od.getScrollCol(),
330             (od.getBoxX() / scalew / av.getCharWidth()), 1.5);
331     assertEquals(od.getScrollRow(),
332             (od.getBoxY() / scaleh / av.getCharHeight()), 1.5);
333
334     // overly large boxY value reset to sequenceHeight - boxHeight
335     mouseClick(od, 10, 520);
336     assertEquals(od.getBoxX(), 10, 1.5);
337     assertEquals(od.getBoxY(), od.getSequencesHeight() - od.getBoxHeight(),
338             1.5);
339     assertEquals(od.getBoxWidth(), boxWidth);
340     assertEquals(od.getBoxHeight(), boxHeight, 1.5);
341     assertEquals(od.getScrollCol(),
342             (od.getBoxX() / scalew / av.getCharWidth()), 1.5);
343     assertEquals(od.getScrollRow(),
344             (od.getBoxY() / scaleh / av.getCharHeight()), 1.5);
345
346     // click past end of alignment, as above
347     mouseClick(od, 3000, 5);
348     assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth(), 1.5);
349     assertEquals(od.getBoxWidth(), boxWidth);
350     assertEquals(od.getBoxHeight(), boxHeight, 1.5);
351     assertEquals(od.getScrollCol(),
352             (od.getBoxX() / scalew / av.getCharWidth()), 1.5);
353     assertEquals(od.getScrollRow(),
354             (od.getBoxY() / scaleh / av.getCharHeight()), 1.5);
355
356     // move viewport so startRes non-zero and then mouseclick
357     moveViewportH(av, od, 50);
358
359     // click at viewport position
360     int oldboxx = od.getBoxX();
361     int oldboxy = od.getBoxY();
362     mouseClick(od, od.getBoxX() + 5, od.getBoxY() + 2);
363     assertEquals(od.getBoxX(), oldboxx + 5, 1.5);
364     assertEquals(od.getBoxWidth(), boxWidth);
365     assertEquals(od.getBoxHeight(), boxHeight, 1.5);
366     assertEquals(od.getScrollCol(),
367             (od.getBoxX() / scalew / av.getCharWidth()), 1.5);
368     assertEquals(od.getBoxY(), oldboxy + 2, 1.5);
369     assertEquals(od.getScrollRow(),
370             (od.getBoxY() / scaleh / av.getCharHeight()), 1.5);
371
372     // click at top corner
373     mouseClick(od, 0, 0);
374     assertEquals(od.getBoxX(), 0);
375     assertEquals(od.getScrollCol(), 0);
376     assertEquals(od.getBoxY(), 0);
377     assertEquals(od.getScrollRow(), 0);
378     assertEquals(od.getBoxWidth(), boxWidth);
379     assertEquals(od.getBoxHeight(), boxHeight, 1.5);
380   }
381
382   /**
383    * Test setting of the box position, when there are hidden cols at the start
384    * of the alignment
385    */
386   @Test(groups = { "Functional" })
387   public void testFromMouseWithHiddenColsAtStart()
388   {
389     AlignViewport av = af.getViewport();
390     OverviewDimensions od = new OverviewDimensions(av);
391
392     // Initial box sizing - default path through code
393     od.setBoxPosition();
394     float scalew = (float) od.getWidth()
395             / (av.getAlignment().getWidth() * av.getCharWidth());
396     float scaleh = (float) od.getSequencesHeight()
397             / (av.getAlignment().getHeight() * av.getCharHeight());
398     int boxWidth = (int) ((av.getEndRes() - av.getStartRes() + 1)
399             * av.getCharWidth() * scalew);
400     int boxHeight = (int) ((av.getEndSeq() - av.getStartSeq())
401             * av.getCharHeight() * scaleh);
402
403     od.checkValid();
404     assertEquals(od.getBoxX(), 0);
405     assertEquals(od.getBoxY(), 0);
406     assertEquals(od.getBoxWidth(), boxWidth);
407     assertEquals(od.getScrollCol(), 0);
408     assertEquals(od.getScrollRow(), 0);
409
410     // hide cols at start and check updated box position is correct
411     // changes boxX but not boxwidth
412     int lastHiddenCol = 30;
413     av.hideColumns(0, lastHiddenCol);
414     od.setBoxPosition();
415     assertEquals(od.getBoxX(),
416             (int) ((lastHiddenCol + 1) * scalew * av.getCharWidth()));
417     assertEquals(od.getBoxWidth(), boxWidth);
418     assertEquals(od.getBoxHeight(), boxHeight);
419
420     // try to click in hidden cols, check box does not move
421     int xpos = 10;
422     mouseClick(od, xpos, 0);
423     assertEquals(od.getBoxX(),
424             (int) ((lastHiddenCol + 1) * scalew * av.getCharWidth()));
425     assertEquals(od.getBoxY(), 0);
426     assertEquals(od.getBoxWidth(), boxWidth);
427     assertEquals(od.getBoxHeight(), boxHeight);
428     assertEquals(od.getScrollRow(), 0);
429     assertEquals(od.getScrollCol(),
430             (int) (xpos / scalew / av.getCharWidth()));
431
432     // click to right of hidden columns, box moves to click point
433     xpos = 40;
434     mouseClick(od, xpos, 0);
435     assertEquals(od.getBoxX(),
436             (int) ((xpos - lastHiddenCol) * scalew * av.getCharWidth()));
437     assertEquals(od.getBoxY(), 0);
438     assertEquals(od.getBoxWidth(), boxWidth);
439     assertEquals(od.getBoxHeight(), boxHeight);
440     assertEquals(od.getScrollRow(), 0);
441     assertEquals(od.getScrollCol(),
442             (int) (xpos / scalew / av.getCharWidth()));
443
444     // click to right of hidden columns such that box runs over right hand side
445     // of alignment
446     // box position is adjusted away from the edge
447     // overly large boxX value reset to width-boxWidth
448     xpos = 100;
449     mouseClick(od, xpos, 5);
450     assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth()
451             - ((int) (lastHiddenCol * scalew * av.getCharWidth())));
452     assertEquals(od.getBoxY(), 5);
453     assertEquals(od.getBoxWidth(), boxWidth);
454     assertEquals(od.getBoxHeight(), boxHeight);
455     assertEquals(od.getScrollCol(),
456             (int) (xpos / scalew / av.getCharWidth()));
457     assertEquals(od.getScrollRow(),
458             (int) (od.getBoxY() / scaleh / av.getCharHeight()));
459
460   }
461
462   @Test(groups = { "Functional" })
463   public void testSetBoxPosWithHiddenColsAtEnd()
464   {
465
466   }
467
468   @Test(groups = { "Functional" })
469   public void testSetBoxPosWithHiddenColsMiddle()
470   {
471     AlignViewport av = af.getViewport();
472     OverviewDimensions od = new OverviewDimensions(av);
473     av.setStartRes(50);
474
475     // hiding columns before current position: changes boxX but not boxwidth
476     od.setBoxPosition();
477     int prevBoxX = od.getBoxX();
478     int prevWidth = od.getBoxWidth();
479
480     av.hideColumns(10, 20);
481     od.setBoxPosition();
482     assertEquals(od.getBoxX(), 75);
483     assertTrue(prevBoxX < od.getBoxX());
484     assertEquals(od.getBoxWidth(), prevWidth);
485
486     // hiding columns after current position: changes end position but not start
487     // so scrollCol and boxX do not change but boxWidth does
488     prevWidth = od.getBoxWidth();
489
490     av.hideColumns(108, 110);
491     od.setBoxPosition();
492     assertEquals(od.getBoxX(), prevBoxX);
493     assertEquals(od.getScrollCol(), 49);
494     // assertEquals(od2.getBoxWidth(), prevWidth + ((int) 2 * av.getCharWidth()
495     // / scalew));
496   }
497
498   @Test(groups = { "Functional" })
499   public void testSetBoxPosWithHiddenRowsAtStart()
500   {
501     AlignViewport av = af.getViewport();
502     OverviewDimensions od = new OverviewDimensions(av);
503     av.setStartRes(50);
504
505     // account for hidden rows
506     SequenceI[] hidden = { seq2, seq3, seq4, seq5, seq6, seq7 };
507     av.showAllHiddenColumns();
508     av.hideSequence(hidden);
509     od.checkValid();
510     assertEquals(od.getBoxY(), 0);
511     assertEquals(od.getScrollRow(), 0);
512   }
513
514   /**
515    * Test that the box position is set correctly when set from the viewport,
516    * with no hidden rows or columns
517    */
518   @Test(groups = { "Functional" })
519   public void testSetBoxFromViewport()
520   {
521     AlignViewport av = af.getViewport();
522     OverviewDimensions od = new OverviewDimensions(av);
523     od.setBoxPosition();
524
525     float scalew = (float) od.getWidth()
526             / (av.getAlignment().getWidth() * av.getCharWidth());
527     float scaleh = (float) od.getSequencesHeight()
528             / (av.getAlignment().getHeight() * av.getCharHeight());
529     int boxWidth = (int) ((av.getEndRes() - av.getStartRes() + 1)
530             * av.getCharWidth() * scalew);
531     int boxHeight = (int) ((av.getEndSeq() - av.getStartSeq())
532             * av.getCharHeight() * scaleh);
533
534     // move viewport to start of alignment
535     moveViewport(av, od, 0, 0);
536     assertEquals(od.getBoxX(), 0);
537     assertEquals(od.getBoxY(), 0);
538     assertEquals(od.getBoxWidth(), boxWidth);
539     assertEquals(od.getBoxHeight(), boxHeight);
540
541     // move viewport to right
542     moveViewportH(av, od, 70);
543     assertEquals(od.getBoxX(), (int) (70 * scalew * av.getCharWidth()));
544     assertEquals(od.getBoxY(), 0);
545     assertEquals(od.getBoxWidth(), boxWidth);
546     assertEquals(od.getBoxHeight(), boxHeight);
547
548     // move viewport down
549     moveViewportV(av, od, 100);
550     assertEquals(od.getBoxX(), (int) (70 * scalew * av.getCharWidth()));
551     assertEquals(od.getBoxY(), (int) (100 * scaleh * av.getCharHeight()));
552     assertEquals(od.getBoxWidth(), boxWidth);
553     assertEquals(od.getBoxHeight(), boxHeight);
554
555     // move viewport to bottom right
556     moveViewport(av, od, 98, 508);
557     assertEquals(od.getBoxX(), (int) (98 * scalew * av.getCharWidth()));
558     assertEquals(od.getBoxY(), (int) (508 * scaleh * av.getCharHeight()));
559     assertEquals(od.getBoxWidth(), boxWidth);
560     assertEquals(od.getBoxHeight(), boxHeight);
561   }
562
563   /*
564    * Move viewport horizontally: startRes + previous width gives new horizontal extent. Vertical extent stays the same.
565    */
566   private void moveViewportH(AlignViewport av, OverviewDimensions od,
567           int startRes)
568   {
569     int width = av.getEndRes() - av.getStartRes();
570     av.setStartRes(startRes);
571     av.setEndRes(startRes + width);
572     od.setBoxPosition();
573   }
574
575   /*
576    * Move viewport vertically: startSeq and endSeq give new vertical extent. Horizontal extent stays the same.
577    */
578   private void moveViewportV(AlignViewport av, OverviewDimensions od,
579           int startSeq)
580   {
581     int height = av.getEndSeq() - av.getStartSeq();
582     av.setStartSeq(startSeq);
583     av.setEndSeq(startSeq + height);
584     od.setBoxPosition();
585   }
586
587   /*
588    * Move viewport horizontally and vertically.
589    */
590   private void moveViewport(AlignViewport av, OverviewDimensions od,
591           int startRes, int startSeq)
592   {
593     int width = av.getEndRes() - av.getStartRes();
594     int height = av.getEndSeq() - av.getStartSeq();
595     av.setStartRes(startRes);
596     av.setEndRes(startRes + width);
597     av.setStartSeq(startSeq);
598     av.setEndSeq(startSeq + height);
599     od.setBoxPosition();
600   }
601
602   /*
603    * Mouse click as position x,y in overview window
604    */
605   private void mouseClick(OverviewDimensions od, int x, int y)
606   {
607     od.setBoxX(x);
608     od.setBoxY(y);
609     od.checkValid();
610     // updates require an OverviewPanel to exist which it doesn't here
611     // so call setBoxPosition() as it would be called by the AlignmentPanel
612     // normally
613     AlignViewport av = af.getViewport();
614     int width = av.getEndRes() - av.getStartRes();
615     int height = av.getEndSeq() - av.getStartSeq();
616     av.setStartRes(od.getScrollCol());
617     av.setEndRes(od.getScrollCol() + width);
618     av.setStartSeq(od.getScrollRow());
619     av.setEndSeq(od.getScrollRow() + height);
620     od.setBoxPosition();
621   }
622 }