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