2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ 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.
23 import jalview.datamodel.AlignmentAnnotation;
24 import jalview.datamodel.Annotation;
25 import jalview.datamodel.ColumnSelection;
26 import jalview.datamodel.HiddenColumns;
27 import jalview.datamodel.SequenceI;
28 import jalview.gui.JalviewColourChooser.ColourChooserListener;
29 import jalview.renderer.AnnotationRenderer;
30 import jalview.renderer.AwtRenderPanelI;
31 import jalview.schemes.FeatureColour;
32 import jalview.schemes.ResidueProperties;
33 import jalview.util.Comparison;
34 import jalview.util.MessageManager;
35 import jalview.viewmodel.ViewportListenerI;
36 import jalview.viewmodel.ViewportRanges;
38 import java.awt.AlphaComposite;
39 import java.awt.Color;
40 import java.awt.Dimension;
41 import java.awt.FontMetrics;
42 import java.awt.Graphics;
43 import java.awt.Graphics2D;
44 import java.awt.Image;
45 import java.awt.Rectangle;
46 import java.awt.RenderingHints;
47 import java.awt.event.ActionEvent;
48 import java.awt.event.ActionListener;
49 import java.awt.event.AdjustmentEvent;
50 import java.awt.event.AdjustmentListener;
51 import java.awt.event.MouseEvent;
52 import java.awt.event.MouseListener;
53 import java.awt.event.MouseMotionListener;
54 import java.awt.event.MouseWheelEvent;
55 import java.awt.event.MouseWheelListener;
56 import java.awt.image.BufferedImage;
57 import java.beans.PropertyChangeEvent;
58 import java.util.ArrayList;
59 import java.util.Collections;
60 import java.util.List;
62 import javax.swing.JColorChooser;
63 import javax.swing.JDialog;
64 import javax.swing.JMenuItem;
65 import javax.swing.JPanel;
66 import javax.swing.JPopupMenu;
67 import javax.swing.Scrollable;
68 import javax.swing.ToolTipManager;
71 * AnnotationPanel displays visible portion of annotation rows below unwrapped
77 public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
78 MouseListener, MouseWheelListener, MouseMotionListener,
79 ActionListener, AdjustmentListener, Scrollable, ViewportListenerI
83 Select, Resize, Undefined
86 String HELIX = MessageManager.getString("label.helix");
88 String SHEET = MessageManager.getString("label.sheet");
91 * For RNA secondary structure "stems" aka helices
93 String STEM = MessageManager.getString("label.rna_helix");
95 String LABEL = MessageManager.getString("label.label");
97 String REMOVE = MessageManager.getString("label.remove_annotation");
99 String COLOUR = MessageManager.getString("action.colour");
101 public final Color HELIX_COLOUR = Color.red.darker();
103 public final Color SHEET_COLOUR = Color.green.darker().darker();
105 public final Color STEM_COLOUR = Color.blue.darker();
108 public AlignViewport av;
112 public int activeRow = -1;
114 public BufferedImage image;
116 public volatile BufferedImage fadedImage;
120 public FontMetrics fm;
122 public int imgWidth = 0;
124 boolean fastPaint = false;
126 // Used For mouse Dragging and resizing graphs
127 int graphStretch = -1;
129 int mouseDragLastX = -1;
131 int mouseDragLastY = -1;
133 DragMode dragMode = DragMode.Undefined;
135 boolean mouseDragging = false;
137 // for editing cursor
142 public final AnnotationRenderer renderer;
144 private MouseWheelListener[] _mwl;
147 * Creates a new AnnotationPanel object.
152 public AnnotationPanel(AlignmentPanel ap)
154 ToolTipManager.sharedInstance().registerComponent(this);
155 ToolTipManager.sharedInstance().setInitialDelay(0);
156 ToolTipManager.sharedInstance().setDismissDelay(10000);
159 this.setLayout(null);
160 addMouseListener(this);
161 addMouseMotionListener(this);
162 ap.annotationScroller.getVerticalScrollBar()
163 .addAdjustmentListener(this);
164 // save any wheel listeners on the scroller, so we can propagate scroll
166 _mwl = ap.annotationScroller.getMouseWheelListeners();
167 // and then set our own listener to consume all mousewheel events
168 ap.annotationScroller.addMouseWheelListener(this);
169 renderer = new AnnotationRenderer();
171 av.getRanges().addPropertyChangeListener(this);
174 public AnnotationPanel(AlignViewport av)
177 renderer = new AnnotationRenderer();
181 public void mouseWheelMoved(MouseWheelEvent e)
186 double wheelRotation = e.getPreciseWheelRotation();
187 if (wheelRotation > 0)
189 av.getRanges().scrollRight(true);
191 else if (wheelRotation < 0)
193 av.getRanges().scrollRight(false);
198 // TODO: find the correct way to let the event bubble up to
199 // ap.annotationScroller
200 for (MouseWheelListener mwl : _mwl)
204 mwl.mouseWheelMoved(e);
215 public Dimension getPreferredScrollableViewportSize()
217 return getPreferredSize();
221 public int getScrollableBlockIncrement(Rectangle visibleRect,
222 int orientation, int direction)
228 public boolean getScrollableTracksViewportHeight()
234 public boolean getScrollableTracksViewportWidth()
240 public int getScrollableUnitIncrement(Rectangle visibleRect,
241 int orientation, int direction)
250 * java.awt.event.AdjustmentListener#adjustmentValueChanged(java.awt.event
254 public void adjustmentValueChanged(AdjustmentEvent evt)
256 // update annotation label display
257 ap.getAlabels().setScrollOffset(-evt.getValue());
261 * Calculates the height of the annotation displayed in the annotation panel.
262 * Callers should normally call the ap.adjustAnnotationHeight method to ensure
263 * all annotation associated components are updated correctly.
266 public int adjustPanelHeight()
268 int height = av.calcPanelHeight();
269 this.setPreferredSize(new Dimension(1, height));
272 // revalidate only when the alignment panel is fully constructed
286 public void actionPerformed(ActionEvent evt)
288 AlignmentAnnotation[] aa = av.getAlignment().getAlignmentAnnotation();
293 Annotation[] anot = aa[activeRow].annotations;
295 if (anot.length < av.getColumnSelection().getMax())
297 Annotation[] temp = new Annotation[av.getColumnSelection().getMax()
299 System.arraycopy(anot, 0, temp, 0, anot.length);
301 aa[activeRow].annotations = anot;
304 String action = evt.getActionCommand();
305 if (action.equals(REMOVE))
307 for (int index : av.getColumnSelection().getSelected())
309 if (av.getAlignment().getHiddenColumns().isVisible(index))
315 else if (action.equals(LABEL))
317 String exMesg = collectAnnotVals(anot, LABEL);
318 String label = JvOptionPane.showInputDialog(this,
319 MessageManager.getString("label.enter_label"), exMesg);
326 if ((label.length() > 0) && !aa[activeRow].hasText)
328 aa[activeRow].hasText = true;
331 for (int index : av.getColumnSelection().getSelected())
333 if (!av.getAlignment().getHiddenColumns().isVisible(index))
338 if (anot[index] == null)
340 anot[index] = new Annotation(label, "", ' ', 0);
344 anot[index].displayCharacter = label;
348 else if (action.equals(COLOUR))
350 final Annotation[] fAnot = anot;
351 String title = MessageManager
352 .getString("label.select_foreground_colour");
353 ColourChooserListener listener = new ColourChooserListener()
356 public void colourSelected(Color c)
358 HiddenColumns hiddenColumns = av.getAlignment().getHiddenColumns();
359 for (int index : av.getColumnSelection().getSelected())
361 if (hiddenColumns.isVisible(index))
363 if (fAnot[index] == null)
365 fAnot[index] = new Annotation("", "", ' ', 0);
367 fAnot[index].colour = c;
371 JalviewColourChooser.showColourChooser(this,
372 title, Color.black, listener);
375 // HELIX, SHEET or STEM
378 String symbol = "\u03B1"; // alpha
380 if (action.equals(HELIX))
384 else if (action.equals(SHEET))
387 symbol = "\u03B2"; // beta
390 // Added by LML to color stems
391 else if (action.equals(STEM))
394 int column = av.getColumnSelection().getSelectedRanges().get(0)[0];
395 symbol = aa[activeRow].getDefaultRnaHelixSymbol(column);
398 if (!aa[activeRow].hasIcons)
400 aa[activeRow].hasIcons = true;
403 String label = JvOptionPane.showInputDialog(MessageManager
404 .getString("label.enter_label_for_the_structure"), symbol);
411 if ((label.length() > 0) && !aa[activeRow].hasText)
413 aa[activeRow].hasText = true;
414 if (action.equals(STEM))
416 aa[activeRow].showAllColLabels = true;
419 for (int index : av.getColumnSelection().getSelected())
421 if (!av.getAlignment().getHiddenColumns().isVisible(index))
426 if (anot[index] == null)
428 anot[index] = new Annotation(label, "", type, 0);
431 anot[index].secondaryStructure = type != 'S' ? type
432 : label.length() == 0 ? ' ' : label.charAt(0);
433 anot[index].displayCharacter = label;
438 av.getAlignment().validateAnnotation(aa[activeRow]);
439 ap.alignmentChanged();
440 ap.alignFrame.setMenusForViewport();
448 * Returns any existing annotation concatenated as a string. For each
449 * annotation, takes the description, if any, else the secondary structure
450 * character (if type is HELIX, SHEET or STEM), else the display character (if
457 private String collectAnnotVals(Annotation[] anots, String type)
459 // TODO is this method wanted? why? 'last' is not used
461 StringBuilder collatedInput = new StringBuilder(64);
463 ColumnSelection viscols = av.getColumnSelection();
464 HiddenColumns hidden = av.getAlignment().getHiddenColumns();
467 * the selection list (read-only view) is in selection order, not
468 * column order; make a copy so we can sort it
470 List<Integer> selected = new ArrayList<>(viscols.getSelected());
471 Collections.sort(selected);
472 for (int index : selected)
474 // always check for current display state - just in case
475 if (!hidden.isVisible(index))
479 String tlabel = null;
480 if (anots[index] != null)
481 { // LML added stem code
482 if (type.equals(HELIX) || type.equals(SHEET) || type.equals(STEM)
483 || type.equals(LABEL))
485 tlabel = anots[index].description;
486 if (tlabel == null || tlabel.length() < 1)
488 if (type.equals(HELIX) || type.equals(SHEET)
489 || type.equals(STEM))
491 tlabel = "" + anots[index].secondaryStructure;
495 tlabel = "" + anots[index].displayCharacter;
499 if (tlabel != null && !tlabel.equals(last))
501 if (last.length() > 0)
503 collatedInput.append(" ");
505 collatedInput.append(tlabel);
509 return collatedInput.toString();
513 * Action on right mouse pressed on Mac is to show a pop-up menu for the
514 * annotation. Action on left mouse pressed is to find which annotation is
515 * pressed and mark the start of a column selection or graph resize operation.
520 public void mousePressed(MouseEvent evt)
523 AlignmentAnnotation[] aa = av.getAlignment().getAlignmentAnnotation();
528 mouseDragLastX = evt.getX();
529 mouseDragLastY = evt.getY();
532 * add visible annotation heights until we reach the y
533 * position, to find which annotation it is in
538 final int y = evt.getY();
539 for (int i = 0; i < aa.length; i++)
543 height += aa[i].height;
552 else if (aa[i].graph > 0)
555 * we have clicked on a resizable graph annotation
564 * isPopupTrigger fires in mousePressed on Mac,
565 * not until mouseRelease on Windows
567 if (evt.isPopupTrigger() && activeRow != -1)
569 showPopupMenu(y, evt.getX());
573 ap.getScalePanel().mousePressed(evt);
577 * Construct and display a context menu at the right-click position
582 void showPopupMenu(final int y, int x)
584 if (av.getColumnSelection() == null
585 || av.getColumnSelection().isEmpty())
590 JPopupMenu pop = new JPopupMenu(
591 MessageManager.getString("label.structure_type"));
594 * Just display the needed structure options
596 if (av.getAlignment().isNucleotide())
598 item = new JMenuItem(STEM);
599 item.addActionListener(this);
604 item = new JMenuItem(HELIX);
605 item.addActionListener(this);
607 item = new JMenuItem(SHEET);
608 item.addActionListener(this);
611 item = new JMenuItem(LABEL);
612 item.addActionListener(this);
614 item = new JMenuItem(COLOUR);
615 item.addActionListener(this);
617 item = new JMenuItem(REMOVE);
618 item.addActionListener(this);
620 pop.show(this, x, y);
624 * Action on mouse up is to clear mouse drag data and call mouseReleased on
625 * ScalePanel, to deal with defining the selection group (if any) defined by
631 public void mouseReleased(MouseEvent evt)
636 mouseDragging = false;
637 dragMode = DragMode.Undefined;
638 ap.getScalePanel().mouseReleased(evt);
641 * isPopupTrigger is set in mouseReleased on Windows
642 * (in mousePressed on Mac)
644 if (evt.isPopupTrigger() && activeRow != -1)
646 showPopupMenu(evt.getY(), evt.getX());
658 public void mouseEntered(MouseEvent evt)
660 ap.getScalePanel().mouseEntered(evt);
670 public void mouseExited(MouseEvent evt)
672 ap.getScalePanel().mouseExited(evt);
682 public void mouseDragged(MouseEvent evt)
685 * todo: if dragMode is Undefined:
686 * - set to Select if dx > dy
687 * - set to Resize if dy > dx
688 * - do nothing if dx == dy
690 final int x = evt.getX();
691 final int y = evt.getY();
692 if (dragMode == DragMode.Undefined)
694 int dx = Math.abs(x - mouseDragLastX);
695 int dy = Math.abs(y - mouseDragLastY);
696 if (graphStretch == -1 || dx > dy)
699 * mostly horizontal drag, or not a graph annotation
701 dragMode = DragMode.Select;
706 * mostly vertical drag
708 dragMode = DragMode.Resize;
712 if (dragMode == DragMode.Undefined)
715 * drag is diagonal - defer deciding whether to
716 * treat as up/down or left/right
723 if (dragMode == DragMode.Resize)
726 * resize graph annotation if mouse was dragged up or down
728 int deltaY = mouseDragLastY - evt.getY();
731 AlignmentAnnotation graphAnnotation = av.getAlignment()
732 .getAlignmentAnnotation()[graphStretch];
733 int newHeight = Math.max(0, graphAnnotation.graphHeight + deltaY);
734 graphAnnotation.graphHeight = newHeight;
736 ap.paintAlignment(false, false);
742 * for mouse drag left or right, delegate to
743 * ScalePanel to adjust the column selection
745 ap.getScalePanel().mouseDragged(evt);
755 * Constructs the tooltip, and constructs and displays a status message, for
756 * the current mouse position
761 public void mouseMoved(MouseEvent evt)
763 AlignmentAnnotation[] aa = av.getAlignment().getAlignmentAnnotation();
767 this.setToolTipText(null);
774 for (int i = 0; i < aa.length; i++)
778 height += aa[i].height;
781 if (evt.getY() < height)
790 this.setToolTipText(null);
794 int column = (evt.getX() / av.getCharWidth())
795 + av.getRanges().getStartRes();
797 if (av.hasHiddenColumns())
799 column = av.getAlignment().getHiddenColumns()
800 .visibleToAbsoluteColumn(column);
803 AlignmentAnnotation ann = aa[row];
804 if (row > -1 && ann.annotations != null
805 && column < ann.annotations.length)
807 buildToolTip(ann, column, aa);
808 setStatusMessage(column, ann);
812 this.setToolTipText(null);
813 ap.alignFrame.statusBar.setText(" ");
818 * Builds a tooltip for the annotation at the current mouse position.
824 void buildToolTip(AlignmentAnnotation ann, int column,
825 AlignmentAnnotation[] anns)
827 if (ann.graphGroup > -1)
829 StringBuilder tip = new StringBuilder(32);
830 tip.append("<html>");
831 for (int i = 0; i < anns.length; i++)
833 if (anns[i].graphGroup == ann.graphGroup
834 && anns[i].annotations[column] != null)
836 tip.append(anns[i].label);
837 String description = anns[i].annotations[column].description;
838 if (description != null && description.length() > 0)
840 tip.append(" ").append(description);
845 if (tip.length() != 6)
847 tip.setLength(tip.length() - 4);
848 this.setToolTipText(tip.toString() + "</html>");
851 else if (ann.annotations[column] != null)
853 String description = ann.annotations[column].description;
854 if (description != null && description.length() > 0)
856 this.setToolTipText(JvSwingUtils.wrapTooltip(true, description));
860 this.setToolTipText(null); // no tooltip if null or empty description
865 // clear the tooltip.
866 this.setToolTipText(null);
871 * Constructs and displays the status bar message
876 void setStatusMessage(int column, AlignmentAnnotation ann)
879 * show alignment column and annotation description if any
881 StringBuilder text = new StringBuilder(32);
882 text.append(MessageManager.getString("label.column")).append(" ")
885 if (ann.annotations[column] != null)
887 String description = ann.annotations[column].description;
888 if (description != null && description.trim().length() > 0)
890 text.append(" ").append(description);
895 * if the annotation is sequence-specific, show the sequence number
896 * in the alignment, and (if not a gap) the residue and position
898 SequenceI seqref = ann.sequenceRef;
901 int seqIndex = av.getAlignment().findIndex(seqref);
904 text.append(", ").append(MessageManager.getString("label.sequence"))
905 .append(" ").append(seqIndex + 1);
906 char residue = seqref.getCharAt(column);
907 if (!Comparison.isGap(residue))
911 if (av.getAlignment().isNucleotide())
913 name = ResidueProperties.nucleotideName
914 .get(String.valueOf(residue));
915 text.append(" Nucleotide: ")
916 .append(name != null ? name : residue);
920 name = 'X' == residue ? "X"
921 : ('*' == residue ? "STOP"
922 : ResidueProperties.aa2Triplet
923 .get(String.valueOf(residue)));
924 text.append(" Residue: ").append(name != null ? name : residue);
926 int residuePos = seqref.findPosition(column);
927 text.append(" (").append(residuePos).append(")");
932 ap.alignFrame.statusBar.setText(text.toString());
942 public void mouseClicked(MouseEvent evt)
944 // if (activeRow != -1)
946 // AlignmentAnnotation[] aa = av.getAlignment().getAlignmentAnnotation();
947 // AlignmentAnnotation anot = aa[activeRow];
951 // TODO mouseClicked-content and drawCursor are quite experimental!
952 public void drawCursor(Graphics graphics, SequenceI seq, int res, int x1,
955 int pady = av.getCharHeight() / 5;
957 graphics.setColor(Color.black);
958 graphics.fillRect(x1, y1, av.getCharWidth(), av.getCharHeight());
960 if (av.validCharWidth)
962 graphics.setColor(Color.white);
964 char s = seq.getCharAt(res);
966 charOffset = (av.getCharWidth() - fm.charWidth(s)) / 2;
967 graphics.drawString(String.valueOf(s), charOffset + x1,
968 (y1 + av.getCharHeight()) - pady);
973 private volatile boolean imageFresh = false;
982 public void paintComponent(Graphics g)
984 super.paintComponent(g);
986 g.setColor(Color.white);
987 g.fillRect(0, 0, getWidth(), getHeight());
991 if (fastPaint || (getVisibleRect().width != g.getClipBounds().width)
992 || (getVisibleRect().height != g.getClipBounds().height))
994 g.drawImage(image, 0, 0, this);
999 imgWidth = (av.getRanges().getEndRes() - av.getRanges().getStartRes()
1000 + 1) * av.getCharWidth();
1005 if (image == null || imgWidth != image.getWidth(this)
1006 || image.getHeight(this) != getHeight())
1010 image = new BufferedImage(imgWidth,
1011 ap.getAnnotationPanel().getHeight(),
1012 BufferedImage.TYPE_INT_RGB);
1013 } catch (OutOfMemoryError oom)
1018 } catch (Exception x)
1023 "Couldn't allocate memory to redraw screen. Please restart Jalview",
1027 gg = (Graphics2D) image.getGraphics();
1031 gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
1032 RenderingHints.VALUE_ANTIALIAS_ON);
1035 gg.setFont(av.getFont());
1036 fm = gg.getFontMetrics();
1037 gg.setColor(Color.white);
1038 gg.fillRect(0, 0, imgWidth, image.getHeight());
1042 drawComponent(gg, av.getRanges().getStartRes(),
1043 av.getRanges().getEndRes() + 1);
1045 g.drawImage(image, 0, 0, this);
1049 * set true to enable redraw timing debug output on stderr
1051 private final boolean debugRedraw = false;
1054 * non-Thread safe repaint
1057 * repaint with horizontal shift in alignment
1059 public void fastPaint(int horizontal)
1061 if ((horizontal == 0) || gg == null
1062 || av.getAlignment().getAlignmentAnnotation() == null
1063 || av.getAlignment().getAlignmentAnnotation().length < 1
1064 || av.isCalcInProgress())
1070 int sr = av.getRanges().getStartRes();
1071 int er = av.getRanges().getEndRes() + 1;
1074 gg.copyArea(0, 0, imgWidth, getHeight(),
1075 -horizontal * av.getCharWidth(), 0);
1077 if (horizontal > 0) // scrollbar pulled right, image to the left
1079 transX = (er - sr - horizontal) * av.getCharWidth();
1080 sr = er - horizontal;
1082 else if (horizontal < 0)
1084 er = sr - horizontal;
1087 gg.translate(transX, 0);
1089 drawComponent(gg, sr, er);
1091 gg.translate(-transX, 0);
1095 // Call repaint on alignment panel so that repaints from other alignment
1096 // panel components can be aggregated. Otherwise performance of the overview
1097 // window and others may be adversely affected.
1098 av.getAlignPanel().repaint();
1101 private volatile boolean lastImageGood = false;
1113 public void drawComponent(Graphics g, int startRes, int endRes)
1115 BufferedImage oldFaded = fadedImage;
1116 if (av.isCalcInProgress())
1120 lastImageGood = false;
1123 // We'll keep a record of the old image,
1124 // and draw a faded image until the calculation
1127 && (fadedImage == null || fadedImage.getWidth() != imgWidth
1128 || fadedImage.getHeight() != image.getHeight()))
1130 // System.err.println("redraw faded image ("+(fadedImage==null ?
1131 // "null image" : "") + " lastGood="+lastImageGood+")");
1132 fadedImage = new BufferedImage(imgWidth, image.getHeight(),
1133 BufferedImage.TYPE_INT_RGB);
1135 Graphics2D fadedG = (Graphics2D) fadedImage.getGraphics();
1137 fadedG.setColor(Color.white);
1138 fadedG.fillRect(0, 0, imgWidth, image.getHeight());
1140 fadedG.setComposite(
1141 AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .3f));
1142 fadedG.drawImage(image, 0, 0, this);
1145 // make sure we don't overwrite the last good faded image until all
1146 // calculations have finished
1147 lastImageGood = false;
1152 if (fadedImage != null)
1154 oldFaded = fadedImage;
1159 g.setColor(Color.white);
1160 g.fillRect(0, 0, (endRes - startRes) * av.getCharWidth(), getHeight());
1162 g.setFont(av.getFont());
1165 fm = g.getFontMetrics();
1168 if ((av.getAlignment().getAlignmentAnnotation() == null)
1169 || (av.getAlignment().getAlignmentAnnotation().length < 1))
1171 g.setColor(Color.white);
1172 g.fillRect(0, 0, getWidth(), getHeight());
1173 g.setColor(Color.black);
1174 if (av.validCharWidth)
1176 g.drawString(MessageManager
1177 .getString("label.alignment_has_no_annotations"), 20, 15);
1182 lastImageGood = renderer.drawComponent(this, av, g, activeRow, startRes,
1184 if (!lastImageGood && fadedImage == null)
1186 fadedImage = oldFaded;
1191 public FontMetrics getFontMetrics()
1197 public Image getFadedImage()
1203 public int getFadedImageWidth()
1208 private int[] bounds = new int[2];
1211 public int[] getVisibleVRange()
1213 if (ap != null && ap.getAlabels() != null)
1215 int sOffset = -ap.getAlabels().getScrollOffset();
1216 int visHeight = sOffset + ap.annotationSpaceFillerHolder.getHeight();
1217 bounds[0] = sOffset;
1218 bounds[1] = visHeight;
1228 * Try to ensure any references held are nulled
1230 public void dispose()
1240 * I created the renderer so I will dispose of it
1242 if (renderer != null)
1249 public void propertyChange(PropertyChangeEvent evt)
1251 // Respond to viewport range changes (e.g. alignment panel was scrolled)
1252 // Both scrolling and resizing change viewport ranges: scrolling changes
1253 // both start and end points, but resize only changes end values.
1254 // Here we only want to fastpaint on a scroll, with resize using a normal
1255 // paint, so scroll events are identified as changes to the horizontal or
1256 // vertical start value.
1257 if (evt.getPropertyName().equals(ViewportRanges.STARTRES))
1259 fastPaint((int) evt.getNewValue() - (int) evt.getOldValue());
1261 else if (evt.getPropertyName().equals(ViewportRanges.STARTRESANDSEQ))
1263 fastPaint(((int[]) evt.getNewValue())[0]
1264 - ((int[]) evt.getOldValue())[0]);
1266 else if (evt.getPropertyName().equals(ViewportRanges.MOVE_VIEWPORT))