JAL-2388 Fixed inherited&new out-by-one errors; further unit tests
[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
25 import jalview.analysis.AlignmentGenerator;
26 import jalview.bin.Jalview;
27 import jalview.datamodel.Alignment;
28 import jalview.datamodel.AlignmentI;
29 import jalview.datamodel.Sequence;
30 import jalview.datamodel.SequenceGroup;
31 import jalview.datamodel.SequenceI;
32 import jalview.gui.AlignFrame;
33 import jalview.gui.AlignViewport;
34 import jalview.gui.Desktop;
35 import jalview.gui.JvOptionPane;
36 import jalview.io.DataSourceType;
37 import jalview.io.FileLoader;
38
39 import java.util.List;
40
41 import org.testng.annotations.AfterClass;
42 import org.testng.annotations.AfterMethod;
43 import org.testng.annotations.BeforeClass;
44 import org.testng.annotations.BeforeMethod;
45 import org.testng.annotations.Test;
46
47 @Test(singleThreaded = true)
48 public class OverviewDimensionsTest {
49
50   SequenceI seq1 = new Sequence(
51           "Seq1",
52           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
53
54   SequenceI seq2 = new Sequence(
55           "Seq2",
56           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
57
58   SequenceI seq3 = new Sequence(
59           "Seq3",
60           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
61
62   SequenceI seq4 = new Sequence(
63           "Seq4",
64           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
65
66   SequenceI seq5 = new Sequence(
67           "Seq5",
68           "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC");
69
70   AlignFrame af;
71   AlignViewport av;
72   AlignmentI al;
73   OverviewDimensions od;
74
75   // cached widths and heights
76   int boxWidth;
77   int boxHeight;
78   int viewHeight;
79   int viewWidth;
80   int alheight;
81   int alwidth;
82
83   @BeforeClass(alwaysRun = true)
84   public void setUpJvOptionPane()
85   {
86     JvOptionPane.setInteractiveMode(false);
87     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
88
89     // create random alignment
90     AlignmentGenerator gen = new AlignmentGenerator(false);
91     al = gen.generate(157, 525, 123, 5, 5);
92   }
93
94   @BeforeMethod(alwaysRun = true)
95   public void setUp()
96   {
97     Jalview.main(new String[] { "-nonews", "-props",
98         "test/jalview/testProps.jvprops" });
99
100     af = new FileLoader().LoadFileWaitTillLoaded(al.toString(),
101             DataSourceType.PASTE);
102
103     /*
104      * wait for Consensus thread to complete
105      */
106     synchronized (this)
107     {
108       while (af.getViewport().getConsensusSeq() == null)
109       {
110         try
111         {
112           wait(50);
113         } catch (InterruptedException e)
114         {
115         }
116       }
117     }
118     
119     av = af.getViewport();
120
121
122
123     while (av.isCalcInProgress())
124     {
125       try
126       {
127         Thread.sleep(50);
128       } catch (InterruptedException e)
129       {
130
131       }
132     }
133
134     av.showAllHiddenColumns();
135     av.showAllHiddenSeqs();
136     av.setSelectionGroup(null);
137     // o/w hidden seqs retain selection group, causes problems later when hiding
138     // sequences
139
140     // wait for conservation calc to complete again
141     while (av.isCalcInProgress())
142     {
143       try
144       {
145         Thread.sleep(50);
146       } catch (InterruptedException e)
147       {
148
149       }
150     }
151
152     viewHeight = av.getEndSeq() - av.getStartSeq() + 1;
153     viewWidth = av.getEndRes() - av.getStartRes() + 1;
154
155     // wait for gui to get set up
156     // this does actually appear to be necessary
157     while (viewHeight != 18 || viewWidth != 63)
158     {
159       try
160       {
161         Thread.sleep(50);
162         av.getAlignPanel().setScrollValues(0, 1);
163         av.getAlignPanel().setScrollValues(1, 0);
164         viewHeight = av.getEndSeq() - av.getStartSeq() + 1;
165         viewWidth = av.getEndRes() - av.getStartRes() + 1;
166       } catch (InterruptedException e)
167       {
168
169       }
170     }
171
172     od = new OverviewDimensions(av.getPosProps(), true);
173     // Initial box sizing - default path through code
174     od.setBoxPosition(av.getAlignment().getHiddenSequences(),
175             av.getColumnSelection(), av.getPosProps());
176
177     mouseClick(od, 0, 0);
178     moveViewport(0, 0);
179
180     // calculate before hidden columns so we get absolute values
181     alheight = av.getAlignment().getHeight();
182     alwidth = av.getAlignment().getWidth();
183
184     boxWidth = Math.round((float) (av.getEndRes() - av.getStartRes() + 1)
185             * od.getWidth() / alwidth);
186     boxHeight = Math.round((float) (av.getEndSeq() - av.getStartSeq() + 1)
187             * od.getSequencesHeight() / alheight);
188     System.out.println(boxHeight);
189
190   }
191
192   @AfterMethod(alwaysRun = true)
193   public void tearDown()
194   {
195     af = null;
196     av = null;
197     Desktop.instance.closeAll_actionPerformed(null);
198   }
199
200   @AfterClass(alwaysRun = true)
201   public void cleanUp()
202   {
203     al = null;
204   }
205
206   /**
207    * Test that the OverviewDimensions constructor sets width and height
208    * correctly
209    */
210   @Test(groups = { "Functional" })
211   public void testConstructor()
212   {
213     SequenceI seqa = new Sequence("Seq1", "ABC");
214     SequenceI seqb = new Sequence("Seq2", "ABC");
215     SequenceI seqc = new Sequence("Seq3", "ABC");
216     SequenceI seqd = new Sequence("Seq4", "ABC");
217     SequenceI seqe = new Sequence("Seq5",
218             "ABCABCABCABCABCABCABCABCBACBACBACBAC");
219
220     int defaultGraphHeight = 20;
221     int maxWidth = 400;
222     int minWidth = 120;
223     int maxSeqHeight = 300;
224     int minSeqHeight = 40;
225
226     // test for alignment with width > height
227     SequenceI[] seqs1 = new SequenceI[] { seqa, seqb };
228     Alignment al1 = new Alignment(seqs1);
229     al1.setDataset(null);
230     AlignViewport av1 = new AlignViewport(al1);
231
232     OverviewDimensions od = new OverviewDimensions(av1.getPosProps(), true);
233     int scaledHeight = 266;
234     assertEquals(od.getGraphHeight(), defaultGraphHeight);
235     assertEquals(od.getSequencesHeight(), scaledHeight);
236     assertEquals(od.getWidth(), maxWidth);
237     assertEquals(od.getHeight(), scaledHeight + defaultGraphHeight);
238
239     // test for alignment with width < height
240     SequenceI[] seqs2 = new SequenceI[] { seqa, seqb, seqc, seqd };
241     Alignment al2 = new Alignment(seqs2);
242     al2.setDataset(null);
243     AlignViewport av2 = new AlignViewport(al2);
244
245     od = new OverviewDimensions(av2.getPosProps(), true);
246     int scaledWidth = 300;
247     assertEquals(od.getGraphHeight(), defaultGraphHeight);
248     assertEquals(od.getSequencesHeight(), maxSeqHeight);
249     assertEquals(od.getWidth(), scaledWidth);
250     assertEquals(od.getHeight(), scaledWidth + defaultGraphHeight);
251
252     // test for alignment with width > height and sequence height scaled below
253     // min value
254     SequenceI[] seqs3 = new SequenceI[] { seqe };
255     Alignment al3 = new Alignment(seqs3);
256     al3.setDataset(null);
257     AlignViewport av3 = new AlignViewport(al3);
258
259     od = new OverviewDimensions(av3.getPosProps(), true);
260     assertEquals(od.getGraphHeight(), defaultGraphHeight);
261     assertEquals(od.getSequencesHeight(), minSeqHeight);
262     assertEquals(od.getWidth(), maxWidth);
263     assertEquals(od.getHeight(), minSeqHeight + defaultGraphHeight);
264
265     // test for alignment with width < height and width scaled below min value
266     SequenceI[] seqs4 = new SequenceI[] { seqa, seqb, seqc, seqd, seqa,
267         seqb, seqc, seqd, seqa, seqb, seqc, seqd, seqa, seqb, seqc, seqd };
268     Alignment al4 = new Alignment(seqs4);
269     al4.setDataset(null);
270     AlignViewport av4 = new AlignViewport(al4);
271
272     od = new OverviewDimensions(av4.getPosProps(), true);
273     assertEquals(od.getGraphHeight(), defaultGraphHeight);
274     assertEquals(od.getSequencesHeight(), maxSeqHeight);
275     assertEquals(od.getWidth(), minWidth);
276     assertEquals(od.getHeight(), maxSeqHeight + defaultGraphHeight);
277
278     Alignment al5 = new Alignment(seqs4);
279     al5.setDataset(null);
280     AlignViewport av5 = new AlignViewport(al5);
281
282     od = new OverviewDimensions(av5.getPosProps(), false);
283     assertEquals(od.getGraphHeight(), 0);
284     assertEquals(od.getSequencesHeight(), maxSeqHeight);
285     assertEquals(od.getWidth(), minWidth);
286     assertEquals(od.getHeight(), maxSeqHeight);
287   }
288
289   /**
290    * Test that validation after mouse adjustments to boxX and boxY sets box
291    * dimensions and scroll values correctly, when there are no hidden rows or
292    * columns.
293    * 
294    * The current implementation uses multiple transformations between coordinate
295    * systems which often involve casting to int, which causes values to be
296    * truncated. As a result we can lose accuracy. The tests below use
297    * approximate test values where appropriate.
298    */
299   @Test(groups = { "Functional" })
300   public void testSetBoxFromMouseClick()
301   {
302     od.updateViewportFromMouse(0, 0,
303             av.getAlignment().getHiddenSequences(),
304             av.getColumnSelection(), av.getPosProps());
305     assertEquals(od.getBoxX(), 0);
306     assertEquals(od.getBoxY(), 0);
307     assertEquals(od.getBoxWidth(), boxWidth);
308     assertEquals(od.getScrollCol(), 0);
309     assertEquals(od.getScrollRow(), 0);
310
311     // negative boxX value reset to 0
312     mouseClick(od, -5, 10);
313     assertEquals(od.getBoxX(), 0);
314     assertEquals(od.getBoxWidth(), boxWidth);
315     assertEquals(od.getBoxHeight(), boxHeight);
316     assertEquals(od.getScrollRow(),
317             Math.round((float) 10 * alheight / od.getSequencesHeight()));
318     assertEquals(od.getScrollCol(), 0);
319
320     // negative boxY value reset to 0
321     mouseClick(od, 6, -2);
322     assertEquals(od.getBoxY(), 0);
323     assertEquals(od.getBoxWidth(), boxWidth);
324     assertEquals(od.getBoxHeight(), boxHeight);
325     assertEquals(od.getScrollCol(),
326             Math.round((float) 6 * alwidth / od.getWidth()));
327     assertEquals(od.getScrollRow(), 0);
328
329     // overly large boxX value reset to width-boxWidth
330     mouseClick(od, 100, 6);
331     assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth() + 1);
332     assertEquals(od.getBoxY(), 6);
333     assertEquals(od.getBoxWidth(), boxWidth);
334     assertEquals(od.getBoxHeight(), boxHeight);
335     assertEquals(od.getScrollCol(),
336             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
337     assertEquals(od.getScrollRow(),
338             Math.round((float) od.getBoxY() * alheight
339                     / od.getSequencesHeight()));
340
341     // overly large boxY value reset to sequenceHeight - boxHeight
342     mouseClick(od, 10, 520);
343     assertEquals(od.getBoxX(), 10);
344     assertEquals(od.getBoxY(), od.getSequencesHeight() - od.getBoxHeight());
345     assertEquals(od.getBoxWidth(), boxWidth);
346     assertEquals(od.getBoxHeight(), boxHeight);
347     assertEquals(od.getScrollCol(),
348             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
349     assertEquals(od.getScrollRow(),
350             Math.round((float) od.getBoxY() * alheight
351                     / od.getSequencesHeight()));
352
353     // click past end of alignment, as above
354     mouseClick(od, 3000, 5);
355     assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth() + 1);
356     assertEquals(od.getBoxWidth(), boxWidth);
357     assertEquals(od.getBoxHeight(), boxHeight);
358     assertEquals(od.getScrollCol(),
359             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
360     assertEquals(od.getScrollRow(),
361             Math.round((float) od.getBoxY() * alheight
362                     / od.getSequencesHeight()));
363
364     // move viewport so startRes non-zero and then mouseclick
365     moveViewportH(50);
366
367     // click at viewport position
368     int oldboxx = od.getBoxX();
369     int oldboxy = od.getBoxY();
370     mouseClick(od, od.getBoxX() + 5, od.getBoxY() + 2);
371     assertEquals(od.getBoxX(), oldboxx + 5);
372     assertEquals(od.getBoxWidth(), boxWidth);
373     assertEquals(od.getBoxHeight(), boxHeight);
374     assertEquals(od.getScrollCol(),
375             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
376     assertEquals(od.getBoxY(), oldboxy + 2);
377     assertEquals(od.getScrollRow(),
378             Math.round((float) od.getBoxY() * alheight
379                     / od.getSequencesHeight()));
380
381     // click at top corner
382     mouseClick(od, 0, 0);
383     assertEquals(od.getBoxX(), 0);
384     assertEquals(od.getScrollCol(), 0);
385     assertEquals(od.getBoxY(), 0);
386     assertEquals(od.getScrollRow(), 0);
387     assertEquals(od.getBoxWidth(), boxWidth);
388     assertEquals(od.getBoxHeight(), boxHeight);
389   }
390
391   /**
392    * Test setting of the box position, when there are hidden cols at the start
393    * of the alignment
394    */
395   @Test(groups = { "Functional" })
396   public void testFromMouseWithHiddenColsAtStart()
397   {
398     od.updateViewportFromMouse(0, 0,
399             av.getAlignment().getHiddenSequences(),
400             av.getColumnSelection(), av.getPosProps());
401     assertEquals(od.getBoxX(), 0);
402     assertEquals(od.getBoxY(), 0);
403     assertEquals(od.getBoxWidth(), boxWidth);
404     assertEquals(od.getScrollCol(), 0);
405     assertEquals(od.getScrollRow(), 0);
406
407     // hide cols at start and check updated box position is correct
408     // changes boxX but not boxwidth
409     int lastHiddenCol = 30;
410     hideColumns(0, lastHiddenCol);
411
412     od.setBoxPosition(av.getAlignment()
413             .getHiddenSequences(), av.getColumnSelection(), av.getPosProps());
414     assertEquals(od.getBoxX(),
415             Math.round((float) (lastHiddenCol + 1) * od.getWidth()
416                     / alwidth));
417     assertEquals(od.getBoxWidth(), boxWidth);
418     assertEquals(od.getBoxHeight(), boxHeight);
419
420     // try to click in hidden cols, check box does not move
421     // this test currently fails as the overview box does not behave like this!
422     int xpos = 10;
423     mouseClick(od, xpos, 0);
424     assertEquals(
425             od.getBoxX(),
426             Math.round((float) (lastHiddenCol + 1) * od.getWidth()
427                     / alwidth));
428     assertEquals(od.getBoxY(), 0);
429     assertEquals(od.getBoxWidth(), boxWidth);
430     assertEquals(od.getBoxHeight(), boxHeight);
431     assertEquals(od.getScrollRow(), 0);
432     assertEquals(od.getScrollCol(), 0);
433
434     // click to right of hidden columns, box moves to click point
435     testBoxIsAtClickPoint(40, 0);
436     assertEquals(od.getScrollRow(), 0);
437     assertEquals(od.getScrollCol(),
438             Math.round((float) 40 * alwidth / od.getWidth())
439                     - (lastHiddenCol + 1));
440
441     // click to right of hidden columns such that box runs over right hand side
442     // of alignment
443     // box position is adjusted away from the edge
444     // overly large boxX value reset to width-boxWidth
445     xpos = 100;
446     mouseClick(od, xpos, 5);
447     assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth() + 1);
448     assertEquals(od.getBoxY(), 5);
449     assertEquals(od.getBoxWidth(), boxWidth);
450     assertEquals(od.getBoxHeight(), boxHeight);
451     assertEquals(od.getScrollCol(),
452             Math.round((float) od.getBoxX() * alwidth / od.getWidth())
453                     - (lastHiddenCol + 1));
454     assertEquals(od.getScrollRow(),
455             Math.round((float) od.getBoxY() * alheight
456                     / od.getSequencesHeight()));
457   }
458
459   /**
460    * Test setting of the box position, when there are hidden cols in the middle
461    * of the alignment
462    */
463   @Test(groups = { "Functional" })
464   public void testFromMouseWithHiddenColsInMiddle()
465   {
466     od.updateViewportFromMouse(0, 0,
467             av.getAlignment().getHiddenSequences(),
468             av.getColumnSelection(), av.getPosProps());
469     assertEquals(od.getBoxX(), 0);
470     assertEquals(od.getBoxY(), 0);
471     assertEquals(od.getBoxWidth(), boxWidth);
472     assertEquals(od.getScrollCol(), 0);
473     assertEquals(od.getScrollRow(), 0);
474     
475     // hide columns 63-73, no change to box position or dimensions
476     int firstHidden = 63;
477     int lastHidden = 73;
478     hideColumns(firstHidden, lastHidden);
479
480     od.setBoxPosition(av.getAlignment()
481             .getHiddenSequences(), av.getColumnSelection(), av.getPosProps());
482     assertEquals(od.getBoxX(), 0);
483     assertEquals(od.getBoxY(), 0);
484     assertEquals(od.getBoxWidth(), boxWidth);
485     assertEquals(od.getScrollCol(), 0);
486     assertEquals(od.getScrollRow(), 0);
487
488     // move box so that it overlaps with hidden cols on one side
489     // box width changes, boxX and scrollCol as for unhidden case
490     int xpos = 55 - boxWidth; // 55 is position in overview approx halfway
491                               // between cols 60 and 70
492     mouseClick(od, xpos, 0);
493     assertEquals(od.getBoxX(), xpos);
494     assertEquals(od.getBoxY(), 0);
495     assertEquals(
496             od.getBoxWidth(),
497             Math.round(boxWidth + (float) (lastHidden - firstHidden + 1)
498                     * od.getWidth() / alwidth));
499     assertEquals(od.getBoxHeight(), boxHeight);
500     assertEquals(od.getScrollCol(),
501             Math.round(xpos * alwidth / od.getWidth()));
502     assertEquals(od.getScrollRow(), 0);
503
504     // move box so that it completely covers hidden cols
505     // box width changes, boxX and scrollCol as for hidden case
506     xpos = 33;
507     mouseClick(od, xpos, 0);
508     assertEquals(od.getBoxX(), xpos);
509     assertEquals(od.getBoxY(), 0);
510     assertEquals(
511             od.getBoxWidth(),
512             Math.round(boxWidth + (float) (lastHidden - firstHidden + 1)
513                     * od.getWidth() / alwidth));
514     assertEquals(od.getBoxHeight(), boxHeight);
515     assertEquals(od.getScrollCol(),
516             Math.round((float) xpos * alwidth / od.getWidth()));
517     assertEquals(od.getScrollRow(), 0);
518
519     // move box so boxX is in hidden cols, box overhangs at right
520     // boxX and scrollCol at left of hidden area, box width extends across
521     // hidden region
522     xpos = 50;
523     mouseClick(od, xpos, 0);
524     assertEquals(od.getBoxX(),
525             Math.round((float) (firstHidden - 1) * od.getWidth() / alwidth));
526     assertEquals(od.getBoxY(), 0);
527     assertEquals(
528             od.getBoxWidth(),
529             boxWidth
530                     + Math.round((float) (lastHidden - firstHidden + 1)
531                             * od.getWidth() / alwidth));
532     assertEquals(od.getBoxHeight(), boxHeight);
533     assertEquals(od.getScrollCol(), firstHidden - 1);
534     assertEquals(od.getScrollRow(), 0);
535
536     // move box so boxX is to right of hidden cols, but does not go beyond full
537     // width of alignment
538     // box width, boxX and scrollCol all as for non-hidden case
539     xpos = 75;
540     testBoxIsAtClickPoint(xpos, 0);
541     assertEquals(od.getScrollRow(), 0);
542     assertEquals(od.getScrollCol(),
543             Math.round(xpos * alwidth / od.getWidth())
544                     - (lastHidden - firstHidden + 1));
545     
546     // move box so it goes beyond full width of alignment
547     // boxX, scrollCol adjusted back, box width normal
548     xpos = 3000;
549     mouseClick(od, xpos, 5);
550     assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth() + 1);
551     assertEquals(od.getBoxY(), 5);
552     assertEquals(od.getBoxWidth(), boxWidth);
553     assertEquals(od.getBoxHeight(), boxHeight);
554     assertEquals(od.getScrollCol(),
555             Math.round(((float) od.getBoxX() * alwidth / od.getWidth())
556                     - (lastHidden - firstHidden + 1)));
557     assertEquals(od.getScrollRow(),
558             Math.round((float) od.getBoxY() * alheight
559                     / od.getSequencesHeight()));
560
561   }
562
563   /**
564    * Test setting of the box position, when there are hidden cols at the end of
565    * the alignment
566    */
567   @Test(groups = { "Functional" })
568   public void testFromMouseWithHiddenColsAtEnd()
569   {
570     od.updateViewportFromMouse(0, 0,
571             av.getAlignment().getHiddenSequences(),
572             av.getColumnSelection(), av.getPosProps());
573     assertEquals(od.getBoxX(), 0);
574     assertEquals(od.getBoxY(), 0);
575     assertEquals(od.getBoxWidth(), boxWidth);
576     assertEquals(od.getScrollCol(), 0);
577     assertEquals(od.getScrollRow(), 0);
578
579     // hide columns 140-164, no change to box position or dimensions
580     int firstHidden = 140;
581     int lastHidden = 164;
582     hideColumns(firstHidden, lastHidden);
583     od.setBoxPosition(av.getAlignment()
584             .getHiddenSequences(), av.getColumnSelection(), av.getPosProps());
585     assertEquals(od.getBoxX(), 0);
586     assertEquals(od.getBoxY(), 0);
587     assertEquals(od.getBoxWidth(), boxWidth);
588     assertEquals(od.getScrollCol(), 0);
589     assertEquals(od.getScrollRow(), 0);
590
591     // click to left of hidden cols, without overlapping
592     // boxX, scrollCol and width as normal
593     int xpos = 5;
594     testBoxIsAtClickPoint(xpos, 0);
595     assertEquals(od.getScrollRow(), 0);
596     assertEquals(od.getScrollCol(),
597             Math.round((float) xpos * alwidth / od.getWidth()));
598
599     // click to left of hidden cols, with overlap
600     // boxX and scrollCol adjusted for hidden cols, width normal
601     /*    xpos = Math.round((float) 145 * od.getWidth() / alwidth) - boxWidth;
602         mouseClick(od, xpos, 0);
603         assertEquals(
604                 od.getBoxX(),
605                 Math.round((firstHidden - 1) * od.getWidth() / alwidth)
606                         - boxWidth);
607         assertEquals(od.getBoxY(), 0);
608         assertEquals(od.getBoxWidth(), boxWidth);
609         assertEquals(od.getBoxHeight(), boxHeight);
610         assertEquals(od.getScrollCol(),
611                 Math.round(od.getBoxX() * alwidth / od.getWidth()));
612         assertEquals(od.getScrollRow(), 0);
613     */
614     // click in hidden cols
615     // boxX and scrollCol adjusted for hidden cols, width normal
616     // TODO breaks as above test
617     /*xpos = 115;
618     assertEquals(
619             od.getBoxX(),
620             Math.round((firstHidden - 1) * scalew * av.getCharWidth())
621                     - od.getBoxWidth());
622     assertEquals(od.getBoxY(), 0);
623     assertEquals(od.getBoxWidth(), boxWidth);
624     assertEquals(od.getBoxHeight(), boxHeight);
625     assertEquals(od.getScrollCol(),
626             Math.round(od.getBoxX() * alwidth / od.getWidth()));
627     assertEquals(od.getScrollRow(), 0);*/
628
629     // click off end of alignment
630     // boxX and scrollCol adjusted for hidden cols, width normal
631     // TODO breaks as above test
632     /*    xpos = 3000;
633         assertEquals(
634                 od.getBoxX(),
635                 Math.round((firstHidden - 1) * scalew * av.getCharWidth())
636                         - od.getBoxWidth());
637         assertEquals(od.getBoxY(), 0);
638         assertEquals(od.getBoxWidth(), boxWidth);
639         assertEquals(od.getBoxHeight(), boxHeight);
640         assertEquals(od.getScrollCol(),
641                 Math.round(od.getBoxX() * alwidth / od.getWidth()));
642         assertEquals(od.getScrollRow(), 0);*/
643   }
644
645   /**
646    * Test that the box position is set correctly when set from the viewport,
647    * with no hidden rows or columns
648    */
649   @Test(groups = { "Functional" })
650   public void testSetBoxFromViewport()
651   {
652     // move viewport to start of alignment
653     moveViewport(0, 0);
654     assertEquals(od.getBoxX(), 0);
655     assertEquals(od.getBoxY(), 0);
656     assertEquals(od.getBoxWidth(), boxWidth);
657     assertEquals(od.getBoxHeight(), boxHeight);
658
659     // move viewport to right
660     moveViewportH(70);
661     assertEquals(od.getBoxX(),
662             Math.round((float) 70 * od.getWidth() / alwidth));
663     assertEquals(od.getBoxY(), 0);
664     assertEquals(od.getBoxWidth(), boxWidth);
665     assertEquals(od.getBoxHeight(), boxHeight);
666
667     // move viewport down
668     moveViewportV(100);
669     assertEquals(od.getBoxX(),
670             Math.round((float) 70 * od.getWidth() / alwidth));
671     assertEquals(od.getBoxY(),
672             Math.round(100 * od.getSequencesHeight() / alheight));
673     assertEquals(od.getBoxWidth(), boxWidth);
674     assertEquals(od.getBoxHeight(), boxHeight);
675
676     // move viewport to bottom right
677     moveViewport(98, 508);
678     assertEquals(od.getBoxX(),
679             Math.round((float) 98 * od.getWidth() / alwidth));
680     assertEquals(od.getBoxY(),
681             Math.round((float) 508 * od.getSequencesHeight() / alheight));
682     assertEquals(od.getBoxWidth(), boxWidth);
683     assertEquals(od.getBoxHeight(), boxHeight);
684   }
685
686   /**
687    * Test that the box position is set correctly when there are hidden columns
688    * at the start
689    */
690   @Test(groups = { "Functional" })
691   public void testSetBoxFromViewportHiddenColsAtStart()
692   {
693     int firstHidden = 0;
694     int lastHidden = 20;
695     hideColumns(firstHidden, lastHidden);
696
697     // move viewport to start of alignment
698     moveViewport(0, 0);
699     assertEquals(od.getBoxX(),
700             Math.round((float) (lastHidden + 1) * od.getWidth() / alwidth));
701     assertEquals(od.getBoxY(), 0);
702     assertEquals(od.getBoxWidth(), boxWidth);
703     assertEquals(od.getBoxHeight(), boxHeight);
704
705     // move viewport to end of alignment - need to make startRes by removing
706     // hidden cols because of how viewport/overview are implemented
707     moveViewport(98 - lastHidden - 1, 0);
708     assertEquals(od.getBoxX(),
709             Math.round((float) 98 * od.getWidth() / alwidth));
710     assertEquals(od.getBoxY(), 0);
711     assertEquals(od.getBoxWidth(), boxWidth);
712     assertEquals(od.getBoxHeight(), boxHeight);
713   }
714
715   /**
716    * Test that the box position is set correctly when there are hidden columns
717    * in the middle
718    */
719   @Test(groups = { "Functional" })
720   public void testSetBoxFromViewportHiddenColsInMiddle()
721   {
722     int firstHidden = 68;
723     int lastHidden = 78;
724     hideColumns(firstHidden, lastHidden);
725
726     // move viewport before hidden columns
727     moveViewport(3, 0);
728
729     assertEquals(od.getBoxX(),
730             Math.round((float) 3 * od.getWidth() / alwidth));
731     assertEquals(od.getBoxY(), 0);
732     System.out.println(od.getBoxWidth());
733     assertEquals(od.getBoxWidth(), boxWidth);
734     System.out.println(od.getBoxWidth());
735     assertEquals(od.getBoxHeight(), boxHeight);
736
737     // move viewport to left of hidden columns with overlap
738     moveViewport(10, 0);
739     assertEquals(od.getBoxX(),
740             Math.round((float) 10 * od.getWidth() / alwidth));
741     assertEquals(od.getBoxY(), 0);
742     assertEquals(
743             od.getBoxWidth(),
744             boxWidth
745                     + Math.round((float) (lastHidden - firstHidden + 1)
746                             * od.getWidth() / alwidth));
747     assertEquals(od.getBoxHeight(), boxHeight);
748
749     // move viewport to straddle hidden columns
750     moveViewport(63, 0);
751     assertEquals(od.getBoxX(),
752             Math.round((float) 63 * od.getWidth() / alwidth));
753     assertEquals(od.getBoxY(), 0);
754     assertEquals(
755             od.getBoxWidth(),
756             boxWidth
757                     + Math.round((lastHidden - firstHidden + 1)
758                             * od.getWidth() / alwidth));
759     assertEquals(od.getBoxHeight(), boxHeight);
760
761     // move viewport to right of hidden columns, no overlap
762     moveViewport(80 - (lastHidden - firstHidden + 1), 0);
763     assertEquals(od.getBoxX(),
764             Math.round((float) 80 * od.getWidth() / alwidth));
765     assertEquals(od.getBoxY(), 0);
766     assertEquals(od.getBoxWidth(), boxWidth);
767     assertEquals(od.getBoxHeight(), boxHeight);
768
769   }
770
771   /**
772    * Test that the box position is set correctly when there are hidden columns
773    * at the end
774    */
775   @Test(groups = { "Functional" })
776   public void testSetBoxFromViewportHiddenColsAtEnd()
777   {
778     int firstHidden = 152;
779     int lastHidden = 164;
780     hideColumns(firstHidden, lastHidden);
781
782     // move viewport before hidden columns
783     moveViewport(3, 0);
784     assertEquals(od.getBoxX(),
785             Math.round((float) 3 * od.getWidth() / alwidth));
786     assertEquals(od.getBoxY(), 0);
787     assertEquals(od.getBoxWidth(), boxWidth);
788     assertEquals(od.getBoxHeight(), boxHeight);
789
790     // move viewport to hidden columns
791     moveViewport(102, 0);
792     assertEquals(od.getBoxX(),
793             Math.round((float) 102 * od.getWidth() / alwidth));
794     assertEquals(od.getBoxY(), 0);
795     assertEquals(od.getBoxWidth(), boxWidth
796                     + Math.round((float) (lastHidden - firstHidden)
797                             * od.getWidth() / alwidth));
798     assertEquals(od.getBoxHeight(), boxHeight);
799   }
800
801   /**
802    * Test that the box position is set correctly when there are hidden rows at
803    * the start
804    */
805   @Test(groups = { "Functional" })
806   public void testSetBoxFromViewportHiddenRowsAtStart()
807   {
808     int firstHidden = 0;
809     int lastHidden = 20;
810     hideSequences(firstHidden, lastHidden + 1, lastHidden + 1);
811
812     // move viewport to start of alignment:
813     // box moves to below hidden rows, height remains same
814     moveViewport(0, 0);
815     assertEquals(od.getBoxX(), 0);
816     assertEquals(od.getBoxY(),
817             Math.round((float) (lastHidden + 1) * od.getSequencesHeight()
818                     / alheight));
819     assertEquals(od.getBoxWidth(), boxWidth);
820     assertEquals(od.getBoxHeight(), boxHeight);
821
822     // move viewport to end of alignment
823     moveViewport(0, 525 - viewHeight - lastHidden - 1);
824     assertEquals(od.getBoxX(), 0);
825     assertEquals(
826             od.getBoxY(),
827             Math.round((float) (525 - viewHeight) * od.getSequencesHeight()
828                     / alheight));
829     assertEquals(od.getBoxWidth(), boxWidth);
830     assertEquals(od.getBoxHeight(), boxHeight);
831   }
832
833   /**
834    * Test that the box position is set correctly when there are hidden rows in
835    * the middle
836    */
837   @Test(groups = { "Functional" })
838   public void testSetBoxFromViewportHiddenRowsInMiddle()
839   {
840     int firstHidden = 200;
841     int lastHidden = 210;
842     hideSequences(firstHidden, lastHidden + 1, lastHidden + 1);
843
844     // move viewport to start of alignment:
845     // box, height etc as in non-hidden case
846     moveViewport(0, 0);
847     assertEquals(od.getBoxX(), 0);
848     assertEquals(od.getBoxY(), 0);
849     assertEquals(od.getBoxWidth(), boxWidth);
850     assertEquals(od.getBoxHeight(), boxHeight);
851
852     // move viewport to straddle hidden rows
853     moveViewport(0, 198);
854     assertEquals(od.getBoxX(), 0);
855     assertEquals(od.getBoxY(), Math.round ((float)198 * od.getSequencesHeight()
856             / alheight));
857     assertEquals(od.getBoxWidth(), boxWidth);
858     assertEquals(
859             od.getBoxHeight(),
860             Math.round((float) (viewHeight + lastHidden - firstHidden + 1)
861                     * od.getSequencesHeight() / alheight));
862   }
863
864   /**
865    * Test that the box position is set correctly when there are hidden rows at
866    * the bottom
867    */
868   @Test(groups = { "Functional" })
869   public void testSetBoxFromViewportHiddenRowsAtEnd()
870   {
871     int firstHidden = 500;
872     int lastHidden = 524;
873     hideSequences(firstHidden - 1, lastHidden, firstHidden - 1);
874
875     // move viewport to start of alignment:
876     // box, height etc as in non-hidden case
877     moveViewport(0, 0);
878     assertEquals(od.getBoxX(), 0);
879     assertEquals(od.getBoxY(), 0);
880     assertEquals(od.getBoxWidth(), boxWidth);
881     assertEquals(od.getBoxHeight(), boxHeight);
882
883     // move viewport to end of alignment
884     // viewport sits above hidden rows and does not include them
885     moveViewport(0, firstHidden - viewHeight - 1);
886     assertEquals(od.getBoxX(), 0);
887     assertEquals(
888             od.getBoxY(),
889             Math.round((float) (firstHidden - viewHeight - 1)
890                     * od.getSequencesHeight() / alheight));
891     assertEquals(od.getBoxWidth(), boxWidth);
892     assertEquals(od.getBoxHeight(), boxHeight);
893
894   }
895
896   /**
897    * Test setting of the box position, when there are hidden rows at the start
898    * of the alignment
899    */
900   @Test(groups = { "Functional" })
901   public void testFromMouseWithHiddenRowsAtStart()
902   {
903     od.updateViewportFromMouse(0, 0,
904             av.getAlignment().getHiddenSequences(),
905             av.getColumnSelection(), av.getPosProps());
906     assertEquals(od.getBoxX(), 0);
907     assertEquals(od.getBoxY(), 0);
908     assertEquals(od.getBoxHeight(), boxHeight);
909     assertEquals(od.getBoxWidth(), boxWidth);
910     assertEquals(od.getScrollCol(), 0);
911     assertEquals(od.getScrollRow(), 0);
912
913     // hide rows at start and check updated box position is correct
914     // changes boxY but not boxheight
915     int lastHiddenRow = 30;
916     hideSequences(0, lastHiddenRow + 1, lastHiddenRow + 1);
917
918     od.setBoxPosition(av.getAlignment()
919             .getHiddenSequences(), av.getColumnSelection(), av.getPosProps());
920     assertEquals(od.getBoxX(), 0);
921     assertEquals(od.getBoxY(),
922             Math.round((float) (lastHiddenRow + 1)
923                     * od.getSequencesHeight() / alheight));
924     assertEquals(od.getBoxWidth(), boxWidth);
925     assertEquals(od.getBoxHeight(), boxHeight);
926
927     // click in hidden rows - same result
928     mouseClick(od, 0, 0);
929     assertEquals(od.getBoxX(), 0);
930     assertEquals(
931             od.getBoxY(),
932             Math.round((float) (lastHiddenRow + 1)
933                     * od.getSequencesHeight() / alheight));
934     assertEquals(od.getBoxWidth(), boxWidth);
935     assertEquals(od.getBoxHeight(), boxHeight);
936
937     // click below hidden rows
938     mouseClick(od, 0, 150);
939     assertEquals(od.getBoxX(), 0);
940     assertEquals(od.getBoxY(), 150);
941     assertEquals(od.getBoxWidth(), boxWidth);
942     assertEquals(od.getBoxHeight(), boxHeight);
943   }
944
945   /**
946    * Test setting of the box position, when there are hidden rows at the middle
947    * of the alignment
948    */
949   @Test(groups = { "Functional" })
950   public void testFromMouseWithHiddenRowsInMiddle()
951   {
952     od.updateViewportFromMouse(0, 0,
953             av.getAlignment().getHiddenSequences(),
954             av.getColumnSelection(), av.getPosProps());
955
956     assertEquals(od.getBoxX(), 0);
957     assertEquals(od.getBoxY(), 0);
958     assertEquals(od.getBoxWidth(), boxWidth);
959     assertEquals(od.getBoxHeight(), boxHeight);
960     assertEquals(od.getScrollCol(), 0);
961     assertEquals(od.getScrollRow(), 0);
962
963     // hide rows in middle and check updated box position is correct
964     // no changes
965     int firstHiddenRow = 50;
966     int lastHiddenRow = 60;
967     hideSequences(firstHiddenRow, lastHiddenRow + 1, lastHiddenRow + 1);
968
969     od.setBoxPosition(av.getAlignment()
970             .getHiddenSequences(), av.getColumnSelection(), av.getPosProps());
971
972     assertEquals(od.getBoxX(), 0);
973     assertEquals(od.getBoxY(), 0);
974     assertEquals(od.getBoxWidth(), boxWidth);
975     assertEquals(od.getBoxHeight(), boxHeight);
976
977     // click above hidden rows, so that box overlaps
978     int ypos = 40;
979     // TODO test fails because box does not change height - dealt with by scroll
980     // values
981     /*    mouseClick(od, 0, Math.round (ypos * alheight / od.getSequencesHeight()));
982         assertEquals(od.getBoxX(), 0);
983         assertEquals(od.getBoxY(), Math.round (ypos * alheight / od.getSequencesHeight()),
984                 1.5);
985         assertEquals(od.getBoxWidth(), boxWidth);
986         assertEquals(
987                 od.getBoxHeight(),
988                 boxHeight
989                         + Math.round ((lastHiddenRow - firstHiddenRow + 1) / scaleh / av
990                                 .getCharHeight()));
991     */
992     // click so that box straddles hidden rows
993     ypos = 48;
994     // TODO test fails because box does not change height - dealt with by scroll
995     // values
996     /*mouseClick(od, 0, Math.round (ypos * alheight / od.getSequencesHeight()));
997     assertEquals(od.getBoxX(), 0);
998     assertEquals(od.getBoxY(), Math.round (ypos * alheight / od.getSequencesHeight()),
999             1.5);
1000     assertEquals(od.getBoxWidth(), boxWidth);
1001     assertEquals(
1002             od.getBoxHeight(),
1003             boxHeight
1004                     + Math.round ((lastHiddenRow - firstHiddenRow + 1) / scaleh / av
1005                             .getCharHeight()));*/
1006   }
1007
1008   /**
1009    * Test setting of the box position, when there are hidden rows at the end of
1010    * the alignment
1011    */
1012   @Test(groups = { "Functional" })
1013   public void testFromMouseWithHiddenRowsAtEnd()
1014   {
1015     od.updateViewportFromMouse(0, 0,
1016             av.getAlignment().getHiddenSequences(),
1017             av.getColumnSelection(), av.getPosProps());
1018     assertEquals(od.getBoxX(), 0);
1019     assertEquals(od.getBoxY(), 0);
1020     assertEquals(od.getBoxWidth(), boxWidth);
1021     assertEquals(od.getBoxHeight(), boxHeight);
1022     assertEquals(od.getScrollCol(), 0);
1023     assertEquals(od.getScrollRow(), 0);
1024
1025     // hide rows at end and check updated box position is correct
1026     // no changes
1027     int firstHidden = 500;
1028     int lastHidden = 524;
1029     hideSequences(firstHidden - 1, lastHidden, firstHidden - 1);
1030
1031     od.setBoxPosition(av.getAlignment()
1032             .getHiddenSequences(), av.getColumnSelection(), av.getPosProps());
1033     assertEquals(od.getBoxX(), 0);
1034     assertEquals(od.getBoxY(), 0);
1035     assertEquals(od.getBoxWidth(), boxWidth);
1036     assertEquals(od.getBoxHeight(), boxHeight);
1037
1038     // click above hidden rows
1039     int ypos = 40; // row 40
1040     mouseClick(od, 0,
1041             Math.round((float) ypos * od.getSequencesHeight() / alheight));
1042     assertEquals(od.getBoxX(), 0);
1043     assertEquals(od.getBoxY(),
1044             Math.round((float) ypos * od.getSequencesHeight() / alheight));
1045     assertEquals(od.getBoxWidth(), boxWidth);
1046     assertEquals(od.getBoxHeight(), boxHeight);
1047
1048     // click above hidden rows so box overlaps
1049     // boxY moved upwards, boxHeight remains same
1050     // TODO fails with boxY located at row 497 - correction done by
1051     // setScrollValues
1052     /*   ypos = 497; // row 497
1053        mouseClick(od, 0, Math.round (ypos * scaleh * av.getCharHeight()));
1054        assertEquals(od.getBoxX(), 0);
1055        assertEquals(
1056                od.getBoxY(),
1057                Math.round ((firstHidden - viewHeight) * scaleh * av.getCharHeight()),
1058                1.5);
1059        assertEquals(od.getBoxWidth(), boxWidth);
1060        assertEquals(od.getBoxHeight(), boxHeight);*/
1061
1062     // click within hidden rows
1063     ypos = 505;
1064     // TODO: fails with wrong boxHeight - correction done by setScrollValues(?)
1065     /*mouseClick(od, 0, Math.round (ypos * scaleh * av.getCharHeight()));
1066     assertEquals(od.getBoxX(), 0);
1067     assertEquals(
1068             od.getBoxY(),
1069             Math.round ((firstHidden - viewHeight) * scaleh * av.getCharHeight()),
1070             1.5);
1071     assertEquals(od.getBoxWidth(), boxWidth);
1072     assertEquals(od.getBoxHeight(), boxHeight);*/
1073   }
1074
1075   /*
1076    * Move viewport horizontally: startRes + previous width gives new horizontal extent. Vertical extent stays the same.
1077    */
1078   private void moveViewportH(int startRes)
1079   {
1080     av.setStartRes(startRes);
1081     av.setEndRes(startRes + viewWidth - 1);
1082     od.setBoxPosition(av.getAlignment()
1083             .getHiddenSequences(), av.getColumnSelection(), av.getPosProps());
1084   }
1085
1086   /*
1087    * Move viewport vertically: startSeq and endSeq give new vertical extent. Horizontal extent stays the same.
1088    */
1089   private void moveViewportV(int startSeq)
1090   {
1091     av.setStartSeq(startSeq);
1092     av.setEndSeq(startSeq + viewHeight - 1);
1093     od.setBoxPosition(av.getAlignment()
1094             .getHiddenSequences(), av.getColumnSelection(), av.getPosProps());
1095   }
1096
1097   /*
1098    * Move viewport horizontally and vertically.
1099    */
1100   private void moveViewport(int startRes, int startSeq)
1101   {
1102     av.setStartRes(startRes);
1103     av.setEndRes(startRes + viewWidth - 1);
1104     av.setStartSeq(startSeq);
1105     av.setEndSeq(startSeq + viewHeight - 1);
1106     od.setBoxPosition(av.getAlignment()
1107             .getHiddenSequences(), av.getColumnSelection(), av.getPosProps());
1108   }
1109
1110   /*
1111    * Mouse click as position x,y in overview window
1112    */
1113   private void mouseClick(OverviewDimensions od, int x, int y)
1114   {
1115     od.updateViewportFromMouse(x, y,
1116             av.getAlignment().getHiddenSequences(),
1117             av.getColumnSelection(), av.getPosProps());
1118     // updates require an OverviewPanel to exist which it doesn't here
1119     // so call setBoxPosition() as it would be called by the AlignmentPanel
1120     // normally
1121     // int width = av.getEndRes() - av.getStartRes();
1122     // int height = av.getEndSeq() - av.getStartSeq();
1123     av.setStartRes(od.getScrollCol());
1124     av.setEndRes(od.getScrollCol() + viewWidth - 1);
1125     av.setStartSeq(od.getScrollRow());
1126     av.setEndSeq(od.getScrollRow() + viewHeight - 1);
1127     od.setBoxPosition(av.getAlignment()
1128             .getHiddenSequences(), av.getColumnSelection(), av.getPosProps());
1129   }
1130   
1131   private void testBoxIsAtClickPoint(int xpos, int ypos)
1132   {
1133     mouseClick(od, xpos, ypos);
1134     assertEquals(od.getBoxX(), xpos);
1135     assertEquals(od.getBoxY(), ypos);
1136     assertEquals(od.getBoxWidth(), boxWidth);
1137     assertEquals(od.getBoxHeight(), boxHeight);
1138
1139   }
1140
1141   /*
1142    * Hide sequences between start and end, using hideseq to do the hiding
1143    * (start <= hideseq <= end. Sequence hideseq is not hidden but the others are
1144    */
1145   private void hideSequences(int start, int end, int hideseq)
1146   {
1147     SequenceGroup sg = new SequenceGroup();
1148     List<SequenceI> allseqs = av.getAlignment().getSequences();
1149     for (int i = start; i <= end; ++i)
1150     {
1151       sg.addSequence(allseqs.get(i), false);
1152     }
1153     av.setSelectionGroup(sg);
1154
1155     /*
1156      * hide group
1157      */
1158     av.hideSequences(allseqs.get(hideseq), true);
1159
1160     while (av.isCalcInProgress())
1161     {
1162       try
1163       {
1164         Thread.sleep(50);
1165       } catch (InterruptedException e)
1166       {
1167         System.out.println("Hiding seqs interruption");
1168       }
1169     }
1170   }
1171
1172   private void hideColumns(int firstHidden, int lastHidden)
1173   {
1174     av.hideColumns(firstHidden, lastHidden);
1175
1176     while (av.isCalcInProgress())
1177     {
1178       try
1179       {
1180         Thread.sleep(50);
1181       } catch (InterruptedException e)
1182       {
1183         System.out.println("Hiding cols interruption");
1184       }
1185     }
1186   }
1187 }