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