/* * 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); od = new OverviewDimensions(av); 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) { od.setBoxX(evt.getX()); od.setBoxY(evt.getY()); checkValid(); } @Override public void mouseReleased(MouseEvent evt) { od.setBoxX(evt.getX()); od.setBoxY(evt.getY()); checkValid(); } @Override public void mouseDragged(MouseEvent evt) { od.setBoxX(evt.getX()); od.setBoxY(evt.getY()); checkValid(); } /** * Check box dimensions and scroll positions and correct if necessary */ private void checkValid() { od.checkValid(); 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().getHeight() + av.getAlignment().getHiddenSequences().getSize(); 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 hasHiddenRows = av.hasHiddenRows(); final boolean hasHiddenCols = av.hasHiddenColumns(); boolean hiddenRow = false; for (int row = 0; row <= od.getSequencesHeight() && !resizeAgain; row++) { if ((int) (row * sampleRow) == lastrow) { sameRow++; continue; } else { // this should largely be a method in Alignment hiddenRow = false; if (hasHiddenRows) { seq = av.getAlignment().getHiddenSequences() .getHiddenSequence(lastrow); if (seq == null) { int index = av.getAlignment().getHiddenSequences() .findIndexWithoutHiddenSeqs(lastrow); seq = av.getAlignment().getSequenceAt(index); } else { hiddenRow = true; } } else { seq = av.getAlignment().getSequenceAt(lastrow); } // end of Alignment method 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); og.drawRect(od.getBoxX(), od.getBoxY(), od.getBoxWidth(), od.getBoxHeight()); og.drawRect(od.getBoxX() + 1, od.getBoxY() + 1, od.getBoxWidth() - 2, od.getBoxHeight() - 2); g.drawImage(offscreen, 0, 0, this); } } }