f6a9d32c71bd017ca50400329499116ab28204fc
[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() + vpranges.getViewportHeight() / 2,
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(), 0);
225     assertEquals(vpranges.getStartSeq(), 0);
226
227     // overly large boxX value reset to width-boxWidth
228     mouseClick(od, 101, 6);
229     assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
230     assertEquals(od.getBoxY(), 1);
231     assertEquals(od.getBoxWidth(), boxWidth);
232     assertEquals(od.getBoxHeight(), boxHeight);
233     assertEquals(vpranges.getStartRes(),
234             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
235     assertEquals(
236             vpranges.getStartSeq(),
237             Math.round((float) od.getBoxY() * alheight
238                     / od.getSequencesHeight()));
239
240     // overly large boxY value reset to sequenceHeight - boxHeight
241     mouseClick(od, 10, 520);
242     assertEquals(od.getBoxX(), 0);
243     assertEquals(od.getBoxY(), od.getSequencesHeight() - od.getBoxHeight());
244     assertEquals(od.getBoxWidth(), boxWidth);
245     assertEquals(od.getBoxHeight(), boxHeight);
246     assertEquals(vpranges.getStartRes(),
247             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
248
249     // here (float) od.getBoxY() * alheight / od.getSequencesHeight() = 507.5
250     // and round rounds to 508; however we get 507 working with row values
251     // hence the subtraction of 1
252     assertEquals(
253             vpranges.getStartSeq(),
254             Math.round((float) od.getBoxY() * alheight
255                     / od.getSequencesHeight()) - 1);
256
257     // click past end of alignment, as above
258     mouseClick(od, 3000, 5);
259     assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
260     assertEquals(od.getBoxWidth(), boxWidth);
261     assertEquals(od.getBoxHeight(), boxHeight);
262     assertEquals(vpranges.getStartRes(),
263             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
264     assertEquals(
265             vpranges.getStartSeq(),
266             Math.round((float) od.getBoxY() * alheight
267                     / od.getSequencesHeight()));
268
269     // move viewport so startRes non-zero and then mouseclick
270     moveViewportH(20);
271
272     // click at viewport position
273     int oldboxx = od.getBoxX();
274     int oldboxy = od.getBoxY();
275     mouseClick(od, od.getBoxX() + od.getBoxWidth() / 2 + 6,
276             od.getBoxY() + od.getBoxHeight() / 2 + 3);
277     assertEquals(od.getBoxX(), oldboxx + 6);
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 + 3);
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(boxWidth / 2, boxHeight / 2);
317
318     // click to right of hidden columns, box moves to click point
319     testBoxIsAtClickPoint(41 + boxWidth / 2, boxHeight / 2);
320     assertEquals(vpranges.getStartSeq(), 0);
321     assertEquals(vpranges.getStartRes(),
322             Math.round((float) 41 * 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 + boxWidth / 2;
329     mouseClick(od, xpos, boxHeight / 2);
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(boxWidth / 2, boxHeight / 2);
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(boxWidth / 2, boxHeight / 2);
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 = 54 - boxWidth / 2; // 54 is position in overview approx halfway
370                               // between cols 60 and 70
371     mouseClick(od, xpos, boxHeight / 2);
372     testBoxIsAtClickPoint(xpos, boxHeight / 2);
373     assertEquals(vpranges.getStartRes(), 1 + // rounding
374             Math.round((xpos - boxWidth / 2) * 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, boxHeight / 2);
381     testBoxIsAtClickPoint(xpos, boxHeight / 2);
382     assertEquals(vpranges.getStartRes(),
383             Math.round((float) (xpos - boxWidth / 2) * alwidth
384                     / od.getWidth()));
385     assertEquals(vpranges.getStartSeq(), 0);
386
387     // move box so boxX is in hidden cols, box overhangs at right
388     // boxX and scrollCol at left of hidden area, box width unchanged
389     xpos = Math.round((float) 50 * od.getWidth() / alwidth) + boxWidth / 2;
390     mouseClick(od, xpos, boxHeight / 2);
391     assertEquals(od.getBoxX() + od.getBoxWidth() / 2, xpos);
392     assertEquals(od.getBoxY(), 0);
393     assertEquals(od.getBoxWidth(), boxWidth);
394     assertEquals(od.getBoxHeight(), boxHeight);
395     assertEquals(vpranges.getStartRes(), 50);
396     assertEquals(vpranges.getStartSeq(), 0);
397
398     // move box so boxX is to right of hidden cols, but does not go beyond full
399     // width of alignment
400     // box width, boxX and scrollCol all as for non-hidden case
401     xpos = Math.round((float) 75 * od.getWidth() / alwidth) + boxWidth / 2;
402     mouseClick(od, xpos, boxHeight / 2);
403     assertEquals(od.getBoxX() + od.getBoxWidth() / 2, xpos);
404     assertEquals(od.getBoxY(), 0);
405     assertEquals(od.getBoxWidth(), boxWidth);
406     assertEquals(od.getBoxHeight(), boxHeight);
407     assertEquals(vpranges.getStartSeq(), 0);
408     assertEquals(vpranges.getStartRes(), 75);
409     
410     // move box so it goes beyond full width of alignment
411     // boxX, scrollCol adjusted back, box width normal
412     xpos = 3000;
413     mouseClick(od, xpos, boxHeight / 2);
414     assertEquals(od.getBoxX(), Math.round(od.getWidth()) - boxWidth);
415     assertEquals(od.getBoxY(), 0);
416     assertEquals(od.getBoxWidth(), boxWidth);
417     assertEquals(od.getBoxHeight(), boxHeight);
418     assertEquals(vpranges.getStartRes(),
419             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
420     assertEquals(vpranges.getStartSeq(), 0);
421
422   }
423
424   /**
425    * Test setting of the box position, when there are hidden cols at the end of
426    * the alignment
427    */
428   @Test(groups = { "Functional" })
429   public void testFromMouseWithHiddenColsAtEnd()
430   {
431     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
432     assertEquals(od.getBoxX(), 0);
433     assertEquals(od.getBoxY(), 0);
434     assertEquals(od.getBoxWidth(), boxWidth);
435     assertEquals(vpranges.getStartRes(), 0);
436     assertEquals(vpranges.getStartSeq(), 0);
437
438     // hide columns 140-164, no change to box position or dimensions
439     int firstHidden = 140;
440     int lastHidden = 164;
441     hiddenCols.hideColumns(firstHidden, lastHidden);
442     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
443     assertEquals(od.getBoxX(), 0);
444     assertEquals(od.getBoxY(), 0);
445     assertEquals(od.getBoxWidth(), boxWidth);
446     assertEquals(vpranges.getStartRes(), 0);
447     assertEquals(vpranges.getStartSeq(), 0);
448
449     // click to left of hidden cols, without overlapping
450     // boxX, scrollCol and width as normal
451     int xpos = 30;
452     int ypos = 6;
453     testBoxIsAtClickPoint(xpos, ypos);
454     assertEquals(vpranges.getStartSeq(), Math.round(
455             (float) (ypos - boxHeight / 2) * alheight / od.getHeight()));
456     assertEquals(vpranges.getStartRes(), Math.round(
457             (float) (xpos - boxWidth / 2) * alwidth / od.getWidth()));
458
459     // click to left of hidden cols, with overlap
460     // boxX and scrollCol adjusted for hidden cols, width normal
461     xpos = Math.round((float) 144 * od.getWidth() / alwidth) - boxWidth;
462     mouseClick(od, xpos, boxHeight / 2);
463     testBoxIsAtClickPoint(xpos, boxHeight / 2);
464     assertEquals(vpranges.getStartRes(),
465             Math.round((float) (xpos - boxWidth / 2) * alwidth
466                     / od.getWidth()));
467     assertEquals(vpranges.getStartSeq(), 0);
468
469     // click off end of alignment
470     // boxX and scrollCol adjusted backwards, width normal
471     xpos = 3000;
472     mouseClick(od, xpos, 0);
473     assertEquals(od.getBoxX(), Math.round(od.getWidth()) - boxWidth);
474     assertEquals(od.getBoxY(), 0);
475     assertEquals(od.getBoxWidth(), boxWidth);
476     assertEquals(od.getBoxHeight(), boxHeight);
477     assertEquals(vpranges.getStartRes(),
478             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
479     assertEquals(vpranges.getStartSeq(), 0);
480   }
481
482   /**
483    * Test that the box position is set correctly when set from the viewport,
484    * with no hidden rows or columns
485    */
486   @Test(groups = { "Functional" })
487   public void testSetBoxFromViewport()
488   {
489     // move viewport to start of alignment
490     moveViewport(0, 0);
491     assertEquals(od.getBoxX(), 0);
492     assertEquals(od.getBoxY(), 0);
493     assertEquals(od.getBoxWidth(), boxWidth);
494     assertEquals(od.getBoxHeight(), boxHeight);
495
496     // move viewport to right
497     moveViewportH(70);
498     assertEquals(od.getBoxX(),
499             Math.round((float) 70 * od.getWidth() / alwidth));
500     assertEquals(od.getBoxY(), 0);
501     assertEquals(od.getBoxWidth(), boxWidth);
502     assertEquals(od.getBoxHeight(), boxHeight);
503
504     // move viewport down
505     moveViewportV(100);
506     assertEquals(od.getBoxX(),
507             Math.round((float) 70 * od.getWidth() / alwidth));
508     assertEquals(od.getBoxY(),
509             Math.round(100 * od.getSequencesHeight() / alheight));
510     assertEquals(od.getBoxWidth(), boxWidth);
511     assertEquals(od.getBoxHeight(), boxHeight);
512
513     // move viewport to bottom right
514     moveViewport(98, 508);
515     assertEquals(od.getBoxX(),
516             Math.round((float) 98 * od.getWidth() / alwidth));
517     assertEquals(od.getBoxY(),
518             Math.round((float) 508 * od.getSequencesHeight() / alheight));
519     assertEquals(od.getBoxWidth(), boxWidth);
520     assertEquals(od.getBoxHeight(), boxHeight);
521   }
522
523   /**
524    * Test that the box position is set correctly when there are hidden columns
525    * at the start
526    */
527   @Test(groups = { "Functional" })
528   public void testSetBoxFromViewportHiddenColsAtStart()
529   {
530     int firstHidden = 0;
531     int lastHidden = 20;
532     hiddenCols.hideColumns(firstHidden, lastHidden);
533
534     // move viewport to start of alignment
535     moveViewport(0, 0);
536     assertEquals(od.getBoxX(), 0);
537     assertEquals(od.getBoxY(), 0);
538     assertEquals(od.getBoxWidth(), boxWidth);
539     assertEquals(od.getBoxHeight(), boxHeight);
540
541     // move viewport to end of alignment - need to make startRes by removing
542     // hidden cols because of how viewport/overview are implemented
543     moveViewport(98 - lastHidden - 1, 0);
544     assertEquals(od.getBoxX(),
545             Math.round((float) (98 - lastHidden - 1) * od.getWidth()
546                     / alwidth));
547     assertEquals(od.getBoxY(), 0);
548     assertEquals(od.getBoxWidth(), boxWidth);
549     assertEquals(od.getBoxHeight(), boxHeight);
550   }
551
552   /**
553    * Test that the box position is set correctly when there are hidden columns
554    * in the middle
555    */
556   @Test(groups = { "Functional" })
557   public void testSetBoxFromViewportHiddenColsInMiddle()
558   {
559     int firstHidden = 68;
560     int lastHidden = 78;
561     hiddenCols.hideColumns(firstHidden, lastHidden);
562
563     // move viewport before hidden columns
564     moveViewport(3, 0);
565
566     assertEquals(od.getBoxX(),
567             Math.round((float) 3 * od.getWidth() / alwidth));
568     assertEquals(od.getBoxY(), 0);
569     assertEquals(od.getBoxWidth(), boxWidth);
570     assertEquals(od.getBoxHeight(), boxHeight);
571
572     // move viewport to left of hidden columns with overlap
573     moveViewport(10, 0);
574     assertEquals(od.getBoxX(),
575             Math.round((float) 10 * od.getWidth() / alwidth));
576     assertEquals(od.getBoxY(), 0);
577     assertEquals(od.getBoxWidth(), boxWidth);
578     assertEquals(od.getBoxHeight(), boxHeight);
579
580     // move viewport to straddle hidden columns
581     moveViewport(63, 0);
582     assertEquals(od.getBoxX(),
583             Math.round((float) 63 * od.getWidth() / alwidth));
584     assertEquals(od.getBoxY(), 0);
585     assertEquals(od.getBoxWidth(), boxWidth);
586     assertEquals(od.getBoxHeight(), boxHeight);
587
588     // move viewport to right of hidden columns, no overlap
589     moveViewport(80 - (lastHidden - firstHidden + 1), 0);
590     assertEquals(od.getBoxX(),
591             Math.round((float) (80 - (lastHidden - firstHidden + 1))
592                     * od.getWidth() / alwidth));
593     assertEquals(od.getBoxY(), 0);
594     assertEquals(od.getBoxWidth(), boxWidth);
595     assertEquals(od.getBoxHeight(), boxHeight);
596
597   }
598
599   /**
600    * Test that the box position is set correctly when there are hidden columns
601    * at the end
602    */
603   @Test(groups = { "Functional" })
604   public void testSetBoxFromViewportHiddenColsAtEnd()
605   {
606     int firstHidden = 152;
607     int lastHidden = 164;
608     hiddenCols.hideColumns(firstHidden, lastHidden);
609
610     // move viewport before hidden columns
611     moveViewport(3, 0);
612     assertEquals(od.getBoxX(),
613             Math.round((float) 3 * od.getWidth() / alwidth));
614     assertEquals(od.getBoxY(), 0);
615     assertEquals(od.getBoxWidth(), boxWidth);
616     assertEquals(od.getBoxHeight(), boxHeight);
617
618     // move viewport to hidden columns
619     // viewport can't actually extend into hidden cols,
620     // so move to the far right edge of the viewport
621     moveViewport(firstHidden - viewWidth, 0);
622     assertEquals(od.getBoxX(),
623             Math.round((float) (firstHidden - viewWidth)
624                     * od.getWidth() / alwidth));
625     assertEquals(od.getBoxY(), 0);
626     assertEquals(od.getBoxWidth(), boxWidth);
627     assertEquals(od.getBoxHeight(), boxHeight);
628   }
629
630   /**
631    * Test that the box position is set correctly when there are hidden rows at
632    * the start
633    */
634   @Test(groups = { "Functional" })
635   public void testSetBoxFromViewportHiddenRowsAtStart()
636   {
637     int firstHidden = 0;
638     int lastHidden = 20;
639     hideSequences(firstHidden, lastHidden);
640
641     // calculate with visible values
642     alheight = vpranges.getVisibleAlignmentHeight();
643     alwidth = vpranges.getVisibleAlignmentWidth();
644
645     boxWidth = Math.round((float) (vpranges.getEndRes()
646             - vpranges.getStartRes() + 1)
647             * od.getWidth() / alwidth);
648     boxHeight = Math.round((float) (vpranges.getEndSeq()
649             - vpranges.getStartSeq() + 1)
650             * od.getSequencesHeight() / alheight);
651
652     // move viewport to start of alignment:
653     // box moves to below hidden rows, height remains same
654     moveViewport(0, 0);
655     assertEquals(od.getBoxX(), 0);
656     assertEquals(od.getBoxY(), 0);
657     assertEquals(od.getBoxWidth(), boxWidth);
658     assertEquals(od.getBoxHeight(), boxHeight);
659
660     // move viewport to end of alignment
661     moveViewport(0, 525 - viewHeight - lastHidden - 1);
662     assertEquals(od.getBoxX(), 0);
663     assertEquals(
664             od.getBoxY(),
665             Math.round((float) (525 - viewHeight - lastHidden - 1)
666                     * od.getSequencesHeight()
667                     / alheight));
668     assertEquals(od.getBoxWidth(), boxWidth);
669     assertEquals(od.getBoxHeight(), boxHeight);
670   }
671
672   /**
673    * Test that the box position is set correctly when there are hidden rows in
674    * the middle
675    */
676   @Test(groups = { "Functional" })
677   public void testSetBoxFromViewportHiddenRowsInMiddle()
678   {
679     int firstHidden = 200;
680     int lastHidden = 210;
681     hideSequences(firstHidden, lastHidden);
682
683     // calculate with visible values
684     alheight = vpranges.getVisibleAlignmentHeight();
685     alwidth = vpranges.getVisibleAlignmentWidth();
686
687     boxWidth = Math.round((float) (vpranges.getEndRes()
688             - vpranges.getStartRes() + 1)
689             * od.getWidth() / alwidth);
690     boxHeight = Math.round((float) (vpranges.getEndSeq()
691             - vpranges.getStartSeq() + 1)
692             * od.getSequencesHeight() / alheight);
693
694     // move viewport to start of alignment:
695     // box, height etc as in non-hidden case
696     moveViewport(0, 0);
697     assertEquals(od.getBoxX(), 0);
698     assertEquals(od.getBoxY(), 0);
699     assertEquals(od.getBoxWidth(), boxWidth);
700     assertEquals(od.getBoxHeight(), boxHeight);
701
702     // move viewport to straddle hidden rows
703     moveViewport(0, 198);
704     assertEquals(od.getBoxX(), 0);
705     assertEquals(od.getBoxY(), Math.round ((float)198 * od.getSequencesHeight()
706             / alheight));
707     assertEquals(od.getBoxWidth(), boxWidth);
708     assertEquals(od.getBoxHeight(), boxHeight);
709   }
710
711   /**
712    * Test that the box position is set correctly when there are hidden rows at
713    * the bottom
714    */
715   @Test(groups = { "Functional" })
716   public void testSetBoxFromViewportHiddenRowsAtEnd()
717   {
718     int firstHidden = 500;
719     int lastHidden = 524;
720     hideSequences(firstHidden, lastHidden);
721
722     // calculate with visible values
723     alheight = vpranges.getVisibleAlignmentHeight();
724     alwidth = vpranges.getVisibleAlignmentWidth();
725
726     boxWidth = Math.round((float) (vpranges.getEndRes()
727             - vpranges.getStartRes() + 1)
728             * od.getWidth() / alwidth);
729     boxHeight = Math.round((float) (vpranges.getEndSeq()
730             - vpranges.getStartSeq() + 1)
731             * od.getSequencesHeight() / alheight);
732
733     // move viewport to start of alignment:
734     // box, height etc as in non-hidden case
735     moveViewport(0, 0);
736     assertEquals(od.getBoxX(), 0);
737     assertEquals(od.getBoxY(), 0);
738     assertEquals(od.getBoxWidth(), boxWidth);
739     assertEquals(od.getBoxHeight(), boxHeight);
740
741     // move viewport to end of alignment
742     // viewport sits above hidden rows and does not include them
743     moveViewport(0, firstHidden - viewHeight - 1);
744     assertEquals(od.getBoxX(), 0);
745     assertEquals(
746             od.getBoxY(),
747             Math.round((float) (firstHidden - viewHeight - 1)
748                     * od.getSequencesHeight() / alheight));
749     assertEquals(od.getBoxWidth(), boxWidth);
750     assertEquals(od.getBoxHeight(), boxHeight);
751
752   }
753
754   /**
755    * Test setting of the box position, when there are hidden rows at the start
756    * of the alignment
757    */
758   @Test(groups = { "Functional" })
759   public void testFromMouseWithHiddenRowsAtStart()
760   {
761     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
762     assertEquals(od.getBoxX(), 0);
763     assertEquals(od.getBoxY(), 0);
764     assertEquals(od.getBoxHeight(), boxHeight);
765     assertEquals(od.getBoxWidth(), boxWidth);
766     assertEquals(vpranges.getStartRes(), 0);
767     assertEquals(vpranges.getStartSeq(), 0);
768
769     // hide rows at start and check updated box position is correct
770     int lastHiddenRow = 30;
771     hideSequences(0, lastHiddenRow);
772
773     // calculate with visible values
774     alheight = vpranges.getVisibleAlignmentHeight();
775     alwidth = vpranges.getVisibleAlignmentWidth();
776
777     boxWidth = Math.round((float) (vpranges.getEndRes()
778             - vpranges.getStartRes() + 1)
779             * od.getWidth() / alwidth);
780     boxHeight = Math.round((float) (vpranges.getEndSeq()
781             - vpranges.getStartSeq() + 1)
782             * od.getSequencesHeight() / alheight);
783
784     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
785     assertEquals(od.getBoxX(), 0);
786     assertEquals(od.getBoxY(), 0);
787     assertEquals(od.getBoxWidth(), boxWidth);
788     assertEquals(od.getBoxHeight(), boxHeight);
789
790     // click below hidden rows
791     mouseClick(od, 0, 151 + boxHeight / 2);
792     assertEquals(od.getBoxX(), 0);
793     assertEquals(od.getBoxY(), 151);
794     assertEquals(od.getBoxWidth(), boxWidth);
795     assertEquals(od.getBoxHeight(), boxHeight);
796   }
797
798   /**
799    * Test setting of the box position, when there are hidden rows at the middle
800    * of the alignment
801    */
802   @Test(groups = { "Functional" })
803   public void testFromMouseWithHiddenRowsInMiddle()
804   {
805     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
806
807     assertEquals(od.getBoxX(), 0);
808     assertEquals(od.getBoxY(), 0);
809     assertEquals(od.getBoxWidth(), boxWidth);
810     assertEquals(od.getBoxHeight(), boxHeight);
811     assertEquals(vpranges.getStartRes(), 0);
812     assertEquals(vpranges.getStartSeq(), 0);
813
814     // hide rows in middle and check updated box position is correct
815     // no changes
816     int firstHiddenRow = 50;
817     int lastHiddenRow = 54;
818     hideSequences(firstHiddenRow, lastHiddenRow);
819
820     // calculate with visible values
821     alheight = vpranges.getVisibleAlignmentHeight();
822     alwidth = vpranges.getVisibleAlignmentWidth();
823
824     boxWidth = Math.round((float) (vpranges.getEndRes()
825             - vpranges.getStartRes() + 1)
826             * od.getWidth() / alwidth);
827     boxHeight = Math.round((float) (vpranges.getEndSeq()
828             - vpranges.getStartSeq() + 1)
829             * od.getSequencesHeight() / alheight);
830
831     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
832
833     assertEquals(od.getBoxX(), 0);
834     assertEquals(od.getBoxY(), 0);
835     assertEquals(od.getBoxWidth(), boxWidth);
836     assertEquals(od.getBoxHeight(), boxHeight);
837
838     // click above hidden rows, so that box overlaps
839     int ypos = 35 + viewHeight / 2; // row value in residues
840     mouseClick(od, 0,
841             Math.round((float) ypos * od.getSequencesHeight() / alheight));
842     assertEquals(od.getBoxX(), 0);
843     assertEquals(od.getBoxY(),
844             Math.round((float) 35 * od.getSequencesHeight() / alheight));
845     assertEquals(od.getBoxWidth(), boxWidth);
846     assertEquals(od.getBoxHeight(), boxHeight);
847
848     // click so that box straddles hidden rows
849     ypos = 45 + viewHeight / 2; // row value in residues
850     mouseClick(od, 0,
851             Math.round((float) ypos * od.getSequencesHeight() / alheight));
852     assertEquals(od.getBoxX(), 0);
853     assertEquals(od.getBoxY(),
854             Math.round((float) 45 * od.getSequencesHeight() / alheight));
855     assertEquals(od.getBoxWidth(), boxWidth);
856     assertEquals(od.getBoxHeight(), boxHeight);
857   }
858
859   /**
860    * Test setting of the box position, when there are hidden rows at the end of
861    * the alignment
862    */
863   @Test(groups = { "Functional" })
864   public void testFromMouseWithHiddenRowsAtEnd()
865   {
866     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
867     assertEquals(od.getBoxX(), 0);
868     assertEquals(od.getBoxY(), 0);
869     assertEquals(od.getBoxWidth(), boxWidth);
870     assertEquals(od.getBoxHeight(), boxHeight);
871     assertEquals(vpranges.getStartRes(), 0);
872     assertEquals(vpranges.getStartSeq(), 0);
873
874     // hide rows at end and check updated box position is correct
875     // no changes
876     int firstHidden = 500;
877     int lastHidden = 524;
878     hideSequences(firstHidden, lastHidden);
879
880     // calculate with visible values
881     alheight = vpranges.getVisibleAlignmentHeight();
882     alwidth = vpranges.getVisibleAlignmentWidth();
883
884     boxWidth = Math.round((float) (vpranges.getEndRes()
885             - vpranges.getStartRes() + 1)
886             * od.getWidth() / alwidth);
887     boxHeight = Math.round((float) (vpranges.getEndSeq()
888             - vpranges.getStartSeq() + 1)
889             * od.getSequencesHeight() / alheight);
890
891     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
892     assertEquals(od.getBoxX(), 0);
893     assertEquals(od.getBoxY(), 0);
894     assertEquals(od.getBoxWidth(), boxWidth);
895     assertEquals(od.getBoxHeight(), boxHeight);
896
897     // click above hidden rows
898     int ypos = 41 + viewHeight / 2; // row 41
899     mouseClick(od, 0,
900             Math.round((float) ypos * od.getSequencesHeight() / alheight));
901     assertEquals(od.getBoxX(), 0);
902     assertEquals(od.getBoxY(),
903             Math.round((float) 41 * od.getSequencesHeight() / alheight));
904     assertEquals(od.getBoxWidth(), boxWidth);
905     assertEquals(od.getBoxHeight(), boxHeight);
906
907     // click above hidden rows so box overlaps
908     // boxY, boxHeight remains same
909     ypos = 497 + viewHeight / 2; // row 497
910     mouseClick(od, 0,
911             Math.round((float) ypos * od.getSequencesHeight() / alheight));
912     assertEquals(od.getBoxX(), 0);
913     assertEquals(
914             od.getBoxY(),
915             Math.round((float) firstHidden * od.getSequencesHeight()
916                     / alheight)
917                     - boxHeight);
918     assertEquals(od.getBoxWidth(), boxWidth);
919     assertEquals(od.getBoxHeight(), boxHeight);
920   }
921
922   /**
923    * Test the function to determine if a point is in the overview's box or not
924    */
925   @Test(groups = { "Functional" })
926   public void testPositionInBox()
927   {
928     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
929
930     assertFalse(od.isPositionInBox(0, 0));
931     assertTrue(od.isPositionInBox(10, 9));
932     assertFalse(od.isPositionInBox(0, 9));
933     assertFalse(od.isPositionInBox(9, 0));
934     assertFalse(od.isPositionInBox(75, 20));
935
936     // hide columns in the box area
937     // makes absolutely no difference
938     hiddenCols.hideColumns(1, 4);
939     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
940     assertFalse(od.isPositionInBox(0, 0));
941     assertTrue(od.isPositionInBox(10, 9));
942     assertFalse(od.isPositionInBox(0, 9));
943     assertFalse(od.isPositionInBox(9, 0));
944     assertFalse(od.isPositionInBox(75, 20));
945
946     // hide sequences in box area
947     // makes absolutely no difference
948     hideSequences(1, 3);
949     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
950     assertFalse(od.isPositionInBox(0, 0));
951     assertTrue(od.isPositionInBox(10, 9));
952     assertFalse(od.isPositionInBox(0, 9));
953     assertFalse(od.isPositionInBox(9, 0));
954     assertFalse(od.isPositionInBox(75, 20));
955   }
956
957   /**
958    * Test the dragging functionality
959    */
960   @Test(groups = { "Functional" })
961   public void testDragging()
962   {
963     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
964     od.setDragPoint(4, 16, al.getHiddenSequences(),
965             hiddenCols);
966     od.adjustViewportFromMouse(20, 22,
967             al.getHiddenSequences(), hiddenCols);
968
969     // updates require an OverviewPanel to exist which it doesn't here
970     // so call setBoxPosition() as it would be called by the AlignmentPanel
971     // normally
972     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
973
974     // corner moves 16 (20-4) right and 6 (22-16) up
975     assertEquals(od.getBoxX(), 16);
976     assertEquals(od.getBoxY(), 6);
977
978     // hide columns - makes no difference
979     hiddenCols.hideColumns(1, 4);
980     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
981     od.setDragPoint(4, 16, al.getHiddenSequences(), hiddenCols);
982     od.adjustViewportFromMouse(20, 22, al.getHiddenSequences(), hiddenCols);
983     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
984
985     // corner moves 16 (20-4) right and 6 (22-16) up
986     assertEquals(od.getBoxX(), 16);
987     assertEquals(od.getBoxY(), 6);
988
989     // hide sequences in box area
990     // makes absolutely no difference
991     hideSequences(1, 3);
992     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols);
993     od.setDragPoint(4, 16, al.getHiddenSequences(), hiddenCols);
994     od.adjustViewportFromMouse(20, 22, al.getHiddenSequences(), hiddenCols);
995     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
996
997     // corner moves 16 (20-4) right and 6 (22-16) up
998     assertEquals(od.getBoxX(), 16);
999     assertEquals(od.getBoxY(), 6);
1000   }
1001
1002   /*
1003    * Move viewport horizontally: startRes + previous width gives new horizontal extent. Vertical extent stays the same.
1004    */
1005   private void moveViewportH(int startRes)
1006   {
1007     vpranges.setViewportStartAndWidth(startRes, viewWidth);
1008     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
1009   }
1010
1011   /*
1012    * Move viewport vertically: startSeq and endSeq give new vertical extent. Horizontal extent stays the same.
1013    */
1014   private void moveViewportV(int startSeq)
1015   {
1016     vpranges.setViewportStartAndHeight(startSeq, viewHeight);
1017     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
1018   }
1019
1020   /*
1021    * Move viewport horizontally and vertically.
1022    */
1023   private void moveViewport(int startRes, int startSeq)
1024   {
1025     vpranges.setViewportStartAndWidth(startRes, viewWidth);
1026     vpranges.setViewportStartAndHeight(startSeq, viewHeight);
1027     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
1028   }
1029
1030   /*
1031    * Mouse click as position x,y in overview window
1032    */
1033   private void mouseClick(OverviewDimensions od, int x, int y)
1034   {
1035     od.updateViewportFromMouse(x, y, al.getHiddenSequences(), hiddenCols);
1036
1037     // updates require an OverviewPanel to exist which it doesn't here
1038     // so call setBoxPosition() as it would be called by the AlignmentPanel
1039     // normally
1040     od.setBoxPosition(al.getHiddenSequences(), hiddenCols);
1041   }
1042   
1043   /*
1044    * Test that the box is positioned with the top left corner at xpos, ypos
1045    * and with the original width and height
1046    */
1047   private void testBoxIsAtClickPoint(int xpos, int ypos)
1048   {
1049     mouseClick(od, xpos, ypos);
1050     assertEquals(od.getBoxX() + od.getBoxWidth() / 2, xpos);
1051     assertEquals(od.getBoxY() + od.getBoxHeight() / 2, ypos);
1052     assertEquals(od.getBoxWidth(), boxWidth);
1053     assertEquals(od.getBoxHeight(), boxHeight);
1054
1055   }
1056
1057   /*
1058    * Hide sequences between start and end
1059    */
1060   private void hideSequences(int start, int end)
1061   {
1062     SequenceI[] allseqs = al.getSequencesArray();
1063     SequenceGroup theseSeqs = new SequenceGroup();
1064     
1065     for (int i = start; i <= end; i++)
1066     {
1067       theseSeqs.addSequence(allseqs[i], false);
1068       al.getHiddenSequences().hideSequence(allseqs[i]);
1069     }
1070
1071     hiddenRepSequences.put(allseqs[start], theseSeqs);
1072   }
1073 }