Merge remote-tracking branch 'origin/develop' into
[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   OverviewDimensions 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 OverviewDimensions(vpranges, true);
92     // Initial box sizing - default path through code
93     od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
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 OverviewDimensions(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 OverviewDimensions(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 OverviewDimensions(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 OverviewDimensions(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 OverviewDimensions(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             vpranges);
204     assertEquals(od.getBoxX(), 0);
205     assertEquals(od.getBoxY(), 0);
206     assertEquals(od.getBoxWidth(), boxWidth);
207     assertEquals(od.getScrollCol(), 0);
208     assertEquals(od.getScrollRow(), 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(od.getScrollRow(),
216             Math.round((float) 10 * alheight / od.getSequencesHeight()));
217     assertEquals(od.getScrollCol(), 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(od.getScrollCol(),
225             Math.round((float) 6 * alwidth / od.getWidth()));
226     assertEquals(od.getScrollRow(), 0);
227
228     // overly large boxX value reset to width-boxWidth
229     mouseClick(od, 100, 6);
230     assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
231     assertEquals(od.getBoxY(), 6);
232     assertEquals(od.getBoxWidth(), boxWidth);
233     assertEquals(od.getBoxHeight(), boxHeight);
234     assertEquals(od.getScrollCol(),
235             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
236     assertEquals(od.getScrollRow(),
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(), 10);
243     assertEquals(od.getBoxY(), od.getSequencesHeight() - od.getBoxHeight());
244     assertEquals(od.getBoxWidth(), boxWidth);
245     assertEquals(od.getBoxHeight(), boxHeight);
246     assertEquals(od.getScrollCol(),
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(od.getScrollRow(),
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(od.getScrollCol(),
262             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
263     assertEquals(od.getScrollRow(),
264             Math.round((float) od.getBoxY() * alheight
265                     / od.getSequencesHeight()));
266
267     // move viewport so startRes non-zero and then mouseclick
268     moveViewportH(50);
269
270     // click at viewport position
271     int oldboxx = od.getBoxX();
272     int oldboxy = od.getBoxY();
273     mouseClick(od, od.getBoxX() + 5, od.getBoxY() + 2);
274     assertEquals(od.getBoxX(), oldboxx + 5);
275     assertEquals(od.getBoxWidth(), boxWidth);
276     assertEquals(od.getBoxHeight(), boxHeight);
277     assertEquals(od.getScrollCol(),
278             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
279     assertEquals(od.getBoxY(), oldboxy + 2);
280     assertEquals(od.getScrollRow(),
281             Math.round((float) od.getBoxY() * alheight
282                     / od.getSequencesHeight()));
283
284     // click at top corner
285     mouseClick(od, 0, 0);
286     assertEquals(od.getBoxX(), 0);
287     assertEquals(od.getScrollCol(), 0);
288     assertEquals(od.getBoxY(), 0);
289     assertEquals(od.getScrollRow(), 0);
290     assertEquals(od.getBoxWidth(), boxWidth);
291     assertEquals(od.getBoxHeight(), boxHeight);
292   }
293
294   /**
295    * Test setting of the box position, when there are hidden cols at the start
296    * of the alignment
297    */
298   @Test(groups = { "Functional" })
299   public void testFromMouseWithHiddenColsAtStart()
300   {
301     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
302             vpranges);
303     assertEquals(od.getBoxX(), 0);
304     assertEquals(od.getBoxY(), 0);
305     assertEquals(od.getBoxWidth(), boxWidth);
306     assertEquals(od.getScrollCol(), 0);
307     assertEquals(od.getScrollRow(), 0);
308
309     // hide cols at start and check updated box position is correct
310     // changes boxX but not boxwidth
311     int lastHiddenCol = 30;
312     hiddenCols.hideColumns(0, lastHiddenCol);
313
314     od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
315     assertEquals(od.getBoxX(),
316             Math.round((float) (lastHiddenCol + 1) * od.getWidth()
317                     / alwidth));
318     assertEquals(od.getBoxWidth(), boxWidth);
319     assertEquals(od.getBoxHeight(), boxHeight);
320
321     // try to click in hidden cols, check box does not move
322     int xpos = 10;
323     mouseClick(od, xpos, 0);
324     assertEquals(
325             od.getBoxX(),
326             Math.round((float) (lastHiddenCol + 1) * od.getWidth()
327                     / alwidth));
328     assertEquals(od.getBoxY(), 0);
329     assertEquals(od.getBoxWidth(), boxWidth);
330     assertEquals(od.getBoxHeight(), boxHeight);
331     assertEquals(od.getScrollRow(), 0);
332     assertEquals(od.getScrollCol(), 0);
333
334     // click to right of hidden columns, box moves to click point
335     testBoxIsAtClickPoint(40, 0);
336     assertEquals(od.getScrollRow(), 0);
337     assertEquals(od.getScrollCol(),
338             Math.round((float) 40 * alwidth / od.getWidth())
339                     - (lastHiddenCol + 1));
340
341     // click to right of hidden columns such that box runs over right hand side
342     // of alignment
343     // box position is adjusted away from the edge
344     // overly large boxX value reset to width-boxWidth
345     xpos = 100;
346     mouseClick(od, xpos, 5);
347     assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
348     assertEquals(od.getBoxY(), 5);
349     assertEquals(od.getBoxWidth(), boxWidth);
350     assertEquals(od.getBoxHeight(), boxHeight);
351     assertEquals(od.getScrollCol(),
352             Math.round((float) od.getBoxX() * alwidth / od.getWidth())
353                     - (lastHiddenCol + 1));
354     assertEquals(od.getScrollRow(),
355             Math.round((float) od.getBoxY() * alheight
356                     / od.getSequencesHeight()));
357   }
358
359   /**
360    * Test setting of the box position, when there are hidden cols in the middle
361    * of the alignment
362    */
363   @Test(groups = { "Functional" })
364   public void testFromMouseWithHiddenColsInMiddle()
365   {
366     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
367             vpranges);
368     assertEquals(od.getBoxX(), 0);
369     assertEquals(od.getBoxY(), 0);
370     assertEquals(od.getBoxWidth(), boxWidth);
371     assertEquals(od.getScrollCol(), 0);
372     assertEquals(od.getScrollRow(), 0);
373     
374     // hide columns 63-73, no change to box position or dimensions
375     int firstHidden = 63;
376     int lastHidden = 73;
377     hiddenCols.hideColumns(firstHidden, lastHidden);
378
379     od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
380     assertEquals(od.getBoxX(), 0);
381     assertEquals(od.getBoxY(), 0);
382     assertEquals(od.getBoxWidth(), boxWidth);
383     assertEquals(od.getScrollCol(), 0);
384     assertEquals(od.getScrollRow(), 0);
385
386     // move box so that it overlaps with hidden cols on one side
387     // box width changes, boxX and scrollCol as for unhidden case
388     int xpos = 55 - boxWidth; // 55 is position in overview approx halfway
389                               // between cols 60 and 70
390     mouseClick(od, xpos, 0);
391     assertEquals(od.getBoxX(), xpos);
392     assertEquals(od.getBoxY(), 0);
393     assertEquals(
394             od.getBoxWidth(),
395             Math.round(boxWidth + (float) (lastHidden - firstHidden + 1)
396                     * od.getWidth() / alwidth));
397     assertEquals(od.getBoxHeight(), boxHeight);
398     assertEquals(od.getScrollCol(),
399             Math.round(xpos * alwidth / od.getWidth()));
400     assertEquals(od.getScrollRow(), 0);
401
402     // move box so that it completely covers hidden cols
403     // box width changes, boxX and scrollCol as for hidden case
404     xpos = 33;
405     mouseClick(od, xpos, 0);
406     assertEquals(od.getBoxX(), xpos);
407     assertEquals(od.getBoxY(), 0);
408     assertEquals(
409             od.getBoxWidth(),
410             Math.round(boxWidth + (float) (lastHidden - firstHidden + 1)
411                     * od.getWidth() / alwidth));
412     assertEquals(od.getBoxHeight(), boxHeight);
413     assertEquals(od.getScrollCol(),
414             Math.round((float) xpos * alwidth / od.getWidth()));
415     assertEquals(od.getScrollRow(), 0);
416
417     // move box so boxX is in hidden cols, box overhangs at right
418     // boxX and scrollCol at left of hidden area, box width extends across
419     // hidden region
420     xpos = 50;
421     mouseClick(od, xpos, 0);
422     assertEquals(od.getBoxX(),
423             Math.round((float) (firstHidden - 1) * od.getWidth() / alwidth));
424     assertEquals(od.getBoxY(), 0);
425     assertEquals(
426             od.getBoxWidth(),
427             boxWidth
428                     + Math.round((float) (lastHidden - firstHidden + 1)
429                             * od.getWidth() / alwidth));
430     assertEquals(od.getBoxHeight(), boxHeight);
431     assertEquals(od.getScrollCol(), firstHidden - 1);
432     assertEquals(od.getScrollRow(), 0);
433
434     // move box so boxX is to right of hidden cols, but does not go beyond full
435     // width of alignment
436     // box width, boxX and scrollCol all as for non-hidden case
437     xpos = 75;
438     testBoxIsAtClickPoint(xpos, 0);
439     assertEquals(od.getScrollRow(), 0);
440     assertEquals(od.getScrollCol(),
441             Math.round(xpos * alwidth / od.getWidth())
442                     - (lastHidden - firstHidden + 1));
443     
444     // move box so it goes beyond full width of alignment
445     // boxX, scrollCol adjusted back, box width normal
446     xpos = 3000;
447     mouseClick(od, xpos, 5);
448     assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
449     assertEquals(od.getBoxY(), 5);
450     assertEquals(od.getBoxWidth(), boxWidth);
451     assertEquals(od.getBoxHeight(), boxHeight);
452     assertEquals(od.getScrollCol(),
453             Math.round(((float) od.getBoxX() * alwidth / od.getWidth())
454                     - (lastHidden - firstHidden + 1)));
455     assertEquals(od.getScrollRow(),
456             Math.round((float) od.getBoxY() * alheight
457                     / od.getSequencesHeight()));
458
459   }
460
461   /**
462    * Test setting of the box position, when there are hidden cols at the end of
463    * the alignment
464    */
465   @Test(groups = { "Functional" })
466   public void testFromMouseWithHiddenColsAtEnd()
467   {
468     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
469             vpranges);
470     assertEquals(od.getBoxX(), 0);
471     assertEquals(od.getBoxY(), 0);
472     assertEquals(od.getBoxWidth(), boxWidth);
473     assertEquals(od.getScrollCol(), 0);
474     assertEquals(od.getScrollRow(), 0);
475
476     // hide columns 140-164, no change to box position or dimensions
477     int firstHidden = 140;
478     int lastHidden = 164;
479     hiddenCols.hideColumns(firstHidden, lastHidden);
480     od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
481     assertEquals(od.getBoxX(), 0);
482     assertEquals(od.getBoxY(), 0);
483     assertEquals(od.getBoxWidth(), boxWidth);
484     assertEquals(od.getScrollCol(), 0);
485     assertEquals(od.getScrollRow(), 0);
486
487     // click to left of hidden cols, without overlapping
488     // boxX, scrollCol and width as normal
489     int xpos = 5;
490     testBoxIsAtClickPoint(xpos, 0);
491     assertEquals(od.getScrollRow(), 0);
492     assertEquals(od.getScrollCol(),
493             Math.round((float) xpos * alwidth / od.getWidth()));
494
495     // click to left of hidden cols, with overlap
496     // boxX and scrollCol adjusted for hidden cols, width normal
497     xpos = Math.round((float) 145 * od.getWidth() / alwidth) - boxWidth;
498     mouseClick(od, xpos, 0);
499     assertEquals(od.getBoxX(),
500             Math.round((float) (firstHidden - 1) * od.getWidth() / alwidth)
501                     - boxWidth + 1);
502     assertEquals(od.getBoxY(), 0);
503     assertEquals(od.getBoxWidth(), boxWidth);
504     assertEquals(od.getBoxHeight(), boxHeight);
505     assertEquals(od.getScrollCol(),
506             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
507     assertEquals(od.getScrollRow(), 0);
508
509     // click in hidden cols
510     // boxX and scrollCol adjusted for hidden cols, width normal
511     xpos = 115;
512     assertEquals(od.getBoxX(),
513             Math.round((float) (firstHidden - 1) * od.getWidth() / alwidth)
514                     - boxWidth + 1);
515     assertEquals(od.getBoxY(), 0);
516     assertEquals(od.getBoxWidth(), boxWidth);
517     assertEquals(od.getBoxHeight(), boxHeight);
518     assertEquals(od.getScrollCol(),
519             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
520     assertEquals(od.getScrollRow(), 0);
521
522     // click off end of alignment
523     // boxX and scrollCol adjusted for hidden cols, width normal
524     xpos = 3000;
525     assertEquals(od.getBoxX(),
526             Math.round((float) (firstHidden - 1) * od.getWidth() / alwidth)
527                     - boxWidth + 1);
528     assertEquals(od.getBoxY(), 0);
529     assertEquals(od.getBoxWidth(), boxWidth);
530     assertEquals(od.getBoxHeight(), boxHeight);
531     assertEquals(od.getScrollCol(),
532             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
533     assertEquals(od.getScrollRow(), 0);
534   }
535
536   /**
537    * Test that the box position is set correctly when set from the viewport,
538    * with no hidden rows or columns
539    */
540   @Test(groups = { "Functional" })
541   public void testSetBoxFromViewport()
542   {
543     // move viewport to start of alignment
544     moveViewport(0, 0);
545     assertEquals(od.getBoxX(), 0);
546     assertEquals(od.getBoxY(), 0);
547     assertEquals(od.getBoxWidth(), boxWidth);
548     assertEquals(od.getBoxHeight(), boxHeight);
549
550     // move viewport to right
551     moveViewportH(70);
552     assertEquals(od.getBoxX(),
553             Math.round((float) 70 * od.getWidth() / alwidth));
554     assertEquals(od.getBoxY(), 0);
555     assertEquals(od.getBoxWidth(), boxWidth);
556     assertEquals(od.getBoxHeight(), boxHeight);
557
558     // move viewport down
559     moveViewportV(100);
560     assertEquals(od.getBoxX(),
561             Math.round((float) 70 * od.getWidth() / alwidth));
562     assertEquals(od.getBoxY(),
563             Math.round(100 * od.getSequencesHeight() / alheight));
564     assertEquals(od.getBoxWidth(), boxWidth);
565     assertEquals(od.getBoxHeight(), boxHeight);
566
567     // move viewport to bottom right
568     moveViewport(98, 508);
569     assertEquals(od.getBoxX(),
570             Math.round((float) 98 * od.getWidth() / alwidth));
571     assertEquals(od.getBoxY(),
572             Math.round((float) 508 * od.getSequencesHeight() / alheight));
573     assertEquals(od.getBoxWidth(), boxWidth);
574     assertEquals(od.getBoxHeight(), boxHeight);
575   }
576
577   /**
578    * Test that the box position is set correctly when there are hidden columns
579    * at the start
580    */
581   @Test(groups = { "Functional" })
582   public void testSetBoxFromViewportHiddenColsAtStart()
583   {
584     int firstHidden = 0;
585     int lastHidden = 20;
586     hiddenCols.hideColumns(firstHidden, lastHidden);
587
588     // move viewport to start of alignment
589     moveViewport(0, 0);
590     assertEquals(od.getBoxX(),
591             Math.round((float) (lastHidden + 1) * od.getWidth() / alwidth));
592     assertEquals(od.getBoxY(), 0);
593     assertEquals(od.getBoxWidth(), boxWidth);
594     assertEquals(od.getBoxHeight(), boxHeight);
595
596     // move viewport to end of alignment - need to make startRes by removing
597     // hidden cols because of how viewport/overview are implemented
598     moveViewport(98 - lastHidden - 1, 0);
599     assertEquals(od.getBoxX(),
600             Math.round((float) 98 * od.getWidth() / alwidth));
601     assertEquals(od.getBoxY(), 0);
602     assertEquals(od.getBoxWidth(), boxWidth);
603     assertEquals(od.getBoxHeight(), boxHeight);
604   }
605
606   /**
607    * Test that the box position is set correctly when there are hidden columns
608    * in the middle
609    */
610   @Test(groups = { "Functional" })
611   public void testSetBoxFromViewportHiddenColsInMiddle()
612   {
613     int firstHidden = 68;
614     int lastHidden = 78;
615     hiddenCols.hideColumns(firstHidden, lastHidden);
616
617     // move viewport before hidden columns
618     moveViewport(3, 0);
619
620     assertEquals(od.getBoxX(),
621             Math.round((float) 3 * od.getWidth() / alwidth));
622     assertEquals(od.getBoxY(), 0);
623     System.out.println(od.getBoxWidth());
624     assertEquals(od.getBoxWidth(), boxWidth);
625     System.out.println(od.getBoxWidth());
626     assertEquals(od.getBoxHeight(), boxHeight);
627
628     // move viewport to left of hidden columns with overlap
629     moveViewport(10, 0);
630     assertEquals(od.getBoxX(),
631             Math.round((float) 10 * od.getWidth() / alwidth));
632     assertEquals(od.getBoxY(), 0);
633     assertEquals(
634             od.getBoxWidth(),
635             boxWidth
636                     + Math.round((float) (lastHidden - firstHidden + 1)
637                             * od.getWidth() / alwidth));
638     assertEquals(od.getBoxHeight(), boxHeight);
639
640     // move viewport to straddle hidden columns
641     moveViewport(63, 0);
642     assertEquals(od.getBoxX(),
643             Math.round((float) 63 * od.getWidth() / alwidth));
644     assertEquals(od.getBoxY(), 0);
645     assertEquals(
646             od.getBoxWidth(),
647             boxWidth
648                     + Math.round((lastHidden - firstHidden + 1)
649                             * od.getWidth() / alwidth));
650     assertEquals(od.getBoxHeight(), boxHeight);
651
652     // move viewport to right of hidden columns, no overlap
653     moveViewport(80 - (lastHidden - firstHidden + 1), 0);
654     assertEquals(od.getBoxX(),
655             Math.round((float) 80 * od.getWidth() / alwidth));
656     assertEquals(od.getBoxY(), 0);
657     assertEquals(od.getBoxWidth(), boxWidth);
658     assertEquals(od.getBoxHeight(), boxHeight);
659
660   }
661
662   /**
663    * Test that the box position is set correctly when there are hidden columns
664    * at the end
665    */
666   @Test(groups = { "Functional" })
667   public void testSetBoxFromViewportHiddenColsAtEnd()
668   {
669     int firstHidden = 152;
670     int lastHidden = 164;
671     hiddenCols.hideColumns(firstHidden, lastHidden);
672
673     // move viewport before hidden columns
674     moveViewport(3, 0);
675     assertEquals(od.getBoxX(),
676             Math.round((float) 3 * od.getWidth() / alwidth));
677     assertEquals(od.getBoxY(), 0);
678     assertEquals(od.getBoxWidth(), boxWidth);
679     assertEquals(od.getBoxHeight(), boxHeight);
680
681     // move viewport to hidden columns
682     // viewport can't actually extend into hidden cols,
683     // so move to the far right edge of the viewport
684     moveViewport(firstHidden - viewWidth, 0);
685     assertEquals(od.getBoxX(),
686             Math.round((float) (firstHidden - viewWidth)
687                     * od.getWidth() / alwidth));
688     assertEquals(od.getBoxY(), 0);
689     assertEquals(od.getBoxWidth(), boxWidth);
690     assertEquals(od.getBoxHeight(), boxHeight);
691   }
692
693   /**
694    * Test that the box position is set correctly when there are hidden rows at
695    * the start
696    */
697   @Test(groups = { "Functional" })
698   public void testSetBoxFromViewportHiddenRowsAtStart()
699   {
700     int firstHidden = 0;
701     int lastHidden = 20;
702     hideSequences(firstHidden, lastHidden);
703
704     // move viewport to start of alignment:
705     // box moves to below hidden rows, height remains same
706     moveViewport(0, 0);
707     assertEquals(od.getBoxX(), 0);
708     assertEquals(od.getBoxY(),
709             Math.round((float) (lastHidden + 1) * od.getSequencesHeight()
710                     / alheight));
711     assertEquals(od.getBoxWidth(), boxWidth);
712     assertEquals(od.getBoxHeight(), boxHeight);
713
714     // move viewport to end of alignment
715     moveViewport(0, 525 - viewHeight - lastHidden - 1);
716     assertEquals(od.getBoxX(), 0);
717     assertEquals(
718             od.getBoxY(),
719             Math.round((float) (525 - viewHeight) * od.getSequencesHeight()
720                     / alheight));
721     assertEquals(od.getBoxWidth(), boxWidth);
722     assertEquals(od.getBoxHeight(), boxHeight);
723   }
724
725   /**
726    * Test that the box position is set correctly when there are hidden rows in
727    * the middle
728    */
729   @Test(groups = { "Functional" })
730   public void testSetBoxFromViewportHiddenRowsInMiddle()
731   {
732     int firstHidden = 200;
733     int lastHidden = 210;
734     hideSequences(firstHidden, lastHidden);
735
736     // move viewport to start of alignment:
737     // box, height etc as in non-hidden case
738     moveViewport(0, 0);
739     assertEquals(od.getBoxX(), 0);
740     assertEquals(od.getBoxY(), 0);
741     assertEquals(od.getBoxWidth(), boxWidth);
742     assertEquals(od.getBoxHeight(), boxHeight);
743
744     // move viewport to straddle hidden rows
745     moveViewport(0, 198);
746     assertEquals(od.getBoxX(), 0);
747     assertEquals(od.getBoxY(), Math.round ((float)198 * od.getSequencesHeight()
748             / alheight));
749     assertEquals(od.getBoxWidth(), boxWidth);
750     assertEquals(
751             od.getBoxHeight(),
752             Math.round((float) (viewHeight + lastHidden - firstHidden + 1)
753                     * od.getSequencesHeight() / alheight));
754   }
755
756   /**
757    * Test that the box position is set correctly when there are hidden rows at
758    * the bottom
759    */
760   @Test(groups = { "Functional" })
761   public void testSetBoxFromViewportHiddenRowsAtEnd()
762   {
763     int firstHidden = 500;
764     int lastHidden = 524;
765     hideSequences(firstHidden, lastHidden);
766
767     // move viewport to start of alignment:
768     // box, height etc as in non-hidden case
769     moveViewport(0, 0);
770     assertEquals(od.getBoxX(), 0);
771     assertEquals(od.getBoxY(), 0);
772     assertEquals(od.getBoxWidth(), boxWidth);
773     assertEquals(od.getBoxHeight(), boxHeight);
774
775     // move viewport to end of alignment
776     // viewport sits above hidden rows and does not include them
777     moveViewport(0, firstHidden - viewHeight - 1);
778     assertEquals(od.getBoxX(), 0);
779     assertEquals(
780             od.getBoxY(),
781             Math.round((float) (firstHidden - viewHeight - 1)
782                     * od.getSequencesHeight() / alheight));
783     assertEquals(od.getBoxWidth(), boxWidth);
784     assertEquals(od.getBoxHeight(), boxHeight);
785
786   }
787
788   /**
789    * Test setting of the box position, when there are hidden rows at the start
790    * of the alignment
791    */
792   @Test(groups = { "Functional" })
793   public void testFromMouseWithHiddenRowsAtStart()
794   {
795     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
796             vpranges);
797     assertEquals(od.getBoxX(), 0);
798     assertEquals(od.getBoxY(), 0);
799     assertEquals(od.getBoxHeight(), boxHeight);
800     assertEquals(od.getBoxWidth(), boxWidth);
801     assertEquals(od.getScrollCol(), 0);
802     assertEquals(od.getScrollRow(), 0);
803
804     // hide rows at start and check updated box position is correct
805     // changes boxY but not boxheight
806     int lastHiddenRow = 30;
807     hideSequences(0, lastHiddenRow);
808
809     od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
810     assertEquals(od.getBoxX(), 0);
811     assertEquals(od.getBoxY(),
812             Math.round((float) (lastHiddenRow + 1)
813                     * od.getSequencesHeight() / alheight));
814     assertEquals(od.getBoxWidth(), boxWidth);
815     assertEquals(od.getBoxHeight(), boxHeight);
816
817     // click in hidden rows - same result
818     mouseClick(od, 0, 0);
819     assertEquals(od.getBoxX(), 0);
820     assertEquals(
821             od.getBoxY(),
822             Math.round((float) (lastHiddenRow + 1)
823                     * od.getSequencesHeight() / alheight));
824     assertEquals(od.getBoxWidth(), boxWidth);
825     assertEquals(od.getBoxHeight(), boxHeight);
826
827     // click below hidden rows
828     mouseClick(od, 0, 150);
829     assertEquals(od.getBoxX(), 0);
830     assertEquals(od.getBoxY(), 150);
831     assertEquals(od.getBoxWidth(), boxWidth);
832     assertEquals(od.getBoxHeight(), boxHeight);
833   }
834
835   /**
836    * Test setting of the box position, when there are hidden rows at the middle
837    * of the alignment
838    */
839   @Test(groups = { "Functional" })
840   public void testFromMouseWithHiddenRowsInMiddle()
841   {
842     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
843             vpranges);
844
845     assertEquals(od.getBoxX(), 0);
846     assertEquals(od.getBoxY(), 0);
847     assertEquals(od.getBoxWidth(), boxWidth);
848     assertEquals(od.getBoxHeight(), boxHeight);
849     assertEquals(od.getScrollCol(), 0);
850     assertEquals(od.getScrollRow(), 0);
851
852     // hide rows in middle and check updated box position is correct
853     // no changes
854     int firstHiddenRow = 50;
855     int lastHiddenRow = 54;
856     hideSequences(firstHiddenRow, lastHiddenRow);
857
858     od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
859
860     assertEquals(od.getBoxX(), 0);
861     assertEquals(od.getBoxY(), 0);
862     assertEquals(od.getBoxWidth(), boxWidth);
863     assertEquals(od.getBoxHeight(), boxHeight);
864
865     // click above hidden rows, so that box overlaps
866     int ypos = 35; // column value in residues
867     mouseClick(od, 0,
868             Math.round((float) ypos * od.getSequencesHeight() / alheight));
869     assertEquals(od.getBoxX(), 0);
870     assertEquals(od.getBoxY(),
871             Math.round((float) ypos * od.getSequencesHeight() / alheight));
872     assertEquals(od.getBoxWidth(), boxWidth);
873     assertEquals(
874             od.getBoxHeight(),
875             boxHeight
876                     + Math.round((float) (lastHiddenRow - firstHiddenRow + 1)
877                             * od.getSequencesHeight() / alheight));
878
879     // click so that box straddles hidden rows
880     ypos = 44; // column value in residues
881     mouseClick(od, 0,
882             Math.round((float) ypos * od.getSequencesHeight() / alheight));
883     assertEquals(od.getBoxX(), 0);
884     assertEquals(od.getBoxY(),
885             Math.round((float) ypos * od.getSequencesHeight() / alheight));
886     assertEquals(od.getBoxWidth(), boxWidth);
887     assertEquals(
888             od.getBoxHeight(),
889             boxHeight
890                     + Math.round((float) (lastHiddenRow - firstHiddenRow + 1)
891                             * od.getSequencesHeight() / alheight));
892   }
893
894   /**
895    * Test setting of the box position, when there are hidden rows at the end of
896    * the alignment
897    */
898   @Test(groups = { "Functional" })
899   public void testFromMouseWithHiddenRowsAtEnd()
900   {
901     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
902             vpranges);
903     assertEquals(od.getBoxX(), 0);
904     assertEquals(od.getBoxY(), 0);
905     assertEquals(od.getBoxWidth(), boxWidth);
906     assertEquals(od.getBoxHeight(), boxHeight);
907     assertEquals(od.getScrollCol(), 0);
908     assertEquals(od.getScrollRow(), 0);
909
910     // hide rows at end and check updated box position is correct
911     // no changes
912     int firstHidden = 500;
913     int lastHidden = 524;
914     hideSequences(firstHidden, lastHidden);
915
916     od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
917     assertEquals(od.getBoxX(), 0);
918     assertEquals(od.getBoxY(), 0);
919     assertEquals(od.getBoxWidth(), boxWidth);
920     assertEquals(od.getBoxHeight(), boxHeight);
921
922     // click above hidden rows
923     int ypos = 40; // row 40
924     mouseClick(od, 0,
925             Math.round((float) ypos * od.getSequencesHeight() / alheight));
926     assertEquals(od.getBoxX(), 0);
927     assertEquals(od.getBoxY(),
928             Math.round((float) ypos * od.getSequencesHeight() / alheight));
929     assertEquals(od.getBoxWidth(), boxWidth);
930     assertEquals(od.getBoxHeight(), boxHeight);
931
932     // click above hidden rows so box overlaps
933     // boxY moved upwards, boxHeight remains same
934     ypos = 497; // row 497
935     mouseClick(od, 0,
936             Math.round((float) ypos * od.getSequencesHeight() / alheight));
937     assertEquals(od.getBoxX(), 0);
938     assertEquals(
939             od.getBoxY(),
940             Math.round((float) (firstHidden - viewHeight)
941                     * od.getSequencesHeight() / alheight));
942     assertEquals(od.getBoxWidth(), boxWidth);
943     assertEquals(od.getBoxHeight(), boxHeight);
944
945     // click within hidden rows
946     ypos = 505;
947     mouseClick(od, 0,
948             Math.round((float) ypos * od.getSequencesHeight() / alheight));
949     assertEquals(od.getBoxX(), 0);
950     assertEquals(
951             od.getBoxY(),
952             Math.round((firstHidden - viewHeight) * od.getSequencesHeight()
953                     / alheight));
954     assertEquals(od.getBoxWidth(), boxWidth);
955     assertEquals(od.getBoxHeight(), boxHeight);
956   }
957
958   /*
959    * Move viewport horizontally: startRes + previous width gives new horizontal extent. Vertical extent stays the same.
960    */
961   private void moveViewportH(int startRes)
962   {
963     vpranges.setStartRes(startRes);
964     vpranges.setEndRes(startRes + viewWidth - 1);
965     od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
966   }
967
968   /*
969    * Move viewport vertically: startSeq and endSeq give new vertical extent. Horizontal extent stays the same.
970    */
971   private void moveViewportV(int startSeq)
972   {
973     vpranges.setStartSeq(startSeq);
974     vpranges.setEndSeq(startSeq + viewHeight - 1);
975     od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
976   }
977
978   /*
979    * Move viewport horizontally and vertically.
980    */
981   private void moveViewport(int startRes, int startSeq)
982   {
983     vpranges.setStartRes(startRes);
984     vpranges.setEndRes(startRes + viewWidth - 1);
985     vpranges.setStartSeq(startSeq);
986     vpranges.setEndSeq(startSeq + viewHeight - 1);
987     od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
988   }
989
990   /*
991    * Mouse click as position x,y in overview window
992    */
993   private void mouseClick(OverviewDimensions od, int x, int y)
994   {
995     od.updateViewportFromMouse(x, y, al.getHiddenSequences(), hiddenCols,
996             vpranges);
997
998     // updates require an OverviewPanel to exist which it doesn't here
999     // so call setBoxPosition() as it would be called by the AlignmentPanel
1000     // normally
1001
1002     vpranges.setStartRes(od.getScrollCol());
1003     vpranges.setEndRes(od.getScrollCol() + viewWidth - 1);
1004     vpranges.setStartSeq(od.getScrollRow());
1005     vpranges.setEndSeq(od.getScrollRow() + viewHeight - 1);
1006     od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
1007   }
1008   
1009   /*
1010    * Test that the box is positioned with the top left corner at xpos, ypos
1011    * and with the original width and height
1012    */
1013   private void testBoxIsAtClickPoint(int xpos, int ypos)
1014   {
1015     mouseClick(od, xpos, ypos);
1016     assertEquals(od.getBoxX(), xpos);
1017     assertEquals(od.getBoxY(), ypos);
1018     assertEquals(od.getBoxWidth(), boxWidth);
1019     assertEquals(od.getBoxHeight(), boxHeight);
1020
1021   }
1022
1023   /*
1024    * Hide sequences between start and end
1025    */
1026   private void hideSequences(int start, int end)
1027   {
1028     SequenceI[] allseqs = al.getSequencesArray();
1029     SequenceGroup theseSeqs = new SequenceGroup();
1030     
1031     for (int i = start; i <= end; i++)
1032     {
1033       theseSeqs.addSequence(allseqs[i], false);
1034       al.getHiddenSequences().hideSequence(allseqs[i]);
1035     }
1036
1037     hiddenRepSequences.put(allseqs[start], theseSeqs);
1038   }
1039 }