/* * 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.gui; import jalview.api.AlignViewportI; import jalview.bin.Cache; import jalview.datamodel.AlignmentI; import jalview.renderer.OverviewRenderer; import jalview.renderer.OverviewResColourFinder; import jalview.viewmodel.OverviewDimensions; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.image.BufferedImage; import javax.swing.JPanel; @SuppressWarnings("serial") public class OverviewCanvas extends JPanel { private static final Color TRANS_GREY = new Color(100, 100, 100, 25); // This is set true if the alignment view changes whilst // the overview is being calculated private volatile boolean restart = false; private volatile boolean updaterunning = false; private boolean disposed = false; BufferedImage lastMiniMe = null; // Can set different properties in this seqCanvas than // main visible SeqCanvas private SequenceRenderer sr; private jalview.renderer.seqfeatures.FeatureRenderer fr; private OverviewDimensions od; private OverviewRenderer or = null; private AlignViewportI av; private OverviewResColourFinder cf; private ProgressPanel progressPanel; private boolean showSequenceFeatures; private boolean showAnnotation; private jalview.api.FeatureRenderer featureRenderer; private OverviewPanel panel; private boolean showProgress; public OverviewCanvas(OverviewPanel panel, OverviewDimensions overviewDims, AlignViewportI alignvp, ProgressPanel pp) { this.panel = panel; od = overviewDims; lastMiniMe = null; av = alignvp; progressPanel = pp; showProgress = (pp != null); sr = new SequenceRenderer(av); sr.renderGaps = false; fr = new jalview.renderer.seqfeatures.FeatureRenderer(av); boolean useLegacy = Cache.getDefault(Preferences.USE_LEGACY_GAP, false); Color gapCol = Cache.getDefaultColour(Preferences.GAP_COLOUR, jalview.renderer.OverviewResColourFinder.OVERVIEW_DEFAULT_GAP); Color hiddenCol = Cache.getDefaultColour(Preferences.HIDDEN_COLOUR, jalview.renderer.OverviewResColourFinder.OVERVIEW_DEFAULT_HIDDEN); cf = new OverviewResColourFinder(useLegacy, gapCol, hiddenCol); setSize(od.getWidth(), od.getHeight()); setPreferredSize(getSize()); // BH 2019.07.29 added } /** * Update the overview dimensions object used by the canvas (e.g. if we change * from showing hidden columns to hiding them or vice versa) * * @param overviewDims */ public void resetOviewDims(OverviewDimensions overviewDims) { od = overviewDims; lastMiniMe = null; } /** * Signals to drawing code that the associated alignment viewport has changed * and a redraw will be required */ public boolean restartDraw() { synchronized (this) { if (updaterunning) { setRestart("restartDraw"); } else { updaterunning = true; restart = false; } return restart; } } private void setRestart(String why) { // System.out.println("OC restart true " + why); restart = true; if (or != null) { or.setRedraw(true); } } /** * Draw the overview sequences * * @param showSequenceFeatures * true if sequence features are to be shown * @param showAnnotation * true if the annotation is to be shown * @param featureRenderer * the renderer to transfer feature colouring from */ public void draw(boolean showSequenceFeatures, boolean showAnnotation, jalview.api.FeatureRenderer featureRenderer) { this.showSequenceFeatures = showSequenceFeatures; this.showAnnotation = showAnnotation; this.featureRenderer = featureRenderer; if (showSequenceFeatures) { fr.transferSettings(featureRenderer); } setPreferredSize(new Dimension(od.getWidth(), od.getHeight())); AlignmentI al = av.getAlignment(); or = new OverviewRenderer(panel.ap, fr, od, al, av.getResidueShading(), cf, showProgress); if (showProgress) { or.addPropertyChangeListener(progressPanel); } or.drawMiniMe(); } synchronized void finalizeDraw(BufferedImage miniMe) { if (showProgress && or != null) { or.removePropertyChangeListener(progressPanel); } if (restart) { or = null; restart = false; if (!disposed) { draw(showSequenceFeatures, showAnnotation, featureRenderer); } } else { if (showAnnotation && or != null) { or.drawGraph(av.getAlignmentConservationAnnotation()); } or = null; updaterunning = false; lastMiniMe = miniMe; repaint(); } } @Override public void paintComponent(Graphics g) { int w = getWidth(); int h = getHeight(); if (w == 0 || od.getBoxWidth() <= 0) { // BH 2019.07.27 removes two unnecessary paints, since boxwidth can be -1 // or 0 during early-stage painting return; } boolean drawMe = (lastMiniMe != null); if (restart) { if (drawMe) { g.drawImage(lastMiniMe, 0, 0, w, h, this); } else { g.setColor(Color.white); g.fillRect(0, 0, w, h); } g.setColor(TRANS_GREY); g.fillRect(0, 0, w, h); drawMe = false; } else if (drawMe) { // is this a resize? if (w != od.getWidth() || h != od.getHeight()) { lastMiniMe = null; return; // // if there is annotation, scale the alignment and annotation // // separately // if (od.getGraphHeight() <= 0 && od.getSequencesHeight() <= 0) // { // od.setWidth(w); // od.setHeight(h); // return; // } // try // { // BufferedImage topImage = lastMiniMe.getSubimage(0, 0, // od.getWidth(), od.getSequencesHeight()); // // BufferedImage bottomImage = lastMiniMe.getSubimage(0, // od.getSequencesHeight(), od.getWidth(), // od.getGraphHeight()); // // // must be done at this point as we rely on using old width/height // // above, and new width/height below // od.setWidth(w); // od.setHeight(h); // // // stick the images back together so lastMiniMe is consistent in the // // event of a repaint - BUT probably not thread safe // // // right -- this fails with fast user action. // // lastMiniMe = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); // Graphics lg = lastMiniMe.getGraphics(); // lg.drawImage(topImage, 0, 0, w, od.getSequencesHeight(), null); // lg.drawImage(bottomImage, 0, od.getSequencesHeight(), w, // od.getGraphHeight(), this); // lg.dispose(); // // } catch (RasterFormatException e) // { // System.out.println("OC Raster Exception " + lastMiniMe.getWidth() // + "/" + w + "," + lastMiniMe.getHeight() + "/" + h + " " // + od.getSequencesHeight() + " " + od.getGraphHeight()); // } // BH 2019: removed -- this is now taken care of using vpbox in // OverviewDimension // // make sure the box is in the right place // od.setBoxPosition(av.getAlignment().getHiddenSequences(), // av.getAlignment().getHiddenColumns()); } } if (drawMe) { g.drawImage(lastMiniMe, 0, 0, w, h, this); } // draw the box g.setColor(Color.red); // System.out.println("OC paintComponent nd=" + ndraw + " nr=" + nrepaint // + " np=" + ++npaint); od.drawBox(g); } // private int ndraw, npaint, nrepaint; // @Override // public void repaint() // { // System.out.println("OC repaint " + (++nrepaint)); // super.repaint(); // } public void dispose() { disposed = true; od = null; lastMiniMe = null; synchronized (this) { setRestart("dispose"); } } }