Clover icon

Coverage Report

  1. Project Clover database Thu Dec 4 2025 16:11:35 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,163
765
121
0.32
8.48
44
2.75

Classes

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