1. Project Clover database Fri Dec 6 2024 13:47:14 GMT
  2. Package jalview.appletgui

File AlignmentPanel.java

 

Coverage histogram

../../img/srcFileCovDistChart0.png
60% of files have more coverage

Code metrics

130
373
44
1
1,162
765
121
0.32
8.48
44
2.75

Classes

Class
Line #
Actions
AlignmentPanel 50 373 121
0.00%
 

Contributing tests

No tests hitting this source file were found.

Source view

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.appletgui;
22   
23    import jalview.analysis.AnnotationSorter;
24    import jalview.api.AlignViewportI;
25    import jalview.api.AlignmentViewPanel;
26    import jalview.bin.JalviewLite;
27    import jalview.datamodel.AlignmentI;
28    import jalview.datamodel.SearchResultsI;
29    import jalview.datamodel.SequenceI;
30    import jalview.structure.StructureSelectionManager;
31    import jalview.viewmodel.ViewportListenerI;
32    import jalview.viewmodel.ViewportRanges;
33   
34    import java.awt.BorderLayout;
35    import java.awt.Color;
36    import java.awt.Dimension;
37    import java.awt.FontMetrics;
38    import java.awt.Frame;
39    import java.awt.Graphics;
40    import java.awt.Panel;
41    import java.awt.Scrollbar;
42    import java.awt.event.AdjustmentEvent;
43    import java.awt.event.AdjustmentListener;
44    import java.awt.event.ComponentAdapter;
45    import java.awt.event.ComponentEvent;
46    import java.beans.PropertyChangeEvent;
47    import java.util.List;
48   
49    @SuppressWarnings("serial")
 
50    public class AlignmentPanel extends Panel
51    implements AdjustmentListener, AlignmentViewPanel, ViewportListenerI
52    {
53   
54    public AlignViewport av;
55   
56    OverviewPanel overviewPanel;
57   
58    SeqPanel seqPanel;
59   
60    IdPanel idPanel;
61   
62    IdwidthAdjuster idwidthAdjuster;
63   
64    public AlignFrame alignFrame;
65   
66    ScalePanel scalePanel;
67   
68    AnnotationPanel annotationPanel;
69   
70    AnnotationLabels alabels;
71   
72    ViewportRanges vpRanges;
73   
74    // this value is set false when selection area being dragged
75    boolean fastPaint = true;
76   
 
77  0 toggle public AlignmentPanel(AlignFrame af, final AlignViewport av)
78    {
79  0 try
80    {
81  0 jbInit();
82    } catch (Exception e)
83    {
84  0 e.printStackTrace();
85    }
86   
87  0 alignFrame = af;
88  0 this.av = av;
89  0 vpRanges = av.getRanges();
90  0 seqPanel = new SeqPanel(av, this);
91  0 idPanel = new IdPanel(av, this);
92  0 scalePanel = new ScalePanel(av, this);
93  0 idwidthAdjuster = new IdwidthAdjuster(this);
94  0 annotationPanel = new AnnotationPanel(this);
95  0 annotationPanelHolder.add(annotationPanel, BorderLayout.CENTER);
96   
97  0 sequenceHolderPanel.add(annotationPanelHolder, BorderLayout.SOUTH);
98  0 alabels = new AnnotationLabels(this);
99   
100  0 setAnnotationVisible(av.isShowAnnotation());
101   
102  0 idPanelHolder.add(idPanel, BorderLayout.CENTER);
103  0 idSpaceFillerPanel1.add(idwidthAdjuster, BorderLayout.CENTER);
104  0 annotationSpaceFillerHolder.add(alabels, BorderLayout.CENTER);
105  0 scalePanelHolder.add(scalePanel, BorderLayout.CENTER);
106  0 seqPanelHolder.add(seqPanel, BorderLayout.CENTER);
107   
108  0 fontChanged();
109  0 setScrollValues(0, 0);
110   
111  0 apvscroll.addAdjustmentListener(this);
112  0 hscroll.addAdjustmentListener(this);
113  0 vscroll.addAdjustmentListener(this);
114   
115  0 addComponentListener(new ComponentAdapter()
116    {
 
117  0 toggle @Override
118    public void componentResized(ComponentEvent evt)
119    {
120    // reset the viewport ranges when the alignment panel is resized
121    // in particular, this initialises the end residue value when Jalview
122    // is initialised
123  0 if (av.getWrapAlignment())
124    {
125  0 int widthInRes = seqPanel.seqCanvas
126    .getWrappedCanvasWidth(seqPanel.seqCanvas.getWidth());
127  0 vpRanges.setViewportWidth(widthInRes);
128    }
129    else
130    {
131  0 int widthInRes = seqPanel.seqCanvas.getWidth()
132    / av.getCharWidth();
133  0 int heightInSeq = seqPanel.seqCanvas.getHeight()
134    / av.getCharHeight();
135   
136  0 vpRanges.setViewportWidth(widthInRes);
137  0 vpRanges.setViewportHeight(heightInSeq);
138    }
139    // setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq());
140  0 if (getSize().height > 0
141    && annotationPanelHolder.getSize().height > 0)
142    {
143  0 validateAnnotationDimensions(false);
144    }
145  0 repaint();
146    }
147   
148    });
149   
150  0 Dimension d = calculateIdWidth();
151  0 idPanel.idCanvas.setSize(d);
152   
153  0 hscrollFillerPanel.setSize(d.width, annotationPanel.getSize().height);
154   
155  0 idPanel.idCanvas.setSize(d.width, seqPanel.seqCanvas.getSize().height);
156  0 annotationSpaceFillerHolder.setSize(d.width,
157    annotationPanel.getSize().height);
158  0 alabels.setSize(d.width, annotationPanel.getSize().height);
159  0 final AlignmentPanel ap = this;
160  0 av.addPropertyChangeListener(new java.beans.PropertyChangeListener()
161    {
 
162  0 toggle @Override
163    public void propertyChange(java.beans.PropertyChangeEvent evt)
164    {
165  0 if (evt.getPropertyName().equals("alignment"))
166    {
167  0 PaintRefresher.Refresh(ap, av.getSequenceSetId(), true, true);
168  0 alignmentChanged();
169    }
170    }
171    });
172  0 av.getRanges().addPropertyChangeListener(this);
173    }
174   
 
175  0 toggle @Override
176    public AlignViewportI getAlignViewport()
177    {
178  0 return av;
179    }
180   
 
181  0 toggle public SequenceRenderer getSequenceRenderer()
182    {
183  0 return seqPanel.seqCanvas.sr;
184    }
185   
 
186  0 toggle @Override
187    public jalview.api.FeatureRenderer getFeatureRenderer()
188    {
189  0 return seqPanel.seqCanvas.fr;
190    }
191   
 
192  0 toggle @Override
193    public jalview.api.FeatureRenderer cloneFeatureRenderer()
194    {
195  0 FeatureRenderer nfr = new FeatureRenderer(av);
196  0 nfr.transferSettings(seqPanel.seqCanvas.fr);
197  0 return nfr;
198    }
199   
 
200  0 toggle public void alignmentChanged()
201    {
202  0 av.alignmentChanged(this);
203   
204  0 if (overviewPanel != null)
205    {
206  0 overviewPanel.updateOverviewImage();
207    }
208   
209  0 alignFrame.updateEditMenuBar();
210   
211  0 repaint();
212    }
213   
 
214  0 toggle public void fontChanged()
215    {
216    // set idCanvas bufferedImage to null
217    // to prevent drawing old image
218  0 idPanel.idCanvas.image = null;
219  0 FontMetrics fm = getFontMetrics(av.getFont());
220   
221  0 scalePanel.setSize(
222    new Dimension(10, av.getCharHeight() + fm.getDescent()));
223  0 idwidthAdjuster.setSize(
224    new Dimension(10, av.getCharHeight() + fm.getDescent()));
225  0 av.updateSequenceIdColours();
226  0 annotationPanel.image = null;
227  0 int ap = annotationPanel.adjustPanelHeight(false);
228  0 Dimension d = calculateIdWidth();
229  0 d.setSize(d.width + 4, seqPanel.seqCanvas.getSize().height);
230  0 alabels.setSize(d.width + 4, ap);
231   
232  0 idPanel.idCanvas.setSize(d);
233  0 hscrollFillerPanel.setSize(d);
234   
235  0 validateAnnotationDimensions(false);
236  0 annotationPanel.repaint();
237  0 validate();
238  0 repaint();
239    }
240   
 
241  0 toggle public void setIdWidth(int w, int h)
242    {
243  0 idPanel.idCanvas.setSize(w, h);
244  0 idPanelHolder.setSize(w, idPanelHolder.getSize().height);
245  0 annotationSpaceFillerHolder.setSize(w,
246    annotationSpaceFillerHolder.getSize().height);
247  0 alabels.setSize(w, alabels.getSize().height);
248  0 validate();
249    }
250   
 
251  0 toggle Dimension calculateIdWidth()
252    {
253  0 if (av.nullFrame == null)
254    {
255  0 av.nullFrame = new Frame();
256  0 av.nullFrame.addNotify();
257    }
258   
259  0 Graphics g = av.nullFrame.getGraphics();
260   
261  0 FontMetrics fm = g.getFontMetrics(av.font);
262  0 AlignmentI al = av.getAlignment();
263   
264  0 int i = 0;
265  0 int idWidth = 0;
266  0 String id;
267  0 while (i < al.getHeight() && al.getSequenceAt(i) != null)
268    {
269  0 SequenceI s = al.getSequenceAt(i);
270  0 id = s.getDisplayId(av.getShowJVSuffix());
271   
272  0 if (fm.stringWidth(id) > idWidth)
273    {
274  0 idWidth = fm.stringWidth(id);
275    }
276  0 i++;
277    }
278   
279    // Also check annotation label widths
280  0 i = 0;
281  0 if (al.getAlignmentAnnotation() != null)
282    {
283  0 fm = g.getFontMetrics(av.nullFrame.getFont());
284  0 while (i < al.getAlignmentAnnotation().length)
285    {
286  0 String label = al.getAlignmentAnnotation()[i].label;
287  0 if (fm.stringWidth(label) > idWidth)
288    {
289  0 idWidth = fm.stringWidth(label);
290    }
291  0 i++;
292    }
293    }
294   
295  0 return new Dimension(idWidth, idPanel.idCanvas.getSize().height);
296    }
297   
298    /**
299    * Highlight the given results on the alignment.
300    *
301    */
 
302  0 toggle public void highlightSearchResults(SearchResultsI results)
303    {
304  0 scrollToPosition(results);
305  0 seqPanel.seqCanvas.highlightSearchResults(results);
306    }
307   
308    /**
309    * scroll the view to show the position of the highlighted region in results
310    * (if any) and redraw the overview
311    *
312    * @param results
313    * @return false if results were not found
314    */
 
315  0 toggle public boolean scrollToPosition(SearchResultsI results)
316    {
317  0 return scrollToPosition(results, true);
318    }
319   
320    /**
321    * scroll the view to show the position of the highlighted region in results
322    * (if any)
323    *
324    * @param results
325    * @param redrawOverview
326    * - when set, the overview will be recalculated (takes longer)
327    * @return false if results were not found
328    */
 
329  0 toggle public boolean scrollToPosition(SearchResultsI results,
330    boolean redrawOverview)
331    {
332  0 return scrollToPosition(results, 0, redrawOverview, false);
333    }
334   
335    /**
336    * scroll the view to show the position of the highlighted region in results
337    * (if any)
338    *
339    * @param results
340    * @param redrawOverview
341    * - when set, the overview will be recalculated (takes longer)
342    * @return false if results were not found
343    */
 
344  0 toggle public boolean scrollToPosition(SearchResultsI results,
345    int verticalOffset, boolean redrawOverview, boolean centre)
346    {
347    // do we need to scroll the panel?
348  0 if (results != null && results.getCount() > 0)
349    {
350  0 AlignmentI alignment = av.getAlignment();
351  0 int seqIndex = alignment.findIndex(results);
352  0 if (seqIndex == -1)
353    {
354  0 return false;
355    }
356    /*
357    * allow for offset of target sequence (actually scroll to one above it)
358    */
359   
360  0 SequenceI seq = alignment.getSequenceAt(seqIndex);
361  0 int[] r = results.getResults(seq, 0, alignment.getWidth());
362  0 if (r == null)
363    {
364  0 if (JalviewLite.debug)
365    {// DEBUG
366  0 jalview.bin.Console.outPrintln(
367    "DEBUG: scroll didn't happen - results not within alignment : "
368    + seq.getStart() + "," + seq.getEnd());
369    }
370  0 return false;
371    }
372  0 if (JalviewLite.debug)
373    {
374    // DEBUG
375    /*
376    * jalview.bin.Console.outPrintln("DEBUG: scroll: start=" + r[0] +
377    * " av.getStartRes()=" + av.getStartRes() + " end=" + r[1] +
378    * " seq.end=" + seq.getEnd() + " av.getEndRes()=" + av.getEndRes() +
379    * " hextent=" + hextent);
380    */
381    }
382  0 int start = r[0];
383  0 int end = r[1];
384   
385    /*
386    * To centre results, scroll to positions half the visible width
387    * left/right of the start/end positions
388    */
389  0 if (centre)
390    {
391  0 int offset = (vpRanges.getEndRes() - vpRanges.getStartRes() + 1) / 2
392    - 1;
393  0 start = Math.max(start - offset, 0);
394  0 end = end + offset - 1;
395    // end = Math.min(end + offset, seq.getEnd() - 1);
396    }
397   
398  0 if (start < 0)
399    {
400  0 return false;
401    }
402  0 if (end == seq.getEnd())
403    {
404  0 return false;
405    }
406   
407    /*
408    * allow for offset of target sequence (actually scroll to one above it)
409    */
410  0 seqIndex = Math.max(0, seqIndex - verticalOffset);
411  0 return scrollTo(start, end, seqIndex, false, redrawOverview);
412    }
413  0 return true;
414    }
415   
 
416  0 toggle public boolean scrollTo(int ostart, int end, int seqIndex,
417    boolean scrollToNearest, boolean redrawOverview)
418    {
419  0 int startv, endv, starts, ends;// , width;
420   
421  0 int start = -1;
422  0 if (av.hasHiddenColumns())
423    {
424  0 AlignmentI al = av.getAlignment();
425  0 start = al.getHiddenColumns().absoluteToVisibleColumn(ostart);
426  0 end = al.getHiddenColumns().absoluteToVisibleColumn(end);
427  0 if (start == end)
428    {
429  0 if (!scrollToNearest && !al.getHiddenColumns().isVisible(ostart))
430    {
431    // don't scroll - position isn't visible
432  0 return false;
433    }
434    }
435    }
436    else
437    {
438  0 start = ostart;
439    }
440   
441  0 if (!av.getWrapAlignment())
442    {
443    /*
444    * int spos=av.getStartRes(),sqpos=av.getStartSeq(); if ((startv =
445    * av.getStartRes()) >= start) { spos=start-1; // seqIn //
446    * setScrollValues(start - 1, seqIndex); } else if ((endv =
447    * av.getEndRes()) <= end) { // setScrollValues(spos=startv + 1 + end -
448    * endv, seqIndex); spos=startv + 1 + end - endv; } else if ((starts =
449    * av.getStartSeq()) > seqIndex) { setScrollValues(av.getStartRes(),
450    * seqIndex); } else if ((ends = av.getEndSeq()) <= seqIndex) {
451    * setScrollValues(av.getStartRes(), starts + seqIndex - ends + 1); }
452    */
453   
454    // below is scrolling logic up to Jalview 2.8.2
455    // if ((av.getStartRes() > end)
456    // || (av.getEndRes() < start)
457    // || ((av.getStartSeq() > seqIndex) || (av.getEndSeq() < seqIndex)))
458    // {
459    // if (start > av.getAlignment().getWidth() - hextent)
460    // {
461    // start = av.getAlignment().getWidth() - hextent;
462    // if (start < 0)
463    // {
464    // start = 0;
465    // }
466    //
467    // }
468    // if (seqIndex > av.getAlignment().getHeight() - vextent)
469    // {
470    // seqIndex = av.getAlignment().getHeight() - vextent;
471    // if (seqIndex < 0)
472    // {
473    // seqIndex = 0;
474    // }
475    // }
476    // setScrollValues(start, seqIndex);
477    // }
478    // logic copied from jalview.gui.AlignmentPanel:
479  0 if ((startv = vpRanges.getStartRes()) >= start)
480    {
481    /*
482    * Scroll left to make start of search results visible
483    */
484  0 setScrollValues(start - 1, seqIndex);
485    }
486  0 else if ((endv = vpRanges.getEndRes()) <= end)
487    {
488    /*
489    * Scroll right to make end of search results visible
490    */
491  0 setScrollValues(startv + 1 + end - endv, seqIndex);
492    }
493  0 else if ((starts = vpRanges.getStartSeq()) > seqIndex)
494    {
495    /*
496    * Scroll up to make start of search results visible
497    */
498  0 setScrollValues(vpRanges.getStartRes(), seqIndex);
499    }
500  0 else if ((ends = vpRanges.getEndSeq()) <= seqIndex)
501    {
502    /*
503    * Scroll down to make end of search results visible
504    */
505  0 setScrollValues(vpRanges.getStartRes(),
506    starts + seqIndex - ends + 1);
507    }
508    /*
509    * Else results are already visible - no need to scroll
510    */
511    }
512    else
513    {
514  0 vpRanges.scrollToWrappedVisible(start);
515    }
516   
517  0 paintAlignment(redrawOverview, false);
518  0 return true;
519    }
520   
 
521  0 toggle public OverviewPanel getOverviewPanel()
522    {
523  0 return overviewPanel;
524    }
525   
 
526  0 toggle public void setOverviewPanel(OverviewPanel op)
527    {
528  0 overviewPanel = op;
529    }
530   
 
531  0 toggle public void setAnnotationVisible(boolean b)
532    {
533  0 if (!av.getWrapAlignment())
534    {
535  0 annotationSpaceFillerHolder.setVisible(b);
536  0 annotationPanelHolder.setVisible(b);
537    }
538    else
539    {
540  0 annotationSpaceFillerHolder.setVisible(false);
541  0 annotationPanelHolder.setVisible(false);
542    }
543  0 validate();
544  0 repaint();
545    }
546   
547    /**
548    * automatically adjust annotation panel height for new annotation whilst
549    * ensuring the alignment is still visible.
550    */
 
551  0 toggle @Override
552    public void adjustAnnotationHeight()
553    {
554    // TODO: display vertical annotation scrollbar if necessary
555    // this is called after loading new annotation onto alignment
556  0 if (alignFrame.getSize().height == 0)
557    {
558  0 jalview.bin.Console.outPrintln(
559    "adjustAnnotationHeight frame size zero NEEDS FIXING");
560    }
561  0 fontChanged();
562  0 validateAnnotationDimensions(true);
563  0 apvscroll.addNotify();
564  0 hscroll.addNotify();
565  0 validate();
566  0 paintAlignment(true, false);
567    }
568   
569    /**
570    * Calculate the annotation dimensions and refresh slider values accordingly.
571    * Need to do repaints/notifys afterwards.
572    */
 
573  0 toggle protected void validateAnnotationDimensions(boolean adjustPanelHeight)
574    {
575  0 int rowHeight = av.getCharHeight();
576  0 int alignmentHeight = rowHeight * av.getAlignment().getHeight();
577  0 int annotationHeight = av.calcPanelHeight();
578   
579  0 int mheight = annotationHeight;
580  0 Dimension d = sequenceHolderPanel.getSize();
581   
582  0 int availableHeight = d.height - scalePanelHolder.getHeight();
583   
584  0 if (adjustPanelHeight)
585    {
586    /*
587    * If not enough vertical space, maximize annotation height while keeping
588    * at least two rows of alignment visible
589    */
590  0 if (annotationHeight + alignmentHeight > availableHeight)
591    {
592  0 annotationHeight = Math.min(annotationHeight,
593    availableHeight - 2 * rowHeight);
594    }
595    }
596    else
597    {
598    // maintain same window layout whilst updating sliders
599  0 annotationHeight = annotationPanelHolder.getSize().height;
600    }
601   
602  0 if (availableHeight - annotationHeight < 5)
603    {
604  0 annotationHeight = availableHeight;
605    }
606   
607  0 annotationPanel.setSize(new Dimension(d.width, annotationHeight));
608  0 annotationPanelHolder.setSize(new Dimension(d.width, annotationHeight));
609    // seqPanelHolder.setSize(d.width, seqandannot - height);
610  0 seqPanel.seqCanvas.setSize(d.width,
611    seqPanel.seqCanvas.getSize().height);
612   
613  0 Dimension e = idPanel.getSize();
614  0 alabels.setSize(new Dimension(e.width, annotationHeight));
615  0 annotationSpaceFillerHolder
616    .setSize(new Dimension(e.width, annotationHeight));
617   
618  0 int s = apvscroll.getValue();
619  0 if (s > mheight - annotationHeight)
620    {
621  0 s = 0;
622    }
623  0 apvscroll.setValues(s, annotationHeight, 0, mheight);
624  0 annotationPanel.setScrollOffset(apvscroll.getValue(), false);
625  0 alabels.setScrollOffset(apvscroll.getValue(), false);
626    }
627   
 
628  0 toggle public void setWrapAlignment(boolean wrap)
629    {
630  0 vpRanges.setStartEndSeq(0, vpRanges.getVisibleAlignmentHeight());
631  0 vpRanges.setStartRes(0);
632  0 scalePanelHolder.setVisible(!wrap);
633   
634  0 hscroll.setVisible(!wrap);
635  0 idwidthAdjuster.setVisible(!wrap);
636   
637  0 if (wrap)
638    {
639  0 annotationPanelHolder.setVisible(false);
640  0 annotationSpaceFillerHolder.setVisible(false);
641    }
642  0 else if (av.isShowAnnotation())
643    {
644  0 annotationPanelHolder.setVisible(true);
645  0 annotationSpaceFillerHolder.setVisible(true);
646    }
647   
648  0 idSpaceFillerPanel1.setVisible(!wrap);
649   
650  0 fontChanged(); // This is so that the scalePanel is resized correctly
651   
652  0 validate();
653  0 sequenceHolderPanel.validate();
654  0 repaint();
655   
656    }
657   
658    int hextent = 0;
659   
660    int vextent = 0;
661   
 
662  0 toggle public void setScrollValues(int xpos, int ypos)
663    {
664  0 int x = xpos;
665  0 int y = ypos;
666   
667  0 if (av.getWrapAlignment())
668    {
669  0 setScrollingForWrappedPanel(x);
670    }
671    else
672    {
673  0 int width = av.getAlignment().getVisibleWidth();
674  0 int height = av.getAlignment().getHeight();
675   
676  0 if (x < 0)
677    {
678  0 x = 0;
679    }
680   
681  0 hextent = seqPanel.seqCanvas.getSize().width / av.getCharWidth();
682  0 vextent = seqPanel.seqCanvas.getSize().height / av.getCharHeight();
683   
684  0 if (hextent > width)
685    {
686  0 hextent = width;
687    }
688   
689  0 if (vextent > height)
690    {
691  0 vextent = height;
692    }
693   
694  0 if ((hextent + x) > width)
695    {
696  0 jalview.bin.Console
697    .errPrintln("hextent was " + hextent + " and x was " + x);
698   
699  0 x = width - hextent;
700    }
701   
702  0 if ((vextent + y) > height)
703    {
704  0 y = height - vextent;
705    }
706   
707  0 if (y < 0)
708    {
709  0 y = 0;
710    }
711   
712  0 if (x < 0)
713    {
714  0 jalview.bin.Console.errPrintln("x was " + x);
715  0 x = 0;
716    }
717   
718  0 hscroll.setValues(x, hextent, 0, width);
719  0 vscroll.setValues(y, vextent, 0, height);
720   
721    // AWT scrollbar does not fire adjustmentValueChanged for setValues
722    // so also call adjustment code!
723  0 adjustHorizontal(x);
724  0 adjustVertical(y);
725   
726  0 sendViewPosition();
727    }
728    }
729   
730    /**
731    * Respond to adjustment event when horizontal or vertical scrollbar is
732    * changed
733    *
734    * @param evt
735    * adjustment event encoding whether apvscroll, hscroll or vscroll
736    * changed
737    */
 
738  0 toggle @Override
739    public void adjustmentValueChanged(AdjustmentEvent evt)
740    {
741    // Note that this event is NOT fired by the AWT scrollbar when setValues is
742    // called. Instead manually call adjustHorizontal and adjustVertical
743    // directly.
744  0 if (evt == null || evt.getSource() == apvscroll)
745    {
746  0 annotationPanel.setScrollOffset(apvscroll.getValue(), false);
747  0 alabels.setScrollOffset(apvscroll.getValue(), false);
748    }
749  0 if (evt == null || evt.getSource() == hscroll)
750    {
751  0 int x = hscroll.getValue();
752  0 adjustHorizontal(x);
753    }
754   
755  0 if (evt == null || evt.getSource() == vscroll)
756    {
757  0 int offy = vscroll.getValue();
758  0 adjustVertical(offy);
759    }
760   
761    }
762   
 
763  0 toggle private void adjustHorizontal(int x)
764    {
765  0 int oldX = vpRanges.getStartRes();
766  0 int oldwidth = vpRanges.getViewportWidth();
767  0 int width = seqPanel.seqCanvas.getWidth() / av.getCharWidth();
768   
769    // if we're scrolling to the position we're already at, stop
770    // this prevents infinite recursion of events when the scroll/viewport
771    // ranges values are the same
772  0 if ((x == oldX) && (width == oldwidth))
773    {
774  0 return;
775    }
776  0 vpRanges.setViewportStartAndWidth(x, width);
777   
778  0 if (av.getWrapAlignment() || !fastPaint)
779    {
780  0 repaint();
781    }
782  0 sendViewPosition();
783    }
784   
 
785  0 toggle private void adjustVertical(int newY)
786    {
787  0 if (av.getWrapAlignment())
788    {
789    /*
790    * if we're scrolling to the position we're already at, stop
791    * this prevents infinite recursion of events when the scroll/viewport
792    * ranges values are the same
793    */
794  0 int oldX = vpRanges.getStartRes();
795  0 int oldY = vpRanges.getWrappedScrollPosition(oldX);
796  0 if (oldY == newY)
797    {
798  0 return;
799    }
800  0 if (newY > -1)
801    {
802    /*
803    * limit page up/down to one width's worth of positions
804    */
805  0 int rowSize = vpRanges.getViewportWidth();
806  0 int newX = newY > oldY ? oldX + rowSize : oldX - rowSize;
807  0 vpRanges.setViewportStartAndWidth(Math.max(0, newX), rowSize);
808    }
809    }
810    else
811    {
812  0 int height = seqPanel.seqCanvas.getHeight() / av.getCharHeight();
813  0 int oldY = vpRanges.getStartSeq();
814  0 int oldheight = vpRanges.getViewportHeight();
815   
816    // if we're scrolling to the position we're already at, stop
817    // this prevents infinite recursion of events when the scroll/viewport
818    // ranges values are the same
819  0 if ((newY == oldY) && (height == oldheight))
820    {
821  0 return;
822    }
823  0 vpRanges.setViewportStartAndHeight(newY, height);
824    }
825  0 if (av.getWrapAlignment() || !fastPaint)
826    {
827  0 repaint();
828    }
829  0 sendViewPosition();
830    }
831   
832    /**
833    * A helper method to return the AlignmentPanel in the other (complementary)
834    * half of a SplitFrame view. Returns null if not in a SplitFrame.
835    *
836    * @return
837    */
 
838  0 toggle private AlignmentPanel getComplementPanel()
839    {
840  0 AlignmentPanel ap = null;
841  0 if (alignFrame != null)
842    {
843  0 SplitFrame sf = alignFrame.getSplitFrame();
844  0 if (sf != null)
845    {
846  0 AlignFrame other = sf.getComplement(alignFrame);
847  0 if (other != null)
848    {
849  0 ap = other.alignPanel;
850    }
851    }
852    }
853  0 return ap;
854    }
855   
856    /**
857    * Follow a scrolling change in the (cDNA/Protein) complementary alignment.
858    * The aim is to keep the two alignments 'lined up' on their centre columns.
859    *
860    * @param sr
861    * holds mapped region(s) of this alignment that we are scrolling
862    * 'to'; may be modified for sequence offset by this method
863    * @param seqOffset
864    * the number of visible sequences to show above the mapped region
865    */
 
866  0 toggle protected void scrollToCentre(SearchResultsI sr, int seqOffset)
867    {
868    /*
869    * To avoid jumpy vertical scrolling (if some sequences are gapped or not
870    * mapped), we can make the scroll-to location a sequence above the one
871    * actually mapped.
872    */
873  0 SequenceI mappedTo = sr.getResults().get(0).getSequence();
874  0 List<SequenceI> seqs = av.getAlignment().getSequences();
875   
876    /*
877    * This is like AlignmentI.findIndex(seq) but here we are matching the
878    * dataset sequence not the aligned sequence
879    */
880  0 boolean matched = false;
881  0 for (SequenceI seq : seqs)
882    {
883  0 if (mappedTo == seq.getDatasetSequence())
884    {
885  0 matched = true;
886  0 break;
887    }
888    }
889  0 if (!matched)
890    {
891  0 return; // failsafe, shouldn't happen
892    }
893   
894    /*
895    * Scroll to position but centring the target residue. Also set a state flag
896    * to prevent adjustmentValueChanged performing this recursively.
897    */
898  0 scrollToPosition(sr, seqOffset, true, true);
899    }
900   
 
901  0 toggle private void sendViewPosition()
902    {
903  0 StructureSelectionManager.getStructureSelectionManager(av.applet)
904    .sendViewPosition(this, vpRanges.getStartRes(),
905    vpRanges.getEndRes(), vpRanges.getStartSeq(),
906    vpRanges.getEndSeq());
907    }
908   
909    /**
910    * Repaint the alignment and annotations, and, optionally, any overview window
911    */
 
912  0 toggle @Override
913    public void paintAlignment(boolean updateOverview,
914    boolean updateStructures)
915    {
916  0 final AnnotationSorter sorter = new AnnotationSorter(getAlignment(),
917    av.isShowAutocalculatedAbove());
918  0 sorter.sort(getAlignment().getAlignmentAnnotation(),
919    av.getSortAnnotationsBy());
920  0 repaint();
921   
922  0 if (updateStructures)
923    {
924  0 jalview.structure.StructureSelectionManager
925    .getStructureSelectionManager(av.applet)
926    .sequenceColoursChanged(this);
927    }
928  0 if (updateOverview)
929    {
930  0 if (overviewPanel != null)
931    {
932  0 overviewPanel.updateOverviewImage();
933    }
934    }
935    }
936   
 
937  0 toggle @Override
938    public void update(Graphics g)
939    {
940  0 paint(g);
941    }
942   
 
943  0 toggle @Override
944    public void paint(Graphics g)
945    {
946  0 invalidate();
947  0 Dimension d = idPanel.idCanvas.getSize();
948  0 final int canvasHeight = seqPanel.seqCanvas.getSize().height;
949  0 if (canvasHeight != d.height)
950    {
951  0 idPanel.idCanvas.setSize(d.width, canvasHeight);
952    }
953   
954  0 setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq());
955   
956  0 seqPanel.seqCanvas.repaint();
957  0 idPanel.idCanvas.repaint();
958  0 if (!av.getWrapAlignment())
959    {
960  0 if (av.isShowAnnotation())
961    {
962  0 alabels.repaint();
963  0 annotationPanel.repaint();
964    }
965  0 scalePanel.repaint();
966    }
967   
968    }
969   
970    /**
971    * Set vertical scroll bar parameters for wrapped panel
972    *
973    * @param topLeftColumn
974    * the column position at top left (0..)
975    */
 
976  0 toggle private void setScrollingForWrappedPanel(int topLeftColumn)
977    {
978  0 int scrollPosition = vpRanges.getWrappedScrollPosition(topLeftColumn);
979  0 int maxScroll = vpRanges.getWrappedMaxScroll(topLeftColumn);
980   
981    /*
982    * a scrollbar's value can be set to at most (maximum-extent)
983    * so we add extent (1) to the maxScroll value
984    */
985  0 vscroll.setUnitIncrement(1);
986  0 vscroll.setValues(scrollPosition, 1, 0, maxScroll + 1);
987    }
988   
989    protected Panel sequenceHolderPanel = new Panel();
990   
991    protected Scrollbar vscroll = new Scrollbar();
992   
993    protected Scrollbar hscroll = new Scrollbar();
994   
995    protected Panel seqPanelHolder = new Panel();
996   
997    protected Panel scalePanelHolder = new Panel();
998   
999    protected Panel idPanelHolder = new Panel();
1000   
1001    protected Panel idSpaceFillerPanel1 = new Panel();
1002   
1003    public Panel annotationSpaceFillerHolder = new Panel();
1004   
1005    protected Panel hscrollFillerPanel = new Panel();
1006   
1007    Panel annotationPanelHolder = new Panel();
1008   
1009    protected Scrollbar apvscroll = new Scrollbar();
1010   
1011    /*
1012    * Flag set while scrolling to follow complementary cDNA/protein scroll. When
1013    * false, suppresses invoking the same method recursively.
1014    */
1015    private boolean scrollComplementaryPanel = true;
1016   
 
1017  0 toggle private void jbInit() throws Exception
1018    {
1019    // idPanelHolder.setPreferredSize(new Dimension(70, 10));
1020  0 this.setLayout(new BorderLayout());
1021   
1022    // sequenceHolderPanel.setPreferredSize(new Dimension(150, 150));
1023  0 sequenceHolderPanel.setLayout(new BorderLayout());
1024  0 seqPanelHolder.setLayout(new BorderLayout());
1025  0 scalePanelHolder.setBackground(Color.white);
1026   
1027    // scalePanelHolder.setPreferredSize(new Dimension(10, 30));
1028  0 scalePanelHolder.setLayout(new BorderLayout());
1029  0 idPanelHolder.setLayout(new BorderLayout());
1030  0 idSpaceFillerPanel1.setBackground(Color.white);
1031   
1032    // idSpaceFillerPanel1.setPreferredSize(new Dimension(10, 30));
1033  0 idSpaceFillerPanel1.setLayout(new BorderLayout());
1034  0 annotationSpaceFillerHolder.setBackground(Color.white);
1035   
1036    // annotationSpaceFillerHolder.setPreferredSize(new Dimension(10, 80));
1037  0 annotationSpaceFillerHolder.setLayout(new BorderLayout());
1038  0 hscroll.setOrientation(Scrollbar.HORIZONTAL);
1039   
1040  0 Panel hscrollHolder = new Panel();
1041  0 hscrollHolder.setLayout(new BorderLayout());
1042  0 hscrollFillerPanel.setBackground(Color.white);
1043  0 apvscroll.setOrientation(Scrollbar.VERTICAL);
1044  0 apvscroll.setVisible(true);
1045  0 apvscroll.addAdjustmentListener(this);
1046   
1047  0 annotationPanelHolder.setBackground(Color.white);
1048  0 annotationPanelHolder.setLayout(new BorderLayout());
1049  0 annotationPanelHolder.add(apvscroll, BorderLayout.EAST);
1050    // hscrollFillerPanel.setPreferredSize(new Dimension(70, 10));
1051  0 hscrollHolder.setBackground(Color.white);
1052   
1053    // annotationScroller.setPreferredSize(new Dimension(10, 80));
1054    // this.setPreferredSize(new Dimension(220, 166));
1055  0 seqPanelHolder.setBackground(Color.white);
1056  0 idPanelHolder.setBackground(Color.white);
1057  0 sequenceHolderPanel.add(scalePanelHolder, BorderLayout.NORTH);
1058  0 sequenceHolderPanel.add(seqPanelHolder, BorderLayout.CENTER);
1059  0 seqPanelHolder.add(vscroll, BorderLayout.EAST);
1060   
1061    // Panel3.add(secondaryPanelHolder, BorderLayout.SOUTH);
1062  0 this.add(idPanelHolder, BorderLayout.WEST);
1063  0 idPanelHolder.add(idSpaceFillerPanel1, BorderLayout.NORTH);
1064  0 idPanelHolder.add(annotationSpaceFillerHolder, BorderLayout.SOUTH);
1065  0 this.add(hscrollHolder, BorderLayout.SOUTH);
1066  0 hscrollHolder.add(hscroll, BorderLayout.CENTER);
1067  0 hscrollHolder.add(hscrollFillerPanel, BorderLayout.WEST);
1068  0 this.add(sequenceHolderPanel, BorderLayout.CENTER);
1069    }
1070   
1071    /**
1072    * hides or shows dynamic annotation rows based on groups and av state flags
1073    */
 
1074  0 toggle public void updateAnnotation()
1075    {
1076  0 updateAnnotation(false);
1077    }
1078   
 
1079  0 toggle public void updateAnnotation(boolean applyGlobalSettings)
1080    {
1081  0 updateAnnotation(applyGlobalSettings, false);
1082    }
1083   
 
1084  0 toggle public void updateAnnotation(boolean applyGlobalSettings,
1085    boolean preserveNewGroupSettings)
1086    {
1087  0 av.updateGroupAnnotationSettings(applyGlobalSettings,
1088    preserveNewGroupSettings);
1089  0 adjustAnnotationHeight();
1090    }
1091   
 
1092  0 toggle @Override
1093    public AlignmentI getAlignment()
1094    {
1095  0 return av.getAlignment();
1096    }
1097   
 
1098  0 toggle @Override
1099    public String getViewName()
1100    {
1101  0 return getName();
1102    }
1103   
 
1104  0 toggle @Override
1105    public StructureSelectionManager getStructureSelectionManager()
1106    {
1107  0 return StructureSelectionManager
1108    .getStructureSelectionManager(av.applet);
1109    }
1110   
 
1111  0 toggle @Override
1112    public void raiseOOMWarning(String string, OutOfMemoryError error)
1113    {
1114    // TODO: JAL-960
1115  0 jalview.bin.Console.errPrintln("Out of memory whilst '" + string + "'");
1116  0 error.printStackTrace();
1117    }
1118   
1119    /**
1120    * Set a flag to say we are scrolling to follow a (cDNA/protein) complement.
1121    *
1122    * @param b
1123    */
 
1124  0 toggle protected void setToScrollComplementPanel(boolean b)
1125    {
1126  0 this.scrollComplementaryPanel = b;
1127    }
1128   
1129    /**
1130    * Get whether to scroll complement panel
1131    *
1132    * @return true if cDNA/protein complement panels should be scrolled
1133    */
 
1134  0 toggle protected boolean isSetToScrollComplementPanel()
1135    {
1136  0 return this.scrollComplementaryPanel;
1137    }
1138   
 
1139  0 toggle @Override
1140    /**
1141    * Property change event fired when a change is made to the viewport ranges
1142    * object associated with this alignment panel's viewport
1143    */
1144    public void propertyChange(PropertyChangeEvent evt)
1145    {
1146    // update this panel's scroll values based on the new viewport ranges values
1147  0 int x = vpRanges.getStartRes();
1148  0 int y = vpRanges.getStartSeq();
1149  0 setScrollValues(x, y);
1150   
1151    // now update any complementary alignment (its viewport ranges object
1152    // is different so does not get automatically updated)
1153  0 if (isSetToScrollComplementPanel())
1154    {
1155  0 setToScrollComplementPanel(false);
1156  0 av.scrollComplementaryAlignment(getComplementPanel());
1157  0 setToScrollComplementPanel(true);
1158    }
1159   
1160    }
1161   
1162    }