/* * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) * Copyright (C) $$Year-Rel$$ The Jalview Authors * * This file is part of Jalview. * * Jalview is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * Jalview is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Jalview. If not, see . * The Jalview Authors are detailed in the 'AUTHORS' file. */ package jalview.appletgui; import jalview.viewmodel.OverviewDimensions; import java.awt.Color; import java.awt.Dimension; import java.awt.Frame; import java.awt.Graphics; import java.awt.Image; import java.awt.Panel; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; public class OverviewPanel extends Panel implements Runnable, MouseMotionListener, MouseListener { private OverviewDimensions od; private Image miniMe; private Image offscreen; private AlignViewport av; private AlignmentPanel ap; private boolean resizing = false; // This is set true if the user resizes whilst // the overview is being calculated private boolean resizeAgain = false; // Can set different properties in this seqCanvas than // main visible SeqCanvas private SequenceRenderer sr; private FeatureRenderer fr; private Frame nullFrame; public OverviewPanel(AlignmentPanel ap) { this.av = ap.av; this.ap = ap; setLayout(null); nullFrame = new Frame(); nullFrame.addNotify(); sr = new SequenceRenderer(av); sr.graphics = nullFrame.getGraphics(); sr.renderGaps = false; sr.forOverview = true; fr = new FeatureRenderer(av); boolean showAnnotation = false; // TODO: in applet this was getSequenceConsensusHash() // check if it makes any functional difference: hconsensus or conservation if (av.getAlignmentConservationAnnotation() == null) { showAnnotation = true; } od = new OverviewDimensions(av, showAnnotation); setSize(new Dimension(od.getWidth(), od.getHeight())); addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent evt) { if ((getWidth() != od.getWidth()) || (getHeight() != (od.getHeight()))) { updateOverviewImage(); } } }); addMouseMotionListener(this); addMouseListener(this); updateOverviewImage(); } @Override public void mouseEntered(MouseEvent evt) { } @Override public void mouseExited(MouseEvent evt) { } @Override public void mouseClicked(MouseEvent evt) { } @Override public void mouseMoved(MouseEvent evt) { } @Override public void mousePressed(MouseEvent evt) { mouseAction(evt); } @Override public void mouseReleased(MouseEvent evt) { mouseAction(evt); } @Override public void mouseDragged(MouseEvent evt) { mouseAction(evt); } private void mouseAction(MouseEvent evt) { od.updateViewportFromMouse(evt.getX(), evt.getY()); ap.setScrollValues(od.getScrollCol(), od.getScrollRow()); ap.paintAlignment(false); } /** * DOCUMENT ME! */ public void updateOverviewImage() { if (resizing) { resizeAgain = true; return; } if (av.isShowSequenceFeatures()) { fr.transferSettings(ap.seqPanel.seqCanvas.fr); } resizing = true; if ((getWidth() > 0) && (getHeight() > 0)) { od.setWidth(getWidth()); // width = getWidth(); od.setHeight(getHeight()); // sequencesHeight = getHeight() - graphHeight; } setSize(new Dimension(od.getWidth(), od.getHeight())); Thread thread = new Thread(this); thread.start(); repaint(); } @Override public void run() { miniMe = null; if (av.isShowSequenceFeatures()) { fr.transferSettings(ap.seqPanel.seqCanvas.getFeatureRenderer()); } if (getSize().width > 0 && getSize().height > 0) { od.setWidth(getSize().width); od.setHeight(getSize().height - od.getGraphHeight()); } setSize(new Dimension(od.getWidth(), od.getHeight())); miniMe = nullFrame.createImage(od.getWidth(), od.getHeight()); offscreen = nullFrame.createImage(od.getWidth(), od.getHeight()); Graphics mg = miniMe.getGraphics(); // od.updateScales(); int alwidth = av.getAlignment().getWidth(); int alheight = av.getAlignment().getAbsoluteHeight(); float sampleCol = alwidth / (float) od.getWidth(); float sampleRow = alheight / (float) od.getSequencesHeight(); buildImage(sampleRow, sampleCol, mg); if (av.getAlignmentConservationAnnotation() != null) { for (int col = 0; col < od.getWidth() && !resizeAgain; col++) { mg.translate(col, od.getSequencesHeight()); ap.annotationPanel.renderer.drawGraph(mg, av.getAlignmentConservationAnnotation(), av.getAlignmentConservationAnnotation().annotations, (int) (sampleCol) + 1, od.getGraphHeight(), (int) (col * sampleCol), (int) (col * sampleCol) + 1); mg.translate(-col, -od.getSequencesHeight()); } } System.gc(); resizing = false; setBoxPosition(); if (resizeAgain) { resizeAgain = false; updateOverviewImage(); } } private void buildImage(float sampleRow, float sampleCol, Graphics mg) { int lastcol = 0; int lastrow = 0; int xstart = 0; int ystart = 0; Color color = Color.yellow; int sameRow = 0; int sameCol = 0; jalview.datamodel.SequenceI seq = null; final boolean hasHiddenCols = av.hasHiddenColumns(); boolean hiddenRow = false; for (int row = 0; row <= od.getSequencesHeight() && !resizeAgain; row++) { if ((int) (row * sampleRow) == lastrow) { sameRow++; } else { // get the sequence which would be at alignment index 'lastrow' if no // columns were hidden, and determine whether it is hidden or not hiddenRow = av.getAlignment().isHidden(lastrow); seq = av.getAlignment().getSequenceAtAbsoluteIndex(lastrow); for (int col = 0; col < od.getWidth(); col++) { if ((int) (col * sampleCol) == lastcol && (int) (row * sampleRow) == lastrow) { sameCol++; } else { lastcol = (int) (col * sampleCol); color = getColumnColourFromSequence(seq, hiddenRow, hasHiddenCols, lastcol); mg.setColor(color); if (sameCol == 1 && sameRow == 1) { mg.drawLine(xstart, ystart, xstart, ystart); } else { mg.fillRect(xstart, ystart, sameCol, sameRow); } xstart = col; sameCol = 1; } } lastrow = (int) (row * sampleRow); ystart = row; sameRow = 1; } } } /* * Find the colour of a sequence at a specified column position */ private Color getColumnColourFromSequence( jalview.datamodel.SequenceI seq, boolean hiddenRow, boolean hasHiddenCols, int lastcol) { Color color; if (seq.getLength() > lastcol) { color = sr.getResidueBoxColour(seq, lastcol); if (av.isShowSequenceFeatures()) { color = fr.findFeatureColour(color, seq, lastcol); } } else { color = Color.white; // White } if (hiddenRow || (hasHiddenCols && !av.getColumnSelection() .isVisible(lastcol))) { color = color.darker().darker(); } return color; } /** * Update the overview panel box when the associated alignment panel is * changed * */ public void setBoxPosition() { od.setBoxPosition(); repaint(); } @Override public void update(Graphics g) { paint(g); } @Override public void paint(Graphics g) { Graphics og = offscreen.getGraphics(); if (miniMe != null) { og.drawImage(miniMe, 0, 0, this); og.setColor(Color.red); od.drawBox(og); g.drawImage(offscreen, 0, 0, this); } } }