2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)
3 * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
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 of the License, or (at your option) any later version.
11 * Jalview is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.
18 package jalview.appletgui;
21 import java.awt.event.*;
23 import jalview.api.AlignmentViewPanel;
24 import jalview.datamodel.*;
25 import jalview.structure.StructureSelectionManager;
27 public class AlignmentPanel extends Panel implements AdjustmentListener,
31 public AlignViewport av;
33 OverviewPanel overviewPanel;
39 IdwidthAdjuster idwidthAdjuster;
41 public AlignFrame alignFrame;
43 ScalePanel scalePanel;
45 AnnotationPanel annotationPanel;
47 AnnotationLabels alabels;
49 // this value is set false when selection area being dragged
50 boolean fastPaint = true;
52 public void finalize()
57 seqPanelHolder = null;
58 sequenceHolderPanel = null;
60 scalePanelHolder = null;
61 annotationPanel = null;
62 annotationPanelHolder = null;
63 annotationSpaceFillerHolder = null;
66 public AlignmentPanel(AlignFrame af, final AlignViewport av)
78 seqPanel = new SeqPanel(av, this);
79 idPanel = new IdPanel(av, this);
80 scalePanel = new ScalePanel(av, this);
81 idwidthAdjuster = new IdwidthAdjuster(this);
82 annotationPanel = new AnnotationPanel(this);
83 annotationPanelHolder.add(annotationPanel, BorderLayout.CENTER);
85 sequenceHolderPanel.add(annotationPanelHolder, BorderLayout.SOUTH);
87 alabels = new AnnotationLabels(this);
89 setAnnotationVisible(av.showAnnotation);
91 idPanelHolder.add(idPanel, BorderLayout.CENTER);
92 idSpaceFillerPanel1.add(idwidthAdjuster, BorderLayout.CENTER);
93 annotationSpaceFillerHolder.add(alabels, BorderLayout.CENTER);
94 scalePanelHolder.add(scalePanel, BorderLayout.CENTER);
95 seqPanelHolder.add(seqPanel, BorderLayout.CENTER);
98 setScrollValues(0, 0);
100 apvscroll.addAdjustmentListener(this);
101 hscroll.addAdjustmentListener(this);
102 vscroll.addAdjustmentListener(this);
104 addComponentListener(new ComponentAdapter()
106 public void componentResized(ComponentEvent evt)
108 setScrollValues(av.getStartRes(), av.getStartSeq());
109 if (getSize().height > 0
110 && annotationPanelHolder.getSize().height > 0)
112 validateAnnotationDimensions(false);
119 Dimension d = calculateIdWidth();
120 idPanel.idCanvas.setSize(d);
122 hscrollFillerPanel.setSize(d.width, annotationPanel.getSize().height);
124 idPanel.idCanvas.setSize(d.width, seqPanel.seqCanvas.getSize().height);
125 annotationSpaceFillerHolder.setSize(d.width,
126 annotationPanel.getSize().height);
127 alabels.setSize(d.width, annotationPanel.getSize().height);
128 final AlignmentPanel ap = this;
129 av.addPropertyChangeListener(new java.beans.PropertyChangeListener()
131 public void propertyChange(java.beans.PropertyChangeEvent evt)
133 if (evt.getPropertyName().equals("alignment"))
135 PaintRefresher.Refresh(ap, av.getSequenceSetId(), true, true);
143 public SequenceRenderer getSequenceRenderer()
145 return seqPanel.seqCanvas.sr;
148 public FeatureRenderer getFeatureRenderer()
150 return seqPanel.seqCanvas.fr;
153 public void alignmentChanged()
155 av.alignmentChanged(this);
157 if (overviewPanel != null)
159 overviewPanel.updateOverviewImage();
162 alignFrame.updateEditMenuBar();
167 public void fontChanged()
169 // set idCanvas bufferedImage to null
170 // to prevent drawing old image
171 idPanel.idCanvas.image = null;
172 FontMetrics fm = getFontMetrics(av.getFont());
174 scalePanel.setSize(new Dimension(10, av.charHeight + fm.getDescent()));
175 idwidthAdjuster.setSize(new Dimension(10, av.charHeight
177 av.updateSequenceIdColours();
178 annotationPanel.image = null;
179 int ap = annotationPanel.adjustPanelHeight(false);
180 Dimension d = calculateIdWidth();
181 d.setSize(d.width + 4, seqPanel.seqCanvas.getSize().height);
182 alabels.setSize(d.width + 4, ap);
184 idPanel.idCanvas.setSize(d);
185 hscrollFillerPanel.setSize(d);
187 validateAnnotationDimensions(false);
188 annotationPanel.repaint();
192 if (overviewPanel != null)
194 overviewPanel.updateOverviewImage();
198 public void setIdWidth(int w, int h)
200 idPanel.idCanvas.setSize(w, h);
201 idPanelHolder.setSize(w, idPanelHolder.getSize().height);
202 annotationSpaceFillerHolder.setSize(w,
203 annotationSpaceFillerHolder.getSize().height);
204 alabels.setSize(w, alabels.getSize().height);
208 Dimension calculateIdWidth()
210 if (av.nullFrame == null)
212 av.nullFrame = new Frame();
213 av.nullFrame.addNotify();
216 Graphics g = av.nullFrame.getGraphics();
218 FontMetrics fm = g.getFontMetrics(av.font);
219 AlignmentI al = av.getAlignment();
224 while (i < al.getHeight() && al.getSequenceAt(i) != null)
226 SequenceI s = al.getSequenceAt(i);
227 id = s.getDisplayId(av.getShowJVSuffix());
229 if (fm.stringWidth(id) > idWidth)
231 idWidth = fm.stringWidth(id);
236 // Also check annotation label widths
238 if (al.getAlignmentAnnotation() != null)
240 fm = g.getFontMetrics(av.nullFrame.getFont());
241 while (i < al.getAlignmentAnnotation().length)
243 String label = al.getAlignmentAnnotation()[i].label;
244 if (fm.stringWidth(label) > idWidth)
246 idWidth = fm.stringWidth(label);
252 return new Dimension(idWidth, idPanel.idCanvas.getSize().height);
256 * Highlight the given results on the alignment.
259 public void highlightSearchResults(SearchResults results)
261 scrollToPosition(results);
262 seqPanel.seqCanvas.highlightSearchResults(results);
266 * scroll the view to show the position of the highlighted region in results
267 * (if any) and redraw the overview
270 * @return false if results were not found
272 public boolean scrollToPosition(SearchResults results)
274 return scrollToPosition(results, true);
278 * scroll the view to show the position of the highlighted region in results
282 * @param redrawOverview
283 * - when set, the overview will be recalculated (takes longer)
284 * @return false if results were not found
286 public boolean scrollToPosition(SearchResults results,
287 boolean redrawOverview)
290 // do we need to scroll the panel?
291 if (results != null && results.getSize() > 0)
293 AlignmentI alignment = av.getAlignment();
294 int seqIndex = alignment.findIndex(results);
299 SequenceI seq = alignment.getSequenceAt(seqIndex);
300 int[] r = results.getResults(seq, 0, alignment.getWidth());
306 .println("DEBUG: scroll didn't happen - results not within alignment : "
307 + seq.getStart() + "," + seq.getEnd());
315 * System.out.println("DEBUG: scroll: start=" + r[0] +
316 * " av.getStartRes()=" + av.getStartRes() + " end=" + r[1] +
317 * " seq.end=" + seq.getEnd() + " av.getEndRes()=" + av.getEndRes() +
318 * " hextent=" + hextent);
327 if (end == seq.getEnd())
331 return scrollTo(start, end, seqIndex, false, redrawOverview);
336 public boolean scrollTo(int ostart, int end, int seqIndex,
337 boolean scrollToNearest, boolean redrawOverview)
339 int startv, endv, starts, ends, width;
342 if (av.hasHiddenColumns())
344 start = av.getColumnSelection().findColumnPosition(ostart);
345 end = av.getColumnSelection().findColumnPosition(end);
348 if (!scrollToNearest && !av.getColumnSelection().isVisible(ostart))
350 // don't scroll - position isn't visible
359 if (!av.wrapAlignment)
362 * int spos=av.getStartRes(),sqpos=av.getStartSeq(); if ((startv =
363 * av.getStartRes()) >= start) { spos=start-1; // seqIn //
364 * setScrollValues(start - 1, seqIndex); } else if ((endv =
365 * av.getEndRes()) <= end) { // setScrollValues(spos=startv + 1 + end -
366 * endv, seqIndex); spos=startv + 1 + end - endv; } else if ((starts =
367 * av.getStartSeq()) > seqIndex) { setScrollValues(av.getStartRes(),
368 * seqIndex); } else if ((ends = av.getEndSeq()) <= seqIndex) {
369 * setScrollValues(av.getStartRes(), starts + seqIndex - ends + 1); }
373 if ((av.getStartRes() > end)
374 || (av.getEndRes() < start)
375 || ((av.getStartSeq() > seqIndex) || (av.getEndSeq() < seqIndex)))
377 if (start > av.getAlignment().getWidth() - hextent)
379 start = av.getAlignment().getWidth() - hextent;
386 if (seqIndex > av.getAlignment().getHeight() - vextent)
388 seqIndex = av.getAlignment().getHeight() - vextent;
394 // System.out.println("trying to scroll to: "+start+" "+seqIndex);
395 setScrollValues(start, seqIndex);
400 scrollToWrappedVisible(start);
402 if (redrawOverview && overviewPanel != null)
404 overviewPanel.setBoxPosition();
406 paintAlignment(redrawOverview);
410 void scrollToWrappedVisible(int res)
412 int cwidth = seqPanel.seqCanvas
413 .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
414 if (res <= av.getStartRes() || res >= (av.getStartRes() + cwidth))
416 vscroll.setValue(res / cwidth);
417 av.startRes = vscroll.getValue() * cwidth;
421 public OverviewPanel getOverviewPanel()
423 return overviewPanel;
426 public void setOverviewPanel(OverviewPanel op)
431 public void setAnnotationVisible(boolean b)
433 if (!av.wrapAlignment)
435 annotationSpaceFillerHolder.setVisible(b);
436 annotationPanelHolder.setVisible(b);
443 * automatically adjust annotation panel height for new annotation whilst
444 * ensuring the alignment is still visible.
446 public void adjustAnnotationHeight()
448 // TODO: display vertical annotation scrollbar if necessary
449 // this is called after loading new annotation onto alignment
450 if (alignFrame.getSize().height == 0)
452 System.out.println("NEEDS FIXING");
455 validateAnnotationDimensions(true);
456 apvscroll.addNotify();
459 paintAlignment(true);
463 * calculate the annotation dimensions and refresh slider values accordingly.
464 * need to do repaints/notifys afterwards.
466 protected void validateAnnotationDimensions(boolean adjustPanelHeight)
468 boolean modified = false;
469 int height = av.calcPanelHeight();
471 if (hscroll.isVisible())
473 height += (minsize = hscroll.getPreferredSize().height);
475 if (apvscroll.isVisible())
477 minsize += apvscroll.getPreferredSize().height;
479 int mheight = height;
480 Dimension d = sequenceHolderPanel.getSize(), e = idPanel.getSize();
481 int seqandannot = d.height - scalePanelHolder.getSize().height;
482 // sets initial preferred height
483 if ((height + 40) > seqandannot / 2)
485 height = seqandannot / 2;
487 if (!adjustPanelHeight)
489 // maintain same window layout whilst updating sliders
490 height = annotationPanelHolder.getSize().height;
493 if (seqandannot - height < 5)
495 height = seqandannot;
497 annotationPanel.setSize(new Dimension(d.width, height));
498 alabels.setSize(new Dimension(e.width, height));
499 annotationSpaceFillerHolder.setSize(new Dimension(e.width, height));
500 annotationPanelHolder.setSize(new Dimension(d.width, height));
501 seqPanelHolder.setSize(d.width, seqandannot - height);
503 .setSize(d.width, seqPanel.seqCanvas.getSize().height);
504 int s = apvscroll.getValue();
505 if (s > mheight - height)
509 apvscroll.setValues(s, height, 0, mheight);
510 annotationPanel.setScrollOffset(apvscroll.getValue());
511 alabels.setScrollOffset(apvscroll.getValue());
514 public void setWrapAlignment(boolean wrap)
518 scalePanelHolder.setVisible(!wrap);
520 hscroll.setVisible(!wrap);
521 idwidthAdjuster.setVisible(!wrap);
525 annotationPanelHolder.setVisible(false);
526 annotationSpaceFillerHolder.setVisible(false);
528 else if (av.showAnnotation)
530 annotationPanelHolder.setVisible(true);
531 annotationSpaceFillerHolder.setVisible(true);
534 idSpaceFillerPanel1.setVisible(!wrap);
536 fontChanged(); // This is so that the scalePanel is resized correctly
547 // return value is true if the scroll is valid
548 public boolean scrollUp(boolean up)
552 if (vscroll.getValue() < 1)
556 setScrollValues(hscroll.getValue(), vscroll.getValue() - 1);
560 if (vextent + vscroll.getValue() >= av.getAlignment().getHeight())
564 setScrollValues(hscroll.getValue(), vscroll.getValue() + 1);
571 public boolean scrollRight(boolean right)
575 if (hscroll.getValue() < 1)
579 setScrollValues(hscroll.getValue() - 1, vscroll.getValue());
583 if (hextent + hscroll.getValue() >= av.getAlignment().getWidth())
587 setScrollValues(hscroll.getValue() + 1, vscroll.getValue());
594 public void setScrollValues(int x, int y)
596 int width = av.getAlignment().getWidth();
597 int height = av.getAlignment().getHeight();
599 if (av.hasHiddenColumns())
601 width = av.getColumnSelection().findColumnPosition(width);
609 hextent = seqPanel.seqCanvas.getSize().width / av.charWidth;
610 vextent = seqPanel.seqCanvas.getSize().height / av.charHeight;
617 if (vextent > height)
622 if ((hextent + x) > width)
624 System.err.println("hextent was " + hextent + " and x was " + x);
629 if ((vextent + y) > height)
631 y = height - vextent;
641 System.err.println("x was " + x);
647 int endSeq = y + vextent;
648 if (endSeq > av.getAlignment().getHeight())
650 endSeq = av.getAlignment().getHeight();
653 av.setEndSeq(endSeq);
655 av.setEndRes((x + (seqPanel.seqCanvas.getSize().width / av.charWidth)) - 1);
657 hscroll.setValues(x, hextent, 0, width);
658 vscroll.setValues(y, vextent, 0, height);
660 if (overviewPanel != null)
662 overviewPanel.setBoxPosition();
668 public void adjustmentValueChanged(AdjustmentEvent evt)
670 int oldX = av.getStartRes();
671 int oldY = av.getStartSeq();
673 if (evt == null || evt.getSource() == apvscroll)
675 annotationPanel.setScrollOffset(apvscroll.getValue());
676 alabels.setScrollOffset(apvscroll.getValue());
677 // annotationPanel.image=null;
678 // alabels.image=null;
679 // alabels.repaint();
680 // annotationPanel.repaint();
682 if (evt == null || evt.getSource() == hscroll)
684 int x = hscroll.getValue();
686 av.setEndRes(x + seqPanel.seqCanvas.getSize().width
687 / av.getCharWidth() - 1);
690 if (evt == null || evt.getSource() == vscroll)
692 int offy = vscroll.getValue();
693 if (av.getWrapAlignment())
695 int rowSize = seqPanel.seqCanvas
696 .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
697 av.setStartRes(vscroll.getValue() * rowSize);
698 av.setEndRes((vscroll.getValue() + 1) * rowSize);
702 av.setStartSeq(offy);
703 av.setEndSeq(offy + seqPanel.seqCanvas.getSize().height
704 / av.getCharHeight());
708 if (overviewPanel != null)
710 overviewPanel.setBoxPosition();
713 int scrollX = av.startRes - oldX;
714 int scrollY = av.startSeq - oldY;
716 if (av.getWrapAlignment() || !fastPaint || av.MAC)
722 // Make sure we're not trying to draw a panel
723 // larger than the visible window
724 if (scrollX > av.endRes - av.startRes)
726 scrollX = av.endRes - av.startRes;
728 else if (scrollX < av.startRes - av.endRes)
730 scrollX = av.startRes - av.endRes;
733 idPanel.idCanvas.fastPaint(scrollY);
734 seqPanel.seqCanvas.fastPaint(scrollX, scrollY);
736 scalePanel.repaint();
737 if (av.getShowAnnotation())
739 annotationPanel.fastPaint(av.getStartRes() - oldX);
746 private void sendViewPosition()
748 StructureSelectionManager.getStructureSelectionManager(av.applet)
749 .sendViewPosition(this, av.startRes, av.endRes, av.startSeq,
753 public void paintAlignment(boolean updateOverview)
759 jalview.structure.StructureSelectionManager
760 .getStructureSelectionManager(av.applet)
761 .sequenceColoursChanged(this);
763 if (overviewPanel != null)
765 overviewPanel.updateOverviewImage();
770 public void update(Graphics g)
775 public void paint(Graphics g)
778 Dimension d = idPanel.idCanvas.getSize();
779 idPanel.idCanvas.setSize(d.width, seqPanel.seqCanvas.getSize().height);
781 if (av.getWrapAlignment())
783 int maxwidth = av.getAlignment().getWidth();
785 if (av.hasHiddenColumns())
787 maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
790 int canvasWidth = seqPanel.seqCanvas
791 .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
795 int max = maxwidth / canvasWidth;
796 vscroll.setMaximum(1 + max);
797 vscroll.setUnitIncrement(1);
798 vscroll.setVisibleAmount(1);
803 setScrollValues(av.getStartRes(), av.getStartSeq());
808 seqPanel.seqCanvas.repaint();
809 scalePanel.repaint();
810 annotationPanel.repaint();
811 idPanel.idCanvas.repaint();
814 protected Panel sequenceHolderPanel = new Panel();
816 protected Scrollbar vscroll = new Scrollbar();
818 protected Scrollbar hscroll = new Scrollbar();
820 protected Panel seqPanelHolder = new Panel();
822 BorderLayout borderLayout1 = new BorderLayout();
824 BorderLayout borderLayout3 = new BorderLayout();
826 protected Panel scalePanelHolder = new Panel();
828 protected Panel idPanelHolder = new Panel();
830 BorderLayout borderLayout5 = new BorderLayout();
832 protected Panel idSpaceFillerPanel1 = new Panel();
834 public Panel annotationSpaceFillerHolder = new Panel();
836 BorderLayout borderLayout6 = new BorderLayout();
838 BorderLayout borderLayout7 = new BorderLayout();
840 Panel hscrollHolder = new Panel();
842 BorderLayout borderLayout10 = new BorderLayout();
844 protected Panel hscrollFillerPanel = new Panel();
846 BorderLayout borderLayout11 = new BorderLayout();
848 BorderLayout borderLayout4 = new BorderLayout();
850 BorderLayout borderLayout2 = new BorderLayout();
852 Panel annotationPanelHolder = new Panel();
854 protected Scrollbar apvscroll = new Scrollbar();
856 BorderLayout borderLayout12 = new BorderLayout();
858 private void jbInit() throws Exception
860 // idPanelHolder.setPreferredSize(new Dimension(70, 10));
861 this.setLayout(borderLayout7);
863 // sequenceHolderPanel.setPreferredSize(new Dimension(150, 150));
864 sequenceHolderPanel.setLayout(borderLayout3);
865 seqPanelHolder.setLayout(borderLayout1);
866 scalePanelHolder.setBackground(Color.white);
868 // scalePanelHolder.setPreferredSize(new Dimension(10, 30));
869 scalePanelHolder.setLayout(borderLayout6);
870 idPanelHolder.setLayout(borderLayout5);
871 idSpaceFillerPanel1.setBackground(Color.white);
873 // idSpaceFillerPanel1.setPreferredSize(new Dimension(10, 30));
874 idSpaceFillerPanel1.setLayout(borderLayout11);
875 annotationSpaceFillerHolder.setBackground(Color.white);
877 // annotationSpaceFillerHolder.setPreferredSize(new Dimension(10, 80));
878 annotationSpaceFillerHolder.setLayout(borderLayout4);
879 hscroll.setOrientation(Scrollbar.HORIZONTAL);
880 hscrollHolder.setLayout(borderLayout10);
881 hscrollFillerPanel.setBackground(Color.white);
882 apvscroll.setOrientation(Scrollbar.VERTICAL);
883 apvscroll.setVisible(true);
884 apvscroll.addAdjustmentListener(this);
886 annotationPanelHolder.setBackground(Color.white);
887 annotationPanelHolder.setLayout(borderLayout12);
888 annotationPanelHolder.add(apvscroll, BorderLayout.EAST);
889 // hscrollFillerPanel.setPreferredSize(new Dimension(70, 10));
890 hscrollHolder.setBackground(Color.white);
892 // annotationScroller.setPreferredSize(new Dimension(10, 80));
893 // this.setPreferredSize(new Dimension(220, 166));
894 seqPanelHolder.setBackground(Color.white);
895 idPanelHolder.setBackground(Color.white);
896 sequenceHolderPanel.add(scalePanelHolder, BorderLayout.NORTH);
897 sequenceHolderPanel.add(seqPanelHolder, BorderLayout.CENTER);
898 seqPanelHolder.add(vscroll, BorderLayout.EAST);
900 // Panel3.add(secondaryPanelHolder, BorderLayout.SOUTH);
901 this.add(idPanelHolder, BorderLayout.WEST);
902 idPanelHolder.add(idSpaceFillerPanel1, BorderLayout.NORTH);
903 idPanelHolder.add(annotationSpaceFillerHolder, BorderLayout.SOUTH);
904 this.add(hscrollHolder, BorderLayout.SOUTH);
905 hscrollHolder.add(hscroll, BorderLayout.CENTER);
906 hscrollHolder.add(hscrollFillerPanel, BorderLayout.WEST);
907 this.add(sequenceHolderPanel, BorderLayout.CENTER);
911 * hides or shows dynamic annotation rows based on groups and av state flags
913 public void updateAnnotation()
915 updateAnnotation(false);
918 public void updateAnnotation(boolean applyGlobalSettings)
920 updateAnnotation(applyGlobalSettings, false);
923 public void updateAnnotation(boolean applyGlobalSettings,
924 boolean preserveNewGroupSettings)
926 av.updateGroupAnnotationSettings(applyGlobalSettings,
927 preserveNewGroupSettings);
928 adjustAnnotationHeight();
932 public AlignmentI getAlignment()
934 return av.getAlignment();
938 public StructureSelectionManager getStructureSelectionManager()
940 return StructureSelectionManager
941 .getStructureSelectionManager(av.applet);
945 public void raiseOOMWarning(String string, OutOfMemoryError error)
948 System.err.println("Out of memory whilst '" + string + "'");
949 error.printStackTrace();