28b7029b5b5c718b5c8c3dfdbdcc8cb5047950aa
[jalview.git] / test / jalview / viewmodel / OverviewDimensionsHideHiddenTest.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.viewmodel;
22
23 import static org.testng.Assert.assertEquals;
24 import static org.testng.Assert.assertFalse;
25 import static org.testng.Assert.assertTrue;
26
27 import jalview.analysis.AlignmentGenerator;
28 import jalview.datamodel.Alignment;
29 import jalview.datamodel.AlignmentI;
30 import jalview.datamodel.ColumnSelection;
31 import jalview.datamodel.HiddenColumns;
32 import jalview.datamodel.Sequence;
33 import jalview.datamodel.SequenceCollectionI;
34 import jalview.datamodel.SequenceGroup;
35 import jalview.datamodel.SequenceI;
36
37 import java.util.Hashtable;
38
39 import org.testng.annotations.AfterClass;
40 import org.testng.annotations.BeforeClass;
41 import org.testng.annotations.BeforeMethod;
42 import org.testng.annotations.Test;
43
44 @Test(singleThreaded = true)
45 public class OverviewDimensionsHideHiddenTest
46 {
47   AlignmentI al;
48
49   OverviewDimensionsHideHidden od;
50
51   // cached widths and heights
52   int boxWidth;
53   int boxHeight;
54   int viewHeight;
55   int viewWidth;
56   int alheight;
57   int alwidth;
58
59   ViewportRanges vpranges;
60
61   Hashtable<SequenceI, SequenceCollectionI> hiddenRepSequences = new Hashtable<>();
62
63   HiddenColumns hiddenCols = new HiddenColumns();
64
65   @BeforeClass(alwaysRun = true)
66   public void setUpAlignment()
67   {
68     // create random alignment
69     AlignmentGenerator gen = new AlignmentGenerator(false);
70     al = gen.generate(157, 525, 123, 5, 5);
71   }
72
73   @BeforeMethod(alwaysRun = true)
74   public void setUp()
75   {
76     if (!hiddenRepSequences.isEmpty())
77     {
78       al.getHiddenSequences().showAll(hiddenRepSequences);
79     }
80     ColumnSelection colsel = new ColumnSelection();
81     hiddenCols.revealAllHiddenColumns(colsel);
82     
83     vpranges = new ViewportRanges(al);
84     vpranges.setViewportStartAndHeight(0, 18);
85     vpranges.setViewportStartAndWidth(0, 63);
86
87     viewHeight = vpranges.getEndSeq() - vpranges.getStartSeq() + 1;
88     viewWidth = vpranges.getEndRes() - vpranges.getStartRes() + 1;
89
90     HiddenColumns hiddenCols = new HiddenColumns();
91
92     od = new OverviewDimensionsHideHidden(vpranges, true);
93     // Initial box sizing - default path through code
94     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
95
96     mouseClick(od, 0, 0);
97     moveViewport(0, 0);
98
99     // calculate with visible values
100     alheight = vpranges.getVisibleAlignmentHeight();
101     alwidth = vpranges.getVisibleAlignmentWidth();
102
103     boxWidth = Math.round((float) (vpranges.getEndRes()
104             - vpranges.getStartRes() + 1)
105             * od.getWidth() / alwidth);
106     boxHeight = Math.round((float) (vpranges.getEndSeq()
107             - vpranges.getStartSeq() + 1)
108             * od.getSequencesHeight() / alheight);
109   }
110
111   @AfterClass(alwaysRun = true)
112   public void cleanUp()
113   {
114     al = null;
115   }
116
117   /**
118    * Test that the OverviewDimensions constructor sets width and height
119    * correctly
120    */
121   @Test(groups = { "Functional" })
122   public void testConstructor()
123   {
124     SequenceI seqa = new Sequence("Seq1", "ABC");
125     SequenceI seqb = new Sequence("Seq2", "ABC");
126     SequenceI seqc = new Sequence("Seq3", "ABC");
127     SequenceI seqd = new Sequence("Seq4", "ABC");
128     SequenceI seqe = new Sequence("Seq5",
129             "ABCABCABCABCABCABCABCABCBACBACBACBAC");
130
131     int defaultGraphHeight = 20;
132     int maxWidth = 400;
133     int minWidth = 120;
134     int maxSeqHeight = 300;
135     int minSeqHeight = 40;
136
137     // test for alignment with width > height
138     SequenceI[] seqs1 = new SequenceI[] { seqa, seqb };
139     Alignment al1 = new Alignment(seqs1);
140     ViewportRanges props = new ViewportRanges(al1);
141
142     OverviewDimensions od = new OverviewDimensionsHideHidden(props, true);
143     int scaledHeight = 267;
144     assertEquals(od.getGraphHeight(), defaultGraphHeight);
145     assertEquals(od.getSequencesHeight(), scaledHeight);
146     assertEquals(od.getWidth(), maxWidth);
147     assertEquals(od.getHeight(), scaledHeight + defaultGraphHeight);
148
149     // test for alignment with width < height
150     SequenceI[] seqs2 = new SequenceI[] { seqa, seqb, seqc, seqd };
151     Alignment al2 = new Alignment(seqs2);
152     props = new ViewportRanges(al2);
153
154     od = new OverviewDimensionsHideHidden(props, true);
155     int scaledWidth = 300;
156     assertEquals(od.getGraphHeight(), defaultGraphHeight);
157     assertEquals(od.getSequencesHeight(), maxSeqHeight);
158     assertEquals(od.getWidth(), scaledWidth);
159     assertEquals(od.getHeight(), scaledWidth + defaultGraphHeight);
160
161     // test for alignment with width > height and sequence height scaled below
162     // min value
163     SequenceI[] seqs3 = new SequenceI[] { seqe };
164     Alignment al3 = new Alignment(seqs3);
165     props = new ViewportRanges(al3);
166
167     od = new OverviewDimensionsHideHidden(props, true);
168     assertEquals(od.getGraphHeight(), defaultGraphHeight);
169     assertEquals(od.getSequencesHeight(), minSeqHeight);
170     assertEquals(od.getWidth(), maxWidth);
171     assertEquals(od.getHeight(), minSeqHeight + defaultGraphHeight);
172
173     // test for alignment with width < height and width scaled below min value
174     SequenceI[] seqs4 = new SequenceI[] { seqa, seqb, seqc, seqd, seqa,
175         seqb, seqc, seqd, seqa, seqb, seqc, seqd, seqa, seqb, seqc, seqd };
176     Alignment al4 = new Alignment(seqs4);
177     props = new ViewportRanges(al4);
178
179     od = new OverviewDimensionsHideHidden(props, true);
180     assertEquals(od.getGraphHeight(), defaultGraphHeight);
181     assertEquals(od.getSequencesHeight(), maxSeqHeight);
182     assertEquals(od.getWidth(), minWidth);
183     assertEquals(od.getHeight(), maxSeqHeight + defaultGraphHeight);
184
185     Alignment al5 = new Alignment(seqs4);
186     props = new ViewportRanges(al5);
187
188     od = new OverviewDimensionsHideHidden(props, false);
189     assertEquals(od.getGraphHeight(), 0);
190     assertEquals(od.getSequencesHeight(), maxSeqHeight);
191     assertEquals(od.getWidth(), minWidth);
192     assertEquals(od.getHeight(), maxSeqHeight);
193   }
194
195   /**
196    * Test that validation after mouse adjustments to boxX and boxY sets box
197    * dimensions and scroll values correctly, when there are no hidden rows or
198    * columns.
199    */
200   @Test(groups = { "Functional" })
201   public void testSetBoxFromMouseClick()
202   {
203     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
204     assertEquals(od.getBoxX(), 0);
205     assertEquals(od.getBoxY(), 0);
206     assertEquals(od.getBoxWidth(), boxWidth);
207     assertEquals(vpranges.getStartRes(), 0);
208     assertEquals(vpranges.getStartSeq(), 0);
209
210     // negative boxX value reset to 0
211     mouseClick(od, -5, 10);
212     assertEquals(od.getBoxX(), 0);
213     assertEquals(od.getBoxWidth(), boxWidth);
214     assertEquals(od.getBoxHeight(), boxHeight);
215     assertEquals(vpranges.getStartSeq(),
216             Math.round((float) 10 * alheight / od.getSequencesHeight()));
217     assertEquals(vpranges.getStartRes(), 0);
218
219     // negative boxY value reset to 0
220     mouseClick(od, 6, -2);
221     assertEquals(od.getBoxY(), 0);
222     assertEquals(od.getBoxWidth(), boxWidth);
223     assertEquals(od.getBoxHeight(), boxHeight);
224     assertEquals(vpranges.getStartRes(),
225             Math.round((float) 6 * alwidth / od.getWidth()));
226     assertEquals(vpranges.getStartSeq(), 0);
227
228     // overly large boxX value reset to width-boxWidth
229     mouseClick(od, 100, 6);
230     assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
231     assertEquals(od.getBoxY(), 6);
232     assertEquals(od.getBoxWidth(), boxWidth);
233     assertEquals(od.getBoxHeight(), boxHeight);
234     assertEquals(vpranges.getStartRes(),
235             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
236     assertEquals(
237             vpranges.getStartSeq(),
238             Math.round((float) od.getBoxY() * alheight
239                     / od.getSequencesHeight()));
240
241     // overly large boxY value reset to sequenceHeight - boxHeight
242     mouseClick(od, 10, 520);
243     assertEquals(od.getBoxX(), 10);
244     assertEquals(od.getBoxY(), od.getSequencesHeight() - od.getBoxHeight());
245     assertEquals(od.getBoxWidth(), boxWidth);
246     assertEquals(od.getBoxHeight(), boxHeight);
247     assertEquals(vpranges.getStartRes(),
248             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
249
250     // here (float) od.getBoxY() * alheight / od.getSequencesHeight() = 507.5
251     // and round rounds to 508; however we get 507 working with row values
252     // hence the subtraction of 1
253     assertEquals(
254             vpranges.getStartSeq(),
255             Math.round((float) od.getBoxY() * alheight
256                     / od.getSequencesHeight()) - 1);
257
258     // click past end of alignment, as above
259     mouseClick(od, 3000, 5);
260     assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
261     assertEquals(od.getBoxWidth(), boxWidth);
262     assertEquals(od.getBoxHeight(), boxHeight);
263     assertEquals(vpranges.getStartRes(),
264             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
265     assertEquals(
266             vpranges.getStartSeq(),
267             Math.round((float) od.getBoxY() * alheight
268                     / od.getSequencesHeight()));
269
270     // move viewport so startRes non-zero and then mouseclick
271     moveViewportH(50);
272
273     // click at viewport position
274     int oldboxx = od.getBoxX();
275     int oldboxy = od.getBoxY();
276     mouseClick(od, od.getBoxX() + 5, od.getBoxY() + 2);
277     assertEquals(od.getBoxX(), oldboxx + 5);
278     assertEquals(od.getBoxWidth(), boxWidth);
279     assertEquals(od.getBoxHeight(), boxHeight);
280     assertEquals(vpranges.getStartRes(),
281             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
282     assertEquals(od.getBoxY(), oldboxy + 2);
283     assertEquals(
284             vpranges.getStartSeq(),
285             Math.round((float) od.getBoxY() * alheight
286                     / od.getSequencesHeight()));
287
288     // click at top corner
289     mouseClick(od, 0, 0);
290     assertEquals(od.getBoxX(), 0);
291     assertEquals(vpranges.getStartRes(), 0);
292     assertEquals(od.getBoxY(), 0);
293     assertEquals(vpranges.getStartSeq(), 0);
294     assertEquals(od.getBoxWidth(), boxWidth);
295     assertEquals(od.getBoxHeight(), boxHeight);
296   }
297
298   /**
299    * Test setting of the box position, when there are hidden cols at the start
300    * of the alignment
301    */
302   @Test(groups = { "Functional" })
303   public void testFromMouseWithHiddenColsAtStart()
304   {
305     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
306     assertEquals(od.getBoxX(), 0);
307     assertEquals(od.getBoxY(), 0);
308     assertEquals(od.getBoxWidth(), boxWidth);
309     assertEquals(vpranges.getStartRes(), 0);
310     assertEquals(vpranges.getStartSeq(), 0);
311
312     // hide cols at start and check updated box position is correct
313     int lastHiddenCol = 30;
314     hiddenCols.hideColumns(0, lastHiddenCol);
315
316     testBoxIsAtClickPoint(0, 0);
317
318     // click to right of hidden columns, box moves to click point
319     testBoxIsAtClickPoint(40, 0);
320     assertEquals(vpranges.getStartSeq(), 0);
321     assertEquals(vpranges.getStartRes(),
322             Math.round((float) 40 * alwidth / od.getWidth()));
323
324     // click to right of hidden columns such that box runs over right hand side
325     // of alignment
326     // box position is adjusted away from the edge
327     // overly large boxX value reset to width-boxWidth
328     int xpos = 100;
329     mouseClick(od, xpos, 0);
330     assertEquals(od.getBoxX(), Math.round(od.getWidth()) - boxWidth);
331     assertEquals(od.getBoxY(), 0);
332     assertEquals(od.getBoxWidth(), boxWidth);
333     assertEquals(od.getBoxHeight(), boxHeight);
334     assertEquals(vpranges.getStartRes(),
335             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
336     assertEquals(vpranges.getStartSeq(), 0);
337   }
338
339   /**
340    * Test setting of the box position, when there are hidden cols in the middle
341    * of the alignment
342    */
343   @Test(groups = { "Functional" })
344   public void testFromMouseWithHiddenColsInMiddle()
345   {
346     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
347     testBoxIsAtClickPoint(0, 0);
348     assertEquals(od.getBoxX(), 0);
349     assertEquals(od.getBoxY(), 0);
350     assertEquals(od.getBoxWidth(), boxWidth);
351     assertEquals(vpranges.getStartRes(), 0);
352     assertEquals(vpranges.getStartSeq(), 0);
353     
354     // hide columns 63-73, no change to box position or dimensions
355     int firstHidden = 63;
356     int lastHidden = 73;
357     hiddenCols.hideColumns(firstHidden, lastHidden);
358
359     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
360     testBoxIsAtClickPoint(0, 0);
361     assertEquals(od.getBoxX(), 0);
362     assertEquals(od.getBoxY(), 0);
363     assertEquals(od.getBoxWidth(), boxWidth);
364     assertEquals(vpranges.getStartRes(), 0);
365     assertEquals(vpranges.getStartSeq(), 0);
366
367     // move box so that it overlaps with hidden cols on one side
368     // box width, boxX and scrollCol as for unhidden case
369     int xpos = 55 - boxWidth; // 55 is position in overview approx halfway
370                               // between cols 60 and 70
371     mouseClick(od, xpos, 0);
372     testBoxIsAtClickPoint(xpos, 0);
373     assertEquals(vpranges.getStartRes(),
374             Math.round(xpos * alwidth / od.getWidth()));
375     assertEquals(vpranges.getStartSeq(), 0);
376
377     // move box so that it completely covers hidden cols
378     // box width, boxX and scrollCol as for unhidden case
379     xpos = 33;
380     mouseClick(od, xpos, 0);
381     testBoxIsAtClickPoint(xpos, 0);
382     assertEquals(vpranges.getStartRes(),
383             Math.round((float) xpos * alwidth / od.getWidth()));
384     assertEquals(vpranges.getStartSeq(), 0);
385
386     // move box so boxX is in hidden cols, box overhangs at right
387     // boxX and scrollCol at left of hidden area, box width unchanged
388     xpos = 50;
389     mouseClick(od, xpos, 0);
390     testBoxIsAtClickPoint(xpos, 0);
391     assertEquals(vpranges.getStartRes(),
392             Math.round((float) xpos * alwidth / od.getWidth()));
393     assertEquals(vpranges.getStartSeq(), 0);
394
395     // move box so boxX is to right of hidden cols, but does not go beyond full
396     // width of alignment
397     // box width, boxX and scrollCol all as for non-hidden case
398     xpos = 75;
399     testBoxIsAtClickPoint(xpos, 0);
400     assertEquals(vpranges.getStartSeq(), 0);
401     assertEquals(vpranges.getStartRes(),
402             Math.round(xpos * alwidth / od.getWidth()));
403     
404     // move box so it goes beyond full width of alignment
405     // boxX, scrollCol adjusted back, box width normal
406     xpos = 3000;
407     mouseClick(od, xpos, 0);
408     assertEquals(od.getBoxX(), Math.round(od.getWidth()) - boxWidth);
409     assertEquals(od.getBoxY(), 0);
410     assertEquals(od.getBoxWidth(), boxWidth);
411     assertEquals(od.getBoxHeight(), boxHeight);
412     assertEquals(vpranges.getStartRes(),
413             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
414     assertEquals(vpranges.getStartSeq(), 0);
415
416   }
417
418   /**
419    * Test setting of the box position, when there are hidden cols at the end of
420    * the alignment
421    */
422   @Test(groups = { "Functional" })
423   public void testFromMouseWithHiddenColsAtEnd()
424   {
425     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
426     assertEquals(od.getBoxX(), 0);
427     assertEquals(od.getBoxY(), 0);
428     assertEquals(od.getBoxWidth(), boxWidth);
429     assertEquals(vpranges.getStartRes(), 0);
430     assertEquals(vpranges.getStartSeq(), 0);
431
432     // hide columns 140-164, no change to box position or dimensions
433     int firstHidden = 140;
434     int lastHidden = 164;
435     hiddenCols.hideColumns(firstHidden, lastHidden);
436     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
437     assertEquals(od.getBoxX(), 0);
438     assertEquals(od.getBoxY(), 0);
439     assertEquals(od.getBoxWidth(), boxWidth);
440     assertEquals(vpranges.getStartRes(), 0);
441     assertEquals(vpranges.getStartSeq(), 0);
442
443     // click to left of hidden cols, without overlapping
444     // boxX, scrollCol and width as normal
445     int xpos = 5;
446     testBoxIsAtClickPoint(xpos, 0);
447     assertEquals(vpranges.getStartSeq(), 0);
448     assertEquals(vpranges.getStartRes(),
449             Math.round((float) xpos * alwidth / od.getWidth()));
450
451     // click to left of hidden cols, with overlap
452     // boxX and scrollCol adjusted for hidden cols, width normal
453     xpos = Math.round((float) 145 * od.getWidth() / alwidth) - boxWidth;
454     mouseClick(od, xpos, 0);
455     testBoxIsAtClickPoint(xpos, 0);
456     assertEquals(vpranges.getStartRes(),
457             Math.round((float) xpos * alwidth / od.getWidth()));
458     assertEquals(vpranges.getStartSeq(), 0);
459
460     // click off end of alignment
461     // boxX and scrollCol adjusted backwards, width normal
462     xpos = 3000;
463     mouseClick(od, xpos, 0);
464     assertEquals(od.getBoxX(), Math.round(od.getWidth()) - boxWidth);
465     assertEquals(od.getBoxY(), 0);
466     assertEquals(od.getBoxWidth(), boxWidth);
467     assertEquals(od.getBoxHeight(), boxHeight);
468     assertEquals(vpranges.getStartRes(),
469             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
470     assertEquals(vpranges.getStartSeq(), 0);
471   }
472
473   /**
474    * Test that the box position is set correctly when set from the viewport,
475    * with no hidden rows or columns
476    */
477   @Test(groups = { "Functional" })
478   public void testSetBoxFromViewport()
479   {
480     // move viewport to start of alignment
481     moveViewport(0, 0);
482     assertEquals(od.getBoxX(), 0);
483     assertEquals(od.getBoxY(), 0);
484     assertEquals(od.getBoxWidth(), boxWidth);
485     assertEquals(od.getBoxHeight(), boxHeight);
486
487     // move viewport to right
488     moveViewportH(70);
489     assertEquals(od.getBoxX(),
490             Math.round((float) 70 * od.getWidth() / alwidth));
491     assertEquals(od.getBoxY(), 0);
492     assertEquals(od.getBoxWidth(), boxWidth);
493     assertEquals(od.getBoxHeight(), boxHeight);
494
495     // move viewport down
496     moveViewportV(100);
497     assertEquals(od.getBoxX(),
498             Math.round((float) 70 * od.getWidth() / alwidth));
499     assertEquals(od.getBoxY(),
500             Math.round(100 * od.getSequencesHeight() / alheight));
501     assertEquals(od.getBoxWidth(), boxWidth);
502     assertEquals(od.getBoxHeight(), boxHeight);
503
504     // move viewport to bottom right
505     moveViewport(98, 508);
506     assertEquals(od.getBoxX(),
507             Math.round((float) 98 * od.getWidth() / alwidth));
508     assertEquals(od.getBoxY(),
509             Math.round((float) 508 * od.getSequencesHeight() / alheight));
510     assertEquals(od.getBoxWidth(), boxWidth);
511     assertEquals(od.getBoxHeight(), boxHeight);
512   }
513
514   /**
515    * Test that the box position is set correctly when there are hidden columns
516    * at the start
517    */
518   @Test(groups = { "Functional" })
519   public void testSetBoxFromViewportHiddenColsAtStart()
520   {
521     int firstHidden = 0;
522     int lastHidden = 20;
523     hiddenCols.hideColumns(firstHidden, lastHidden);
524
525     // move viewport to start of alignment
526     moveViewport(0, 0);
527     assertEquals(od.getBoxX(), 0);
528     assertEquals(od.getBoxY(), 0);
529     assertEquals(od.getBoxWidth(), boxWidth);
530     assertEquals(od.getBoxHeight(), boxHeight);
531
532     // move viewport to end of alignment - need to make startRes by removing
533     // hidden cols because of how viewport/overview are implemented
534     moveViewport(98 - lastHidden - 1, 0);
535     assertEquals(od.getBoxX(),
536             Math.round((float) (98 - lastHidden - 1) * od.getWidth()
537                     / alwidth));
538     assertEquals(od.getBoxY(), 0);
539     assertEquals(od.getBoxWidth(), boxWidth);
540     assertEquals(od.getBoxHeight(), boxHeight);
541   }
542
543   /**
544    * Test that the box position is set correctly when there are hidden columns
545    * in the middle
546    */
547   @Test(groups = { "Functional" })
548   public void testSetBoxFromViewportHiddenColsInMiddle()
549   {
550     int firstHidden = 68;
551     int lastHidden = 78;
552     hiddenCols.hideColumns(firstHidden, lastHidden);
553
554     // move viewport before hidden columns
555     moveViewport(3, 0);
556
557     assertEquals(od.getBoxX(),
558             Math.round((float) 3 * od.getWidth() / alwidth));
559     assertEquals(od.getBoxY(), 0);
560     assertEquals(od.getBoxWidth(), boxWidth);
561     assertEquals(od.getBoxHeight(), boxHeight);
562
563     // move viewport to left of hidden columns with overlap
564     moveViewport(10, 0);
565     assertEquals(od.getBoxX(),
566             Math.round((float) 10 * od.getWidth() / alwidth));
567     assertEquals(od.getBoxY(), 0);
568     assertEquals(od.getBoxWidth(), boxWidth);
569     assertEquals(od.getBoxHeight(), boxHeight);
570
571     // move viewport to straddle hidden columns
572     moveViewport(63, 0);
573     assertEquals(od.getBoxX(),
574             Math.round((float) 63 * od.getWidth() / alwidth));
575     assertEquals(od.getBoxY(), 0);
576     assertEquals(od.getBoxWidth(), boxWidth);
577     assertEquals(od.getBoxHeight(), boxHeight);
578
579     // move viewport to right of hidden columns, no overlap
580     moveViewport(80 - (lastHidden - firstHidden + 1), 0);
581     assertEquals(od.getBoxX(),
582             Math.round((float) (80 - (lastHidden - firstHidden + 1))
583                     * od.getWidth() / alwidth));
584     assertEquals(od.getBoxY(), 0);
585     assertEquals(od.getBoxWidth(), boxWidth);
586     assertEquals(od.getBoxHeight(), boxHeight);
587
588   }
589
590   /**
591    * Test that the box position is set correctly when there are hidden columns
592    * at the end
593    */
594   @Test(groups = { "Functional" })
595   public void testSetBoxFromViewportHiddenColsAtEnd()
596   {
597     int firstHidden = 152;
598     int lastHidden = 164;
599     hiddenCols.hideColumns(firstHidden, lastHidden);
600
601     // move viewport before hidden columns
602     moveViewport(3, 0);
603     assertEquals(od.getBoxX(),
604             Math.round((float) 3 * od.getWidth() / alwidth));
605     assertEquals(od.getBoxY(), 0);
606     assertEquals(od.getBoxWidth(), boxWidth);
607     assertEquals(od.getBoxHeight(), boxHeight);
608
609     // move viewport to hidden columns
610     // viewport can't actually extend into hidden cols,
611     // so move to the far right edge of the viewport
612     moveViewport(firstHidden - viewWidth, 0);
613     assertEquals(od.getBoxX(),
614             Math.round((float) (firstHidden - viewWidth)
615                     * od.getWidth() / alwidth));
616     assertEquals(od.getBoxY(), 0);
617     assertEquals(od.getBoxWidth(), boxWidth);
618     assertEquals(od.getBoxHeight(), boxHeight);
619   }
620
621   /**
622    * Test that the box position is set correctly when there are hidden rows at
623    * the start
624    */
625   @Test(groups = { "Functional" })
626   public void testSetBoxFromViewportHiddenRowsAtStart()
627   {
628     int firstHidden = 0;
629     int lastHidden = 20;
630     hideSequences(firstHidden, lastHidden);
631
632     // calculate with visible values
633     alheight = vpranges.getVisibleAlignmentHeight();
634     alwidth = vpranges.getVisibleAlignmentWidth();
635
636     boxWidth = Math.round((float) (vpranges.getEndRes()
637             - vpranges.getStartRes() + 1)
638             * od.getWidth() / alwidth);
639     boxHeight = Math.round((float) (vpranges.getEndSeq()
640             - vpranges.getStartSeq() + 1)
641             * od.getSequencesHeight() / alheight);
642
643     // move viewport to start of alignment:
644     // box moves to below hidden rows, height remains same
645     moveViewport(0, 0);
646     assertEquals(od.getBoxX(), 0);
647     assertEquals(od.getBoxY(), 0);
648     assertEquals(od.getBoxWidth(), boxWidth);
649     assertEquals(od.getBoxHeight(), boxHeight);
650
651     // move viewport to end of alignment
652     moveViewport(0, 525 - viewHeight - lastHidden - 1);
653     assertEquals(od.getBoxX(), 0);
654     assertEquals(
655             od.getBoxY(),
656             Math.round((float) (525 - viewHeight - lastHidden - 1)
657                     * od.getSequencesHeight()
658                     / alheight));
659     assertEquals(od.getBoxWidth(), boxWidth);
660     assertEquals(od.getBoxHeight(), boxHeight);
661   }
662
663   /**
664    * Test that the box position is set correctly when there are hidden rows in
665    * the middle
666    */
667   @Test(groups = { "Functional" })
668   public void testSetBoxFromViewportHiddenRowsInMiddle()
669   {
670     int firstHidden = 200;
671     int lastHidden = 210;
672     hideSequences(firstHidden, lastHidden);
673
674     // calculate with visible values
675     alheight = vpranges.getVisibleAlignmentHeight();
676     alwidth = vpranges.getVisibleAlignmentWidth();
677
678     boxWidth = Math.round((float) (vpranges.getEndRes()
679             - vpranges.getStartRes() + 1)
680             * od.getWidth() / alwidth);
681     boxHeight = Math.round((float) (vpranges.getEndSeq()
682             - vpranges.getStartSeq() + 1)
683             * od.getSequencesHeight() / alheight);
684
685     // move viewport to start of alignment:
686     // box, height etc as in non-hidden case
687     moveViewport(0, 0);
688     assertEquals(od.getBoxX(), 0);
689     assertEquals(od.getBoxY(), 0);
690     assertEquals(od.getBoxWidth(), boxWidth);
691     assertEquals(od.getBoxHeight(), boxHeight);
692
693     // move viewport to straddle hidden rows
694     moveViewport(0, 198);
695     assertEquals(od.getBoxX(), 0);
696     assertEquals(od.getBoxY(), Math.round ((float)198 * od.getSequencesHeight()
697             / alheight));
698     assertEquals(od.getBoxWidth(), boxWidth);
699     assertEquals(od.getBoxHeight(), boxHeight);
700   }
701
702   /**
703    * Test that the box position is set correctly when there are hidden rows at
704    * the bottom
705    */
706   @Test(groups = { "Functional" })
707   public void testSetBoxFromViewportHiddenRowsAtEnd()
708   {
709     int firstHidden = 500;
710     int lastHidden = 524;
711     hideSequences(firstHidden, lastHidden);
712
713     // calculate with visible values
714     alheight = vpranges.getVisibleAlignmentHeight();
715     alwidth = vpranges.getVisibleAlignmentWidth();
716
717     boxWidth = Math.round((float) (vpranges.getEndRes()
718             - vpranges.getStartRes() + 1)
719             * od.getWidth() / alwidth);
720     boxHeight = Math.round((float) (vpranges.getEndSeq()
721             - vpranges.getStartSeq() + 1)
722             * od.getSequencesHeight() / alheight);
723
724     // move viewport to start of alignment:
725     // box, height etc as in non-hidden case
726     moveViewport(0, 0);
727     assertEquals(od.getBoxX(), 0);
728     assertEquals(od.getBoxY(), 0);
729     assertEquals(od.getBoxWidth(), boxWidth);
730     assertEquals(od.getBoxHeight(), boxHeight);
731
732     // move viewport to end of alignment
733     // viewport sits above hidden rows and does not include them
734     moveViewport(0, firstHidden - viewHeight - 1);
735     assertEquals(od.getBoxX(), 0);
736     assertEquals(
737             od.getBoxY(),
738             Math.round((float) (firstHidden - viewHeight - 1)
739                     * od.getSequencesHeight() / alheight));
740     assertEquals(od.getBoxWidth(), boxWidth);
741     assertEquals(od.getBoxHeight(), boxHeight);
742
743   }
744
745   /**
746    * Test setting of the box position, when there are hidden rows at the start
747    * of the alignment
748    */
749   @Test(groups = { "Functional" })
750   public void testFromMouseWithHiddenRowsAtStart()
751   {
752     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
753     assertEquals(od.getBoxX(), 0);
754     assertEquals(od.getBoxY(), 0);
755     assertEquals(od.getBoxHeight(), boxHeight);
756     assertEquals(od.getBoxWidth(), boxWidth);
757     assertEquals(vpranges.getStartRes(), 0);
758     assertEquals(vpranges.getStartSeq(), 0);
759
760     // hide rows at start and check updated box position is correct
761     int lastHiddenRow = 30;
762     hideSequences(0, lastHiddenRow);
763
764     // calculate with visible values
765     alheight = vpranges.getVisibleAlignmentHeight();
766     alwidth = vpranges.getVisibleAlignmentWidth();
767
768     boxWidth = Math.round((float) (vpranges.getEndRes()
769             - vpranges.getStartRes() + 1)
770             * od.getWidth() / alwidth);
771     boxHeight = Math.round((float) (vpranges.getEndSeq()
772             - vpranges.getStartSeq() + 1)
773             * od.getSequencesHeight() / alheight);
774
775     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
776     assertEquals(od.getBoxX(), 0);
777     assertEquals(od.getBoxY(), 0);
778     assertEquals(od.getBoxWidth(), boxWidth);
779     assertEquals(od.getBoxHeight(), boxHeight);
780
781     // click below hidden rows
782     mouseClick(od, 0, 150);
783     assertEquals(od.getBoxX(), 0);
784     assertEquals(od.getBoxY(), 150);
785     assertEquals(od.getBoxWidth(), boxWidth);
786     assertEquals(od.getBoxHeight(), boxHeight);
787   }
788
789   /**
790    * Test setting of the box position, when there are hidden rows at the middle
791    * of the alignment
792    */
793   @Test(groups = { "Functional" })
794   public void testFromMouseWithHiddenRowsInMiddle()
795   {
796     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
797
798     assertEquals(od.getBoxX(), 0);
799     assertEquals(od.getBoxY(), 0);
800     assertEquals(od.getBoxWidth(), boxWidth);
801     assertEquals(od.getBoxHeight(), boxHeight);
802     assertEquals(vpranges.getStartRes(), 0);
803     assertEquals(vpranges.getStartSeq(), 0);
804
805     // hide rows in middle and check updated box position is correct
806     // no changes
807     int firstHiddenRow = 50;
808     int lastHiddenRow = 54;
809     hideSequences(firstHiddenRow, lastHiddenRow);
810
811     // calculate with visible values
812     alheight = vpranges.getVisibleAlignmentHeight();
813     alwidth = vpranges.getVisibleAlignmentWidth();
814
815     boxWidth = Math.round((float) (vpranges.getEndRes()
816             - vpranges.getStartRes() + 1)
817             * od.getWidth() / alwidth);
818     boxHeight = Math.round((float) (vpranges.getEndSeq()
819             - vpranges.getStartSeq() + 1)
820             * od.getSequencesHeight() / alheight);
821
822     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
823
824     assertEquals(od.getBoxX(), 0);
825     assertEquals(od.getBoxY(), 0);
826     assertEquals(od.getBoxWidth(), boxWidth);
827     assertEquals(od.getBoxHeight(), boxHeight);
828
829     // click above hidden rows, so that box overlaps
830     int ypos = 35; // column value in residues
831     mouseClick(od, 0,
832             Math.round((float) ypos * od.getSequencesHeight() / alheight));
833     assertEquals(od.getBoxX(), 0);
834     assertEquals(od.getBoxY(),
835             Math.round((float) ypos * od.getSequencesHeight() / alheight));
836     assertEquals(od.getBoxWidth(), boxWidth);
837     assertEquals(od.getBoxHeight(), boxHeight);
838
839     // click so that box straddles hidden rows
840     ypos = 44; // column value in residues
841     mouseClick(od, 0,
842             Math.round((float) ypos * od.getSequencesHeight() / alheight));
843     assertEquals(od.getBoxX(), 0);
844     assertEquals(od.getBoxY(),
845             Math.round((float) ypos * od.getSequencesHeight() / alheight));
846     assertEquals(od.getBoxWidth(), boxWidth);
847     assertEquals(od.getBoxHeight(), boxHeight);
848   }
849
850   /**
851    * Test setting of the box position, when there are hidden rows at the end of
852    * the alignment
853    */
854   @Test(groups = { "Functional" })
855   public void testFromMouseWithHiddenRowsAtEnd()
856   {
857     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
858     assertEquals(od.getBoxX(), 0);
859     assertEquals(od.getBoxY(), 0);
860     assertEquals(od.getBoxWidth(), boxWidth);
861     assertEquals(od.getBoxHeight(), boxHeight);
862     assertEquals(vpranges.getStartRes(), 0);
863     assertEquals(vpranges.getStartSeq(), 0);
864
865     // hide rows at end and check updated box position is correct
866     // no changes
867     int firstHidden = 500;
868     int lastHidden = 524;
869     hideSequences(firstHidden, lastHidden);
870
871     // calculate with visible values
872     alheight = vpranges.getVisibleAlignmentHeight();
873     alwidth = vpranges.getVisibleAlignmentWidth();
874
875     boxWidth = Math.round((float) (vpranges.getEndRes()
876             - vpranges.getStartRes() + 1)
877             * od.getWidth() / alwidth);
878     boxHeight = Math.round((float) (vpranges.getEndSeq()
879             - vpranges.getStartSeq() + 1)
880             * od.getSequencesHeight() / alheight);
881
882     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
883     assertEquals(od.getBoxX(), 0);
884     assertEquals(od.getBoxY(), 0);
885     assertEquals(od.getBoxWidth(), boxWidth);
886     assertEquals(od.getBoxHeight(), boxHeight);
887
888     // click above hidden rows
889     int ypos = 40; // row 40
890     mouseClick(od, 0,
891             Math.round((float) ypos * od.getSequencesHeight() / alheight));
892     assertEquals(od.getBoxX(), 0);
893     assertEquals(od.getBoxY(),
894             Math.round((float) ypos * od.getSequencesHeight() / alheight));
895     assertEquals(od.getBoxWidth(), boxWidth);
896     assertEquals(od.getBoxHeight(), boxHeight);
897
898     // click above hidden rows so box overlaps
899     // boxY, boxHeight remains same
900     ypos = 497; // row 497
901     mouseClick(od, 0,
902             Math.round((float) ypos * od.getSequencesHeight() / alheight));
903     assertEquals(od.getBoxX(), 0);
904     assertEquals(
905             od.getBoxY(),
906             Math.round((float) firstHidden * od.getSequencesHeight()
907                     / alheight)
908                     - boxHeight);
909     assertEquals(od.getBoxWidth(), boxWidth);
910     assertEquals(od.getBoxHeight(), boxHeight);
911   }
912
913   /**
914    * Test the function to determine if a point is in the overview's box or not
915    */
916   @Test(groups = { "Functional" })
917   public void testPositionInBox()
918   {
919     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
920
921     assertFalse(od.isPositionInBox(0, 0));
922     assertTrue(od.isPositionInBox(10, 9));
923     assertFalse(od.isPositionInBox(0, 9));
924     assertFalse(od.isPositionInBox(9, 0));
925     assertFalse(od.isPositionInBox(75, 20));
926
927     // hide columns in the box area
928     // makes absolutely no difference
929     hiddenCols.hideColumns(1, 4);
930     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
931     assertFalse(od.isPositionInBox(0, 0));
932     assertTrue(od.isPositionInBox(10, 9));
933     assertFalse(od.isPositionInBox(0, 9));
934     assertFalse(od.isPositionInBox(9, 0));
935     assertFalse(od.isPositionInBox(75, 20));
936
937     // hide sequences in box area
938     // makes absolutely no difference
939     hideSequences(1, 3);
940     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
941     assertFalse(od.isPositionInBox(0, 0));
942     assertTrue(od.isPositionInBox(10, 9));
943     assertFalse(od.isPositionInBox(0, 9));
944     assertFalse(od.isPositionInBox(9, 0));
945     assertFalse(od.isPositionInBox(75, 20));
946   }
947
948   /*
949    * Move viewport horizontally: startRes + previous width gives new horizontal extent. Vertical extent stays the same.
950    */
951   private void moveViewportH(int startRes)
952   {
953     vpranges.setViewportStartAndWidth(startRes, viewWidth);
954     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
955   }
956
957   /*
958    * Move viewport vertically: startSeq and endSeq give new vertical extent. Horizontal extent stays the same.
959    */
960   private void moveViewportV(int startSeq)
961   {
962     vpranges.setViewportStartAndHeight(startSeq, viewHeight);
963     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
964   }
965
966   /*
967    * Move viewport horizontally and vertically.
968    */
969   private void moveViewport(int startRes, int startSeq)
970   {
971     vpranges.setViewportStartAndWidth(startRes, viewWidth);
972     vpranges.setViewportStartAndHeight(startSeq, viewHeight);
973     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
974   }
975
976   /*
977    * Mouse click as position x,y in overview window
978    */
979   private void mouseClick(OverviewDimensions od, int x, int y)
980   {
981     od.updateViewportFromMouse(x, y, al.getHiddenSequences(), hiddenCols);
982
983     // updates require an OverviewPanel to exist which it doesn't here
984     // so call setBoxPosition() as it would be called by the AlignmentPanel
985     // normally
986     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
987   }
988   
989   /*
990    * Test that the box is positioned with the top left corner at xpos, ypos
991    * and with the original width and height
992    */
993   private void testBoxIsAtClickPoint(int xpos, int ypos)
994   {
995     mouseClick(od, xpos, ypos);
996     assertEquals(od.getBoxX(), xpos);
997     assertEquals(od.getBoxY(), ypos);
998     assertEquals(od.getBoxWidth(), boxWidth);
999     assertEquals(od.getBoxHeight(), boxHeight);
1000
1001   }
1002
1003   /*
1004    * Hide sequences between start and end
1005    */
1006   private void hideSequences(int start, int end)
1007   {
1008     SequenceI[] allseqs = al.getSequencesArray();
1009     SequenceGroup theseSeqs = new SequenceGroup();
1010     
1011     for (int i = start; i <= end; i++)
1012     {
1013       theseSeqs.addSequence(allseqs[i], false);
1014       al.getHiddenSequences().hideSequence(allseqs[i]);
1015     }
1016
1017     hiddenRepSequences.put(allseqs[start], theseSeqs);
1018   }
1019 }