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