2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
\r
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
\r
5 * This file is part of Jalview.
\r
7 * Jalview is free software: you can redistribute it and/or
\r
8 * modify it under the terms of the GNU General Public License
\r
9 * as published by the Free Software Foundation, either version 3
\r
10 * of the License, or (at your option) any later version.
\r
12 * Jalview is distributed in the hope that it will be useful, but
\r
13 * WITHOUT ANY WARRANTY; without even the implied warranty
\r
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r
15 * PURPOSE. See the GNU General Public License for more details.
\r
17 * You should have received a copy of the GNU General Public License
\r
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
\r
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
\r
21 package jalview.appletgui;
\r
23 import jalview.datamodel.AlignmentAnnotation;
\r
24 import jalview.datamodel.Annotation;
\r
25 import jalview.renderer.AnnotationRenderer;
\r
26 import jalview.renderer.AwtRenderPanelI;
\r
27 import jalview.util.MessageManager;
\r
28 import jalview.util.Platform;
\r
30 import java.awt.Color;
\r
31 import java.awt.Dimension;
\r
32 import java.awt.Font;
\r
33 import java.awt.FontMetrics;
\r
34 import java.awt.Graphics;
\r
35 import java.awt.Image;
\r
36 import java.awt.MenuItem;
\r
37 import java.awt.Panel;
\r
38 import java.awt.PopupMenu;
\r
39 import java.awt.event.ActionEvent;
\r
40 import java.awt.event.ActionListener;
\r
41 import java.awt.event.AdjustmentEvent;
\r
42 import java.awt.event.AdjustmentListener;
\r
43 import java.awt.event.InputEvent;
\r
44 import java.awt.event.MouseEvent;
\r
45 import java.awt.event.MouseListener;
\r
46 import java.awt.event.MouseMotionListener;
\r
48 public class AnnotationPanel extends Panel implements AwtRenderPanelI,
\r
49 AdjustmentListener, ActionListener, MouseListener,
\r
58 final String HELIX = "Helix";
\r
60 final String SHEET = "Sheet";
\r
63 * For RNA secondary structure "stems" aka helices
\r
65 final String STEM = "RNA Helix";
\r
67 final String LABEL = "Label";
\r
69 final String REMOVE = "Remove Annotation";
\r
71 final String COLOUR = "Colour";
\r
73 final Color HELIX_COLOUR = Color.red.darker();
\r
75 final Color SHEET_COLOUR = Color.green.darker().darker();
\r
85 boolean fastPaint = false;
\r
87 // Used For mouse Dragging and resizing graphs
\r
88 int graphStretch = -1;
\r
90 int graphStretchY = -1;
\r
92 boolean mouseDragging = false;
\r
94 public static int GRAPH_HEIGHT = 40;
\r
96 boolean MAC = false;
\r
98 public final AnnotationRenderer renderer;
\r
100 public AnnotationPanel(AlignmentPanel ap)
\r
102 MAC = Platform.isAMac();
\r
106 int height = adjustPanelHeight();
\r
107 ap.apvscroll.setValues(0, getSize().height, 0, height);
\r
109 addMouseMotionListener(this);
\r
111 addMouseListener(this);
\r
113 // ap.annotationScroller.getVAdjustable().addAdjustmentListener( this );
\r
114 renderer = new AnnotationRenderer();
\r
117 public AnnotationPanel(AlignViewport av)
\r
120 renderer = new AnnotationRenderer();
\r
124 public void adjustmentValueChanged(AdjustmentEvent evt)
\r
135 public void actionPerformed(ActionEvent evt)
\r
137 AlignmentAnnotation[] aa = av.getAlignment().getAlignmentAnnotation();
\r
142 Annotation[] anot = aa[activeRow].annotations;
\r
144 if (anot.length < av.getColumnSelection().getMax())
\r
146 Annotation[] temp = new Annotation[av.getColumnSelection().getMax() + 2];
\r
147 System.arraycopy(anot, 0, temp, 0, anot.length);
\r
149 aa[activeRow].annotations = anot;
\r
153 if (av.getColumnSelection() != null
\r
154 && av.getColumnSelection().size() > 0
\r
155 && anot[av.getColumnSelection().getMin()] != null)
\r
157 label = anot[av.getColumnSelection().getMin()].displayCharacter;
\r
160 if (evt.getActionCommand().equals(REMOVE))
\r
162 for (int i = 0; i < av.getColumnSelection().size(); i++)
\r
164 anot[av.getColumnSelection().columnAt(i)] = null;
\r
167 else if (evt.getActionCommand().equals(LABEL))
\r
169 label = enterLabel(label, "Enter Label");
\r
176 if ((label.length() > 0) && !aa[activeRow].hasText)
\r
178 aa[activeRow].hasText = true;
\r
181 for (int i = 0; i < av.getColumnSelection().size(); i++)
\r
183 int index = av.getColumnSelection().columnAt(i);
\r
185 if (!av.getColumnSelection().isVisible(index))
\r
190 if (anot[index] == null)
\r
192 anot[index] = new Annotation(label, "", ' ', 0);
\r
195 anot[index].displayCharacter = label;
\r
198 else if (evt.getActionCommand().equals(COLOUR))
\r
200 UserDefinedColours udc = new UserDefinedColours(this, Color.black,
\r
203 Color col = udc.getColor();
\r
205 for (int i = 0; i < av.getColumnSelection().size(); i++)
\r
207 int index = av.getColumnSelection().columnAt(i);
\r
209 if (!av.getColumnSelection().isVisible(index))
\r
214 if (anot[index] == null)
\r
216 anot[index] = new Annotation("", "", ' ', 0);
\r
219 anot[index].colour = col;
\r
226 String symbol = "\u03B1";
\r
228 if (evt.getActionCommand().equals(HELIX))
\r
232 else if (evt.getActionCommand().equals(SHEET))
\r
238 // Added by LML to color stems
\r
239 else if (evt.getActionCommand().equals(STEM))
\r
245 if (!aa[activeRow].hasIcons)
\r
247 aa[activeRow].hasIcons = true;
\r
250 label = enterLabel(symbol, "Enter Label");
\r
257 if ((label.length() > 0) && !aa[activeRow].hasText)
\r
259 aa[activeRow].hasText = true;
\r
260 if (evt.getActionCommand().equals(STEM))
\r
262 aa[activeRow].showAllColLabels = true;
\r
266 for (int i = 0; i < av.getColumnSelection().size(); i++)
\r
268 int index = av.getColumnSelection().columnAt(i);
\r
270 if (!av.getColumnSelection().isVisible(index))
\r
275 if (anot[index] == null)
\r
277 anot[index] = new Annotation(label, "", type, 0);
\r
280 anot[index].secondaryStructure = type != 'S' ? type : label
\r
281 .length() == 0 ? ' ' : label.charAt(0);
\r
282 anot[index].displayCharacter = label;
\r
286 av.getAlignment().validateAnnotation(aa[activeRow]);
\r
288 ap.alignmentChanged();
\r
289 adjustPanelHeight();
\r
295 String enterLabel(String text, String label)
\r
297 EditNameDialog dialog = new EditNameDialog(text, null, label, null,
\r
298 ap.alignFrame, "Enter Label", 400, 200, true);
\r
302 return dialog.getName();
\r
311 public void mousePressed(MouseEvent evt)
\r
313 AlignmentAnnotation[] aa = av.getAlignment().getAlignmentAnnotation();
\r
319 int height = -scrollOffset;
\r
322 for (int i = 0; i < aa.length; i++)
\r
326 height += aa[i].height;
\r
329 if (evt.getY() < height)
\r
331 if (aa[i].editable)
\r
335 else if (aa[i].graph > 0)
\r
339 graphStretchY = evt.getY();
\r
346 if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK
\r
347 && activeRow != -1)
\r
349 if (av.getColumnSelection() == null)
\r
354 PopupMenu pop = new PopupMenu(
\r
355 MessageManager.getString("label.structure_type"));
\r
358 * Just display the needed structure options
\r
360 if (av.getAlignment().isNucleotide() == true)
\r
362 item = new MenuItem(STEM);
\r
363 item.addActionListener(this);
\r
368 item = new MenuItem(HELIX);
\r
369 item.addActionListener(this);
\r
371 item = new MenuItem(SHEET);
\r
372 item.addActionListener(this);
\r
375 item = new MenuItem(LABEL);
\r
376 item.addActionListener(this);
\r
378 item = new MenuItem(COLOUR);
\r
379 item.addActionListener(this);
\r
381 item = new MenuItem(REMOVE);
\r
382 item.addActionListener(this);
\r
384 ap.alignFrame.add(pop);
\r
385 pop.show(this, evt.getX(), evt.getY());
\r
390 ap.scalePanel.mousePressed(evt);
\r
394 public void mouseReleased(MouseEvent evt)
\r
397 graphStretchY = -1;
\r
398 mouseDragging = false;
\r
399 if (needValidating)
\r
402 needValidating = false;
\r
404 ap.scalePanel.mouseReleased(evt);
\r
408 public void mouseClicked(MouseEvent evt)
\r
412 boolean needValidating = false;
\r
415 public void mouseDragged(MouseEvent evt)
\r
417 if (graphStretch > -1)
\r
419 av.getAlignment().getAlignmentAnnotation()[graphStretch].graphHeight += graphStretchY
\r
421 if (av.getAlignment().getAlignmentAnnotation()[graphStretch].graphHeight < 0)
\r
423 av.getAlignment().getAlignmentAnnotation()[graphStretch].graphHeight = 0;
\r
425 graphStretchY = evt.getY();
\r
426 av.calcPanelHeight();
\r
427 needValidating = true;
\r
428 ap.paintAlignment(true);
\r
432 ap.scalePanel.mouseDragged(evt);
\r
437 public void mouseMoved(MouseEvent evt)
\r
439 AlignmentAnnotation[] aa = av.getAlignment().getAlignmentAnnotation();
\r
446 int height = -scrollOffset;
\r
447 for (int i = 0; i < aa.length; i++)
\r
452 height += aa[i].height;
\r
455 if (evt.getY() < height)
\r
462 int res = evt.getX() / av.getCharWidth() + av.getStartRes();
\r
464 if (av.hasHiddenColumns())
\r
466 res = av.getColumnSelection().adjustForHiddenColumns(res);
\r
469 if (row > -1 && res < aa[row].annotations.length
\r
470 && aa[row].annotations[res] != null)
\r
472 StringBuffer text = new StringBuffer("Sequence position " + (res + 1));
\r
473 if (aa[row].annotations[res].description != null)
\r
475 text.append(" " + aa[row].annotations[res].description);
\r
477 ap.alignFrame.statusBar.setText(text.toString());
\r
482 public void mouseEntered(MouseEvent evt)
\r
484 ap.scalePanel.mouseEntered(evt);
\r
488 public void mouseExited(MouseEvent evt)
\r
490 ap.scalePanel.mouseExited(evt);
\r
493 public int adjustPanelHeight()
\r
495 return adjustPanelHeight(true);
\r
498 public int adjustPanelHeight(boolean repaint)
\r
500 int height = av.calcPanelHeight();
\r
501 this.setSize(new Dimension(getSize().width, height));
\r
510 * calculate the height for visible annotation, revalidating bounds where
\r
511 * necessary ABSTRACT GUI METHOD
\r
513 * @return total height of annotation
\r
516 public void addEditableColumn(int i)
\r
518 if (activeRow == -1)
\r
520 AlignmentAnnotation[] aa = av.getAlignment().getAlignmentAnnotation();
\r
526 for (int j = 0; j < aa.length; j++)
\r
528 if (aa[j].editable)
\r
538 public void update(Graphics g)
\r
544 public void paint(Graphics g)
\r
546 Dimension d = getSize();
\r
547 imgWidth = d.width;
\r
548 // (av.endRes - av.startRes + 1) * av.charWidth;
\r
549 if (imgWidth < 1 || d.height < 1)
\r
553 if (image == null || imgWidth != image.getWidth(this)
\r
554 || d.height != image.getHeight(this))
\r
556 image = createImage(imgWidth, d.height);
\r
557 gg = image.getGraphics();
\r
558 gg.setFont(av.getFont());
\r
559 fm = gg.getFontMetrics();
\r
565 g.drawImage(image, 0, 0, this);
\r
570 gg.setColor(Color.white);
\r
571 gg.fillRect(0, 0, getSize().width, getSize().height);
\r
572 drawComponent(gg, av.startRes, av.endRes + 1);
\r
574 g.drawImage(image, 0, 0, this);
\r
577 public void fastPaint(int horizontal)
\r
579 if (horizontal == 0
\r
580 || av.getAlignment().getAlignmentAnnotation() == null
\r
581 || av.getAlignment().getAlignmentAnnotation().length < 1)
\r
587 gg.copyArea(0, 0, imgWidth, getSize().height,
\r
588 -horizontal * av.getCharWidth(), 0);
\r
589 int sr = av.startRes, er = av.endRes + 1, transX = 0;
\r
591 if (horizontal > 0) // scrollbar pulled right, image to the left
\r
593 transX = (er - sr - horizontal) * av.getCharWidth();
\r
594 sr = er - horizontal;
\r
596 else if (horizontal < 0)
\r
598 er = sr - horizontal;
\r
601 gg.translate(transX, 0);
\r
603 drawComponent(gg, sr, er);
\r
605 gg.translate(-transX, 0);
\r
621 public void drawComponent(Graphics g, int startRes, int endRes)
\r
623 Font ofont = av.getFont();
\r
626 g.setColor(Color.white);
\r
627 g.fillRect(0, 0, (endRes - startRes) * av.getCharWidth(),
\r
632 fm = g.getFontMetrics();
\r
635 if ((av.getAlignment().getAlignmentAnnotation() == null)
\r
636 || (av.getAlignment().getAlignmentAnnotation().length < 1))
\r
638 g.setColor(Color.white);
\r
639 g.fillRect(0, 0, getSize().width, getSize().height);
\r
640 g.setColor(Color.black);
\r
641 if (av.validCharWidth)
\r
643 g.drawString(MessageManager
\r
644 .getString("label.alignment_has_no_annotations"), 20, 15);
\r
649 g.translate(0, -scrollOffset);
\r
650 renderer.drawComponent(this, av, g, activeRow, startRes, endRes);
\r
651 g.translate(0, +scrollOffset);
\r
654 int scrollOffset = 0;
\r
656 public void setScrollOffset(int value, boolean repaint)
\r
658 scrollOffset = value;
\r
666 public FontMetrics getFontMetrics()
\r
672 public Image getFadedImage()
\r
678 public int getFadedImageWidth()
\r
683 private int[] bounds = new int[2];
\r
686 public int[] getVisibleVRange()
\r
688 if (ap != null && ap.alabels != null)
\r
690 int sOffset = -ap.alabels.scrollOffset;
\r
691 int visHeight = sOffset + ap.annotationPanelHolder.getHeight();
\r
692 bounds[0] = sOffset;
\r
693 bounds[1] = visHeight;
\r