2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3 * Copyright (C) 2014 The Jalview Authors
5 * This file is part of Jalview.
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.
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.
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.
21 package jalview.appletgui;
24 import java.awt.event.*;
26 import jalview.api.AlignmentViewPanel;
27 import jalview.datamodel.*;
28 import jalview.structure.StructureSelectionManager;
30 public class AlignmentPanel extends Panel implements AdjustmentListener,
34 public AlignViewport av;
36 OverviewPanel overviewPanel;
42 IdwidthAdjuster idwidthAdjuster;
44 public AlignFrame alignFrame;
46 ScalePanel scalePanel;
48 AnnotationPanel annotationPanel;
50 AnnotationLabels alabels;
52 // this value is set false when selection area being dragged
53 boolean fastPaint = true;
55 public void finalize()
60 seqPanelHolder = null;
61 sequenceHolderPanel = null;
63 scalePanelHolder = null;
64 annotationPanel = null;
65 annotationPanelHolder = null;
66 annotationSpaceFillerHolder = null;
69 public AlignmentPanel(AlignFrame af, final AlignViewport av)
81 seqPanel = new SeqPanel(av, this);
82 idPanel = new IdPanel(av, this);
83 scalePanel = new ScalePanel(av, this);
84 idwidthAdjuster = new IdwidthAdjuster(this);
85 annotationPanel = new AnnotationPanel(this);
86 annotationPanelHolder.add(annotationPanel, BorderLayout.CENTER);
88 sequenceHolderPanel.add(annotationPanelHolder, BorderLayout.SOUTH);
89 alabels = new AnnotationLabels(this);
91 setAnnotationVisible(av.showAnnotation);
93 idPanelHolder.add(idPanel, BorderLayout.CENTER);
94 idSpaceFillerPanel1.add(idwidthAdjuster, BorderLayout.CENTER);
95 annotationSpaceFillerHolder.add(alabels, BorderLayout.CENTER);
96 scalePanelHolder.add(scalePanel, BorderLayout.CENTER);
97 seqPanelHolder.add(seqPanel, BorderLayout.CENTER);
100 setScrollValues(0, 0);
102 apvscroll.addAdjustmentListener(this);
103 hscroll.addAdjustmentListener(this);
104 vscroll.addAdjustmentListener(this);
106 addComponentListener(new ComponentAdapter()
108 public void componentResized(ComponentEvent evt)
110 setScrollValues(av.getStartRes(), av.getStartSeq());
111 if (getSize().height > 0
112 && annotationPanelHolder.getSize().height > 0)
114 validateAnnotationDimensions(false);
121 Dimension d = calculateIdWidth();
122 idPanel.idCanvas.setSize(d);
124 hscrollFillerPanel.setSize(d.width, annotationPanel.getSize().height);
126 idPanel.idCanvas.setSize(d.width, seqPanel.seqCanvas.getSize().height);
127 annotationSpaceFillerHolder.setSize(d.width,
128 annotationPanel.getSize().height);
129 alabels.setSize(d.width, annotationPanel.getSize().height);
130 final AlignmentPanel ap = this;
131 av.addPropertyChangeListener(new java.beans.PropertyChangeListener()
133 public void propertyChange(java.beans.PropertyChangeEvent evt)
135 if (evt.getPropertyName().equals("alignment"))
137 PaintRefresher.Refresh(ap, av.getSequenceSetId(), true, true);
144 public SequenceRenderer getSequenceRenderer()
146 return seqPanel.seqCanvas.sr;
149 public FeatureRenderer getFeatureRenderer()
151 return seqPanel.seqCanvas.fr;
154 public void alignmentChanged()
156 av.alignmentChanged(this);
158 if (overviewPanel != null)
160 overviewPanel.updateOverviewImage();
163 alignFrame.updateEditMenuBar();
168 public void fontChanged()
170 // set idCanvas bufferedImage to null
171 // to prevent drawing old image
172 idPanel.idCanvas.image = null;
173 FontMetrics fm = getFontMetrics(av.getFont());
175 scalePanel.setSize(new Dimension(10, av.charHeight + fm.getDescent()));
176 idwidthAdjuster.setSize(new Dimension(10, av.charHeight
178 av.updateSequenceIdColours();
179 annotationPanel.image = null;
180 int ap = annotationPanel.adjustPanelHeight(false);
181 Dimension d = calculateIdWidth();
182 d.setSize(d.width + 4, seqPanel.seqCanvas.getSize().height);
183 alabels.setSize(d.width + 4, ap);
185 idPanel.idCanvas.setSize(d);
186 hscrollFillerPanel.setSize(d);
188 validateAnnotationDimensions(false);
189 annotationPanel.repaint();
193 if (overviewPanel != null)
195 overviewPanel.updateOverviewImage();
199 public void setIdWidth(int w, int h)
201 idPanel.idCanvas.setSize(w, h);
202 idPanelHolder.setSize(w, idPanelHolder.getSize().height);
203 annotationSpaceFillerHolder.setSize(w,
204 annotationSpaceFillerHolder.getSize().height);
205 alabels.setSize(w, alabels.getSize().height);
209 Dimension calculateIdWidth()
211 if (av.nullFrame == null)
213 av.nullFrame = new Frame();
214 av.nullFrame.addNotify();
217 Graphics g = av.nullFrame.getGraphics();
219 FontMetrics fm = g.getFontMetrics(av.font);
220 AlignmentI al = av.getAlignment();
225 while (i < al.getHeight() && al.getSequenceAt(i) != null)
227 SequenceI s = al.getSequenceAt(i);
228 id = s.getDisplayId(av.getShowJVSuffix());
230 if (fm.stringWidth(id) > idWidth)
232 idWidth = fm.stringWidth(id);
237 // Also check annotation label widths
239 if (al.getAlignmentAnnotation() != null)
241 fm = g.getFontMetrics(av.nullFrame.getFont());
242 while (i < al.getAlignmentAnnotation().length)
244 String label = al.getAlignmentAnnotation()[i].label;
245 if (fm.stringWidth(label) > idWidth)
247 idWidth = fm.stringWidth(label);
253 return new Dimension(idWidth, idPanel.idCanvas.getSize().height);
257 * Highlight the given results on the alignment.
260 public void highlightSearchResults(SearchResults results)
262 scrollToPosition(results);
263 seqPanel.seqCanvas.highlightSearchResults(results);
267 * scroll the view to show the position of the highlighted region in results
268 * (if any) and redraw the overview
271 * @return false if results were not found
273 public boolean scrollToPosition(SearchResults results)
275 return scrollToPosition(results, true);
279 * scroll the view to show the position of the highlighted region in results
283 * @param redrawOverview
284 * - when set, the overview will be recalculated (takes longer)
285 * @return false if results were not found
287 public boolean scrollToPosition(SearchResults results,
288 boolean redrawOverview)
291 // do we need to scroll the panel?
292 if (results != null && results.getSize() > 0)
294 AlignmentI alignment = av.getAlignment();
295 int seqIndex = alignment.findIndex(results);
300 SequenceI seq = alignment.getSequenceAt(seqIndex);
301 int[] r = results.getResults(seq, 0, alignment.getWidth());
307 .println("DEBUG: scroll didn't happen - results not within alignment : "
308 + seq.getStart() + "," + seq.getEnd());
316 * System.out.println("DEBUG: scroll: start=" + r[0] +
317 * " av.getStartRes()=" + av.getStartRes() + " end=" + r[1] +
318 * " seq.end=" + seq.getEnd() + " av.getEndRes()=" + av.getEndRes() +
319 * " hextent=" + hextent);
328 if (end == seq.getEnd())
332 return scrollTo(start, end, seqIndex, false, redrawOverview);
337 public boolean scrollTo(int ostart, int end, int seqIndex,
338 boolean scrollToNearest, boolean redrawOverview)
340 int startv, endv, starts, ends, width;
343 if (av.hasHiddenColumns())
345 start = av.getColumnSelection().findColumnPosition(ostart);
346 end = av.getColumnSelection().findColumnPosition(end);
349 if (!scrollToNearest && !av.getColumnSelection().isVisible(ostart))
351 // don't scroll - position isn't visible
360 if (!av.wrapAlignment)
363 * int spos=av.getStartRes(),sqpos=av.getStartSeq(); if ((startv =
364 * av.getStartRes()) >= start) { spos=start-1; // seqIn //
365 * setScrollValues(start - 1, seqIndex); } else if ((endv =
366 * av.getEndRes()) <= end) { // setScrollValues(spos=startv + 1 + end -
367 * endv, seqIndex); spos=startv + 1 + end - endv; } else if ((starts =
368 * av.getStartSeq()) > seqIndex) { setScrollValues(av.getStartRes(),
369 * seqIndex); } else if ((ends = av.getEndSeq()) <= seqIndex) {
370 * setScrollValues(av.getStartRes(), starts + seqIndex - ends + 1); }
374 if ((av.getStartRes() > end)
375 || (av.getEndRes() < start)
376 || ((av.getStartSeq() > seqIndex) || (av.getEndSeq() < seqIndex)))
378 if (start > av.getAlignment().getWidth() - hextent)
380 start = av.getAlignment().getWidth() - hextent;
387 if (seqIndex > av.getAlignment().getHeight() - vextent)
389 seqIndex = av.getAlignment().getHeight() - vextent;
395 // System.out.println("trying to scroll to: "+start+" "+seqIndex);
396 setScrollValues(start, seqIndex);
401 scrollToWrappedVisible(start);
403 if (redrawOverview && overviewPanel != null)
405 overviewPanel.setBoxPosition();
407 paintAlignment(redrawOverview);
411 void scrollToWrappedVisible(int res)
413 int cwidth = seqPanel.seqCanvas
414 .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
415 if (res <= av.getStartRes() || res >= (av.getStartRes() + cwidth))
417 vscroll.setValue(res / cwidth);
418 av.startRes = vscroll.getValue() * cwidth;
422 public OverviewPanel getOverviewPanel()
424 return overviewPanel;
427 public void setOverviewPanel(OverviewPanel op)
432 public void setAnnotationVisible(boolean b)
434 if (!av.wrapAlignment)
436 annotationSpaceFillerHolder.setVisible(b);
437 annotationPanelHolder.setVisible(b);
441 annotationSpaceFillerHolder.setVisible(false);
442 annotationPanelHolder.setVisible(false);
449 * automatically adjust annotation panel height for new annotation whilst
450 * ensuring the alignment is still visible.
452 public void adjustAnnotationHeight()
454 // TODO: display vertical annotation scrollbar if necessary
455 // this is called after loading new annotation onto alignment
456 if (alignFrame.getSize().height == 0)
458 System.out.println("NEEDS FIXING");
461 validateAnnotationDimensions(true);
462 apvscroll.addNotify();
465 paintAlignment(true);
469 * calculate the annotation dimensions and refresh slider values accordingly.
470 * need to do repaints/notifys afterwards.
472 protected void validateAnnotationDimensions(boolean adjustPanelHeight)
474 boolean modified = false;
475 int height = av.calcPanelHeight();
477 if (hscroll.isVisible())
479 height += (minsize = hscroll.getPreferredSize().height);
481 if (apvscroll.isVisible())
483 minsize += apvscroll.getPreferredSize().height;
485 int mheight = height;
486 Dimension d = sequenceHolderPanel.getSize(), e = idPanel.getSize();
487 int seqandannot = d.height - scalePanelHolder.getSize().height;
489 if (adjustPanelHeight)
491 // NOTE: this logic is different in the application. Need a better
492 // algorithm to define behaviour
493 // sets initial preferred height
494 // try and set height according to alignment
495 float sscaling = (float) ((av.getCharHeight() * av.getAlignment()
496 .getHeight()) / (1.0 * mheight));
499 // if the alignment is too big then
500 // default is 0.5 split
501 height = seqandannot / 2;
505 // otherwise just set the panel so that one row of sequence is visible
506 height = -av.getCharHeight() * 1
507 + (int) (seqandannot * (1 - sscaling));
512 // maintain same window layout whilst updating sliders
513 height = annotationPanelHolder.getSize().height;
516 if (seqandannot - height < 5)
518 height = seqandannot;
520 annotationPanel.setSize(new Dimension(d.width, height));
521 alabels.setSize(new Dimension(e.width, height));
522 annotationSpaceFillerHolder.setSize(new Dimension(e.width, height));
523 annotationPanelHolder.setSize(new Dimension(d.width, height));
524 // seqPanelHolder.setSize(d.width, seqandannot - height);
526 .setSize(d.width, seqPanel.seqCanvas.getSize().height);
527 int s = apvscroll.getValue();
528 if (s > mheight - height)
532 apvscroll.setValues(s, height, 0, mheight);
533 annotationPanel.setScrollOffset(apvscroll.getValue(), false);
534 alabels.setScrollOffset(apvscroll.getValue(), false);
537 public void setWrapAlignment(boolean wrap)
541 scalePanelHolder.setVisible(!wrap);
543 hscroll.setVisible(!wrap);
544 idwidthAdjuster.setVisible(!wrap);
548 annotationPanelHolder.setVisible(false);
549 annotationSpaceFillerHolder.setVisible(false);
551 else if (av.showAnnotation)
553 annotationPanelHolder.setVisible(true);
554 annotationSpaceFillerHolder.setVisible(true);
557 idSpaceFillerPanel1.setVisible(!wrap);
559 fontChanged(); // This is so that the scalePanel is resized correctly
562 sequenceHolderPanel.validate();
571 // return value is true if the scroll is valid
572 public boolean scrollUp(boolean up)
576 if (vscroll.getValue() < 1)
580 setScrollValues(hscroll.getValue(), vscroll.getValue() - 1);
584 if (vextent + vscroll.getValue() >= av.getAlignment().getHeight())
588 setScrollValues(hscroll.getValue(), vscroll.getValue() + 1);
595 public boolean scrollRight(boolean right)
599 if (hscroll.getValue() < 1)
603 setScrollValues(hscroll.getValue() - 1, vscroll.getValue());
607 if (hextent + hscroll.getValue() >= av.getAlignment().getWidth())
611 setScrollValues(hscroll.getValue() + 1, vscroll.getValue());
618 public void setScrollValues(int x, int y)
620 int width = av.getAlignment().getWidth();
621 int height = av.getAlignment().getHeight();
623 if (av.hasHiddenColumns())
625 width = av.getColumnSelection().findColumnPosition(width);
633 hextent = seqPanel.seqCanvas.getSize().width / av.charWidth;
634 vextent = seqPanel.seqCanvas.getSize().height / av.charHeight;
641 if (vextent > height)
646 if ((hextent + x) > width)
648 System.err.println("hextent was " + hextent + " and x was " + x);
653 if ((vextent + y) > height)
655 y = height - vextent;
665 System.err.println("x was " + x);
671 int endSeq = y + vextent;
672 if (endSeq > av.getAlignment().getHeight())
674 endSeq = av.getAlignment().getHeight();
677 av.setEndSeq(endSeq);
679 av.setEndRes((x + (seqPanel.seqCanvas.getSize().width / av.charWidth)) - 1);
681 hscroll.setValues(x, hextent, 0, width);
682 vscroll.setValues(y, vextent, 0, height);
684 if (overviewPanel != null)
686 overviewPanel.setBoxPosition();
692 public void adjustmentValueChanged(AdjustmentEvent evt)
694 int oldX = av.getStartRes();
695 int oldY = av.getStartSeq();
697 if (evt == null || evt.getSource() == apvscroll)
699 annotationPanel.setScrollOffset(apvscroll.getValue(), false);
700 alabels.setScrollOffset(apvscroll.getValue(), false);
701 // annotationPanel.image=null;
702 // alabels.image=null;
703 // alabels.repaint();
704 // annotationPanel.repaint();
706 if (evt == null || evt.getSource() == hscroll)
708 int x = hscroll.getValue();
710 av.setEndRes(x + seqPanel.seqCanvas.getSize().width
711 / av.getCharWidth() - 1);
714 if (evt == null || evt.getSource() == vscroll)
716 int offy = vscroll.getValue();
717 if (av.getWrapAlignment())
719 int rowSize = seqPanel.seqCanvas
720 .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
721 av.setStartRes(vscroll.getValue() * rowSize);
722 av.setEndRes((vscroll.getValue() + 1) * rowSize);
726 av.setStartSeq(offy);
727 av.setEndSeq(offy + seqPanel.seqCanvas.getSize().height
728 / av.getCharHeight());
732 if (overviewPanel != null)
734 overviewPanel.setBoxPosition();
737 int scrollX = av.startRes - oldX;
738 int scrollY = av.startSeq - oldY;
740 if (av.getWrapAlignment() || !fastPaint || av.MAC)
746 // Make sure we're not trying to draw a panel
747 // larger than the visible window
748 if (scrollX > av.endRes - av.startRes)
750 scrollX = av.endRes - av.startRes;
752 else if (scrollX < av.startRes - av.endRes)
754 scrollX = av.startRes - av.endRes;
757 idPanel.idCanvas.fastPaint(scrollY);
758 seqPanel.seqCanvas.fastPaint(scrollX, scrollY);
760 scalePanel.repaint();
761 if (av.getShowAnnotation())
763 annotationPanel.fastPaint(av.getStartRes() - oldX);
770 private void sendViewPosition()
772 StructureSelectionManager.getStructureSelectionManager(av.applet)
773 .sendViewPosition(this, av.startRes, av.endRes, av.startSeq,
777 public void paintAlignment(boolean updateOverview)
783 jalview.structure.StructureSelectionManager
784 .getStructureSelectionManager(av.applet)
785 .sequenceColoursChanged(this);
787 if (overviewPanel != null)
789 overviewPanel.updateOverviewImage();
794 public void update(Graphics g)
799 public void paint(Graphics g)
802 Dimension d = idPanel.idCanvas.getSize();
803 idPanel.idCanvas.setSize(d.width, seqPanel.seqCanvas.getSize().height);
805 if (av.getWrapAlignment())
807 int maxwidth = av.getAlignment().getWidth();
809 if (av.hasHiddenColumns())
811 maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
814 int canvasWidth = seqPanel.seqCanvas
815 .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
819 int max = maxwidth / canvasWidth;
820 vscroll.setMaximum(1 + max);
821 vscroll.setUnitIncrement(1);
822 vscroll.setVisibleAmount(1);
827 setScrollValues(av.getStartRes(), av.getStartSeq());
830 seqPanel.seqCanvas.repaint();
831 idPanel.idCanvas.repaint();
832 if (!av.wrapAlignment)
834 if (av.showAnnotation)
837 annotationPanel.repaint();
839 scalePanel.repaint();
844 protected Panel sequenceHolderPanel = new Panel();
846 protected Scrollbar vscroll = new Scrollbar();
848 protected Scrollbar hscroll = new Scrollbar();
850 protected Panel seqPanelHolder = new Panel();
852 BorderLayout borderLayout1 = new BorderLayout();
854 BorderLayout borderLayout3 = new BorderLayout();
856 protected Panel scalePanelHolder = new Panel();
858 protected Panel idPanelHolder = new Panel();
860 BorderLayout borderLayout5 = new BorderLayout();
862 protected Panel idSpaceFillerPanel1 = new Panel();
864 public Panel annotationSpaceFillerHolder = new Panel();
866 BorderLayout borderLayout6 = new BorderLayout();
868 BorderLayout borderLayout7 = new BorderLayout();
870 Panel hscrollHolder = new Panel();
872 BorderLayout borderLayout10 = new BorderLayout();
874 protected Panel hscrollFillerPanel = new Panel();
876 BorderLayout borderLayout11 = new BorderLayout();
878 BorderLayout borderLayout4 = new BorderLayout();
880 BorderLayout borderLayout2 = new BorderLayout();
882 Panel annotationPanelHolder = new Panel();
884 protected Scrollbar apvscroll = new Scrollbar();
886 BorderLayout borderLayout12 = new BorderLayout();
888 private void jbInit() throws Exception
890 // idPanelHolder.setPreferredSize(new Dimension(70, 10));
891 this.setLayout(borderLayout7);
893 // sequenceHolderPanel.setPreferredSize(new Dimension(150, 150));
894 sequenceHolderPanel.setLayout(borderLayout3);
895 seqPanelHolder.setLayout(borderLayout1);
896 scalePanelHolder.setBackground(Color.white);
898 // scalePanelHolder.setPreferredSize(new Dimension(10, 30));
899 scalePanelHolder.setLayout(borderLayout6);
900 idPanelHolder.setLayout(borderLayout5);
901 idSpaceFillerPanel1.setBackground(Color.white);
903 // idSpaceFillerPanel1.setPreferredSize(new Dimension(10, 30));
904 idSpaceFillerPanel1.setLayout(borderLayout11);
905 annotationSpaceFillerHolder.setBackground(Color.white);
907 // annotationSpaceFillerHolder.setPreferredSize(new Dimension(10, 80));
908 annotationSpaceFillerHolder.setLayout(borderLayout4);
909 hscroll.setOrientation(Scrollbar.HORIZONTAL);
910 hscrollHolder.setLayout(borderLayout10);
911 hscrollFillerPanel.setBackground(Color.white);
912 apvscroll.setOrientation(Scrollbar.VERTICAL);
913 apvscroll.setVisible(true);
914 apvscroll.addAdjustmentListener(this);
916 annotationPanelHolder.setBackground(Color.white);
917 annotationPanelHolder.setLayout(borderLayout12);
918 annotationPanelHolder.add(apvscroll, BorderLayout.EAST);
919 // hscrollFillerPanel.setPreferredSize(new Dimension(70, 10));
920 hscrollHolder.setBackground(Color.white);
922 // annotationScroller.setPreferredSize(new Dimension(10, 80));
923 // this.setPreferredSize(new Dimension(220, 166));
924 seqPanelHolder.setBackground(Color.white);
925 idPanelHolder.setBackground(Color.white);
926 sequenceHolderPanel.add(scalePanelHolder, BorderLayout.NORTH);
927 sequenceHolderPanel.add(seqPanelHolder, BorderLayout.CENTER);
928 seqPanelHolder.add(vscroll, BorderLayout.EAST);
930 // Panel3.add(secondaryPanelHolder, BorderLayout.SOUTH);
931 this.add(idPanelHolder, BorderLayout.WEST);
932 idPanelHolder.add(idSpaceFillerPanel1, BorderLayout.NORTH);
933 idPanelHolder.add(annotationSpaceFillerHolder, BorderLayout.SOUTH);
934 this.add(hscrollHolder, BorderLayout.SOUTH);
935 hscrollHolder.add(hscroll, BorderLayout.CENTER);
936 hscrollHolder.add(hscrollFillerPanel, BorderLayout.WEST);
937 this.add(sequenceHolderPanel, BorderLayout.CENTER);
941 * hides or shows dynamic annotation rows based on groups and av state flags
943 public void updateAnnotation()
945 updateAnnotation(false);
948 public void updateAnnotation(boolean applyGlobalSettings)
950 updateAnnotation(applyGlobalSettings, false);
953 public void updateAnnotation(boolean applyGlobalSettings,
954 boolean preserveNewGroupSettings)
956 av.updateGroupAnnotationSettings(applyGlobalSettings,
957 preserveNewGroupSettings);
958 adjustAnnotationHeight();
962 public AlignmentI getAlignment()
964 return av.getAlignment();
968 public StructureSelectionManager getStructureSelectionManager()
970 return StructureSelectionManager
971 .getStructureSelectionManager(av.applet);
975 public void raiseOOMWarning(String string, OutOfMemoryError error)
978 System.err.println("Out of memory whilst '" + string + "'");
979 error.printStackTrace();